10#include "tpcclibConfig.h"
25static char *info[] = {
26 "Calculates Fractional Uptake Rate (FUR) or FUR-based Metabolic Rate (MR)",
27 "from regional PET TTACs. Information on FUR in:",
28 "https://www.turkupetcentre.net/petanalysis/model_fur.html",
30 "Usage: @P [Options] inputfile ttacfile starttime endtime resultfile",
32 "FUR calculation start and stop time must be entered in minutes;",
33 "set both to zero to use the whole time range from TTAC data.",
37 " Concentration of native substrate in arterial plasma (mM),",
38 " for example plasma glucose in [18F]FDG studies.",
39 " With this option the metabolic rate (umol/(min*100 g)) is calculated.",
41 " Lumped Constant in MR calculation; default is 1.0.",
43 " Tissue density in MR calculation; default is 1.0 g/ml.",
45 " FUR as a function of time is written in specified file; this can be",
46 " used to study the time-dependence of FUR estimates.",
48 " Input AUC is normally calculated from 0 to the middle time of FUR",
49 " calculation time; in special cases this option can be used to",
50 " calculate it from 0 to the specified time instead.",
52 " Tentative option for calculating FUR as ratio of tissue derivative and",
53 " plasma. This does not affect the FUR curve made with option -curve.",
56 "Example 1. Calculation of FUR from dynamic PET data from 45 to 60 min:",
57 " @P ua2918ap.kbq ua2918dy1.dft 45 60 ua2918fur.res",
59 "Example 2. Calculation of glucose uptake, when tissue density is 1.04,",
60 "plasma glucose concentration is 5.2 mM, lumped constant is 0.52, from",
61 "a static (one frame) scan:",
62 " @P -Ca=5.2 -LC=0.52 -d=1.04 a864ap.kbq a864dy1.dft 0 0 a864mrglu.res",
64 "FUR and MR results are saved in result file format by default, but if",
65 "filename extension is set to .dft, .csv, .dat, or .html, results are saved",
68 "The unit of FUR is (mL plasma)/(min*(mL tissue)) by default, and",
69 "umol/(min*100 g) if metabolic rate is calculated.",
71 "See also: patlak, dftinteg, taccalc, tactime, dftsuv, rescoll, imgfur",
73 "Keywords: TAC, modelling, FUR, retention index, irreversible uptake",
90#define DEFAULT_LC 1.00
92#ifndef DEFAULT_DENSITY
93#define DEFAULT_DENSITY 1.00
101int main(
int argc,
char **argv)
103 int ai, help=0, version=0, verbose=1;
105 char inpfile[FILENAME_MAX], petfile[FILENAME_MAX];
106 char curfile[FILENAME_MAX], outfile[FILENAME_MAX], tmp[1024], *cptr;
107 DFT input, auc, pet, avg;
109 double startTime=-1.0, endTime=-1.0, aucTime=-1.0;
110 double LC=-1.0, Ca=-1.0, density=-1.0;
117 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
118 inpfile[0]=petfile[0]=outfile[0]=curfile[0]=(char)0;
121 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
122 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
124 if(strncasecmp(cptr,
"CA=", 3)==0) {
125 Ca=
atof_dpi(cptr+3);
if(Ca>0.0)
continue;
126 }
else if(strncasecmp(cptr,
"LC=", 3)==0) {
127 LC=
atof_dpi(cptr+3);
if(LC>0.0)
continue;
128 }
else if(strncasecmp(cptr,
"D=", 2)==0) {
129 density=
atof_dpi(cptr+2);
if(density>0.0)
continue;
130 }
else if(strncasecmp(cptr,
"DENSITY=", 8)==0) {
131 density=
atof_dpi(cptr+8);
if(density>0.0)
continue;
132 }
else if(strncasecmp(cptr,
"DERIVATIVE", 5)==0) {
133 fur_mode=1;
continue;
134 }
else if(strncasecmp(cptr,
"CURVE=", 6)==0 && strlen(cptr)>6) {
135 strcpy(curfile, cptr+6);
continue;
136 }
else if(strncasecmp(cptr,
"IT=", 3)==0) {
137 aucTime=
atof_dpi(cptr+3);
if(aucTime>0.0)
continue;
139 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
144 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
149 for(; ai<argc; ai++) {
151 strcpy(inpfile, argv[ai]);
continue;
152 }
else if(!petfile[0]) {
153 strcpy(petfile, argv[ai]);
continue;
154 }
else if(startTime<0.0) {
155 startTime=
atof_dpi(argv[ai]);
if(startTime<0.0) startTime=0.0;
157 }
else if(endTime<0.0) {
158 endTime=
atof_dpi(argv[ai]);
if(endTime<0.0) endTime=0.0;
160 }
else if(!outfile[0]) {
161 strcpy(outfile, argv[ai]);
continue;
163 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
169 fprintf(stderr,
"Error: missing result file name.\n");
177 fprintf(stderr,
"Warning: LC not set, using default %g\n", LC);
180 density=DEFAULT_DENSITY;
181 fprintf(stderr,
"Warning: tissue density not set, using default %g\n",
185 if(LC>0.0) fprintf(stderr,
"Warning: LC was set but is not used.\n");
187 fprintf(stderr,
"Warning: tissue density was set but is not used.\n");
190 if(endTime<startTime) {
191 fprintf(stderr,
"Error: invalid time range.\n");
194 if(startTime==endTime && startTime>0.5) {
195 startTime-=0.5; endTime+=0.5;
201 printf(
"inpfile := %s\n", inpfile);
202 printf(
"petfile := %s\n", petfile);
203 printf(
"outfile := %s\n", outfile);
204 printf(
"curfile := %s\n", curfile);
206 printf(
"startTime := %g min\n", startTime);
207 printf(
"endTime := %g min\n", endTime);
210 printf(
"aucTime := %g min\n", aucTime);
213 printf(
"Ca := %g\n", Ca);
214 printf(
"LC := %g\n", LC);
215 printf(
"density := %g\n", density);
217 printf(
"fur_mode := %d\n", fur_mode);
225 if(verbose>1) printf(
"reading regional data %s\n", petfile);
227 fprintf(stderr,
"Error in reading '%s': %s\n", petfile,
dfterrmsg);
231 fprintf(stderr,
"Error: missing values in %s\n", petfile);
240 if(verbose>2) fprintf(stdout,
"checking frame overlap in %s\n", petfile);
243 fprintf(stderr,
"Error: %s has overlapping frame times.\n", petfile);
250 if(ret) fprintf(stderr,
"Warning: check that regional data times are in minutes.\n");
252 if(endTime<=1.0E-02) {
254 startTime=pet.
x1[0]; endTime=pet.
x2[pet.
frameNr-1];
256 startTime=pet.
x[0]; endTime=pet.
x[pet.
frameNr-1];
259 printf(
"startTime := %g min\n", startTime);
260 printf(
"endTime := %g min\n", endTime);
268 if(verbose>1) printf(
"calculating average\n");
269 ret=
dftTimeIntegral(&pet, startTime, endTime, &avg, 1, tmp, verbose-3);
271 fprintf(stderr,
"Error: %s.\n", tmp);
273 printf(
"dftTimeIntegral(pet, %g, %g, avg, 1, tmp) := %d\n", startTime, endTime, ret);
276 if(verbose>1) fprintf(stdout,
"%s.\n", tmp);
279 double k, ksd, b, bsd, r, ysd;
281 fprintf(stdout,
"calculating slope\n"); fflush(stdout);}
282 for(ri=0; ri<pet.
voiNr; ri++) {
284 &k, &ksd, &b, &bsd, &r, &ysd);
289 fprintf(stderr,
"Error: tissue slope calculation not successful.\n");
290 if(verbose>1) printf(
" ret := %d\n", ret);
295 printf(
"Regional tissue value or derivative\n");
296 for(
int ri=0; ri<avg.
voiNr; ri++)
297 printf(
"%s : %g\n", avg.
voi[ri].
name, avg.
voi[ri].
y[0]);
303 if(verbose>1) printf(
"Reading input file %s\n", inpfile);
305 fprintf(stderr,
"Error in reading '%s': %s\n", inpfile,
dfterrmsg);
309 fprintf(stderr,
"Warning: only first TAC is used as input.\n");
313 fprintf(stderr,
"Error: missing values in %s\n", inpfile);
322 if(ret) fprintf(stderr,
"Warning: check that input times are in minutes.\n");
329 fprintf(stderr,
"Warning: check the units of input and regional data.\n");
338 if(verbose>1) {printf(
"calculating FUR curve\n"); fflush(stdout);}
343 fprintf(stderr,
"Warning: cannot allocate memory for FUR curves\n");
347 for(fi=0; fi<pet.
frameNr; fi++) {
348 if(pet.
x[fi]<startTime || pet.
x[fi]>endTime)
continue;
352 if(ret!=0) {fprintf(stderr,
"Warning (%d): %s\n", ret, tmp);
break;}
353 if(auc.
voi[0].
y[0]<1.0E-006)
continue;
358 for(ri=0; ri<fur.
voiNr; ri++)
362 if(ret!=0)
goto failed;
367 fprintf(stderr,
"Error in writing %s: %s\n", curfile,
dfterrmsg);
377 if(aucTime<=0.0) aucTime=0.5*(startTime+endTime);
381 ret=
dftTimeIntegral(&input, startTime, endTime, &auc, 1, tmp, verbose-3);
383 fprintf(stderr,
"Error (%d): %s\n", ret, tmp);
389 printf(
"AUC[%g-%g] := %g\n", auc.
x1[0], auc.
x2[0], auc.
voi[0].
y[0]);
391 printf(
"Input[%g-%g] := %g\n", auc.
x1[0], auc.
x2[0], auc.
voi[0].
y[0]);
401 for(
int ri=0; ri<avg.
voiNr; ri++) avg.
voi[ri].
y[0]/=auc.
voi[0].
y[0];
413 MRf=100.*Ca/(density*LC);
415 fprintf(stdout,
"converting FUR to metabolic rate with factor %g\n", MRf);
416 for(
int ri=0; ri<avg.
voiNr; ri++) avg.
voi[ri].
y[0]*=MRf;
425 fprintf(stderr,
"Error: %s\n", tmp);
428 if(verbose>2) printf(
"%s\n", tmp);
431 cptr=strrchr(outfile,
'.');
432 if(cptr!=NULL && strcasecmp(cptr,
".DFT")==0) {
435 fprintf(stderr,
"Error in writing %s: %s\n", outfile,
dfterrmsg);
438 }
else if(cptr!=NULL && strcasecmp(cptr,
".CSV")==0) {
442 fprintf(stderr,
"Error in writing %s: %s\n", outfile,
dfterrmsg);
445 }
else if(cptr!=NULL && strcasecmp(cptr,
".DAT")==0) {
449 fprintf(stderr,
"Error in writing %s: %s\n", outfile,
dfterrmsg);
456 fprintf(stderr,
"Error: %s.\n", tmp);
461 cptr=strrchr(petfile,
'/');
if(cptr==NULL) cptr=strrchr(petfile,
'\\');
462 if(cptr==NULL) cptr=petfile;
else cptr++; strcpy(res.
datafile, cptr);
463 cptr=strrchr(inpfile,
'/');
if(cptr==NULL) cptr=strrchr(inpfile,
'\\');
464 if(cptr==NULL) cptr=inpfile;
else cptr++; strcpy(res.
plasmafile, cptr);
470 if(Ca>0.0) strcpy(res.
parname[0],
"MR");
else strcpy(res.
parname[0],
"FUR");
472 ret=
resWrite(&res, outfile, verbose-3);
474 fprintf(stderr,
" Error (%d) in writing file %s\n", ret, outfile);
480 if(Ca<=0.0) fprintf(stdout,
"FUR(s) saved in %s.\n", outfile);
481 else fprintf(stdout,
"MRs saved in %s.\n", outfile);
int backupExistingFile(char *filename, char *backup_ext, char *status)
double atof_dpi(char *str)
int dftdup(DFT *dft1, DFT *dft2)
int dftDeleteFrameOverlap(DFT *dft)
void dftSetComments(DFT *dft)
int dftSortByFrame(DFT *dft)
int dft_nr_of_NA(DFT *dft)
int dftTimeIntegral(DFT *dft, double t1, double t2, DFT *idft, int calc_mode, char *status, int verbose)
int dftRead(char *filename, DFT *data)
int dftWrite(DFT *data, char *filename)
int dftToResult(DFT *dft, RES *res, char *status)
void dftUnitToDFT(DFT *dft, int dunit)
int dftUnitConversion(DFT *dft, int dunit)
int dftTimeunitConversion(DFT *dft, int tunit)
Header file for libtpccurveio.
#define DFT_FORMAT_CSV_UK
int resWrite(RES *res, char *filename, int verbose)
#define DFT_TIME_STARTEND
Header file for libtpcmisc.
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)
Header file for libtpcmodel.
int pearson4(double *x, double *y, int nr, double start, double end, double *k, double *kSD, double *b, double *bSD, double *r, double *ySD)
Calculate slope and intercept of a line and Pearson's correlation coefficient.
Header file for libtpcmodext.
char unit[MAX_UNITS_LEN+1]
char parname[MAX_RESPARAMS][MAX_RESPARNAME_LEN+1]
char plasmafile[FILENAME_MAX]
char datafile[FILENAME_MAX]
char name[MAX_REGIONNAME_LEN+1]