9#include "tpcclibConfig.h"
34double func_1tcm(
int parNr,
double *p,
void*);
36typedef struct FITDATA {
67static char *info[] = {
68 "Non-linear fitting of 1TCM to regional TTACs using PTAC as input function",
69 "and BTAC for vascular volume correction. Delay time between TTACs and",
70 "PTAC/BTAC is fitted by default. Regional radioactivity concentration is",
71 "modelled as Cpet(t) = Vb*Cb(t) + Ct(t),",
72 "and thus the estimated parameters are reported per total ROI volume.",
74 "Usage: @P [Options] ptacfile btacfile ttacfile [parfile]",
78 " Tissue data length, used in the fitting, is restricted to",
81 " Blood volume is constrained to given value (mL/mL).",
82 " If Vb is set to zero, then btacfile is not read, but a place filler",
83 " must nonetheless be given.",
85 " Delay time is constrained to given value (sec).",
87 " With -wf Weights are based on frame length or sampling interval;",
88 " with -wfd the late frames are given less weight by using formula",
89 " weight=(frame duration)*exp(-t*ln(2)/halflife) (Thiele et al, 2008);",
90 " with -w1 all weights are set to 1.0 (no weighting);",
91 " by default, weights in TTAC file are used, if available.",
93 " Isotope, for example C-11, in case it is not found inside TTAC, but",
94 " is needed with option -wfd.",
96 " Fitted and measured TACs are plotted in specified SVG file.",
98 " Fitted TTACs at BTAC sample times are saved in specified TAC file.",
101 "If time units are not specified in files, minutes are assumed.",
103 "See also: fitk2, fit_h2o, bfmh2o, fit_wrlv",
105 "Keywords: TAC, modelling, compartmental model",
134int tacReadModelingData2(
138 const char *tissuefile,
141 const char *inputfile1,
144 const char *inputfile2,
147 const char *inputfile3,
168 int verbose=0;
if(status!=NULL) verbose=status->
verbose;
169 if(verbose>0) printf(
"%s()\n", __func__);
170 if(tis==NULL || inp==NULL) {
174 if(tissuefile==NULL || inputfile1==NULL ||
strnlen(inputfile1, 1)<1) {
181 if(inputfile2!=NULL &&
strnlen(inputfile2, 1)>0) input_nr++;
182 if(inputfile3!=NULL &&
strnlen(inputfile3, 1)>0) {
189 if(verbose>2) printf(
"input_nr := %d\n", input_nr);
193 if(fitSampleNr!=NULL) *fitSampleNr=0;
199 if(verbose>1) printf(
"reading tissue data in %s\n", tissuefile);
200 ret=
tacRead(tis, tissuefile, status);
216 statusSet(status, __func__, __FILE__, __LINE__, ret);
228 if(verbose>1) printf(
"reading input data 1 in %s\n", inputfile1);
229 ret=
tacRead(inp, inputfile1, status);
235 fprintf(stderr,
"Warning: input sample time units not known.\n");}
240 if(verbose>0) fprintf(stderr,
"Warning: using only first TAC in %s\n", inputfile1);
261 for(
int ii=2; ii<=input_nr; ii++) {
262 if(ii==2) fname=(
char*)inputfile2;
else fname=(
char*)inputfile3;
263 if(verbose>1) printf(
"reading input data %d in %s\n", ii, fname);
264 ret=
tacRead(&tmptac, fname, status);
268 if(verbose>0) fprintf(stderr,
"Warning: using only first TAC in %s\n", fname);
303 if(ret && verbose>0) {
304 fprintf(stderr,
"Warning: check that regional data times are in minutes.\n");
307 if(ret && verbose>0) {
308 fprintf(stderr,
"Warning: check that input data times are in minutes.\n");
314 if(ret || iend<=0.0 || tend<=0.0) {
319 if(tend>10.0*iend || tend<0.10*iend) {
320 if(verbose>0) fprintf(stderr,
"Warning: check the sample time units.\n");
324 if(ret && verbose>0) {
325 fprintf(stderr,
"Warning: check the calibration units.\n");
331 if(verbose>1) printf(
"checking and setting fit time length\n");
333 double starttime=0, endtime=*fitdur;
334 int fnr=
tacFittime(tis, &starttime, &endtime, NULL, NULL, status);
336 fprintf(stdout,
"tis.sampleNr := %d\n", tis->
sampleNr);
337 fprintf(stdout,
"starttime := %g\n", starttime);
338 fprintf(stdout,
"endtime := %g\n", endtime);
341 fprintf(stdout,
"fitSampleNr := %d\n", fnr);
344 if(fitSampleNr!=NULL) *fitSampleNr=fnr;
347 if(*fitdur>1.2*iend) {
354 if(cutInput && iend>*fitdur) {
355 if(verbose>1) printf(
"cut off too many input samples\n");
358 if(inp->
isframe) f=0.5*(inp->
x1[i]+inp->
x2[i]);
else f=inp->
x[i];
359 if(f>(*fitdur))
break;
361 if(i<inp->sampleNr) i++;
368 if(verbose>2) fprintf(stdout,
"inp.sampleNr := %d\n", inp->
sampleNr);
402 int verbose=0;
if(status!=NULL) verbose=status->
verbose;
403 if(verbose>0) printf(
"%s(ttac, ptac, %d, %d, par)\n", __func__, tcn, vbc);
404 if(ttac==NULL || ptac==NULL || par==NULL || tcn<1 || tcn>3) {
426int main(
int argc,
char **argv)
428 int ai, help=0, version=0, verbose=1;
429 char ptacfile[FILENAME_MAX], btacfile[FILENAME_MAX], ttacfile[FILENAME_MAX],
430 parfile[FILENAME_MAX], svgfile[FILENAME_MAX], simfile[FILENAME_MAX];
432 double fixed_dt=nan(
"");
433 double fixed_vb=nan(
"");
434 double tstop=nan(
"");
442 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
443 ptacfile[0]=btacfile[0]=ttacfile[0]=parfile[0]=svgfile[0]=simfile[0]=(char)0;
445 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
447 char *cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(!*cptr)
continue;
448 if(strcasecmp(cptr,
"W1")==0) {
450 }
else if(strcasecmp(cptr,
"WF")==0) {
452 }
else if(strcasecmp(cptr,
"WFD")==0) {
454 }
else if(strncasecmp(cptr,
"I=", 2)==0) {
456 fprintf(stderr,
"Error: invalid isotope '%s'.\n", cptr+2);
return(1);}
458 }
else if(strncasecmp(cptr,
"DELAY=", 6)==0 && strlen(cptr)>6) {
459 if(!
atofCheck(cptr+6, &fixed_dt) && fixed_dt>=0.0)
continue;
460 }
else if(strncasecmp(cptr,
"DT=", 3)==0 && strlen(cptr)>3) {
461 if(!
atofCheck(cptr+3, &fixed_dt) && fixed_dt>=0.0)
continue;
462 }
else if(strncasecmp(cptr,
"END=", 4)==0 && strlen(cptr)>4) {
463 if(!
atofCheck(cptr+4, &tstop) && tstop>0.0)
continue;
464 }
else if(strncasecmp(cptr,
"STOP=", 5)==0 && strlen(cptr)>5) {
465 if(!
atofCheck(cptr+5, &tstop) && tstop>0.0)
continue;
466 }
else if(strncasecmp(cptr,
"VB=", 3)==0 && strlen(cptr)>3) {
467 if(!
atofCheck(cptr+3, &fixed_vb) && fixed_vb>=0.0 && fixed_vb<1.0)
continue;
468 }
else if(strncasecmp(cptr,
"SVG=", 4)==0 && strlen(cptr)>4) {
469 strlcpy(svgfile, cptr+4, FILENAME_MAX);
continue;
470 }
else if(strncasecmp(cptr,
"SIM=", 4)==0 && strlen(cptr)>4) {
471 strlcpy(simfile, cptr+4, FILENAME_MAX);
continue;
473 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
482 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
487 if(ai<argc)
strlcpy(ptacfile, argv[ai++], FILENAME_MAX);
488 if(ai<argc)
strlcpy(btacfile, argv[ai++], FILENAME_MAX);
489 if(ai<argc)
strlcpy(ttacfile, argv[ai++], FILENAME_MAX);
490 if(ai<argc)
strlcpy(parfile, argv[ai++], FILENAME_MAX);
492 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
497 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
501 if(fixed_vb==0.0) btacfile[0]=(char)0;
505 printf(
"ptacfile := %s\n", ptacfile);
506 printf(
"btacfile := %s\n", btacfile);
507 printf(
"ttacfile := %s\n", ttacfile);
508 if(parfile[0]) printf(
"parfile := %s\n", parfile);
509 if(svgfile[0]) printf(
"svgfile := %s\n", svgfile);
510 if(simfile[0]) printf(
"simfile := %s\n", simfile);
511 printf(
"weightMethod := %d\n", weightMethod);
512 if(!isnan(tstop)) printf(
"tstop := %g\n", tstop);
513 if(!isnan(fixed_dt)) printf(
"fixed_dt := %g\n", fixed_dt);
514 if(!isnan(fixed_vb)) printf(
"fixed_vb := %g\n", fixed_vb);
522 if(verbose>0) {printf(
"reading tissue and input data\n"); fflush(stdout);}
525 double fitdur=1.0E+10;
if(tstop>0.01) fitdur=tstop;
527 if(tacReadModelingData2(ttacfile, ptacfile, btacfile, NULL, &fitdur, 0,
528 &fitSampleNr, &ttac, &input, &status)!=
TPCERROR_OK) {
535 printf(
"tacNr := %d\n", ttac.
tacNr);
536 printf(
"tac.sampleNr := %d\n", ttac.
sampleNr);
537 printf(
"input.sampleNr := %d\n", input.
sampleNr);
538 printf(
"fitSampleNr := %d\n", fitSampleNr);
541 printf(
"fitdur := %g s\n", fitdur);
548 if(verbose>0) {printf(
"setting weights\n"); fflush(stdout);}
555 if(verbose>2) printf(
"wsampleNr := %u\n", wsampleNr);
557 fprintf(stderr,
"Error: too few samples for fitting.\n");
564 fprintf(stderr,
"Error: invalid data sample times.\n");
568 printf(
"xmin := %g\n", xmin);
569 printf(
"xmax := %g\n", xmax);
576 if(verbose>1) {printf(
"preparing space for parameters\n"); fflush(stdout);}
589 iftPut(&par.
h,
"program", buf, 0, NULL);
593 for(
int i=0; i<par.
tacNr; i++) {
606 iftPut(&par.
h,
"datafile", ttacfile, 0, NULL);
607 iftPut(&par.
h,
"plasma", ptacfile, 0, NULL);
608 iftPut(&par.
h,
"blood", btacfile, 0, NULL);
614 if(fixed_dt<0.0 || fixed_dt>0.0) {
615 if(verbose>1) {printf(
"correcting data for user-defined delay time\n"); fflush(stdout);}
620 if(verbose>1) {printf(
" input data moved %g s\n", -fixed_dt); fflush(stdout);}
628 if(verbose>1) {printf(
"correcting data for user-defined Vb\n"); fflush(stdout);}
633 fprintf(stderr,
"Error: %s\n",
errorMsg(ret));
645 ret=
tacVb(&ttac, -1, &bitac, fixed_vb, 0, 1, &status);
651 if(verbose>1) {printf(
" corrected for Vb %g\n", fixed_vb); fflush(stdout);}
660 if(verbose>2) {printf(
"multi-linear solution to get good initial guess\n"); fflush(stdout);}
663 if(fixed_vb) ret=nnlsRTCM(&ttac, &input, 1, 0, &mlpar, &status);
664 else ret=nnlsRTCM(&ttac, &input, 1, 1, &mlpar, &status);
678 if(verbose==1) {printf(
"\n fitting...\n"); fflush(stdout);}
679 for(
int ri=0; ri<ttac.
tacNr; ri++) {
680 if(verbose>1) {printf(
"\n fitting %s\n", ttac.
c[ri].
name); fflush(stdout);}
699double func_1tcm(
int parNr,
double *p,
void *fdata)
701 FITDATA *d=(FITDATA*)fdata;
703 if(d->verbose>0) {printf(
"%s()\n", __func__); fflush(stdout);}
704 if(parNr!=5 || p==NULL || fdata==NULL || d->ni<1 || d->nt<1)
return(nan(
""));
706 printf(
"p[]: %g", p[0]);
707 for(
int i=1; i<parNr; i++) printf(
" %g", p[i]);
708 printf(
"\n"); fflush(stdout);
712 double tau=p[0];
if(tau<0.0) tau=0.0;
714 double Vb=p[2];
if(Vb<0.0) Vb=0.0;
715 double K1=p[3]/60.0;
if(K1<0.0) K1=0.0;
716 double k2=p[4]/60.0;
if(k2<0.0) k2=0.0;
719 double x[d->ni], y[d->ni], sy[d->ni];
720 for(
unsigned int i=0; i<d->ni; i++) x[i]=d->xi[i]+deltaT;
721 for(
unsigned int i=0; i<d->ni; i++) y[i]=d->yi[i];
722 if(
simDispersion(x, y, d->ni, tau, 0.0, sy)!=0)
return(nan(
""));
725 if(
simC1(x, y, d->ni, K1, k2, sy)!=0)
return(nan(
""));
726 for(
unsigned int i=0; i<d->ni; i++) sy[i]+=Vb*y[i];
729 if(d->xt1==NULL || d->xt2==NULL) {
730 if(
liInterpolate(x, sy, d->ni, d->xt, d->syt, NULL, NULL, d->nt, 3, 1, 0))
733 if(
liInterpolateForPET(x, sy, d->ni, d->xt1, d->xt2, d->syt, NULL, NULL, d->nt, 3, 1, 0))
738 if(d->verbose>2) {fprintf(stdout,
"computing WSS...\n"); fflush(stdout);}
740 for(
unsigned i=0; i<d->nt; i++) {
741 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)
int tacDelay(TAC *tac, double dt, int ti, TPCSTATUS *status)
Move TAC y values (concentrations) in time, keeping sample times (x values) intact.
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.
char * isotopeName(int isotope_code)
int isotopeIdentify(const char *isotope)
int tacVb(TAC *ttac, const int i, TAC *btac, double Vb, const int simVb, const int petVolume, TPCSTATUS *status)
Correct TTACs for vascular blood, or simulate its effect.
int tacInterpolateInto(TAC *inp, TAC *tac, TAC *itac, TAC *iitac, TPCSTATUS *status)
Add TACs from one TAC structure into another TAC structure, interpolating the input TACs and allocati...
int tacInterpolate(TAC *inp, TAC *xinp, TAC *tac, TAC *itac, TAC *iitac, TPCSTATUS *status)
Interpolate and/or integrate TACs from one TAC structure into a new TAC structure,...
unsigned int modelCodeIndex(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)
void statusInit(TPCSTATUS *s)
char * errorMsg(tpcerror e)
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
size_t strnlen(const char *s, size_t n)
size_t strlcpy(char *dst, const char *src, size_t dstsize)
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 tacExtract(TAC *d1, TAC *d2, const int i)
Extract the specified TAC from existing TAC structure into a new TAC.
int tacGetIsotope(TAC *tac)
void tacSetIsotope(TAC *tac, int isotope)
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
char * tacFormattxt(tacformat c)
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 tacSetWeights(TAC *tac, weights weightMethod, int weightNr, TPCSTATUS *status)
unsigned int tacWSampleNr(TAC *tac)
int tacSampleXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
int tacCorrectFrameOverlap(TAC *d, TPCSTATUS *status)
Correct PET frame start and end times if frames are slightly overlapping or have small gaps in betwee...
int tacXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
Header file for libtpccm.
Header file for library libtpcextensions.
@ WEIGHTING_OFF
Not weighted or weights not available (weights for all included samples are 1.0).
@ WEIGHTING_ON_FD
Weights based on decay and sample frequency or frame length (Thiele et al, 2008).
@ WEIGHTING_UNKNOWN
Not known; usually assumed that not weighted.
@ WEIGHTING_ON_F
Weights based on sample frequency or frame length.
@ UNIT_ML_PER_ML_MIN
mL/(mL*min)
@ UNIT_UNKNOWN
Unknown unit.
@ TPCERROR_INVALID_XRANGE
Invalid sample time range.
@ TPCERROR_FAIL
General error.
@ TPCERROR_NO_DATA
File contains no data.
@ TPCERROR_TOO_FEW
File contains too few samples.
@ TPCERROR_MISSING_DATA
File contains missing values.
char * unitName(int unit_code)
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_TSV_UK
UK TSV (point as decimal separator).
Header file for libtpcrand.
Header file for library libtpctac.
Header file for libtpctacmod.