9#include "tpcclibConfig.h"
30double func_1tcm(
int parNr,
double *p,
void*);
32typedef struct FITDATA {
63static char *info[] = {
64 "Non-linear fitting of 1TCM to regional TTACs using PTAC as input function",
65 "and BTAC for vascular volume correction. Delay time between TTACs and",
66 "PTAC/BTAC is fitted by default. Regional radioactivity concentration is",
67 "modelled as Cpet(t) = Vb*Cb(t) + Ct(t),",
68 "and thus the estimated parameters are reported per total ROI volume.",
70 "Usage: @P [Options] ptacfile btacfile ttacfile [parfile]",
74 " Tissue data length, used in the fitting, is restricted to",
77 " Blood volume is constrained to given value (mL/mL).",
78 " If Vb is set to zero, then btacfile is not read, but a place filler",
79 " must nonetheless be given.",
81 " Delay time is constrained to given value (sec).",
83 " With -wf Weights are based on frame length or sampling interval;",
84 " with -wfd the late frames are given less weight by using formula",
85 " weight=(frame duration)*exp(-t*ln(2)/halflife) (Thiele et al, 2008);",
86 " with -w1 all weights are set to 1.0 (no weighting);",
87 " by default, weights in TTAC file are used, if available.",
89 " Isotope, for example C-11, in case it is not found inside TTAC, but",
90 " is needed with option -wfd.",
92 " Fitted and measured TACs are plotted in specified SVG file.",
94 " Fitted TTACs at BTAC sample times are saved in specified TAC file.",
97 "If time units are not specified in files, minutes are assumed.",
99 "See also: fitk2, fit_h2o, bfmh2o, fit_wrlv",
101 "Keywords: TAC, modelling, compartmental model",
130int tacReadModelingData2(
134 const char *tissuefile,
137 const char *inputfile1,
140 const char *inputfile2,
143 const char *inputfile3,
164 int verbose=0;
if(status!=NULL) verbose=status->
verbose;
165 if(verbose>0) printf(
"%s()\n", __func__);
166 if(tis==NULL || inp==NULL) {
170 if(tissuefile==NULL || inputfile1==NULL ||
strnlen(inputfile1, 1)<1) {
177 if(inputfile2!=NULL &&
strnlen(inputfile2, 1)>0) input_nr++;
178 if(inputfile3!=NULL &&
strnlen(inputfile3, 1)>0) {
185 if(verbose>2) printf(
"input_nr := %d\n", input_nr);
189 if(fitSampleNr!=NULL) *fitSampleNr=0;
195 if(verbose>1) printf(
"reading tissue data in %s\n", tissuefile);
196 ret=
tacRead(tis, tissuefile, status);
212 statusSet(status, __func__, __FILE__, __LINE__, ret);
224 if(verbose>1) printf(
"reading input data 1 in %s\n", inputfile1);
225 ret=
tacRead(inp, inputfile1, status);
231 fprintf(stderr,
"Warning: input sample time units not known.\n");}
236 if(verbose>0) fprintf(stderr,
"Warning: using only first TAC in %s\n", inputfile1);
257 for(
int ii=2; ii<=input_nr; ii++) {
258 if(ii==2) fname=(
char*)inputfile2;
else fname=(
char*)inputfile3;
259 if(verbose>1) printf(
"reading input data %d in %s\n", ii, fname);
260 ret=
tacRead(&tmptac, fname, status);
264 if(verbose>0) fprintf(stderr,
"Warning: using only first TAC in %s\n", fname);
299 if(ret && verbose>0) {
300 fprintf(stderr,
"Warning: check that regional data times are in minutes.\n");
303 if(ret && verbose>0) {
304 fprintf(stderr,
"Warning: check that input data times are in minutes.\n");
310 if(ret || iend<=0.0 || tend<=0.0) {
315 if(tend>10.0*iend || tend<0.10*iend) {
316 if(verbose>0) fprintf(stderr,
"Warning: check the sample time units.\n");
320 if(ret && verbose>0) {
321 fprintf(stderr,
"Warning: check the calibration units.\n");
327 if(verbose>1) printf(
"checking and setting fit time length\n");
329 double starttime=0, endtime=*fitdur;
330 int fnr=
tacFittime(tis, &starttime, &endtime, NULL, NULL, status);
332 fprintf(stdout,
"tis.sampleNr := %d\n", tis->
sampleNr);
333 fprintf(stdout,
"starttime := %g\n", starttime);
334 fprintf(stdout,
"endtime := %g\n", endtime);
337 fprintf(stdout,
"fitSampleNr := %d\n", fnr);
340 if(fitSampleNr!=NULL) *fitSampleNr=fnr;
343 if(*fitdur>1.2*iend) {
350 if(cutInput && iend>*fitdur) {
351 if(verbose>1) printf(
"cut off too many input samples\n");
354 if(inp->
isframe) f=0.5*(inp->
x1[i]+inp->
x2[i]);
else f=inp->
x[i];
355 if(f>(*fitdur))
break;
357 if(i<inp->sampleNr) i++;
364 if(verbose>2) fprintf(stdout,
"inp.sampleNr := %d\n", inp->
sampleNr);
398 int verbose=0;
if(status!=NULL) verbose=status->
verbose;
399 if(verbose>0) printf(
"%s(ttac, ptac, %d, %d, par)\n", __func__, tcn, vbc);
400 if(ttac==NULL || ptac==NULL || par==NULL || tcn<1 || tcn>3) {
422int main(
int argc,
char **argv)
424 int ai, help=0, version=0, verbose=1;
425 char ptacfile[FILENAME_MAX], btacfile[FILENAME_MAX], ttacfile[FILENAME_MAX],
426 parfile[FILENAME_MAX], svgfile[FILENAME_MAX], simfile[FILENAME_MAX];
428 double fixed_dt=nan(
"");
429 double fixed_vb=nan(
"");
430 double tstop=nan(
"");
438 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
439 ptacfile[0]=btacfile[0]=ttacfile[0]=parfile[0]=svgfile[0]=simfile[0]=(char)0;
441 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
443 char *cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(!*cptr)
continue;
444 if(strcasecmp(cptr,
"W1")==0) {
446 }
else if(strcasecmp(cptr,
"WF")==0) {
448 }
else if(strcasecmp(cptr,
"WFD")==0) {
450 }
else if(strncasecmp(cptr,
"I=", 2)==0) {
452 fprintf(stderr,
"Error: invalid isotope '%s'.\n", cptr+2);
return(1);}
454 }
else if(strncasecmp(cptr,
"DELAY=", 6)==0 && strlen(cptr)>6) {
455 if(!
atofCheck(cptr+6, &fixed_dt) && fixed_dt>=0.0)
continue;
456 }
else if(strncasecmp(cptr,
"DT=", 3)==0 && strlen(cptr)>3) {
457 if(!
atofCheck(cptr+3, &fixed_dt) && fixed_dt>=0.0)
continue;
458 }
else if(strncasecmp(cptr,
"END=", 4)==0 && strlen(cptr)>4) {
459 if(!
atofCheck(cptr+4, &tstop) && tstop>0.0)
continue;
460 }
else if(strncasecmp(cptr,
"STOP=", 5)==0 && strlen(cptr)>5) {
461 if(!
atofCheck(cptr+5, &tstop) && tstop>0.0)
continue;
462 }
else if(strncasecmp(cptr,
"VB=", 3)==0 && strlen(cptr)>3) {
463 if(!
atofCheck(cptr+3, &fixed_vb) && fixed_vb>=0.0 && fixed_vb<1.0)
continue;
464 }
else if(strncasecmp(cptr,
"SVG=", 4)==0 && strlen(cptr)>4) {
465 strlcpy(svgfile, cptr+4, FILENAME_MAX);
continue;
466 }
else if(strncasecmp(cptr,
"SIM=", 4)==0 && strlen(cptr)>4) {
467 strlcpy(simfile, cptr+4, FILENAME_MAX);
continue;
469 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
478 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
483 if(ai<argc)
strlcpy(ptacfile, argv[ai++], FILENAME_MAX);
484 if(ai<argc)
strlcpy(btacfile, argv[ai++], FILENAME_MAX);
485 if(ai<argc)
strlcpy(ttacfile, argv[ai++], FILENAME_MAX);
486 if(ai<argc)
strlcpy(parfile, argv[ai++], FILENAME_MAX);
488 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
493 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
497 if(fixed_vb==0.0) btacfile[0]=(char)0;
501 printf(
"ptacfile := %s\n", ptacfile);
502 printf(
"btacfile := %s\n", btacfile);
503 printf(
"ttacfile := %s\n", ttacfile);
504 if(parfile[0]) printf(
"parfile := %s\n", parfile);
505 if(svgfile[0]) printf(
"svgfile := %s\n", svgfile);
506 if(simfile[0]) printf(
"simfile := %s\n", simfile);
507 printf(
"weightMethod := %d\n", weightMethod);
508 if(!isnan(tstop)) printf(
"tstop := %g\n", tstop);
509 if(!isnan(fixed_dt)) printf(
"fixed_dt := %g\n", fixed_dt);
510 if(!isnan(fixed_vb)) printf(
"fixed_vb := %g\n", fixed_vb);
518 if(verbose>0) {printf(
"reading tissue and input data\n"); fflush(stdout);}
521 double fitdur=1.0E+10;
if(tstop>0.01) fitdur=tstop;
523 if(tacReadModelingData2(ttacfile, ptacfile, btacfile, NULL, &fitdur, 0,
524 &fitSampleNr, &ttac, &input, &status)!=
TPCERROR_OK) {
531 printf(
"tacNr := %d\n", ttac.
tacNr);
532 printf(
"tac.sampleNr := %d\n", ttac.
sampleNr);
533 printf(
"input.sampleNr := %d\n", input.
sampleNr);
534 printf(
"fitSampleNr := %d\n", fitSampleNr);
537 printf(
"fitdur := %g s\n", fitdur);
544 if(verbose>0) {printf(
"setting weights\n"); fflush(stdout);}
551 if(verbose>2) printf(
"wsampleNr := %u\n", wsampleNr);
553 fprintf(stderr,
"Error: too few samples for fitting.\n");
560 fprintf(stderr,
"Error: invalid data sample times.\n");
564 printf(
"xmin := %g\n", xmin);
565 printf(
"xmax := %g\n", xmax);
572 if(verbose>1) {printf(
"preparing space for parameters\n"); fflush(stdout);}
585 iftPut(&par.
h,
"program", buf, 0, NULL);
589 for(
int i=0; i<par.
tacNr; i++) {
602 iftPut(&par.
h,
"datafile", ttacfile, 0, NULL);
603 iftPut(&par.
h,
"plasma", ptacfile, 0, NULL);
604 iftPut(&par.
h,
"blood", btacfile, 0, NULL);
610 if(fixed_dt<0.0 || fixed_dt>0.0) {
611 if(verbose>1) {printf(
"correcting data for user-defined delay time\n"); fflush(stdout);}
616 if(verbose>1) {printf(
" input data moved %g s\n", -fixed_dt); fflush(stdout);}
624 if(verbose>1) {printf(
"correcting data for user-defined Vb\n"); fflush(stdout);}
629 fprintf(stderr,
"Error: %s\n",
errorMsg(ret));
641 ret=
tacVb(&ttac, -1, &bitac, fixed_vb, 0, 1, &status);
647 if(verbose>1) {printf(
" corrected for Vb %g\n", fixed_vb); fflush(stdout);}
656 if(verbose>2) {printf(
"multi-linear solution to get good initial guess\n"); fflush(stdout);}
659 if(fixed_vb) ret=nnlsRTCM(&ttac, &input, 1, 0, &mlpar, &status);
660 else ret=nnlsRTCM(&ttac, &input, 1, 1, &mlpar, &status);
674 if(verbose==1) {printf(
"\n fitting...\n"); fflush(stdout);}
675 for(
int ri=0; ri<ttac.
tacNr; ri++) {
676 if(verbose>1) {printf(
"\n fitting %s\n", ttac.
c[ri].
name); fflush(stdout);}
695double func_1tcm(
int parNr,
double *p,
void *fdata)
697 FITDATA *d=(FITDATA*)fdata;
699 if(d->verbose>0) {printf(
"%s()\n", __func__); fflush(stdout);}
700 if(parNr!=5 || p==NULL || fdata==NULL || d->ni<1 || d->nt<1)
return(nan(
""));
702 printf(
"p[]: %g", p[0]);
703 for(
int i=1; i<parNr; i++) printf(
" %g", p[i]);
704 printf(
"\n"); fflush(stdout);
708 double tau=p[0];
if(tau<0.0) tau=0.0;
710 double Vb=p[2];
if(Vb<0.0) Vb=0.0;
711 double K1=p[3]/60.0;
if(K1<0.0) K1=0.0;
712 double k2=p[4]/60.0;
if(k2<0.0) k2=0.0;
715 double x[d->ni], y[d->ni], sy[d->ni];
716 for(
unsigned int i=0; i<d->ni; i++) x[i]=d->xi[i]+deltaT;
717 for(
unsigned int i=0; i<d->ni; i++) y[i]=d->yi[i];
718 if(
simDispersion(x, y, d->ni, tau, 0.0, sy)!=0)
return(nan(
""));
721 if(
simC1(x, y, d->ni, K1, k2, sy)!=0)
return(nan(
""));
722 for(
unsigned int i=0; i<d->ni; i++) sy[i]+=Vb*y[i];
725 if(d->xt1==NULL || d->xt2==NULL) {
726 if(
liInterpolate(x, sy, d->ni, d->xt, d->syt, NULL, NULL, d->nt, 3, 1, 0))
729 if(
liInterpolateForPET(x, sy, d->ni, d->xt1, d->xt2, d->syt, NULL, NULL, d->nt, 3, 1, 0))
734 if(d->verbose>2) {fprintf(stdout,
"computing WSS...\n"); fflush(stdout);}
736 for(
unsigned i=0; i<d->nt; i++) {
737 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.