10#include "tpcclibConfig.h"
29double *t, *cr, *ct, *tis, *w;
31double wss_wo_penalty=0.0;
33double frtmFunc(
int parNr,
double *p,
void*);
37static char *info[] = {
38 "NLLSQ estimation of R1 (=K1/K1'), k2, k3, and BPnd (binding potential)",
39 "using the (full) reference tissue compartment model, FRTM/RTCM (1,3).",
40 "Assumption is that K1/k2 is the same in all brain regions, but 1TCM with",
41 "plasma input does not need to fit the tissue curves satisfactorily",
42 "as is assumed in SRTM (2), and Cref(t) is not assumed to be the same as",
43 "Cfree(t) as is assumed in the ratio methods.",
45 "Usage: @P [Options] ttacfile reference endtime resultfile",
47 "TTAC file can be in DFT or PMOD format. Sample times must be in minutes.",
48 "If TTAC file contains weights, those are used in the NLLSQ fitting.",
49 "Reference region TAC can be given separate TAC file or as the name or number",
50 "of the reference region in TTAC file.",
54 " Instead of BPnd, program saves the DVR (=BPnd+1) values.",
56 " Specify the constraints for model parameters;",
57 " This file with default values can be created by giving this option",
58 " as the only command-line argument to this program.",
60 " Standard deviations are calculated and saved in results (y), or",
61 " not calculated (n).",
63 " 95% Confidence limits are calculated and saved in results (y), or",
64 " not calculated (n).",
66 " All weights are set to 1.0 (no weighting); by default, weights in",
67 " TTAC file are used, if available.",
69 " Weight by sampling interval.",
71 " Fitted regional TACs are written in file.",
73 " Fitted and measured TACs are plotted in specified SVG file.",
77 "Values of R1, k2, k3, and BPnd are written in the specified result file.",
78 "Fitted curves are written in DFT format, if file name is given.",
80 "Example 1: file a789.tac contains regions-of-interest and reference region,",
81 "with name 'cereb all'. The whole time range is used in the fit.",
82 " @P a789.tac 'cereb all' 999 a789.res",
84 "Example 2: Reference region TAC is in a separate file, a789ref.tac;",
85 "standard deviations and confidence limits are also estimated.",
86 " @P -SD=y -CL=y a789.tac a789ref.tac 999 a789.res",
89 "1. Cunningham VJ, Hume SP, Price GR, Ahier RG, Cremer JE, Jones AKP.",
90 " Compartmental analysis of diprenorphine binding to opiate receptors",
91 " in the rat in vivo and its comparison with equilibrium data in vitro.",
92 " J Cereb Blood Flow Metab 1991;11:1-9.",
93 "2. Lammertsma AA, Hume SP. Simplified reference tissue model for PET",
94 " receptor studies. Neuroimage 1996;4:153-158.",
95 "3. Oikonen V, Sederholm K. TPCMOD0002: Model equations for reference tissue",
96 " compartmental models. https://www.turkupetcentre.net/reports/tpcmod0002.pdf",
98 "See also: bfmsrtm, tacweigh, rescoll, logan, fit_srtm, sim_rtcm",
100 "Keywords: TAC, modelling, binding potential, RTCM, reference input",
119int main(
int argc,
char **argv)
121 int ai, help=0, version=0, verbose=1;
122 char rtacfile[FILENAME_MAX], ttacfile[FILENAME_MAX], resfile[FILENAME_MAX],
123 fitfile[FILENAME_MAX], svgfile[FILENAME_MAX], limfile[FILENAME_MAX];
124 char *cptr, tmp[256];
125 double fitdur=nan(
"");
128 int doBootstrap=0, doSD=0, doCL=0;
129 double *sd, *cl1, *cl2;
135 def_pmin[0]=0.001; def_pmax[0]=10.0;
136 def_pmin[1]=0.000001; def_pmax[1]=1.0;
137 def_pmin[2]=0.0; def_pmax[2]=1.0;
138 def_pmin[3]=0.0; def_pmax[3]=60.0;
143 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
144 rtacfile[0]=ttacfile[0]=resfile[0]=fitfile[0]=svgfile[0]=limfile[0]=(char)0;
146 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
147 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
149 if(strncasecmp(cptr,
"CL", 2)==0) {
150 if(strlen(cptr)==2) {doCL=1;
continue;}
151 cptr+=2;
if(*cptr==
'=') {
153 if(*cptr==
'Y' || *cptr==
'y') {doCL=1;
continue;}
154 if(*cptr==
'N' || *cptr==
'n') {doCL=0;
continue;}
156 }
else if(strncasecmp(cptr,
"SD", 2)==0) {
157 if(strlen(cptr)==2) {doSD=1;
continue;}
158 cptr+=2;
if(*cptr==
'=') {
160 if(*cptr==
'Y' || *cptr==
'y') {doSD=1;
continue;}
161 if(*cptr==
'N' || *cptr==
'n') {doSD=0;
continue;}
163 }
else if(strncasecmp(cptr,
"LIM=", 4)==0 && strlen(cptr)>4) {
164 strlcpy(limfile, cptr+4, FILENAME_MAX);
continue;
165 }
else if(strcasecmp(cptr,
"LIM")==0) {
166 strcpy(limfile,
"stdout");
continue;
167 }
else if(strcasecmp(cptr,
"DVR")==0) {
169 }
else if(strcasecmp(cptr,
"W1")==0) {
171 }
else if(strcasecmp(cptr,
"WF")==0) {
173 }
else if(strncasecmp(cptr,
"FIT=", 4)==0) {
174 strlcpy(fitfile, cptr+4, FILENAME_MAX);
if(strlen(fitfile)>0)
continue;
175 }
else if(strncasecmp(cptr,
"SVG=", 4)==0) {
176 strlcpy(svgfile, cptr+4, FILENAME_MAX);
if(strlen(svgfile)>0)
continue;
178 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
183 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
188 if(ai<argc)
strlcpy(ttacfile, argv[ai++], FILENAME_MAX);
189 if(ai<argc)
strlcpy(rtacfile, argv[ai++], FILENAME_MAX);
192 fprintf(stderr,
"Error: invalid fit time: '%s'.\n", argv[ai]);
195 if(fitdur==0) fitdur=1.0E+10;
198 if(ai<argc)
strlcpy(resfile, argv[ai++], FILENAME_MAX);
200 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
203 if(doSD || doCL) doBootstrap=1;
else doBootstrap=0;
207 printf(
"ttacfile := %s\n", ttacfile);
208 printf(
"reference := %s\n", rtacfile);
209 printf(
"resfile := %s\n", resfile);
210 printf(
"fitfile := %s\n", fitfile);
211 printf(
"svgfile := %s\n", svgfile);
212 printf(
"limfile := %s\n", limfile);
213 printf(
"required_fittime := %g min\n", fitdur);
214 printf(
"weights := %d\n", weights);
215 printf(
"doDVR := %d\n", doDVR);
216 printf(
"doBootstrap := %d\n", doBootstrap);
217 printf(
"doSD := %d\n", doSD);
218 printf(
"doCL := %d\n", doCL);
223 if(limfile[0] && !ttacfile[0]) {
225 if(strcasecmp(limfile,
"stdout")!=0 && access(limfile, 0) != -1) {
226 fprintf(stderr,
"Error: parameter constraint file %s exists.\n", limfile);
229 if(verbose>1 && strcasecmp(limfile,
"stdout")!=0)
230 printf(
"writing parameter constraints file\n");
243 fprintf(stderr,
"Error in writing '%s': %s\n", limfile, ift.
status);
246 if(strcasecmp(limfile,
"stdout")!=0)
247 fprintf(stdout,
"Parameter file %s with initial values written.\n", limfile);
254 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
263 if(verbose>1) printf(
"reading %s\n", limfile);
266 ret=
iftRead(&ift, limfile, 1, 0);
268 fprintf(stderr,
"Error in reading '%s': %s\n", limfile, ift.
status);
271 if(verbose>10)
iftWrite(&ift,
"stdout", 0);
282 if(n==0) {fprintf(stderr,
"Error: invalid parameter file.\n");
return(9);}
286 for(
int pi=0; pi<parNr; pi++) {
287 if(verbose>3) printf(
" %d %g %g\n", pi+1, def_pmin[pi], def_pmax[pi]);
288 if(def_pmin[pi]<0.0 && pi!=3) ret++;
289 if(def_pmax[pi]<def_pmin[pi]) ret++;
290 if(def_pmax[pi]>def_pmin[pi]) n++;
291 if(verbose>3 && ret>0) printf(
" -> invalid\n");
294 fprintf(stderr,
"Error: invalid parameter constraints.\n");
298 fprintf(stderr,
"Error: no model parameters left free for fitting.\n");
302 printf(
"Parameter constraints:\n");
303 for(
int pi=0; pi<parNr; pi++) {
304 printf(
"def_pmin[%d] := %g\n", pi+1, def_pmin[pi]);
305 printf(
"def_pmax[%d] := %g\n", pi+1, def_pmax[pi]);
314 if(verbose>1) printf(
"reading %s\n", ttacfile);
317 fprintf(stderr,
"Error in reading '%s': %s\n", ttacfile,
dfterrmsg);
322 fprintf(stderr,
"Error: missing sample(s) in %s\n", ttacfile);
329 if(ret) fprintf(stderr,
"Warning: check that regional data times are in minutes.\n");
332 if(verbose>2) fprintf(stdout,
"checking frame overlap in %s\n", ttacfile);
335 fprintf(stderr,
"Error: %s has overlapping frame times.\n", ttacfile);
341 double starttime, endtime;
342 starttime=0.0; endtime=fitdur;
343 fitframeNr=
fittime_from_dft(&dft, &starttime, &endtime, &first, &last, verbose-2);
345 fprintf(stderr,
"Error: too few data points for a decent fit.\n");
349 printf(
"dft.frameNr := %d\n", dft.
frameNr);
350 printf(
"starttime := %g\n", starttime);
351 printf(
"endtime := %g\n", endtime);
352 printf(
"first := %d\n", first);
353 printf(
"last := %d\n", last);
354 printf(
"fitframeNr := %d\n", fitframeNr);
360 fprintf(stderr,
"Error: TACs must start at time zero.\n");
363 if(dft.
x1[0]>0.0833333) {
364 fprintf(stderr,
"Warning: TACs should start at time zero.\n");
367 if(verbose>2) printf(
"Tissue calibration unit := %s\n", dft.
unit);
372 for(
int i=0; i<dft.
frameNr; i++) dft.
w[i]=1.0;
373 }
else if(weights==2) {
375 fprintf(stderr,
"Error: cannot set data weights.\n");
379 fprintf(stderr,
"Warning: data is not weighted.\n");
383 fprintf(stdout,
"common_data_weights := %g", dft.
w[0]);
384 for(
int i=1; i<dft.
frameNr; i++) fprintf(stdout,
", %g", dft.
w[i]);
385 fprintf(stdout,
"\n");
392 if(verbose>1) printf(
"\nreading reference\n");
393 int inputtype=-1, ref=-1;
396 fprintf(stderr,
"Error in reading reference input: %s\n", tmp);
397 dftEmpty(&dft);
if(verbose>1) printf(
"ret := %d\n", ret);
401 fprintf(stderr,
"Warning: several reference regions found: %s selected.\n", dft.
voi[ref].
name);
402 }
else if(verbose>1) printf(
"reference_region := %s\n", dft.
voi[ref].
name);
403 if(verbose>2) printf(
"inputtype := %d\n", inputtype);
408 for(
int ri=0; ri<dft.
voiNr; ri++)
411 for(
int ri=0; ri<dft.
voiNr; ri++)
419 fprintf(stderr,
"Error: cannot allocate more memory.\n");
424 strcpy(dft.
voi[bsi].
name,
"BS");
432 if(verbose>1) printf(
"initializing result data\n");
435 fprintf(stderr,
"Error: cannot set-up memory for results.\n");
441 if(inputtype!=5 && rtacfile[0]) strcpy(res.
reffile, rtacfile);
457 pi++; strcpy(res.
parname[pi],
"k2"); strcpy(res.
parunit[pi],
"1/min");
458 pi++; strcpy(res.
parname[pi],
"k3"); strcpy(res.
parunit[pi],
"1/min");
459 pi++;
if(doDVR==0) strcpy(res.
parname[pi],
"BP");
else strcpy(res.
parname[pi],
"DVR");
461 pi++; strcpy(res.
parname[pi],
"WSS"); strcpy(res.
parunit[pi],
"");
470 if(verbose>0) printf(
"\nfitting...\n");
471 int tgoNr=0, neighNr=0, iterNr=0;
474 t=dft.
x; cr=dft.
voi[ref].
y;
475 double refIntegral=dft.
voi[ref].
y3[fitframeNr-1];
477 for(
int ri=0; ri<dft.
voiNr; ri++)
if(ri!=ref) {
479 if(verbose>1) printf(
"Region %d %s\n", ri+1, dft.
voi[ri].
name);
481 tis=dft.
voi[ri].
y; ct=dft.
voi[ri].
y2; w=dft.
w;
485 for(
int pi=0; pi<parNr; pi++) {pmin[pi]=def_pmin[pi]; pmax[pi]=def_pmax[pi];}
488 if(!limfile[0] && refIntegral>0.0) {
490 a=(dft.
voi[ri].
y3[fitframeNr-1]/refIntegral);
493 pmin[3]=b; pmax[3]=c;
496 printf(
"Parameter constraints:\n");
497 for(
int pi=0; pi<parNr; pi++) printf(
" %10.3E - %10.3E\n", pmin[pi], pmax[pi]);
501 if(verbose>2) printf(
" fitting curve...\n");
506 ret=
tgo(pmin, pmax, frtmFunc, NULL, parNr, neighNr, &wss, p, tgoNr, iterNr, verbose-8);
508 fprintf(stderr,
"Error in optimization (%d).\n", ret);
512 for(
int pi=0; pi<parNr; pi++) printf(
" %g", p[pi]);
513 printf(
" -> WSS=%g\n", p[parNr]); fflush(stdout);
517 p[parNr]=wss=wss_wo_penalty;
518 if(verbose>2) printf(
"wss := %g\nfitframeNr := %d\n", wss, fitframeNr);
522 if(verbose>2) printf(
" bootstrapping...\n");
525 if(doSD) sd=res.
voi[ri].
sd;
else sd=NULL;
526 if(doCL) {cl1=res.
voi[ri].
cl1; cl2=res.
voi[ri].
cl2;}
else cl1=cl2=NULL;
528 0, cl1, cl2, sd, p, pmin, pmax, fitframeNr,
533 parNr, w, frtmFunc, tmp, verbose-5
536 fprintf(stderr,
"Error in bootstrap: %s\n", tmp);
537 for(
int pi=0; pi<parNr; pi++) {
538 if(doSD) sd[pi]=nan(
"");
539 if(doCL) cl1[pi]=cl2[pi]=nan(
"");
547 if(verbose>0) {fprintf(stdout,
"\n"); fflush(stdout);}
560 if(verbose>1) printf(
"converting BP to DVR\n");
561 for(
int ri=0; ri<res.
voiNr; ri++) {
563 if(doCL && !isnan(res.
voi[ri].
cl1[3])) res.
voi[ri].
cl1[3]+=1.0;
564 if(doCL && !isnan(res.
voi[ri].
cl2[3])) res.
voi[ri].
cl2[3]+=1.0;
571 if(verbose>0) {
resPrint(&res); fprintf(stdout,
"\n");}
577 if(verbose>1) printf(
"saving results in %s\n", resfile);
578 ret=
resWrite(&res, resfile, verbose-5);
580 fprintf(stderr,
"Error in writing '%s': %s\n", resfile,
reserrmsg);
584 if(verbose>0) fprintf(stdout,
"Model parameters written in %s\n", resfile);
591 if(svgfile[0] || fitfile[0]) {
598 fprintf(stderr,
"Error: cannot save fitted curves.\n");
602 for(
int ri=0; ri<dft.
voiNr; ri++)
604 for(
int fi=0; fi<fitframeNr; fi++)
610 if(verbose>1) printf(
"saving SVG plot\n");
611 sprintf(tmp,
"FRTM fit ");
614 0.0, nan(
""), svgfile, verbose-8);
616 fprintf(stderr,
"Error (%d) in writing '%s'.\n", ret, svgfile);
620 if(verbose>0) printf(
"Plots written in %s\n", svgfile);
630 if(verbose>1) printf(
"saving fitted curves\n");
632 sprintf(dft2.
comments,
"# program := %s\n", tmp);
634 fprintf(stderr,
"Error in writing '%s': %s\n", fitfile,
dfterrmsg);
638 if(verbose>0) printf(
"Fitted TACs written in %s\n", fitfile);
657double frtmFunc(
int parNr,
double *p,
void *fdata)
660 double R1, k2, k3, k4, BP, d, wss=0.0;
668 R1=pa[0]; k2=pa[1]; k3=pa[2]; BP=pa[3];
669 if(BP>0.0) k4=k3/BP;
else k4=0.0;
672 ret=
simRTCM(t, cr, fitframeNr, R1, k2, k3, k4, ct, NULL, NULL);
674 fprintf(stderr,
" error %d in simulation\n", ret);
679 for(
int i=0; i<fitframeNr; i++)
if(w[i]>0.0) {
685 if(0) printf(
"R1=%g k2=%g k3=%g BP=%g => %g\n", R1, k2, k3, BP, wss);
int bootstrap(int iterNr, double *cLim1, double *cLim2, double *SD, double *parameter, double *lowlim, double *uplim, int frameNr, double *origTac, double *fitTac, double *bsTac, int parNr, double *weight, double(*objf)(int, double *, void *), char *status, int verbose)
int modelCheckParameters(int par_nr, double *lower_p, double *upper_p, double *test_p, double *accept_p, double *penalty)
int atof_with_check(char *double_as_string, double *result_value)
int dftdup(DFT *dft1, DFT *dft2)
int dftDeleteFrameOverlap(DFT *dft)
int dftAddmem(DFT *dft, int voiNr)
int dftSortByFrame(DFT *dft)
int dftDelete(DFT *dft, int voi)
int dft_nr_of_NA(DFT *dft)
int dftRead(char *filename, DFT *data)
int dftWrite(DFT *data, char *filename)
int res_allocate_with_dft(RES *res, DFT *dft)
int dftTimeunitConversion(DFT *dft, int tunit)
int fittime_from_dft(DFT *dft, double *startTime, double *endTime, int *first, int *last, int verbose)
int iftPutDouble(IFT *ift, char *key, double value, char *cmt_type, int verbose)
int iftRead(IFT *ift, char *filename, int is_key_required, int verbose)
int iftWrite(IFT *ift, char *filename, int verbose)
int iftGetDoubleValue(IFT *ift, int si, const char *key, double *value, int verbose)
int petintegrate(double *x1, double *x2, double *y, int nr, double *newyi, double *newyii)
int integrate(double *x, double *y, int nr, double *yi)
Header file for libtpccurveio.
int resWrite(RES *res, char *filename, int verbose)
int resDelete(RES *res, int voi)
#define DFT_TIME_STARTEND
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
size_t strlcpy(char *dst, const char *src, size_t dstsize)
void tpcProgramName(const char *program, int version, int copyright, char *prname, int n)
char * petTunit(int tunit)
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)
Header file for libtpcmodel.
int tgo(double *lowlim, double *uplim, double(*objf)(int, double *, void *), void *objfData, int dim, int neighNr, double *fmin, double *gmin, int samNr, int tgoNr, int verbose)
int simRTCM(double *t, double *cr, int nr, double R1, double k2, double k3, double k4, double *ct, double *cta, double *ctb)
Header file for libtpcmodext.
int dftWeightByFreq(DFT *dft)
int plot_fitrange_svg(DFT *dft1, DFT *dft2, char *main_title, double x1, double x2, double y1, double y2, char *fname, int verbose)
Header file for libtpcsvg.
char studynr[MAX_STUDYNR_LEN+1]
char comments[_DFT_COMMENT_LEN+1]
char unit[MAX_UNITS_LEN+1]
char parname[MAX_RESPARAMS][MAX_RESPARNAME_LEN+1]
char datafile[FILENAME_MAX]
char reffile[FILENAME_MAX]
char parunit[MAX_RESPARAMS][MAX_RESPARNAME_LEN+1]
double parameter[MAX_RESPARAMS]
double cl2[MAX_RESPARAMS]
double cl1[MAX_RESPARAMS]
char voiname[MAX_REGIONSUBNAME_LEN+1]
char name[MAX_REGIONNAME_LEN+1]