9#include "tpcclibConfig.h"
27static char *info[] = {
28 "Compartmental model based spectral analysis of regional PET data.",
29 "Basis functions (from 1 to n) are formed with a range of k2 from zero to",
30 "a given maximum, with the provided PTAC as input function.",
31 "Model Croi(t) = Vb*Cb(t) + Ct[1](t) + Ct[2](t) + ... + Ct[n](t)",
32 "is fitted to the provided TTACs.",
35 " | |--K1[i=1]->| Ct[i=1] | ",
36 " | |<-k2[i=1]--|_________| ",
39 " | |--K1[i=n]->| Ct[i=n] | ",
40 " | |<-k2[i=n]--|_________| ",
43 "Croi = Vb*Cb + K1[i=1]*Ct[i=1] + ... K1[i=n]*Ct[i=n]",
45 "Usage: @P [options] ptacfile btacfile ttacfile maxk2 parfile [safile]",
48 " -n=<Number of basis functions>",
49 " Set the number of basis functions; by default 100, minimum 10.",
51 " Set minimum value for k2 in units 1/min; by default 0.005 min-1.",
52 " Do not set to zero or very low value, but if you want to add basis",
53 " function with k2=0 (trapping compartment), enter minimum k2 as",
56 " Basis function curves are written in specified file.",
58 " Fitted regional TTACs are written in specified file.",
61 "Parameters Vb and K1 will be written in parameter file as the weights",
62 "of the basis functions (Vb as the weight of BTAC, and K1 as the sum of",
63 "weights of other basis functions), and k2 as the weighted average of",
64 "k2-derived basis functions.",
65 "In the optional SA file, the weights for each k2-derived basis functions",
66 "are listed in TAC format.",
68 "See also: fitdelay, bfmh2o, lhsol, hist2svg",
70 "Keywords: TAC, modelling, compartmental model, LLSQ",
89int main(
int argc,
char **argv)
91 int ai, help=0, version=0, verbose=1;
92 char ptacfile[FILENAME_MAX], btacfile[FILENAME_MAX], ttacfile[FILENAME_MAX],
93 bffile[FILENAME_MAX], parfile[FILENAME_MAX], safile[FILENAME_MAX], fitfile[FILENAME_MAX];
101 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
102 ptacfile[0]=btacfile[0]=ttacfile[0]=bffile[0]=parfile[0]=safile[0]=fitfile[0]=(char)0;
104 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
106 char *cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(!*cptr)
continue;
107 if(strncasecmp(cptr,
"BF=", 3)==0) {
108 strlcpy(bffile, cptr+3, FILENAME_MAX);
if(strlen(bffile)>0)
continue;
109 }
else if(strncasecmp(cptr,
"FIT=", 4)==0) {
110 strlcpy(fitfile, cptr+4, FILENAME_MAX);
if(strlen(fitfile)>0)
continue;
111 }
else if(strncasecmp(cptr,
"N=", 2)==0) {
112 if(
atoiCheck(cptr+2, &bfNr)==0 && bfNr>=10)
continue;
113 }
else if(strncasecmp(cptr,
"NR=", 3)==0) {
114 if(
atoiCheck(cptr+3, &bfNr)==0 && bfNr>=10)
continue;
115 }
else if(strncasecmp(cptr,
"MINK2=", 6)==0) {
116 if(
atofCheck(cptr+6, &k2min)==0 && fabs(k2min)>=1.0E-04)
continue;
118 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
127 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
132 if(ai<argc)
strlcpy(ptacfile, argv[ai++], FILENAME_MAX);
133 if(ai<argc)
strlcpy(btacfile, argv[ai++], FILENAME_MAX);
134 if(ai<argc)
strlcpy(ttacfile, argv[ai++], FILENAME_MAX);
136 if(
atofCheck(argv[ai], &k2max) || !(k2max>1.0E-03)) {
137 fprintf(stderr,
"Error: invalid k2 maximum '%s'.\n", argv[ai]);
return(1);}
140 if(ai<argc)
strlcpy(parfile, argv[ai++], FILENAME_MAX);
141 if(ai<argc)
strlcpy(safile, argv[ai++], FILENAME_MAX);
143 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
148 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
155 printf(
"ptacfile := %s\n", ptacfile);
156 printf(
"btacfile := %s\n", btacfile);
157 printf(
"ttacfile := %s\n", ttacfile);
158 printf(
"parfile := %s\n", parfile);
159 if(safile[0]) printf(
"safile := %s\n", safile);
160 if(bffile[0]) printf(
"bffile := %s\n", bffile);
161 if(fitfile[0]) printf(
"fitfile := %s\n", fitfile);
162 printf(
"k2max := %g\n", k2max);
163 printf(
"k2min := %g\n", k2min);
164 printf(
"n := %d\n", bfNr);
171 if(verbose>1) printf(
"reading tissue and input data\n");
173 double fitdur=1.0E+10;
175 tacReadModelingData(ttacfile, ptacfile, btacfile, NULL, &fitdur, 0, NULL, &ttac, &itac, &status);
182 printf(
"tacNr := %d\n", ttac.
tacNr);
183 printf(
"ttac.sampleNr := %d\n", ttac.
sampleNr);
184 printf(
"itac.sampleNr := %d\n", itac.
sampleNr);
187 printf(
"fitdur := %g s\n", fitdur);
190 fprintf(stderr,
"Error: too few data samples.\n");
201 if(verbose>1) printf(
"interpolating BTAC to TTAC sample times\n");
213 if(verbose>1) printf(
"calculating basis functions\n");
215 bfm1TCM(&itac, &ttac, bfNr, -k2min, k2max, 1, &bf, &status);
217 if(verbose>1) fprintf(stderr,
"Error: cannot calculate basis functions.\n");
221 if(verbose>2 && bfNr<=20) {
222 printf(
"\nBF k2 values:\n");
223 for(
int i=0; i<bf.
tacNr; i++) printf(
"\t%d\t%g\n", 1+i, bf.
c[i].
size);
227 if(verbose>1) printf(
"writing %s\n", bffile);
228 FILE *fp; fp=fopen(bffile,
"w");
230 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", bffile);
241 if(verbose>0) {printf(
"basis functions saved in %s.\n", bffile); fflush(stdout);}
248 if(verbose>1) {printf(
"initializing result data\n"); fflush(stdout);}
263 iftPut(&par.
h,
"program", buf, 0, NULL);
265 iftPut(&par.
h,
"plasmafile", ptacfile, 0, NULL);
266 iftPut(&par.
h,
"bloodfile", btacfile, 0, NULL);
267 iftPut(&par.
h,
"datafile", ttacfile, 0, NULL);
269 iftPut(&par.
h,
"fitmethod",
"NNLS", 0, NULL);
273 for(i=0; i<par.
tacNr; i++) {
290 if(verbose>1) {printf(
"allocating memory for SA results\n"); fflush(stdout);}
294 fprintf(stderr,
"Error: cannot allocate memory for SA results.\n");
299 fprintf(stderr,
"Error: cannot allocate memory for SA results.\n");
304 for(
int i=0; i<bfNr; i++) sa.
x[i]=bf.
c[i].
size;
312 if(verbose>1) {printf(
"allocating memory for fitted TTACs\n"); fflush(stdout);}
314 fprintf(stderr,
"Error: cannot allocate memory for fitted TTACs.\n");
324 if(verbose>1) {printf(
"allocating memory for NNLS\n"); fflush(stdout);}
326 int llsq_n=1+bf.
tacNr;
327 double *llsq_mat=(
double*)malloc((2*llsq_n*llsq_m)*
sizeof(
double));
329 fprintf(stderr,
"Error: cannot allocate memory for NNLS.\n");
333 double **llsq_a=(
double**)malloc(llsq_n*
sizeof(
double*));
335 fprintf(stderr,
"Error: cannot allocate memory for NNLS.\n");
336 fprintf(stderr,
"Error: cannot allocate memory for NNLS.\n");
341 for(
int ni=0; ni<llsq_n; ni++) llsq_a[ni]=llsq_mat+ni*llsq_m;
342 double r2, llsq_b[llsq_m], llsq_x[llsq_n], llsq_wp[llsq_n], llsq_zz[llsq_m];
344 double *matbackup=llsq_mat+llsq_n*llsq_m;
349 for(
int ti=0; ti<ttac.
tacNr; ti++) {
351 if(verbose>1 && ttac.
tacNr>1) {
352 printf(
"Region %d %s\n", 1+ti, ttac.
c[ti].
name); fflush(stdout);}
355 for(
int mi=0; mi<llsq_m; mi++)
356 llsq_b[mi]=ttac.
c[ti].
y[mi];
357 for(
int mi=0; mi<llsq_m; mi++)
358 llsq_mat[mi]=tbtac.
c[1].
y[mi];
359 for(
int bi=0; bi<bf.
tacNr; bi++)
360 for(
int mi=0; mi<llsq_m; mi++)
361 llsq_mat[mi+(1+bi)*llsq_m]=bf.
c[bi].
y[mi];
363 for(
int i=0; i<llsq_n*llsq_m; i++) matbackup[i]=llsq_mat[i];
365 if(verbose>3) printf(
"starting NNLS...\n");
366 int ret=
nnls(llsq_a, llsq_m, llsq_n, llsq_b, llsq_x, &r2, llsq_wp, llsq_zz, indexp);
367 if(verbose>3) printf(
" ... done.\n");
369 fprintf(stderr,
"Warning: no NNLS solution for %s\n", ttac.
c[ti].
name);
370 for(
int ni=0; ni<llsq_n; ni++) llsq_x[ni]=0.0;
373 fprintf(stderr,
"Warning: maximum iterations reached for %s\n", ttac.
c[ti].
name);
376 for(
int ni=1; ni<llsq_n; ni++) sa.
c[ti].
y[ni-1]=llsq_x[ni];
378 par.
r[ti].
p[2]=llsq_x[0];
380 for(
int i=0; i<sa.
sampleNr; i++) par.
r[ti].
p[0]+=sa.
c[ti].
y[i];
383 if(par.
r[ti].
p[0]>1.0E-06) par.
r[ti].
p[1]/=par.
r[ti].
p[0];
387 for(
int mi=0; mi<llsq_m; mi++) {
388 ftac.
c[ti].
y[mi]=0.0;
389 for(
int ni=0; ni<llsq_n; ni++) ftac.
c[ti].
y[mi]+=llsq_x[ni]*matbackup[mi+ni*llsq_m];
393 free(llsq_a); free(llsq_mat);
405 if(verbose>1) printf(
"writing %s\n", parfile);
406 FILE *fp; fp=fopen(parfile,
"w");
408 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", parfile);
420 if(verbose>0) printf(
"Results saved in %s.\n", parfile);
428 if(verbose>1) printf(
"writing %s\n", safile);
429 FILE *fp; fp=fopen(safile,
"w");
431 fprintf(stderr,
"Error: cannot open file for writing (%s)\n", safile);
442 if(verbose>0) printf(
"SA results written in %s.\n", safile);
450 if(verbose>1) printf(
"writing %s\n", fitfile);
452 FILE *fp; fp=fopen(fitfile,
"w");
454 fprintf(stderr,
"Error: cannot open file for writing fitted TTACs.\n");
465 if(verbose>0) printf(
"fitted TACs saved in %s.\n", fitfile);
int bfm1TCM(TAC *input, TAC *tissue, int bfNr, const double k2min, const double k2max, const int distr, TAC *bf, TPCSTATUS *status)
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 iftPut(IFT *ift, const char *key, const char *value, char comment, TPCSTATUS *status)
int atoiCheck(const char *s, int *v)
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,...
int nnls(double **a, int m, int n, double *b, double *x, double *rnorm, double *wp, double *zzp, int *indexp)
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)
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)
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.
char * tacFormattxt(tacformat c)
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
int tacSetX(TAC *d, TPCSTATUS *status)
Set TAC x values based on x1 and x2 values, or guess x1 and x2 values based on x values.
Header file for libtpcbfm.
Header file for library libtpcextensions.
@ UNIT_ML_PER_ML_MIN
mL/(mL*min)
@ UNIT_UNKNOWN
Unknown unit.
@ TPCERROR_FAIL
General error.
char * unitName(int unit_code)
Header file for library libtpcift.
Header file for libtpcli.
Header file for libtpclinopt.
Header file for libtpcpar.
@ PAR_FORMAT_UNKNOWN
Unknown format.
@ PAR_FORMAT_TSV_UK
UK TSV (point as decimal separator).
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
@ TAC_FORMAT_PMOD
PMOD TAC format.
Header file for libtpctacmod.