9#include "tpcclibConfig.h"
24static char *info[] = {
25 "Calculate an average curve of several bolus input curves with different",
26 "sample times. For simulations.",
28 "Usage: @P [Options] meanfile tacfiles",
32 " Set the nr of samples to use for bolus appearance time; default is 2.",
33 " Set nr=0, if different appearance time is not to be considered.",
35 " Peak time is used to align TACs instead of bolus appearance time.",
37 " TACs are not scaled to a common AUC.",
39 " Standard deviations are not written in output file.",
43 " @P apmean.kbq up????ap.kbq",
44 "Example 2 (Windows OS):",
45 " dir /b *.kbq > filelist.txt",
46 " @P apmean.dat filelist.txt",
48 "TAC datafiles must contain a time column, and one or more concentration",
49 "columns separated by space(s) or tabulator(s). Only the first concentration",
50 "column is used in calculations.",
51 "If only one input datafile is given, it is assumed to contain a list of",
52 "bolus datafiles with paths if necessary. Tabs, commas and newlines can be",
53 "used to separate filenames in the list file.",
55 "Output datafile will contain three columns: time, avg concentration and s.d.",
56 "Program will determine the new sample times based on the shortest of input",
59 "Detailed program description:",
60 " 1) Read first curve from each datafile",
61 " 2) Replace NaNs with interpolated values.",
62 " 3) Determine bolus appearance time in each curve based on certain number",
63 " of samples with highest slope.",
64 " 4) Move all curves in time to have a common appearance time.",
65 " 5) Search the bolus curve with shortest sampling duration.",
66 " 6) Calculate AUC from 0 to that time from all curves separately.",
67 " 7) Scale all bolus curves to have the same average AUC.",
68 " 8) Interpolate all bolus curves to common sample times.",
69 " 9) Calculate the mean and s.d. curve of all bolus curves.",
70 "10) Write the mean and s.d. data in a specified ASCII datafile.",
72 "See also: avgttac, avgfract, dftavg, tacadd, interpol, tac2svg, tacformat",
74 "Keywords: TAC, simulation, modelling, input",
93int main(
int argc,
char **argv)
95 int ai, help=0, version=0, verbose=1;
97 int slopeNr=2, scaling=1, save_errors=1;
99 char *cptr, ofile[FILENAME_MAX],
108 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
112 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
114 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
115 if(strncasecmp(cptr,
"NR=", 3)==0) {
116 slopeNr=atoi(cptr+3);
continue;
117 }
else if(strncasecmp(cptr,
"NS", 2)==0) {
119 }
else if(strncasecmp(cptr,
"NE", 2)==0) {
120 save_errors=0;
continue;
121 }
else if(strcasecmp(cptr,
"PEAK")==0) {
124 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
127 if(usePeak) slopeNr=0;
130 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
135 for(; ai<argc; ai++) {
137 strlcpy(ofile, argv[ai], FILENAME_MAX);
continue;
139 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
145 if(!ofile[0] || filelist.
token_nr<1) {
146 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
152 printf(
"usePeak := %d\n", usePeak);
153 if(!usePeak) printf(
"slopeNr := %d\n", slopeNr);
154 printf(
"scaling := %d\n", scaling);
155 printf(
"save_errors := %d\n", save_errors);
156 printf(
"ofile := %s\n", ofile);
157 printf(
"token_nr := %d\n", filelist.
token_nr);
167 if(verbose>2) printf(
"filenames were given on command-line\n");
169 strcpy(tmp, filelist.
tok[0]);
170 if(access(tmp, 0) == -1) {
171 fprintf(stderr,
"Error: '%s' is not accessible.\n", tmp);
175 if(verbose>1) printf(
"reading filenames in %s\n", tmp);
178 fprintf(stderr,
"Error %d in reading filename list %s\n", ret, tmp);
189 if(verbose>1) printf(
"dftNr := %d\n", dftNr);
191 for(bi=0; bi<dftNr; bi++) {
193 fprintf(stdout,
"Bolus datafile #%d: '%s'\n", bi+1, filelist.
tok[bi]);
194 if(access(filelist.
tok[bi], 0) == -1) {
195 fprintf(stderr,
"Error: bolus file '%s' is not accessible.\n",
201 dftlist=(
DFT*)malloc(dftNr*
sizeof(
DFT));
203 fprintf(stderr,
"Error: out of memory.\n");
207 for(bi=0; bi<dftNr; bi++) {
208 if(verbose>2) printf(
"reading %s\n", filelist.
tok[bi]);
211 fprintf(stderr,
"Error in reading '%s': %s\n",filelist.
tok[bi],
dfterrmsg);
214 if(verbose>3) printf(
" -> %d frames and %d curves\n",
215 dftlist[bi].frameNr, dftlist[bi].voiNr);
216 if(dftlist[bi].frameNr<2) {
217 fprintf(stderr,
"Error: only one sample time in '%s'.\n",filelist.
tok[bi]);
221 if(bi==0) strcpy(studynr, dftlist[bi].studynr);
222 else {
if(strcasecmp(studynr, dftlist[bi].studynr)!=0) strcpy(studynr,
"");}
224 if(dftlist[bi].voiNr>1) {
225 fprintf(stderr,
"Warning: only first TAC in %s is read.\n",
231 fprintf(stderr,
"Error: cannot replace missing data in %s\n",
239 bolusv=(
double*)malloc(dftNr*
sizeof(
double));
241 fprintf(stderr,
"Error: out of memory.\n");
243 for(bi=dftNr-1; bi>=0; bi--)
dftEmpty(dftlist+bi);
253 if(verbose>1) printf(
"determining the bolus appearance times\n");
254 double slope, ic, meanAppTime;
256 for(bi=0; bi<dftNr; bi++) {
257 bolusv[bi]=0.0;
if(slopeNr<2)
continue;
259 f=dftlist[bi].
voi[0].
y[0]; n=0;
260 for(fi=1; fi<dftlist[bi].
frameNr; fi++)
if(dftlist[bi].voi[0].y[fi]>f) {
261 f=dftlist[bi].
voi[0].
y[fi]; n=fi;
263 if(verbose>2) printf(
"curve #%d: max %g at sample %d\n", bi+1, f, n+1);
266 if(n==0) {bolusv[bi]=nan(
"");
continue;}
270 dftlist[bi].x, dftlist[bi].voi[0].y, dftlist[bi].frameNr, slopeNr,
271 &slope, &ic, NULL, NULL
274 fprintf(stderr,
"Error (%d): cannot calculate max slope.\n", ret);
276 for(bi=dftNr-1; bi>=0; bi--)
dftEmpty(dftlist+bi);
280 if(slope!=0.0) bolusv[bi]=-ic/slope;
else bolusv[bi]=nan(
"");
282 printf(
" curve #%d: slopeMax %g appTime %g\n", bi+1, slope, bolusv[bi]);
286 for(bi=0; bi<dftNr; bi++)
if(!isnan(bolusv[bi]) && bolusv[bi]>0.0) {
287 meanAppTime+=bolusv[bi]; n++;}
289 meanAppTime/=(double)n;
290 if(verbose>0) fprintf(stdout,
"Mean appearance time is %g\n", meanAppTime);
293 if(slopeNr>0)
for(bi=0; bi<dftNr; bi++)
if(!isnan(bolusv[bi])) {
294 g=meanAppTime-bolusv[bi];
296 fprintf(stdout,
"%s : %g change in sample times\n", filelist.
tok[bi], g);
297 for(fi=0; fi<dftlist[bi].
frameNr; fi++) {
298 dftlist[bi].
x[fi]+=g; dftlist[bi].
x1[fi]+=g; dftlist[bi].
x2[fi]+=g;}
299 if(verbose==11)
dftPrint(dftlist+bi);
302 for(bi=0; bi<dftNr; bi++)
if(dftlist[bi].x[0]>0.0) {
305 if(dftlist[bi].x[1]>meanAppTime) dftlist[bi].
x[0]=meanAppTime;
313 if(verbose>1) printf(
"determining the peak times\n");
316 for(bi=0; bi<dftNr; bi++) {
318 NULL, &maxv, NULL, NULL, NULL, NULL);
320 fprintf(stderr,
"Error: cannot determine TAC peak.\n");
322 for(bi=dftNr-1; bi>=0; bi--)
dftEmpty(dftlist+bi);
326 if(verbose>2) printf(
"curve #%d: max %g at %g\n", bi+1, maxv, bolusv[bi]);
330 latestPeak=bolusv[0];
331 for(bi=1; bi<dftNr; bi++)
if(bolusv[bi]>latestPeak) latestPeak=bolusv[bi];
332 if(verbose>2) printf(
"latest peak time is %g\n", latestPeak);
334 for(bi=0; bi<dftNr; bi++) {
335 g=latestPeak-bolusv[bi];
337 fprintf(stdout,
"%s : %g change in sample times\n", filelist.
tok[bi], g);
338 for(fi=0; fi<dftlist[bi].
frameNr; fi++) {
339 dftlist[bi].
x[fi]+=g; dftlist[bi].
x1[fi]+=g; dftlist[bi].
x2[fi]+=g;}
340 if(verbose==11)
dftPrint(dftlist+bi);
347 double shortestTime, longestTime;
349 shortestTime=longestTime=dftlist[0].
x[dftlist[0].
frameNr-1];
350 for(bi=1; bi<dftNr; bi++) {
351 if(dftlist[bi].x[dftlist[bi].frameNr-1]<shortestTime)
352 shortestTime=dftlist[bi].
x[dftlist[bi].
frameNr-1];
353 else if(dftlist[bi].x[dftlist[bi].frameNr-1]>longestTime)
354 longestTime=dftlist[bi].
x[dftlist[bi].
frameNr-1];
357 printf(
"The shortest and longest bolus curve lengths are %g and %g\n",
358 shortestTime, longestTime);
359 if(shortestTime<=0.0) {
360 fprintf(stderr,
"Error: check the bolus sample times!\n");
361 for(bi=dftNr-1; bi>=0; bi--)
dftEmpty(dftlist+bi);
368 x[0]=0.0; x[1]=shortestTime;
369 for(bi=0; bi<dftNr; bi++) {
370 ret=
interpolate(dftlist[bi].x, dftlist[bi].voi[0].y, dftlist[bi].frameNr,
371 x, NULL, yi, NULL, 2);
373 fprintf(stderr,
"Error %d in AUC calculation: check sample times!\n", ret);
375 for(bi=dftNr-1; bi>=0; bi--)
dftEmpty(dftlist+bi);
377 free(bolusv);
return(8);
379 bolusv[bi]=yi[1]-yi[0];
380 if(verbose>3) printf(
"Curve #%d: AUC0-%g = %g\n", bi+1, shortestTime, bolusv[bi]);
383 f=0.0;
for(bi=0; bi<dftNr; bi++) f+=bolusv[bi];
385 if(verbose>2) fprintf(stdout,
"Mean AUC is %g\n", f);
388 if(verbose>1) printf(
"scaling the levels of curves based on AUC\n");
389 for(bi=0; bi<dftNr; bi++) {
392 fprintf(stdout,
"%s : scaling with factor %g\n", filelist.
tok[bi], g);
393 for(fi=0; fi<dftlist[bi].
frameNr; fi++) dftlist[bi].voi[0].y[fi]*=g;
394 if(verbose==13)
dftPrint(dftlist+bi);
405 f=0.5*(shortestTime+longestTime);
406 if(verbose>1) printf(
"interpolating to time %g\n", f);
409 fprintf(stderr,
"Error %d: cannot create interpolated curve.\n", ret);
411 for(bi=dftNr-1; bi>=0; bi--)
dftEmpty(dftlist+bi);
413 free(bolusv);
return(11);
418 f=dftlist[bi].
x[dftlist[bi].
frameNr-1];
419 for(fi=idft.
frameNr-1; fi>0; fi--)
420 if(idft.
x[fi-1]>=f) idft.
voi[bi].
y[fi]=nan(
"");
else break;
424 fprintf(stderr,
"Error %d in memory allocation.\n", ret);
426 for(bi=dftNr-1; bi>=0; bi--)
dftEmpty(dftlist+bi);
427 free(dftlist); free(bolusv);
dftEmpty(&idft);
return(11);
430 for(bi=1; bi<dftNr; bi++) {
431 ret=
interpolate4pet(dftlist[bi].x, dftlist[bi].voi[0].y, dftlist[bi].frameNr,
434 fprintf(stderr,
"Error %d in interpolation of %dth curve.\n", ret, bi+1);
436 for(bi=dftNr-1; bi>=0; bi--)
dftEmpty(dftlist+bi);
437 free(dftlist); free(bolusv);
dftEmpty(&idft);
return(12);
441 f=dftlist[bi].
x[dftlist[bi].
frameNr-1];
442 for(fi=idft.
frameNr-1; fi>0; fi--)
443 if(idft.
x[fi-1]>=f) idft.
voi[bi].
y[fi]=nan(
"");
else break;
451 for(bi=dftNr-1; bi>=0; bi--)
dftEmpty(dftlist+bi);
452 free(dftlist); free(bolusv);
458 if(verbose>1) printf(
"calculating mean and sd\n");
459 for(fi=m=0; fi<idft.
frameNr; fi++) {
462 for(bi=0; bi<idft.
voiNr; bi++)
if(!isnan(idft.
voi[bi].
y[fi])) {
463 g+=idft.
voi[bi].
y[fi];
464 h+=idft.
voi[bi].
y[fi]*idft.
voi[bi].
y[fi];
467 if(verbose>6) printf(
" sample %d sum=%g n=%d\n", 1+fi, g, n);
470 idft.
voi[0].
y2[m]=g/(double)n;
472 if(n<2) {idft.
voi[1].
y2[m]=0.0;}
else {
473 g*=g; idft.
voi[1].
y2[m]=sqrt( (h-g/(
double)n)/(
double)(n-1) );}
484 if(verbose>1) printf(
"writing average data in %s\n", ofile);
485 if(*studynr==
'\0' || strcmp(studynr,
".")==0) strcpy(idft.
studynr,
"mean");
486 else strcpy(idft.
studynr, studynr);
488 if(save_errors) idft.
voiNr=2;
else idft.
voiNr=1;
491 for(fi=0; fi<idft.
frameNr; fi++) {
499 fprintf(stderr,
"Error in writing '%s': %s\n", ofile,
dfterrmsg);
505 if(!save_errors) fprintf(stderr,
"Average curve written in %s\n", ofile);
506 else fprintf(stderr,
"Average and SD curves written in %s\n", ofile);
int dftAddnullframe(DFT *data)
int dftMinMaxTAC(DFT *dft, int tacindex, double *minx, double *maxx, double *miny, double *maxy, int *mini, int *maxi, int *mins, int *maxs)
int dftAddmem(DFT *dft, int voiNr)
void dftSetComments(DFT *dft)
int dftRead(char *filename, DFT *data)
int dftWrite(DFT *data, char *filename)
int interpolate(double *x, double *y, int nr, double *newx, double *newy, double *newyi, double *newyii, int newnr)
Linear interpolation and integration.
int interpolate4pet(double *x, double *y, int nr, double *newx1, double *newx2, double *newy, double *newyi, double *newyii, int newnr)
Interpolate and integrate TAC to PET frames.
Header file for libtpccurveio.
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
void str_token_list_empty(STR_TOKEN_LIST *lst)
void str_token_list_init(STR_TOKEN_LIST *lst)
int str_token_list_add(STR_TOKEN_LIST *lst, char *new_item)
size_t strlcpy(char *dst, const char *src, size_t dstsize)
int str_token_list_read(const char *filename, STR_TOKEN_LIST *lst)
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 highest_slope(double *x, double *y, int n, int slope_n, double *m, double *c, double *xi, double *xh)
Header file for libtpcmodext.
char studynr[MAX_STUDYNR_LEN+1]
char comments[_DFT_COMMENT_LEN+1]
char voiname[MAX_REGIONSUBNAME_LEN+1]