10#include "tpcclibConfig.h"
26static char *info[] = {
27 "Calculate K1, k2, and K1/k2 using multiple-time graphical analysis (MTGA)",
28 "for reversible PET ligands (Yokoi plot) (1,2,3) from regional PET TACs.",
30 "Usage: @P [options] tacfile input starttime endtime resultfile",
34 " Standard deviations are saved (y) or not saved (n, default) in results.",
36 " Plots are written in specified file in Scalable Vector Graphics (SVG) 1.1",
37 " format; specification in https://www.w3.org/TR/SVG/",
39 " Data for plots is written in TSV format for easy importing in Excel",
40 " or OpenOffice spreadsheet, where the data can be viewed.",
44 "1. Yokoi T, Iida H, Itoh H, Kanno I. A new graphic plot analysis for cerebral",
45 " blood flow and partition coefficient with iodine-123-iodoamphetamine",
46 " and dynamic SPECT validation studies using oxygen-15-water and PET.",
47 " J Nucl Med. 1993; 34(3): 498-505.",
48 "2. Ito H, Yokoi T, Ikoma Y, et al. A new graphic plot analysis for",
49 " determination of neuroreceptor binding in positron emission tomography",
50 " studies. NeuroImage 2010; 49(1): 578-586.",
51 "3. Ito H, Ikoma Y, Seki C, et al. Visual evaluation of kinetic",
52 " characteristics of PET probe for neuroreceptors using a two-phase graphic",
53 " plot analysis. Ann Nucl Med. 2017; 31(4): 273-282.",
55 "See also: logan, patlak, fitk2, lhsol",
57 "Keywords: TAC, MTGA, modelling, K1, Vt",
76int main(
int argc,
char **argv)
78 int ai, help=0, version=0, verbose=1;
79 char tacfile[FILENAME_MAX], inpfile[FILENAME_MAX], resfile[FILENAME_MAX];
80 char svgfile[FILENAME_MAX], plotfile[FILENAME_MAX];
82 double tstart=nan(
""), tstop=nan(
"");
87 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
88 tacfile[0]=inpfile[0]=resfile[0]=svgfile[0]=plotfile[0]=(char)0;
90 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
92 char *cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(!*cptr)
continue;
93 if(strncasecmp(cptr,
"SVG=", 4)==0) {
94 strlcpy(svgfile, cptr+4, FILENAME_MAX);
if(strlen(svgfile)>0)
continue;
95 }
else if(strncasecmp(cptr,
"PLOT=", 5)==0) {
96 strlcpy(plotfile, cptr+5, FILENAME_MAX);
if(strlen(plotfile)>0)
continue;
97 }
else if(strncasecmp(cptr,
"SD=", 3)==0) {
98 save_stat=
tpcYesNo(cptr+3);
if(save_stat>=0)
continue;
100 fprintf(stderr,
"Error: invalid option '%s'\n", argv[ai]);
109 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
114 if(ai<argc)
strlcpy(tacfile, argv[ai++], FILENAME_MAX);
115 if(ai<argc)
strlcpy(inpfile, argv[ai++], FILENAME_MAX);
118 fprintf(stderr,
"Error: invalid start time '%s'.\n", argv[ai]);
return(1);}
123 fprintf(stderr,
"Error: invalid stop time '%s'.\n", argv[ai]);
return(1);}
126 if(ai<argc)
strlcpy(resfile, argv[ai++], FILENAME_MAX);
128 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
133 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
137 if(!isnan(tstart) && !isnan(tstop) && tstop<=tstart) {
138 fprintf(stderr,
"Error: illegal time range %g-%g\n", tstart, tstop);
145 printf(
"tacfile := %s\n", tacfile);
146 printf(
"inpfile := %s\n", inpfile);
147 printf(
"resfile := %s\n", resfile);
148 if(svgfile[0]) printf(
"svgfile := %s\n", svgfile);
149 if(plotfile[0]) printf(
"plotfile := %s\n", plotfile);
150 printf(
"tstart := %g\n", tstart);
151 printf(
"tstop := %g\n", tstop);
152 printf(
"save_stat := %d\n", save_stat);
159 if(verbose>0) printf(
"reading tissue and input data\n");
163 if(tstop>0.01) fitdur=tstop;
else fitdur=1.0E+10;
166 &fitSampleNr, &tac, &input, &status)!=
TPCERROR_OK) {
172 printf(
"tacNr := %d\n", tac.
tacNr);
173 printf(
"tac.sampleNr := %d\n", tac.
sampleNr);
174 printf(
"input.sampleNr := %d\n", input.
sampleNr);
175 printf(
"fitSampleNr := %d\n", fitSampleNr);
178 printf(
"fitdur := %g s\n", fitdur);
185 printf(
"istart := %d\n", istart);
186 printf(
"istop := %d\n", istop);
188 int fitNr=1+istop-istart;
190 fprintf(stderr,
"Error: invalid line fit range.\n");
198 if(verbose>1) printf(
"integrating and interpolating input TAC\n");
210 if(verbose>1) printf(
"integrating TTAC\n");
223 if(verbose>1) {printf(
"initializing parameter data\n"); fflush(stdout);}
238 iftPut(&par.
h,
"program", buf, 0, NULL);
240 iftPut(&par.
h,
"datafile", tacfile, 0, NULL);
241 iftPut(&par.
h,
"inputfile", inpfile, 0, NULL);
244 iftPut(&par.
h,
"study_number", buf, 0, NULL);
246 iftPut(&par.
h,
"model",
"Yokoi plot", 0, NULL);
253 i++; strcpy(par.
n[i].
name,
"K1/k2");
261 fprintf(stderr,
"Error: cannot allocate space for plots.\n");
271 if(verbose>1) {printf(
"\ncalculating one TTAC at a time...\n"); fflush(stdout);}
273 for(
int ti=0; ti<tac.
tacNr; ti++) {
274 if(verbose>2 && tac.
tacNr>1) {printf(
"Region %d %s\n", 1+ti, tac.
c[ti].
name); fflush(stdout);}
276 double plotx[fitSampleNr];
277 for(
int i=0; i<fitSampleNr; i++) plotx[i]=tac1.
c[ti].
y[i]/input1.
c[0].
y[i];
279 double ploty[fitSampleNr];
280 for(
int i=0; i<fitSampleNr; i++) ploty[i]=tac.
c[ti].
y[i]/input1.
c[0].
y[i];
282 printf(
"\tX\tY\tCt\tiCt\tiCp\tT\n");
283 for(
int i=0; i<fitSampleNr; i++)
if(i>=istart && i<=istop)
284 printf(
"\t%.3g\t%.3g\t%.3g\t%.3g\t%.3g\t%g\n", plotx[i], ploty[i], tac.
c[ti].
y[i],
285 tac1.
c[ti].
y[i], input1.
c[0].
y[i], tac.
x[i]);
288 double slope, ic, slope_sd, ic_sd, xic, xic_sd, y_sd;
291 n=
fitLine(plotx+istart, ploty+istart, fitNr, &slope, &ic);
294 &slope, &slope_sd, &ic, &ic_sd, &xic, &xic_sd, NULL, &y_sd);
295 if(n==0 || isnan(slope) || isnan(ic)) {
296 fprintf(stderr,
"Error: cannot fit %s\n", tac.
c[ti].
name); fflush(stderr);
300 par.
r[ti].
p[1]=-slope;
301 par.
r[ti].
p[2]=-ic/slope;
303 par.
r[ti].
sd[0]=ic_sd;
304 par.
r[ti].
sd[1]=slope_sd;
305 par.
r[ti].
sd[2]=xic_sd;
309 par.
r[ti].
end=tac.
x[istop];
314 fprintf(stderr,
"Error: cannot copy plot data.\n"); fflush(stderr);
319 for(
int i=0; i<fitSampleNr; i++)
320 if(isfinite(plotx[i])) plots.
tac[plots.
nr].
x[i]=plotx[i];
321 else plots.
tac[plots.
nr].
x[i]=nan(
"");
324 for(
int i=0; i<fitSampleNr; i++) {
325 plots.
tac[plots.
nr].
c[0].
y[i]=plots.
tac[plots.
nr].
c[1].
y[i]=nan(
"");
326 if(isfinite(ploty[i])) {
327 if(i>=istart && i<=istop) plots.
tac[plots.
nr].
c[0].
y[i]=ploty[i];
328 else plots.
tac[plots.
nr].
c[1].
y[i]=ploty[i];
331 plots.
tac[plots.
nr].
c[2].
y[i]=ic+slope*plotx[i];
337 fprintf(stderr,
"Error: cannot calculate Yokoi MTGA.\n");
341 if(verbose>1) {printf(
"... done.\n"); fflush(stdout);}
353 if(verbose>1) {printf(
"writing %s\n", resfile); fflush(stdout);}
358 FILE *fp; fp=fopen(resfile,
"w");
360 fprintf(stderr,
"Error: cannot open file for writing parameters.\n");
370 if(verbose>0) {printf(
"Results saved in %s.\n", resfile); fflush(stdout);}
378 if(verbose>1) {printf(
"writing %s\n", plotfile); fflush(stdout);}
379 FILE *fp; fp=fopen(plotfile,
"w");
381 fprintf(stderr,
"Error: cannot open file for writing plot data.\n");
385 fprintf(fp,
"Yokoi plot");
389 for(
int ti=0; ti<plots.
nr; ti++)
if(plots.
tac[ti].
sampleNr>0) {
390 fprintf(fp,
"\n%s\n", plots.
tac[ti].
c[0].
name);
391 fprintf(fp,
"X\tFitted\tIgnored\tRegression\n");
393 if(isfinite(plots.
tac[ti].
x[i])) fprintf(fp,
"%g", plots.
tac[ti].
x[i]);
395 if(isfinite(plots.
tac[ti].
c[0].
y[i])) fprintf(fp,
"%g", plots.
tac[ti].
c[0].
y[i]);
397 if(isfinite(plots.
tac[ti].
c[1].
y[i])) fprintf(fp,
"%g", plots.
tac[ti].
c[1].
y[i]);
399 if(isfinite(plots.
tac[ti].
c[2].
y[i])) fprintf(fp,
"%g", plots.
tac[ti].
c[2].
y[i]);
404 if(verbose>0) {printf(
"Plot data saved in %s.\n", plotfile); fflush(stdout);}
412 if(verbose>1) {printf(
"writing %s\n", svgfile); fflush(stdout);}
413 char mtitle[256]; strcpy(mtitle,
"Yokoi plot");
416 strcat(mtitle,
" "); strcat(mtitle, buf);
424 if(verbose>0) {printf(
"Plot saved in %s.\n", svgfile); fflush(stdout);}
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)
unsigned int doubleGEIndex(double *a, const unsigned int n, double lim)
unsigned int doubleGTIndex(double *a, const unsigned int n, double lim)
int iftPut(IFT *ift, const char *key, const char *value, char comment, TPCSTATUS *status)
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 mtacAllocate(MTAC *mtac, int nr)
void mtacFree(MTAC *mtac)
void mtacInit(MTAC *mtac)
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 tpcYesNo(const char *s)
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 fitLinePearson(double *x, double *y, const int n, double *m, double *msd, double *c, double *csd, double *d, double *dsd, double *r, double *ysd)
int fitLine(double *x, double *y, const int n, double *m, double *c)
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]
IFT h
Optional (but often useful) header information.
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
int tacAllocate(TAC *tac, int sampleNr, int tacNr)
int mtgaPlotSVG(MTAC *mtac, const char *main_title, const char *fname, TPCSTATUS *status)
int tacGetHeaderStudynr(IFT *h, char *s, TPCSTATUS *status)
char * tacFormattxt(tacformat c)
Header file for library libtpcextensions.
@ UNIT_ML_PER_ML_MIN
mL/(mL*min)
@ TPCERROR_FAIL
General error.
char * unitName(int unit_code)
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.
Header file for libtpctacmod.