10#include "tpcclibConfig.h"
29double *t, *cr, *ct, *tis, *w;
31double wss_wo_penalty=0.0;
33double srtmFunc(
int parNr,
double *p,
void*);
37static char *info[] = {
38 "NLLSQ estimation of R1 (=K1/K1'), k2 and, BPnd (binding potential) using",
39 "simplified reference tissue compartment model, SRTM (1,2,3).",
40 "Assumptions are that K1/k2 is the same in all brain regions, and that ",
41 "1TCM with plasma input could fit the tissue curves satisfactorily.",
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 " Instead of BPnd, program saves the DVR (=BPnd+1) values.",
54 " Specify the constraints for model parameters;",
55 " This file with default values can be created by giving this option",
56 " as the only command-line argument to this program.",
58 " Standard deviations are calculated and saved in results (y), or",
59 " not calculated (n).",
61 " 95% Confidence limits are calculated and saved in results (y), or",
62 " not calculated (n).",
64 " All weights are set to 1.0 (no weighting); by default, weights in",
65 " TTAC file are used, if available.",
67 " Weight by sampling interval.",
69 " Fitted regional TACs are written in file.",
71 " Fitted and measured TACs are plotted in specified SVG file.",
75 "Values of R1, k2, k2', and BPnd are written in the specified result file.",
76 "Fitted curves are written in DFT format, if file name is given.",
78 "Example 1: file a789.tac contains regions-of-interest and reference region,",
79 "with name 'cereb all'. The whole time range is used in the fit.",
80 " @P a789.tac 'cereb all' 999 a789.res",
82 "Example 2: Reference region TAC is in a separate file, a789ref.tac;",
83 "standard deviations and confidence limits are also estimated.",
84 " @P -SD=y -CL=y a789.tac a789ref.tac 999 a789.res",
87 "1. Cunningham VJ, Hume SP, Price GR, Ahier RG, Cremer JE, Jones AKP.",
88 " Compartmental analysis of diprenorphine binding to opiate receptors",
89 " in the rat in vivo and its comparison with equilibrium data in vitro.",
90 " J Cereb Blood Flow Metab 1991;11:1-9.",
91 "2. Lammertsma AA, Hume SP. Simplified reference tissue model for PET",
92 " receptor studies. Neuroimage 1996;4:153-158.",
93 "3. Oikonen V, Sederholm K. TPCMOD0002: Model equations for reference tissue",
94 " compartmental models. https://www.turkupetcentre.net/reports/tpcmod0002.pdf",
96 "See also: bfmsrtm, tacweigh, rescoll, logan, fit_frtm, sim_rtcm",
98 "Keywords: TAC, modelling, binding potential, SRTM, reference input",
117int main(
int argc,
char **argv)
119 int ai, help=0, version=0, verbose=1;
120 char rtacfile[FILENAME_MAX], ttacfile[FILENAME_MAX], resfile[FILENAME_MAX],
121 fitfile[FILENAME_MAX], svgfile[FILENAME_MAX], limfile[FILENAME_MAX];
122 char *cptr, tmp[256];
123 double fitdur=nan(
"");
126 int doBootstrap=0, doSD=0, doCL=0;
127 double *sd, *cl1, *cl2;
133 def_pmin[0]=0.001; def_pmax[0]=10.0;
134 def_pmin[1]=0.000001; def_pmax[1]=10.0;
135 def_pmin[2]=0.0; def_pmax[2]=60.0;
140 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
141 rtacfile[0]=ttacfile[0]=resfile[0]=fitfile[0]=svgfile[0]=limfile[0]=(char)0;
143 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
144 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
146 if(strncasecmp(cptr,
"CL", 2)==0) {
147 if(strlen(cptr)==2) {doCL=1;
continue;}
148 cptr+=2;
if(*cptr==
'=') {
150 if(*cptr==
'Y' || *cptr==
'y') {doCL=1;
continue;}
151 if(*cptr==
'N' || *cptr==
'n') {doCL=0;
continue;}
153 }
else if(strncasecmp(cptr,
"SD", 2)==0) {
154 if(strlen(cptr)==2) {doSD=1;
continue;}
155 cptr+=2;
if(*cptr==
'=') {
157 if(*cptr==
'Y' || *cptr==
'y') {doSD=1;
continue;}
158 if(*cptr==
'N' || *cptr==
'n') {doSD=0;
continue;}
160 }
else if(strncasecmp(cptr,
"LIM=", 4)==0 && strlen(cptr)>4) {
161 strlcpy(limfile, cptr+4, FILENAME_MAX);
continue;
162 }
else if(strcasecmp(cptr,
"LIM")==0) {
163 strcpy(limfile,
"stdout");
continue;
164 }
else if(strcasecmp(cptr,
"DVR")==0) {
166 }
else if(strcasecmp(cptr,
"W1")==0) {
168 }
else if(strcasecmp(cptr,
"WF")==0) {
170 }
else if(strncasecmp(cptr,
"FIT=", 4)==0) {
171 strlcpy(fitfile, cptr+4, FILENAME_MAX);
if(strlen(fitfile)>0)
continue;
172 }
else if(strncasecmp(cptr,
"SVG=", 4)==0) {
173 strlcpy(svgfile, cptr+4, FILENAME_MAX);
if(strlen(svgfile)>0)
continue;
175 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
180 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
185 if(ai<argc)
strlcpy(ttacfile, argv[ai++], FILENAME_MAX);
186 if(ai<argc)
strlcpy(rtacfile, argv[ai++], FILENAME_MAX);
189 fprintf(stderr,
"Error: invalid fit time: '%s'.\n", argv[ai]);
192 if(fitdur==0) fitdur=1.0E+10;
195 if(ai<argc)
strlcpy(resfile, argv[ai++], FILENAME_MAX);
197 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
200 if(doSD || doCL) doBootstrap=1;
else doBootstrap=0;
204 printf(
"ttacfile := %s\n", ttacfile);
205 printf(
"reference := %s\n", rtacfile);
206 printf(
"resfile := %s\n", resfile);
207 printf(
"fitfile := %s\n", fitfile);
208 printf(
"svgfile := %s\n", svgfile);
209 printf(
"limfile := %s\n", limfile);
210 printf(
"required_fittime := %g min\n", fitdur);
211 printf(
"weights := %d\n", weights);
212 printf(
"doDVR := %d\n", doDVR);
213 printf(
"doBootstrap := %d\n", doBootstrap);
214 printf(
"doSD := %d\n", doSD);
215 printf(
"doCL := %d\n", doCL);
220 if(limfile[0] && !ttacfile[0]) {
222 if(strcasecmp(limfile,
"stdout")!=0 && access(limfile, 0) != -1) {
223 fprintf(stderr,
"Error: parameter constraint file %s exists.\n", limfile);
226 if(verbose>1 && strcasecmp(limfile,
"stdout")!=0)
227 printf(
"writing parameter constraints file\n");
238 fprintf(stderr,
"Error in writing '%s': %s\n", limfile, ift.
status);
241 if(strcasecmp(limfile,
"stdout")!=0)
242 fprintf(stdout,
"Parameter file %s with initial values written.\n", limfile);
249 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
259 if(verbose>1) printf(
"reading %s\n", limfile);
262 ret=
iftRead(&ift, limfile, 1, 0);
264 fprintf(stderr,
"Error in reading '%s': %s\n", limfile, ift.
status);
267 if(verbose>10)
iftWrite(&ift,
"stdout", 0);
276 if(n==0) {fprintf(stderr,
"Error: invalid parameter file.\n");
return(9);}
280 for(
int pi=0; pi<parNr; pi++) {
281 if(verbose>3) printf(
" %d %g %g\n", pi+1, def_pmin[pi], def_pmax[pi]);
284 if(def_pmax[pi]<=0.0) ret++;
285 if(def_pmax[pi]<def_pmin[pi]) ret++;
286 if(def_pmax[pi]>def_pmin[pi]) n++;
287 if(verbose>3 && ret>0) printf(
" -> invalid\n");
290 fprintf(stderr,
"Error: invalid parameter constraints.\n");
294 fprintf(stderr,
"Error: no model parameters left free for fitting.\n");
298 printf(
"Parameter constraints:\n");
299 for(
int pi=0; pi<parNr; pi++) {
300 printf(
"def_pmin[%d] := %g\n", pi+1, def_pmin[pi]);
301 printf(
"def_pmax[%d] := %g\n", pi+1, def_pmax[pi]);
310 if(verbose>1) printf(
"reading %s\n", ttacfile);
313 fprintf(stderr,
"Error in reading '%s': %s\n", ttacfile,
dfterrmsg);
318 fprintf(stderr,
"Error: missing sample(s) in %s\n", ttacfile);
325 if(ret) fprintf(stderr,
"Warning: check that regional data times are in minutes.\n");
328 if(verbose>2) fprintf(stdout,
"checking frame overlap in %s\n", ttacfile);
331 fprintf(stderr,
"Error: %s has overlapping frame times.\n", ttacfile);
337 double starttime, endtime;
338 starttime=0.0; endtime=fitdur;
339 fitframeNr=
fittime_from_dft(&dft, &starttime, &endtime, &first, &last, verbose-2);
341 fprintf(stderr,
"Error: too few data points for a decent fit.\n");
345 printf(
"dft.frameNr := %d\n", dft.
frameNr);
346 printf(
"starttime := %g\n", starttime);
347 printf(
"endtime := %g\n", endtime);
348 printf(
"first := %d\n", first);
349 printf(
"last := %d\n", last);
350 printf(
"fitframeNr := %d\n", fitframeNr);
356 fprintf(stderr,
"Error: TACs must start at time zero.\n");
359 if(dft.
x1[0]>0.0833333) {
360 fprintf(stderr,
"Warning: TACs should start at time zero.\n");
363 if(verbose>2) printf(
"Tissue calibration unit := %s\n", dft.
unit);
368 for(
int i=0; i<dft.
frameNr; i++) dft.
w[i]=1.0;
369 }
else if(weights==2) {
371 fprintf(stderr,
"Error: cannot set data weights.\n");
375 fprintf(stderr,
"Warning: data is not weighted.\n");
379 fprintf(stdout,
"common_data_weights := %g", dft.
w[0]);
380 for(
int i=1; i<dft.
frameNr; i++) fprintf(stdout,
", %g", dft.
w[i]);
381 fprintf(stdout,
"\n");
388 if(verbose>1) printf(
"\nreading reference\n");
389 int inputtype=-1, ref=-1;
392 fprintf(stderr,
"Error in reading reference input: %s\n", tmp);
393 dftEmpty(&dft);
if(verbose>1) printf(
"ret := %d\n", ret);
397 fprintf(stderr,
"Warning: several reference regions found: %s selected.\n", dft.
voi[ref].
name);
398 }
else if(verbose>1) printf(
"reference_region := %s\n", dft.
voi[ref].
name);
399 if(verbose>2) printf(
"inputtype := %d\n", inputtype);
404 for(
int ri=0; ri<dft.
voiNr; ri++)
407 for(
int ri=0; ri<dft.
voiNr; ri++)
415 fprintf(stderr,
"Error: cannot allocate more memory.\n");
420 strcpy(dft.
voi[bsi].
name,
"BS");
428 if(verbose>1) printf(
"initializing result data\n");
431 fprintf(stderr,
"Error: cannot set-up memory for results.\n");
437 if(inputtype!=5 && rtacfile[0]) strcpy(res.
reffile, rtacfile);
452 pi++; strcpy(res.
parname[pi],
"k2"); strcpy(res.
parunit[pi],
"1/min");
453 pi++; strcpy(res.
parname[pi],
"k2r"); strcpy(res.
parunit[pi],
"1/min");
454 pi++;
if(doDVR==0) strcpy(res.
parname[pi],
"BP");
else strcpy(res.
parname[pi],
"DVR");
456 pi++; strcpy(res.
parname[pi],
"WSS"); strcpy(res.
parunit[pi],
"");
465 if(verbose>0) printf(
"\nfitting...\n");
466 int tgoNr=0, neighNr=0, iterNr=0;
469 t=dft.
x; cr=dft.
voi[ref].
y;
470 double refIntegral=dft.
voi[ref].
y3[fitframeNr-1];
472 for(
int ri=0; ri<dft.
voiNr; ri++)
if(ri!=ref) {
474 if(verbose>1) printf(
"Region %d %s\n", ri+1, dft.
voi[ri].
name);
476 tis=dft.
voi[ri].
y; ct=dft.
voi[ri].
y2; w=dft.
w;
480 for(
int pi=0; pi<parNr; pi++) {pmin[pi]=def_pmin[pi]; pmax[pi]=def_pmax[pi];}
483 if(!limfile[0] && refIntegral>0.0) {
485 a=(dft.
voi[ri].
y3[fitframeNr-1]/refIntegral);
488 pmin[2]=b; pmax[2]=c;
491 printf(
"Parameter constraints:\n");
492 for(
int pi=0; pi<parNr; pi++) printf(
" %10.3E - %10.3E\n", pmin[pi], pmax[pi]);
496 if(verbose>2) printf(
" fitting curve...\n");
501 ret=
tgo(pmin, pmax, srtmFunc, NULL, parNr, neighNr, &wss, p, tgoNr, iterNr, verbose-8);
503 fprintf(stderr,
"Error in optimization (%d).\n", ret);
507 for(
int pi=0; pi<parNr; pi++) printf(
" %g", p[pi]);
508 printf(
" -> WSS=%g\n", p[parNr]); fflush(stdout);
512 p[parNr]=wss=wss_wo_penalty;
513 if(verbose>2) printf(
"wss := %g\nfitframeNr := %d\n", wss, fitframeNr);
517 if(verbose>2) printf(
" bootstrapping...\n");
520 if(doSD) sd=res.
voi[ri].
sd;
else sd=NULL;
521 if(doCL) {cl1=res.
voi[ri].
cl1; cl2=res.
voi[ri].
cl2;}
else cl1=cl2=NULL;
523 0, cl1, cl2, sd, p, pmin, pmax, fitframeNr,
528 parNr, w, srtmFunc, tmp, verbose-5
531 fprintf(stderr,
"Error in bootstrap: %s\n", tmp);
532 for(
int pi=0; pi<parNr; pi++) {
533 if(doSD) sd[pi]=nan(
"");
534 if(doCL) cl1[pi]=cl2[pi]=nan(
"");
542 if(verbose>0) {fprintf(stdout,
"\n"); fflush(stdout);}
555 if(verbose>1) printf(
"converting BP to DVR\n");
556 for(
int ri=0; ri<res.
voiNr; ri++) {
558 if(doCL && !isnan(res.
voi[ri].
cl1[2])) res.
voi[ri].
cl1[2]+=1.0;
559 if(doCL && !isnan(res.
voi[ri].
cl2[2])) res.
voi[ri].
cl2[2]+=1.0;
566 for(
int ri=0; ri<res.
voiNr; ri++) {
581 if(verbose>0) {
resPrint(&res); fprintf(stdout,
"\n");}
587 if(verbose>1) printf(
"saving results in %s\n", resfile);
588 ret=
resWrite(&res, resfile, verbose-5);
590 fprintf(stderr,
"Error in writing '%s': %s\n", resfile,
reserrmsg);
594 if(verbose>0) fprintf(stdout,
"Model parameters written in %s\n", resfile);
601 if(svgfile[0] || fitfile[0]) {
608 fprintf(stderr,
"Error: cannot save fitted curves.\n");
612 for(
int ri=0; ri<dft.
voiNr; ri++)
614 for(
int fi=0; fi<fitframeNr; fi++)
620 if(verbose>1) printf(
"saving SVG plot\n");
621 sprintf(tmp,
"SRTM fit ");
624 0.0, nan(
""), svgfile, verbose-8);
626 fprintf(stderr,
"Error (%d) in writing '%s'.\n", ret, svgfile);
630 if(verbose>0) printf(
"Plots written in %s\n", svgfile);
640 if(verbose>1) printf(
"saving fitted curves\n");
642 sprintf(dft2.
comments,
"# program := %s\n", tmp);
644 fprintf(stderr,
"Error in writing '%s': %s\n", fitfile,
dfterrmsg);
648 if(verbose>0) printf(
"Fitted TACs written in %s\n", fitfile);
667double srtmFunc(
int parNr,
double *p,
void *fdata)
670 double R1, k2, BP, d, wss=0.0;
678 R1=pa[0]; k2=pa[1]; BP=pa[2];
681 ret=
simSRTM(t, cr, fitframeNr, R1, k2, BP, ct);
683 fprintf(stderr,
" error %d in simulation\n", ret);
688 for(
int i=0; i<fitframeNr; i++)
if(w[i]>0.0) {
694 if(0) printf(
"R1=%g k2=%g BP=%g => %g\n", R1, k2, 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 simSRTM(double *t, double *cr, int nr, double R1, double k2, double BP, double *ct)
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]