8#include "tpcclibConfig.h"
24static char *info[] = {
25 "Calculates perfusion ratio from regional radiowater PET data.",
26 "In animal disease models, such as UUO model, one of kidneys is affected",
27 "by the disease model and the other kidney serves as reference organ.",
28 "Perfusion ratio can be calculated from AUCs of tissue curves without",
29 "input function (1, 2). AUCs are limited to the time of the first peak of",
30 "the control tissue curve.",
32 "Usage: @P [options] tacfile reference [outputfile]",
36 " Extend or shorten AUC calculation past the peak by specified time",
37 " (sec). Positive time extends, negative time shortens the time range.",
39 " Force given single reference region for every other TAC.",
42 "As an example, if TAC file rabbit34.tac contains tissue regions with names",
43 "UUO cortex, UUO medulla, CTRL cortex, CTRL medulla,",
44 "then to calculate AUC ratio between UUO and CTRL cortex, and",
45 "between UUO and CTRL medulla, enter command",
46 " @P rabbit34.tac CTRL rabbit34.par",
47 "Program calculates AUCs from 0 to the peak time of the individual",
48 "reference TAC, and saves AUC ratios in parameter file.",
51 "1. Xia et al. Hypertension 2008;51(2):466-473.",
52 "2. Gulaldi et al. Biomed Res Int. 2013;835859.",
54 "See also: tacpeak, interpol, taccalc, fit_h2o, dftratio",
56 "Keywords: TAC, modelling, perfusion, ratio",
75int main(
int argc,
char **argv)
77 int ai, help=0, version=0, verbose=1;
79 char tacfile[FILENAME_MAX], outfile[FILENAME_MAX], refname[256];
80 double extra_time=nan(
"");
87 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
88 tacfile[0]=outfile[0]=refname[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(strcasecmp(cptr,
"DRY")==0) {
95 }
else if(strcasecmp(cptr,
"FR")==0) {
96 force_ref=1;
continue;
97 }
else if(strncasecmp(cptr,
"ETIME=", 6)==0) {
98 extra_time=
atofVerified(cptr+6);
if(!isnan(extra_time))
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(refname, argv[ai++], 256);
116 if(ai<argc)
strlcpy(outfile, argv[ai++], FILENAME_MAX);
117 if(ai<argc) {fprintf(stderr,
"Error: too many arguments: '%s'.\n", argv[ai]);
return(1);}
120 if(!refname[0]) {
tpcPrintUsage(argv[0], info, stdout);
return(1);}
121 if(strcasecmp(tacfile, outfile)==0) {
122 fprintf(stderr,
"Error: input file would be overwritten.\n");
128 printf(
"tacfile := %s\n", tacfile);
129 printf(
"refname := %s\n", refname);
130 if(!isnan(extra_time)) printf(
"extra_time := %g\n", extra_time);
131 if(outfile[0]) printf(
"outfile := %s\n", outfile);
132 printf(
"force_ref := %d\n", force_ref);
140 if(verbose>1) printf(
"reading %s\n", tacfile);
142 ret=
tacRead(&tac, tacfile, &status);
144 fprintf(stderr,
"Error (%d): %s\n", ret,
errorMsg(status.
error));
149 printf(
"tacNr := %d\n", tac.
tacNr);
150 printf(
"sampleNr := %d\n", tac.
sampleNr);
154 if(verbose>3)
iftWrite(&tac.
h, stdout, NULL);
156 fprintf(stderr,
"Error: no data to calculate AUC ratio.\n");
160 fprintf(stderr,
"Error: sample times not available.\n");
164 fprintf(stderr,
"Error: missing values in the TAC file.\n");
173 fprintf(stderr,
"Error: invalid sample times.\n");
176 if(verbose>1) printf(
"time range: %g - %g\n", x1, x2);
179 if(!isnan(extra_time)) {
182 if(verbose>0) printf(
"extra_time converted to minutes.\n");
184 fprintf(stderr,
"Warning: sample time assumed to be in seconds.\n");
191 fprintf(stderr,
"Error: specified reference TAC not found.\n");
194 if(refNr==tac.
tacNr) {
195 fprintf(stderr,
"Error: all regions match the reference.\n");
200 if(verbose>2 || (verbose>0 && refNr!=1)) {
201 printf(
"%d tac(s) match name '%s'\n", refNr, refname); fflush(stdout);
204 if(refNr>1 && verbose>0) {
205 printf(
"%d tac(s) match name '%s'\n", refNr, refname); fflush(stdout);
209 fprintf(stderr,
"Error: cannot select best match for '%s'.\n", refname);
218 if(verbose>1) {printf(
"integrating TACs\n"); fflush(stdout);}
229 if(verbose>2) {printf(
"allocating place for results\n"); fflush(stdout);}
232 fprintf(stderr,
"Error: cannot allocate memory for results.\n");
243 iftPut(&par.
h,
"program", buf, 0, NULL);
251 iftPut(&par.
h,
"datafile", tacfile, 0, NULL);
252 iftPut(&par.
h,
"reference_name", refname, 0, NULL);
258 if(verbose>1) {printf(
"computing...\n"); fflush(stdout);}
261 if(verbose>0) {printf(
"reference '%s'\n", tac.
c[refindex].
name); fflush(stdout);}
264 if(
tacYRange(&tac, refindex, NULL, NULL, NULL, &maxi, NULL, NULL)!=0) {
265 fprintf(stderr,
"Error: no peak found for %s\n", tac.
c[refindex].
name);
269 printf(
" peak at time %g, sample %d, AUC %g\n", tac.
x[maxi], 1+maxi, auc.
c[refindex].
y[maxi]);
272 for(
int rj=0; rj<tac.
tacNr; rj++)
if(rj!=refindex) {
279 if(isnan(extra_time) || fabs(extra_time)<1.0E-06) {
281 if(verbose>4) {printf(
" AUC %g\n", auc.
c[rj].
y[maxi]); fflush(stdout);}
282 par.
r[par.
tacNr].
p[0]=auc.
c[rj].
y[maxi]/auc.
c[refindex].
y[maxi];
285 double et=tac.
x[maxi]+extra_time;
286 if(et>x2) et=x2;
else if(et<x1) et=x1;
288 double newx[1], newy[1], auc1, auc2;
290 ret=
liInterpolate(auc.
x, auc.
c[refindex].
y, auc.
sampleNr, newx, newy, NULL, NULL, 1, 3, 1, 0);
293 ret=
liInterpolate(auc.
x, auc.
c[rj].
y, auc.
sampleNr, newx, newy, NULL, NULL, 1, 3, 1, 0);
295 if(ret || isnan(auc1) || isnan(auc2)) {
296 fprintf(stderr,
"Error: cannot interpolate.\n");
299 if(verbose>4) {printf(
" AUCs %g/%g\n", auc2, auc1); fflush(stdout);}
300 par.
r[par.
tacNr].
p[0]=auc2/auc1;
309 }
else for(
int ri=0; ri<tac.
tacNr; ri++)
if(tac.
c[ri].
sw==1) {
310 if(verbose>2) {printf(
"reference '%s'\n", tac.
c[ri].
name); fflush(stdout);}
313 if(
tacYRange(&tac, ri, NULL, NULL, NULL, &maxi, NULL, NULL)!=0) {
314 if(verbose>0) fprintf(stderr,
"Error: no peak found for %s\n", tac.
c[ri].
name);
318 printf(
" peak at time %g, sample %d, AUC %g\n", tac.
x[maxi], 1+maxi, auc.
c[ri].
y[maxi]);
322 char part1[FILENAME_MAX], part2[FILENAME_MAX];
323 strcpy(part1, tac.
c[ri].
name);
char *cptr=
strdelstr(part1, refname);
324 strcpy(part2, cptr); *cptr=(char)0;
326 if(verbose>3) {printf(
" searching matches for '%s'...'%s'\n", part1, part2); fflush(stdout);}
328 for(
int rj=0; rj<tac.
tacNr; rj++)
if(tac.
c[rj].
sw==0) {
329 if(verbose>4) {printf(
" checking '%s'\n", tac.
c[rj].
name); fflush(stdout);}
330 int m=strlen(tac.
c[rj].
name);
if(m<1)
continue;
331 int n=strlen(part1);
if(m<n)
continue;
332 if(n>0 && strncasecmp(tac.
c[rj].
name, part1, n))
continue;
333 n=strlen(part2);
if(m<n)
continue;
334 if(n>0 && strcasecmp(tac.
c[rj].
name+m-n, part2))
continue;
335 if(verbose>4) {printf(
" match\n"); fflush(stdout);}
339 if(strlen(p1)>0) strcpy(par.
r[par.
tacNr].
name, p1);
340 if(strlen(p1)>0 && strlen(p2)>0) strcat(par.
r[par.
tacNr].
name,
" ");
341 if(strlen(p2)>0) strcat(par.
r[par.
tacNr].
name, p2);
350 if(isnan(extra_time) || fabs(extra_time)<1.0E-06) {
352 if(verbose>4) {printf(
" AUC %g\n", auc.
c[rj].
y[maxi]); fflush(stdout);}
353 par.
r[par.
tacNr].
p[0]=auc.
c[rj].
y[maxi]/auc.
c[ri].
y[maxi];
356 double et=tac.
x[maxi]+extra_time;
357 if(et>x2) et=x2;
else if(et<x1) et=x1;
359 double newx[1], newy[1], auc1, auc2;
361 ret=
liInterpolate(auc.
x, auc.
c[ri].
y, auc.
sampleNr, newx, newy, NULL, NULL, 1, 3, 1, 0);
364 ret=
liInterpolate(auc.
x, auc.
c[rj].
y, auc.
sampleNr, newx, newy, NULL, NULL, 1, 3, 1, 0);
366 if(ret || isnan(auc1) || isnan(auc2)) {
367 fprintf(stderr,
"Error: cannot interpolate.\n");
370 if(verbose>4) {printf(
" AUCs %g/%g\n", auc2, auc1); fflush(stdout);}
371 par.
r[par.
tacNr].
p[0]=auc2/auc1;
382 fprintf(stderr,
"Warning: no matches for '%s'\n", tac.
c[ri].
name);
384 fprintf(stderr,
"Warning: %d matches for '%s'\n", matchNr, tac.
c[ri].
name);
394 fprintf(stderr,
"Error: no data to calculate perfusion ratio.\n");
402 if(verbose>1) printf(
" saving %s\n", outfile);
403 FILE *fp=fopen(outfile,
"w");
405 fprintf(stderr,
"Error: cannot open file for writing.\n");
414 if(verbose>0) printf(
"perfusion ratios saved in %s\n", outfile);
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,...
double atofVerified(const char *s)
int iftPut(IFT *ift, const char *key, const char *value, char comment, TPCSTATUS *status)
int iftWrite(IFT *ift, FILE *fp, TPCSTATUS *status)
int liInterpolate(double *x, double *y, const int nr, double *newx, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
Linear interpolation and/or integration with trapezoidal method.
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 parAllocate(PAR *par, int parNr, int tacNr)
int parSetStudyNr(PAR *par, const char *s)
int parWrite(PAR *par, FILE *fp, parformat format, int extra, TPCSTATUS *status)
int parFormatFromExtension(const char *s)
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)
void statusInit(TPCSTATUS *s)
char * errorMsg(tpcerror e)
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
char * strdup(const char *s)
int strCleanSpaces(char *s)
char * strTrimLeft(char *s, const size_t t)
size_t strlcpy(char *dst, const char *src, size_t dstsize)
char * strdelstr(char *s1, const char *s2)
IFT h
Optional (but often useful) header information.
char name[MAX_PARNAME_LEN+1]
char name[MAX_TACNAME_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 studynrFromFilename(const char *fname, char *studynr, int force)
int tacGetHeaderStudynr(IFT *h, char *s, TPCSTATUS *status)
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
char * tacFormattxt(tacformat c)
int tacSortByTime(TAC *d, TPCSTATUS *status)
int tacSelectTACs(TAC *d, const char *region_name, int reset, TPCSTATUS *status)
int tacSelectBestReference(TAC *d)
int tacSampleXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
int tacIsX(TAC *d)
Verify if TAC structure contains reasonable x values (times).
int tacYRange(TAC *d, int i, double *ymin, double *ymax, int *smin, int *smax, int *imin, int *imax)
Get the range of y values (concentrations) in TAC struct.
Header file for library libtpcextensions.
char * unitName(int unit_code)
#define MAX_STUDYNR_LEN
Define max study number length.
Header file for library libtpcift.
Header file for libtpcli.
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.