TPCCLIB
Loading...
Searching...
No Matches
avgttac.c
Go to the documentation of this file.
1
8/*****************************************************************************/
9#include "tpcclibConfig.h"
10/*****************************************************************************/
11#include <stdio.h>
12#include <stdlib.h>
13#include <unistd.h>
14#include <string.h>
15#include <math.h>
16/*****************************************************************************/
17#include "tpcextensions.h"
18#include "tpcift.h"
19#include "tpccsv.h"
20#include "tpctac.h"
21#include "tpcstatist.h"
22/*****************************************************************************/
23
24/*****************************************************************************/
25static char *info[] = {
26 "Calculate average TTAC(s) from several PET TTAC files with equal sample",
27 "(frame) times and regions. Each region is processed separately.",
28 "TTACs are not scaled in this process, therefore user must scale the data",
29 "to for example SUV or %ID before using this program.",
30 " ",
31 "Usage: @P [Options] meanfile tacfiles",
32 " ",
33 "Options:",
34 " -sd=<filename>",
35 " Regional standard deviations are written into given datafile.",
36 " --force",
37 " Program does not mind if the time or calibration units do not match",
38 " or files contain variable number of TACs."
39 " -stdoptions", // List standard options like --help, -v, etc
40 " ",
41 "If only one input datafile is given, it is assumed to contain a list of",
42 "bolus datafiles with paths if necessary. Tabs, commas and newlines can be",
43 "used to separate filenames in the list file.",
44 " ",
45 "Example 1:",
46 " avgttac meansuv.dft *suv.dft",
47 "Example 2:",
48 " dir /b *suv.dft > filelist.txt",
49 " avgttac meansuv.dft filelist.txt",
50 " ",
51 "See also: avgbolus, avgfract, dftavg, dftsuv, tacsort, taccut, tacren",
52 " ",
53 "Keywords: TAC, average, modelling, simulation",
54 0};
55/*****************************************************************************/
56
57/*****************************************************************************/
58/* Turn on the globbing of the command line, since it is disabled by default in
59 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
60 In Unix&Linux wildcard command line processing is enabled by default. */
61/*
62#undef _CRT_glob
63#define _CRT_glob -1
64*/
65int _dowildcard = -1;
66/*****************************************************************************/
67
68/*****************************************************************************/
72int main(int argc, char **argv)
73{
74 int ai, help=0, version=0, verbose=1;
75 char *cptr, outfile[FILENAME_MAX], sdfile[FILENAME_MAX];
76 int forceMode=0;
77 int ret, fileNr;
78 CSV csv;
79
80
81 /*
82 * Get arguments
83 */
84 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
85 outfile[0]=sdfile[0]=(char)0;
86 csvInit(&csv);
87 /* Options */
88 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
89 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
90 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
91 if(strncasecmp(cptr, "SD=", 3)==0) {
92 if(strlcpy(sdfile, cptr+3, FILENAME_MAX)>0) continue;
93 } else if(strncasecmp(cptr, "FORCE", 1)==0) {
94 forceMode=1; continue;
95 }
96 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
97 return(1);
98 } else break; // tac name argument may start with '-'
99
100 TPCSTATUS status; statusInit(&status);
101 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
102 status.verbose=verbose-4;
103
104 /* Print help or version? */
105 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
106 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
107 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
108
109 /* Process other arguments, starting from the first non-option */
110 /* First one is the filename for averages */
111 if(ai<argc) {strlcpy(outfile, argv[ai], FILENAME_MAX); ai++;}
112 if(ai==argc) {
113 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
114 return(1);
115 }
116 /* If only one argument left, then that is the filename of file list */
117 if(ai==argc-1) {
118 if(verbose>1) printf("reading filename list in %s\n", argv[ai]);
119 FILE *fp;
120 fp=fopen(argv[ai], "r"); if(fp==NULL) {
121 fprintf(stderr, "Error: cannot open file %s\n", argv[ai]); return(1);}
122 ret=csvRead(&csv, fp, &status); fclose(fp);
123 if(ret!=TPCERROR_OK) {
124 fprintf(stderr, "Error: %s\n", errorMsg(status.error)); return(1);}
125 } else {
126 if(verbose>1) printf("filenames listed as arguments\n");
127 for(; ai<argc; ai++) csvPutString(&csv, argv[ai], 1);
128 }
129
130 /* In verbose mode print arguments and options */
131 if(verbose>1) {
132 printf("outfile := %s\n", outfile);
133 if(sdfile[0]) printf("sdfile := %s\n", sdfile);
134 printf("forceMode := %d\n", forceMode);
135 printf("files:\n"); csvWrite(&csv, 0, stdout, NULL);
136 }
137
138 /* Check that files exist, and that there are at least two of them */
139 fileNr=0;
140 for(int i=0; i<csv.nr; i++) {
141 if(access(csv.c[i].content, 0) == -1) {
142 fprintf(stderr, "Error: file '%s' is not accessible.\n", csv.c[i].content);
143 csvFree(&csv); return(2);
144 }
145 fileNr++;
146 }
147 if(verbose>1) printf("fileNr := %d\n", fileNr);
148 if(fileNr<2) {
149 fprintf(stderr, "Error: too few TAC files for averaging.\n");
150 csvFree(&csv); return(2);
151 }
152
153
154
155 /*
156 * Read all TTAC files
157 */
158 /* Allocate memory for an array of TACs */
159 TAC *taclist;
160 taclist=(TAC*)malloc(fileNr*sizeof(TAC));
161 if(taclist==NULL) {
162 fprintf(stderr, "Error: out of memory.\n");
163 csvFree(&csv); return(3);
164 }
165 /* Initiate TAC structs */
166 for(int i=0; i<fileNr; i++) tacInit(taclist+i);
167 /* Read TTAC files */
168 for(int i=0; i<fileNr; i++) {
169 if(verbose>1) printf("reading %s\n", csv.c[i].content);
170 if(tacRead(taclist+i, csv.c[i].content, &status)) {
171 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
172 for(int j=0; j<i; j++) tacFree(taclist+j);
173 csvFree(&csv); free(taclist); return(3);
174 }
175 if(verbose>2) {
176 printf("fileformat := %s\n", tacFormattxt(taclist[i].format));
177 printf("tacNr := %d\n", taclist[i].tacNr);
178 printf("sampleNr := %d\n", taclist[i].sampleNr);
179 }
180 /* Check that data does not have missing values that cannot be fixed */
181 if(tacFixNaNs(taclist+i)) {
182 fprintf(stderr, "Warning: missing sample(s) in %s\n", csv.c[i].content);
183 }
184 }
185
186 if(verbose>1) printf("checking data...\n");
187
188 /* Check that TAC files have at least as many regions and samples as
189 the first file has */
190 int tacNr, sampleNr;
191 {
192 int n=0, m=0;
193 tacNr=taclist[0].tacNr; sampleNr=taclist[0].sampleNr;
194 for(int i=1; i<fileNr; i++) {
195 if(taclist[i].tacNr!=tacNr) {
196 m++; if(taclist[i].tacNr<tacNr) tacNr=taclist[i].tacNr;
197 }
198 if(taclist[i].sampleNr!=sampleNr) {
199 n++; if(taclist[i].sampleNr<sampleNr) sampleNr=taclist[i].sampleNr;
200 }
201 }
202 if(!forceMode && (n>0 || m>0)) {
203 if(n>0) fprintf(stderr, "Error: different nr of samples.\n");
204 if(m>0) fprintf(stderr, "Error: different nr of regions.\n");
205 for(int i=0; i<fileNr; i++) tacFree(taclist+i);
206 csvFree(&csv); free(taclist); return(3);
207 }
208 if(n>0) fprintf(stderr, "Warning: different nr of samples.\n");
209 if(m>0) fprintf(stderr, "Warning: different nr of regions.\n");
210 }
211 if(verbose>1) {
212 printf("commonSampleNr := %d\n", sampleNr);
213 printf("commonTacNr := %d\n", tacNr);
214 }
215
216 /* Convert TAC units when necessary */
217 for(int i=1; i<fileNr; i++) {
218 ret=tacXUnitConvert(taclist+i, taclist[0].tunit, &status);
220 if(ret==TPCERROR_OK) {
221 ret=tacYUnitConvert(taclist+i, taclist[0].cunit, &status);
223 }
224 if(ret!=TPCERROR_OK) { // failed
225 /* failing is a problem if units are to be verified */
226 if(!forceMode) {
227 fprintf(stderr, "Error: TAC units do match.\n");
228 for(int i=0; i<fileNr; i++) tacFree(taclist+i);
229 csvFree(&csv); free(taclist); return(4);
230 }
231 }
232 }
233
234 /* Check region names, if more than one TAC per file */
235 if(!forceMode && tacNr>1) {
236 for(int i=1; i<fileNr; i++) {
237 for(int j=0; j<tacNr; j++) {
238 if(tacCompareNames(taclist, taclist+i, j, &status)) {
239 fprintf(stderr, "Error: TAC names do match.\n");
240 for(int i=0; i<fileNr; i++) tacFree(taclist+i);
241 csvFree(&csv); free(taclist); return(5);
242 }
243 }
244 }
245 }
246
247
248
249 /*
250 * Calculate mean TACs
251 */
252 if(verbose>1) printf("calculating mean...\n");
253 /* Allocate memory for mean TACs */
254 TAC tacmean, tacsd;
255 tacInit(&tacmean); tacInit(&tacsd);
256 if(tacAllocate(&tacmean, sampleNr, tacNr)!=TPCERROR_OK) {
257 fprintf(stderr, "Error: cannot allocate memory for mean TACs.\n");
258 for(int i=0; i<fileNr; i++) tacFree(taclist+i);
259 csvFree(&csv); free(taclist); return(6);
260 }
261 tacmean.sampleNr=sampleNr; tacmean.tacNr=tacNr;
262 ret=tacCopyHdr(taclist, &tacmean);
263 if(ret!=TPCERROR_OK) {
264 fprintf(stderr, "Error: cannot copy TAC header.\n");
265 for(int i=0; i<fileNr; i++) tacFree(taclist+i);
266 csvFree(&csv); free(taclist); tacFree(&tacmean); return(6);
267 }
268 tacmean.weighting=WEIGHTING_OFF;
269 tacSetHeaderStudynr(&tacmean.h, "Mean");
270 for(int i=0; i<tacNr; i++) tacCopyTacchdr(taclist[0].c+i, tacmean.c+i);
271 /* Copy sample times */
272 ret=tacXCopy(taclist, &tacmean, 0, sampleNr-1);
273 if(ret!=TPCERROR_OK) {
274 fprintf(stderr, "Error: cannot copy sample times.\n");
275 for(int i=0; i<fileNr; i++) tacFree(taclist+i);
276 csvFree(&csv); free(taclist); tacFree(&tacmean); return(6);
277 }
278 /* Allocate place for SDs too, if required */
279 if(sdfile[0]) {
280 if(tacDuplicate(&tacmean, &tacsd)!=TPCERROR_OK) {
281 fprintf(stderr, "Error: cannot allocate memory for SD data.\n");
282 for(int i=0; i<fileNr; i++) tacFree(taclist+i);
283 csvFree(&csv); free(taclist); tacFree(&tacmean); return(6);
284 }
285 tacSetHeaderStudynr(&tacsd.h, "SD");
286 }
287 /* Compute the mean, and SD if required */
288 for(int i=0; i<tacNr; i++) {
289 double tempd[fileNr], mean, sd;
290 for(int j=0; j<sampleNr; j++) {
291 for(int k=0; k<fileNr; k++) tempd[k]=taclist[k].c[i].y[j];
292 statMeanSD(tempd, fileNr, &mean, &sd, NULL);
293 tacmean.c[i].y[j]=mean;
294 if(sdfile[0]) tacsd.c[i].y[j]=sd;
295 }
296 /* also ROI size */
297 for(int k=0; k<fileNr; k++) tempd[k]=taclist[k].c[i].size;
298 statMeanSD(tempd, fileNr, &mean, &sd, NULL);
299 tacmean.c[i].size=mean;
300 if(sdfile[0]) tacsd.c[i].size=sd;
301 }
302
303 for(int i=0; i<fileNr; i++) tacFree(taclist+i);
304 free(taclist);
305 csvFree(&csv);
306
307
308 /*
309 * Save data
310 */
311 if(verbose>1) printf("writing %s\n", outfile);
312 FILE *fp; fp=fopen(outfile, "w");
313 if(fp==NULL) {
314 fprintf(stderr, "Error: cannot open file for writing.\n");
315 tacFree(&tacmean); tacFree(&tacsd);
316 return(11);
317 }
318 ret=tacWrite(&tacmean, fp, TAC_FORMAT_UNKNOWN, 1, &status);
319 fclose(fp);
320 if(ret!=TPCERROR_OK) {
321 fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
322 tacFree(&tacmean); tacFree(&tacsd); return(12);
323 }
324 if(verbose>0) printf("Mean TAC(s) written in %s\n", outfile);
325 if(sdfile[0]) {
326 if(verbose>1) printf("writing %s\n", sdfile);
327 FILE *fp; fp=fopen(sdfile, "w");
328 if(fp==NULL) {
329 fprintf(stderr, "Error: cannot open file for writing.\n");
330 tacFree(&tacmean); tacFree(&tacsd);
331 return(21);
332 }
333 ret=tacWrite(&tacsd, fp, TAC_FORMAT_UNKNOWN, 1, &status);
334 fclose(fp);
335 if(ret!=TPCERROR_OK) {
336 fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
337 tacFree(&tacmean); tacFree(&tacsd); return(22);
338 }
339 if(verbose>0) printf("TAC SDs written in %s\n", sdfile);
340 }
341
342 /* Free memory */
343 tacFree(&tacmean); tacFree(&tacsd);
344
345 return(0);
346}
347/*****************************************************************************/
348
349/*****************************************************************************/
void csvInit(CSV *csv)
Definition csv.c:22
int csvPutString(CSV *csv, const char *s, int newline)
Definition csv.c:144
void csvFree(CSV *csv)
Definition csv.c:38
int csvRead(CSV *csv, FILE *fp, TPCSTATUS *status)
Definition csvio.c:124
int csvWrite(CSV *csv, int regular, FILE *fp, TPCSTATUS *status)
Definition csvio.c:52
int statMeanSD(double *data, unsigned int n, double *mean, double *sd, unsigned int *vn)
Definition mean.c:25
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:47
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:169
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:339
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:114
void statusInit(TPCSTATUS *s)
Definition statusmsg.c:104
char * errorMsg(tpcerror e)
Definition statusmsg.c:68
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:632
char * content
Definition tpccsv.h:30
Definition tpccsv.h:36
CSV_item * c
Definition tpccsv.h:38
int nr
Definition tpccsv.h:42
double * y
Definition tpctac.h:75
double size
Definition tpctac.h:71
Definition tpctac.h:87
int sampleNr
Definition tpctac.h:89
IFT h
Optional (but often useful) header information.
Definition tpctac.h:141
TACC * c
Definition tpctac.h:117
weights weighting
Definition tpctac.h:115
int tacNr
Definition tpctac.h:91
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
void tacFree(TAC *tac)
Definition tac.c:106
int tacDuplicate(TAC *tac1, TAC *tac2)
Make a duplicate of TAC structure.
Definition tac.c:356
int tacAllocate(TAC *tac, int sampleNr, int tacNr)
Definition tac.c:130
void tacInit(TAC *tac)
Definition tac.c:24
int tacCopyTacchdr(TACC *d1, TACC *d2)
Definition tac.c:282
int tacCopyHdr(TAC *tac1, TAC *tac2)
Copy TAC header data from tac1 to tac2.
Definition tac.c:310
int tacCompareNames(TAC *d1, TAC *d2, const int i, TPCSTATUS *status)
Definition taccomp.c:67
int tacSetHeaderStudynr(IFT *h, const char *s)
Definition tacift.c:79
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
Definition tacio.c:413
char * tacFormattxt(tacformat c)
Definition tacio.c:98
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
Definition tacio.c:332
int tacFixNaNs(TAC *tac)
Definition tacnan.c:121
int tacYUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
Definition tacunits.c:72
int tacXUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
Definition tacunits.c:23
int tacXCopy(TAC *tac1, TAC *tac2, int i1, int i2)
Definition tacx.c:24
Header file for library libtpccsv.
Header file for library libtpcextensions.
@ WEIGHTING_OFF
Not weighted or weights not available (weights for all included samples are 1.0).
@ TPCERROR_UNKNOWN_UNIT
Unknown data unit.
@ TPCERROR_OK
No error.
Header file for library libtpcift.
Header file for libtpcstatist.
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
Definition tpctac.h:28