10#include "tpcclibConfig.h"
29double *t, *cr, *ct, *tis, *w;
31double wss_wo_penalty=0.0;
33double rrtmFunc(
int parNr,
double *p,
void*);
37static char *info[] = {
38 "NLLSQ estimation of R1 (=K1/K1'), k2, and k3 applying the reduced reference",
39 "tissue compartment model, RRTM (1). This model is based on the reference",
40 "tissue compartment model (2, 3), but here it is assumed that the binding or",
41 "metabolism of tracer is irreversible (k4=0) during the PET scanning.",
43 "Usage: @P [Options] ttacfile reference endtime resultfile",
45 "TTAC file can be in DFT or PMOD format. Sample times must be in minutes.",
46 "If TTAC file contains weights, those are used in the NLLSQ fitting.",
47 "Reference region TAC can be given separate TAC file or as the name or number",
48 "of the reference region in TTAC file.",
52 " Specify the constraints for model parameters;",
53 " This file with default values can be created by giving this option",
54 " as the only command-line argument to this program.",
56 " Standard deviations are calculated and saved in results (y), or",
57 " not calculated (n).",
59 " 95% Confidence limits are calculated and saved in results (y), or",
60 " not calculated (n).",
62 " All weights are set to 1.0 (no weighting); by default, weights in",
63 " TTAC file are used, if available.",
65 " Weight by sampling interval.",
67 " Fitted regional TACs are written in file.",
69 " Fitted and measured TACs are plotted in specified SVG file.",
73 "Values of R1, k2, and k3 are written in the specified result file.",
74 "Fitted curves are written in DFT format, if file name is given.",
76 "Example 1: file a789.dft contains regions-of-interest and reference region,",
77 "with name 'cereb'. The whole time range is used in the fit.",
78 "Fitted TACs are plotted in SVG format.",
79 " @P -svg=a789rrtm.svg a789.dft cereb 999 a789.res",
81 "Example 2: Reference region TAC is in a separate file, a789ref.dft.",
82 "Standard deviations and confidence limits are also estimated.",
83 "TAC data from injection to 60 min is used in the fitting.",
84 " @P -SD=y -CL=y a789.dft a789ref.dft 60 a789.res",
86 "Example 3a: Create a file containing default parameter limits:",
89 "Example 3b: Apply user-defined parameter constraints specified in rrtm.lim:",
90 " @P -lim=rrtm.lim a789.dft cereb 999 a789.res",
93 "1. Oikonen V. Model equations for reference tissue compartmental models.",
94 " https://www.turkupetcentre.net/reports/tpcmod0002.pdf",
95 "2. Cunningham VJ, Hume SP, Price GR, Ahier RG, Cremer JE, Jones AKP.",
96 " Compartmental analysis of diprenorphine binding to opiate receptors",
97 " in the rat in vivo and its comparison with equilibrium data in vitro.",
98 " J Cereb Blood Flow Metab 1991;11:1-9.",
99 "3. Lammertsma AA, Hume SP. Simplified reference tissue model for PET",
100 " receptor studies. NeuroImage 1996;4:153-158.",
102 "See also: patlak, fitk3, tacweigh, rescoll, sim_rtcm, fit_trtm",
104 "Keywords: TAC, modelling, irreversible uptake, RTCM, reference input",
123int main(
int argc,
char **argv)
125 int ai, help=0, version=0, verbose=1;
126 char rtacfile[FILENAME_MAX], ttacfile[FILENAME_MAX], resfile[FILENAME_MAX],
127 fitfile[FILENAME_MAX], svgfile[FILENAME_MAX], limfile[FILENAME_MAX];
128 char *cptr, tmp[256];
129 double fitdur=nan(
"");
131 int doBootstrap=0, doSD=0, doCL=0;
132 double *sd, *cl1, *cl2;
138 def_pmin[0]=0.001; def_pmax[0]=2.0;
139 def_pmin[1]=0.000001; def_pmax[1]=0.5;
140 def_pmin[2]=0.0; def_pmax[2]=1.0;
145 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
146 rtacfile[0]=ttacfile[0]=resfile[0]=fitfile[0]=svgfile[0]=limfile[0]=(char)0;
148 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
149 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
151 if(strncasecmp(cptr,
"CL", 2)==0) {
152 if(strlen(cptr)==2) {doCL=1;
continue;}
153 cptr+=2;
if(*cptr==
'=') {
155 if(*cptr==
'Y' || *cptr==
'y') {doCL=1;
continue;}
156 if(*cptr==
'N' || *cptr==
'n') {doCL=0;
continue;}
158 }
else if(strncasecmp(cptr,
"SD", 2)==0) {
159 if(strlen(cptr)==2) {doSD=1;
continue;}
160 cptr+=2;
if(*cptr==
'=') {
162 if(*cptr==
'Y' || *cptr==
'y') {doSD=1;
continue;}
163 if(*cptr==
'N' || *cptr==
'n') {doSD=0;
continue;}
165 }
else if(strncasecmp(cptr,
"LIM=", 4)==0 && strlen(cptr)>4) {
166 strlcpy(limfile, cptr+4, FILENAME_MAX);
continue;
167 }
else if(strcasecmp(cptr,
"LIM")==0) {
168 strcpy(limfile,
"stdout");
continue;
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(
"doBootstrap := %d\n", doBootstrap);
216 printf(
"doSD := %d\n", doSD);
217 printf(
"doCL := %d\n", doCL);
222 if(limfile[0] && !ttacfile[0]) {
224 if(strcasecmp(limfile,
"stdout")!=0 && access(limfile, 0) != -1) {
225 fprintf(stderr,
"Error: parameter constraint file %s exists.\n", limfile);
228 if(verbose>1 && strcasecmp(limfile,
"stdout")!=0)
229 printf(
"writing parameter constraints file\n");
240 fprintf(stderr,
"Error in writing '%s': %s\n", limfile, ift.
status);
243 if(strcasecmp(limfile,
"stdout")!=0)
244 fprintf(stdout,
"Parameter file %s with initial values written.\n", limfile);
251 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
260 if(verbose>1) printf(
"reading %s\n", limfile);
263 ret=
iftRead(&ift, limfile, 1, 0);
265 fprintf(stderr,
"Error in reading '%s': %s\n", limfile, ift.
status);
268 if(verbose>10)
iftWrite(&ift,
"stdout", 0);
277 if(n==0) {fprintf(stderr,
"Error: invalid parameter file.\n");
return(9);}
281 for(
int pi=0; pi<parNr; pi++) {
282 if(verbose>3) printf(
" %d %g %g\n", pi+1, def_pmin[pi], def_pmax[pi]);
283 if(def_pmin[pi]<0.0) ret++;
284 if(def_pmax[pi]<def_pmin[pi]) ret++;
285 if(def_pmax[pi]>def_pmin[pi]) n++;
286 if(verbose>3 && ret>0) printf(
" -> invalid\n");
289 fprintf(stderr,
"Error: invalid parameter constraints.\n");
293 fprintf(stderr,
"Error: no model parameters left free for fitting.\n");
297 printf(
"Parameter constraints:\n");
298 for(
int pi=0; pi<parNr; pi++) {
299 printf(
"def_pmin[%d] := %g\n", pi+1, def_pmin[pi]);
300 printf(
"def_pmax[%d] := %g\n", pi+1, def_pmax[pi]);
309 if(verbose>1) printf(
"reading %s\n", ttacfile);
312 fprintf(stderr,
"Error in reading '%s': %s\n", ttacfile,
dfterrmsg);
317 fprintf(stderr,
"Error: missing sample(s) in %s\n", ttacfile);
324 if(ret) fprintf(stderr,
"Warning: check that regional data times are in minutes.\n");
327 if(verbose>2) fprintf(stdout,
"checking frame overlap in %s\n", ttacfile);
330 fprintf(stderr,
"Error: %s has overlapping frame times.\n", ttacfile);
336 double starttime, endtime;
337 starttime=0.0; endtime=fitdur;
338 fitframeNr=
fittime_from_dft(&dft, &starttime, &endtime, &first, &last, verbose-2);
340 fprintf(stderr,
"Error: too few data points for a decent fit.\n");
344 printf(
"dft.frameNr := %d\n", dft.
frameNr);
345 printf(
"starttime := %g\n", starttime);
346 printf(
"endtime := %g\n", endtime);
347 printf(
"first := %d\n", first);
348 printf(
"last := %d\n", last);
349 printf(
"fitframeNr := %d\n", fitframeNr);
355 fprintf(stderr,
"Error: TACs must start at time zero.\n");
358 if(dft.
x1[0]>0.0833333) {
359 fprintf(stderr,
"Warning: TACs should start at time zero.\n");
362 if(verbose>2) printf(
"Tissue calibration unit := %s\n", dft.
unit);
367 for(
int i=0; i<dft.
frameNr; i++) dft.
w[i]=1.0;
368 }
else if(weights==2) {
370 fprintf(stderr,
"Error: cannot set data weights.\n");
374 fprintf(stderr,
"Warning: data is not weighted.\n");
378 fprintf(stdout,
"common_data_weights := %g", dft.
w[0]);
379 for(
int i=1; i<dft.
frameNr; i++) fprintf(stdout,
", %g", dft.
w[i]);
380 fprintf(stdout,
"\n");
387 if(verbose>1) printf(
"\nreading reference\n");
388 int inputtype=-1, ref=-1;
391 fprintf(stderr,
"Error in reading reference input: %s\n", tmp);
392 dftEmpty(&dft);
if(verbose>1) printf(
"ret := %d\n", ret);
396 fprintf(stderr,
"Warning: several reference regions found: %s selected.\n", dft.
voi[ref].
name);
397 }
else if(verbose>1) printf(
"reference_region := %s\n", dft.
voi[ref].
name);
398 if(verbose>2) printf(
"inputtype := %d\n", inputtype);
404 fprintf(stderr,
"Error: cannot allocate more memory.\n");
409 strcpy(dft.
voi[bsi].
name,
"BS");
417 if(verbose>1) printf(
"initializing result data\n");
420 fprintf(stderr,
"Error: cannot set-up memory for results.\n");
426 if(inputtype!=5 && rtacfile[0]) strcpy(res.
reffile, rtacfile);
442 pi++; strcpy(res.
parname[pi],
"k2"); strcpy(res.
parunit[pi],
"1/min");
443 pi++; strcpy(res.
parname[pi],
"k3"); strcpy(res.
parunit[pi],
"1/min");
444 pi++; strcpy(res.
parname[pi],
"WSS"); strcpy(res.
parunit[pi],
"");
452 if(verbose>0) printf(
"\nfitting...\n");
453 int tgoNr=0, neighNr=0, iterNr=0;
456 t=dft.
x; cr=dft.
voi[ref].
y;
458 for(
int ri=0; ri<dft.
voiNr; ri++)
if(ri!=ref) {
460 if(verbose>1) printf(
"Region %d %s\n", ri+1, dft.
voi[ri].
name);
462 tis=dft.
voi[ri].
y; ct=dft.
voi[ri].
y2; w=dft.
w;
466 for(
int pi=0; pi<parNr; pi++) {pmin[pi]=def_pmin[pi]; pmax[pi]=def_pmax[pi];}
468 printf(
"Parameter constraints:\n");
469 for(
int pi=0; pi<parNr; pi++) printf(
" %10.3E - %10.3E\n", pmin[pi], pmax[pi]);
473 if(verbose>2) printf(
" fitting curve...\n");
478 ret=
tgo(pmin, pmax, rrtmFunc, NULL, parNr, neighNr, &wss, p, tgoNr, iterNr, verbose-8);
480 fprintf(stderr,
"Error in optimization (%d).\n", ret);
484 for(
int pi=0; pi<parNr; pi++) printf(
" %g", p[pi]);
485 printf(
" -> WSS=%g\n", p[parNr]); fflush(stdout);
489 p[parNr]=wss=wss_wo_penalty;
490 if(verbose>2) printf(
"wss := %g\nfitframeNr := %d\n", wss, fitframeNr);
494 if(verbose>2) printf(
" bootstrapping...\n");
497 if(doSD) sd=res.
voi[ri].
sd;
else sd=NULL;
498 if(doCL) {cl1=res.
voi[ri].
cl1; cl2=res.
voi[ri].
cl2;}
else cl1=cl2=NULL;
500 0, cl1, cl2, sd, p, pmin, pmax, fitframeNr,
505 parNr, w, rrtmFunc, tmp, verbose-5
508 fprintf(stderr,
"Error in bootstrap: %s\n", tmp);
509 for(
int pi=0; pi<parNr; pi++) {
510 if(doSD) sd[pi]=nan(
"");
511 if(doCL) cl1[pi]=cl2[pi]=nan(
"");
519 if(verbose>0) {fprintf(stdout,
"\n"); fflush(stdout);}
531 if(verbose>0) {
resPrint(&res); fprintf(stdout,
"\n");}
537 if(verbose>1) printf(
"saving results in %s\n", resfile);
538 ret=
resWrite(&res, resfile, verbose-5);
540 fprintf(stderr,
"Error in writing '%s': %s\n", resfile,
reserrmsg);
544 if(verbose>0) fprintf(stdout,
"Model parameters written in %s\n", resfile);
551 if(svgfile[0] || fitfile[0]) {
558 fprintf(stderr,
"Error: cannot save fitted curves.\n");
562 for(
int ri=0; ri<dft.
voiNr; ri++)
564 for(
int fi=0; fi<fitframeNr; fi++)
570 if(verbose>1) printf(
"saving SVG plot\n");
571 sprintf(tmp,
"RRTM fit ");
574 0.0, nan(
""), svgfile, verbose-8);
576 fprintf(stderr,
"Error (%d) in writing '%s'.\n", ret, svgfile);
580 if(verbose>0) printf(
"Plots written in %s\n", svgfile);
590 if(verbose>1) printf(
"saving fitted curves\n");
592 sprintf(dft2.
comments,
"# program := %s\n", tmp);
594 fprintf(stderr,
"Error in writing '%s': %s\n", fitfile,
dfterrmsg);
598 if(verbose>0) printf(
"Fitted TACs written in %s\n", fitfile);
617double rrtmFunc(
int parNr,
double *p,
void *fdata)
620 double R1, k2, k3, d, wss=0.0;
628 R1=pa[0]; k2=pa[1]; k3=pa[2];
631 ret=
simRTCM(t, cr, fitframeNr, R1, k2, k3, 0.0, ct, NULL, NULL);
633 fprintf(stderr,
" error %d in simulation\n", ret);
638 for(
int i=0; i<fitframeNr; i++)
if(w[i]>0.0) {
644 if(0) printf(
"R1=%g k2=%g k3=%g => %g\n", R1, k2, k3, 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)
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]