TPCCLIB
Loading...
Searching...
No Matches
tacmean.c
Go to the documentation of this file.
1
9/*****************************************************************************/
10#include "tpcclibConfig.h"
11/*****************************************************************************/
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <math.h>
16/*****************************************************************************/
17#include "tpcextensions.h"
18#include "tpcift.h"
19#include "tpctac.h"
20#include "tpcpar.h"
21/*****************************************************************************/
22
23/*****************************************************************************/
24static char *info[] = {
25 "Calculate average TAC of all regional TACs in the TTAC file.",
26 "Weighted average TAC can be used as a 'head curve' in time delay correction,",
27 "if reliable count-rate data is not available.",
28 "Optionally, the same file name can be given to TTAC file and avg file to",
29 "add the mean TAC into the original data file.",
30 " ",
31 "Usage: @P [options] ttacfile [avgfile]",
32 " ",
33 "Options:",
34 " -ws",
35 " TACs are weighted by the VOI sizes, if available in the TTAC file.",
36 " -wf=<filename>",
37 " TACs are weighted by values given in parameter file.",
38 " If any TAC is not found in parameter file or value is invalid, zero",
39 " weight is applied to that TAC.",
40 " Parameter named as 'weight' or 'w' is used if available; if not then",
41 " the first parameter is used.",
42 " -sd=<filename>",
43 " SD curve is calculated and saved; weights are not applied.",
44 " -cv=<filename>",
45 " CV curve is calculated and saved; weights are not applied.",
46 " -stdoptions", // List standard options like --help, -v, etc
47 " ",
48 "See also: taclist, tacadd, imghead, dftavg, avgttac, tacren, parmean",
49 " ",
50 "Keywords: TAC, average, standard deviation, noise, head-curve",
51 0};
52/*****************************************************************************/
53
54/*****************************************************************************/
55/* Turn on the globbing of the command line, since it is disabled by default in
56 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
57 In Unix&Linux wildcard command line processing is enabled by default. */
58/*
59#undef _CRT_glob
60#define _CRT_glob -1
61*/
62int _dowildcard = -1;
63/*****************************************************************************/
64
65/*****************************************************************************/
69int main(int argc, char **argv)
70{
71 int ai, help=0, version=0, verbose=1;
72 char *cptr, tacfile[FILENAME_MAX], avgfile[FILENAME_MAX],
73 cvfile[FILENAME_MAX], sdfile[FILENAME_MAX],
74 wfile[FILENAME_MAX];
75 int weightMode=0; // 0=none, 1=sizes, 2=from file
76 int ret;
77
78
79 /*
80 * Get arguments
81 */
82 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
83 avgfile[0]=cvfile[0]=sdfile[0]=wfile[0]=(char)0;
84 /* Options */
85 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
86 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
87 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
88 if(strncasecmp(cptr, "SD=", 3)==0) {
89 if(strlcpy(sdfile, cptr+3, FILENAME_MAX)>0) continue;
90 } else if(strncasecmp(cptr, "CV=", 3)==0) {
91 if(strlcpy(cvfile, cptr+3, FILENAME_MAX)>0) continue;
92 } else if(strncasecmp(cptr, "WF=", 3)==0) {
93 if(strlcpy(wfile, cptr+3, FILENAME_MAX)>0 && weightMode==0) {weightMode=2; continue;}
94 } else if(strcasecmp(cptr, "WS")==0) {
95 if(weightMode==0) {weightMode=1; continue;}
96 }
97 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
98 return(1);
99 } else break;
100
101 TPCSTATUS status; statusInit(&status);
102 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
103 status.verbose=verbose-4;
104
105 /* Print help or version? */
106 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
107 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
108 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
109
110 /* Process other arguments, starting from the first non-option */
111 if(ai<argc) {strlcpy(tacfile, argv[ai], FILENAME_MAX); ai++;}
112 if(ai<argc) {strlcpy(avgfile, argv[ai], FILENAME_MAX); ai++;}
113 if(ai<argc) {
114 fprintf(stderr, "Error: too many arguments: '%s'.\n", argv[ai]);
115 return(1);
116 }
117
118 /* Did we get all the information that we need? */
119 if(!tacfile[0]) {
120 fprintf(stderr, "Error: missing TTAC filename.\n");
121 return(1);
122 }
123 if(!avgfile[0] && !sdfile[0] && !cvfile[0]) {
124 fprintf(stderr, "Error: missing output filename.\n");
125 return(1);
126 }
127 /* Check that SD or CV curves are not computed when using weights */
128 if(weightMode!=0 && (sdfile[0] || cvfile[0])) {
129 fprintf(stderr, "Error: SD and CV cannot be computed with TAC weighting.\n");
130 return(1);
131 }
132
133 /* In verbose mode print arguments and options */
134 if(verbose>1) {
135 printf("tacfile := %s\n", tacfile);
136 if(avgfile[0]) printf("avgfile := %s\n", avgfile);
137 if(sdfile[0]) printf("sdfile := %s\n", sdfile);
138 if(cvfile[0]) printf("cvfile := %s\n", cvfile);
139 if(wfile[0]) printf("wfile := %s\n", wfile);
140 printf("weightMode := %d\n", weightMode);
141 }
142
143
144
145 /*
146 * Read the TTAC file
147 */
148 if(verbose>1) printf("reading %s\n", tacfile);
149 TAC tac; tacInit(&tac);
150 ret=tacRead(&tac, tacfile, &status);
151 if(ret!=TPCERROR_OK) {
152 fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
153 tacFree(&tac); return(2);
154 }
155 int isSize=tacIsSize(&tac);
156 if(verbose>2) {
157 printf("fileformat := %s\n", tacFormattxt(tac.format));
158 printf("tacNr := %d\n", tac.tacNr);
159 printf("sampleNr := %d\n", tac.sampleNr);
160 printf("isSize := %d\n", isSize);
161 }
162 /* If no sizes, then weighting based on those is not possible */
163 if(weightMode==1 && isSize==0) {
164 fprintf(stderr, "Error: data does not contain ROI sizes.\n");
165 tacFree(&tac); return(2);
166 }
167
168
169 /*
170 * Read the weight file, if requested
171 */
172 if(weightMode==2) {
173 if(verbose>1) printf("reading %s\n", wfile);
174 PAR par; parInit(&par);
175 ret=parRead(&par, wfile, &status);
176 if(ret!=TPCERROR_OK) {
177 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
178 parFree(&par); tacFree(&tac); return(3);
179 }
180 if(verbose>6) {
181 printf("file contents:\n");
182 parWrite(&par, stdout, PAR_FORMAT_CSV_UK, 1, NULL);
183 } else if(verbose>2) {
184 printf("fileformat := %s\n", parFormattxt(par.format));
185 printf("parNr := %d\n", par.parNr);
186 printf("tacNr := %d\n", par.tacNr);
187 }
188 /* Select the parameter to use as weight */
189 int wp=0; // First parameter by default
190 if(par.parNr>1) { // except if there is parameter named as 'weight(s)' or 'w'
191 for(int i=0; i<par.parNr; i++)
192 if(strcasecmp(par.n[i].name, "W")==0) {wp=i; break;}
193 for(int i=0; i<par.parNr; i++)
194 if(strncasecmp(par.n[i].name, "WEIGHTS", 6)==0) {wp=i; break;}
195 if(verbose>0) printf("Parameter '%s' used as weight.\n", par.n[wp].name);
196 }
197 /* Try to get weighting parameters for each TAC */
198 for(int j=0; j<par.tacNr; j++) par.r[j].sw=0; // mark as not used
199 int okNr=0;
200 for(int i=0; i<tac.tacNr; i++) {
201 tac.c[i].size=0.0;
202 for(int j=0; j<par.tacNr; j++) if(par.r[j].sw==0) {
203 if(roinameMatch(tac.c[i].name, par.r[j].name, NULL)) {
204 if(par.r[j].p[wp]>=0.0) tac.c[i].size=par.r[j].p[wp];
205 par.r[j].sw=1;
206 okNr++;
207 break;
208 }
209 }
210 }
211 parFree(&par);
212 if(okNr==0) {
213 fprintf(stderr, "Error: no weights found for TACs.\n");
214 tacFree(&tac); return(3);
215 }
216 /* Convert parameter values to weights */
217 double wsum=0.0;
218 for(int i=0; i<tac.tacNr; i++) wsum+=tac.c[i].size;
219 if(!(wsum>1.0E-10)) {
220 fprintf(stderr, "Error: invalid weights.\n");
221 tacFree(&tac); return(3);
222 }
223 if(verbose>1) printf("TAC weights:\n");
224 for(int i=0; i<tac.tacNr; i++) {
225 tac.c[i].size/=wsum;
226 if(verbose>1) printf("\t%s\t%1.3f\n", tac.c[i].name, tac.c[i].size);
227 }
228 }
229
230
231 /*
232 * Calculate mean, SD, and CV or TACs
233 */
234 if(verbose>1) printf("calculating means...\n");
235
236 /* Allocate memory for mean TACs */
237 TAC mtac; tacInit(&mtac);
238 if(tacAllocate(&mtac, tac.sampleNr, 3)!=TPCERROR_OK) {
239 fprintf(stderr, "Error: cannot allocate memory for means.\n");
240 tacFree(&tac); return(3);
241 }
242 mtac.sampleNr=tac.sampleNr; mtac.tacNr=3;
243 ret=tacCopyHdr(&tac, &mtac);
244 if(ret!=TPCERROR_OK) {
245 fprintf(stderr, "Error: cannot copy TAC header.\n");
246 tacFree(&tac); tacFree(&mtac); return(3);
247 }
249 /* Copy sample times */
250 ret=tacXCopy(&tac, &mtac, 0, tac.sampleNr-1);
251 if(ret!=TPCERROR_OK) {
252 fprintf(stderr, "Error: cannot copy sample times.\n");
253 tacFree(&tac); tacFree(&mtac); return(3);
254 }
255 /* Set TAC names */
256 strcpy(mtac.c[0].name, "Mean");
257 strcpy(mtac.c[1].name, "SD");
258 strcpy(mtac.c[2].name, "CV");
259
260 /* Calculate non-weighted mean, SD, and CV */
261 /* Proceed one time frame at a time */
262 int valid_n=0;
263 for(int j=0; j<tac.sampleNr; j++) {
264 double sum=0.0;
265 int m=0;
266 for(int i=0; i<tac.tacNr; i++)
267 if(!isnan(tac.c[i].y[j])) {
268 sum+=tac.c[i].y[j];
269 m++;
270 }
271 if(m==0) {
272 if(verbose>1)
273 fprintf(stderr, "Warning: no valid samples in frame %d.\n", 1+j);
274 mtac.c[0].y[j]=mtac.c[1].y[j]=mtac.c[2].y[j]=nan("");
275 continue; // next frame
276 }
277 mtac.c[0].y[j]=sum/(double)m;
278 /* Calculate SD and CV, if required */
279 if(sdfile[0] || cvfile[0]) {
280 if(m==1) {
281 mtac.c[1].y[j]=mtac.c[2].y[j]=0.0;
282 } else {
283 double sumsqr=0.0, sqrsum;
284 for(int i=0; i<tac.tacNr; i++)
285 if(!isnan(tac.c[i].y[j]))
286 sumsqr+=tac.c[i].y[j]*tac.c[i].y[j];
287 sqrsum=sum*sum;
288 mtac.c[1].y[j]=sqrt( (sumsqr - sqrsum/(double)m) / (double)(m-1) );
289 if(fabs(mtac.c[0].y[j])<1.0E-30) mtac.c[2].y[j]=nan("");
290 else mtac.c[2].y[j]=mtac.c[1].y[j]/fabs(mtac.c[0].y[j]);
291 }
292 }
293 valid_n++;
294 } // next time frame
295 if(valid_n==0) {
296 fprintf(stderr, "Error: file contains no valid data.\n");
297 tacFree(&tac); tacFree(&mtac); return(4);
298 }
299
300
301 /* If weighting was not requested, then save mean TAC */
302 if(avgfile[0] && weightMode==0) {
303 mtac.tacNr=1;
304 TAC *otac;
305 if(strcasecmp(tacfile, avgfile)!=0) { // Save into separate file
306 if(verbose>1) printf("writing %s\n", avgfile);
307 otac=&mtac;
308 } else { // Add into input TAC file
309 strcpy(avgfile, tacfile); // to prevent problems with upper/lower case characters
310 if(verbose>1) printf("adding mean to %s\n", avgfile);
311 ret=tacAllocateMore(&tac, 1);
312 if(ret==TPCERROR_OK) ret=tacCopyTacc(&mtac.c[0], &tac.c[tac.tacNr], tac.sampleNr);
313 if(ret!=TPCERROR_OK) {
314 fprintf(stderr, "Error: cannot add mean TAC.\n");
315 tacFree(&tac); tacFree(&mtac); return(11);
316 }
317 tac.tacNr++;
318 otac=&tac;
319 }
320 FILE *fp; fp=fopen(avgfile, "w");
321 if(fp==NULL) {
322 fprintf(stderr, "Error: cannot open file for writing.\n");
323 tacFree(&tac); tacFree(&mtac); return(11);
324 }
325 ret=tacWrite(otac, fp, TAC_FORMAT_UNKNOWN, 1, &status);
326 fclose(fp);
327 if(ret!=TPCERROR_OK) {
328 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
329 tacFree(&tac); tacFree(&mtac); return(11);
330 }
331 }
332
333 /* If requested, save SD curve */
334 if(sdfile[0]) {
335 tacCopyTacc(&mtac.c[1], &mtac.c[0], mtac.sampleNr);
336 mtac.tacNr=1;
337 if(verbose>1) printf("writing %s\n", sdfile);
338 FILE *fp; fp=fopen(sdfile, "w");
339 if(fp==NULL) {
340 fprintf(stderr, "Error: cannot open file for writing.\n");
341 tacFree(&tac); tacFree(&mtac); return(12);
342 }
343 ret=tacWrite(&mtac, fp, TAC_FORMAT_UNKNOWN, 1, &status);
344 fclose(fp);
345 if(ret!=TPCERROR_OK) {
346 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
347 tacFree(&tac); tacFree(&mtac); return(12);
348 }
349 }
350
351 /* If requested, save CV curve */
352 if(cvfile[0]) {
353 tacCopyTacc(&mtac.c[2], &mtac.c[0], mtac.sampleNr);
354 mtac.tacNr=1;
355 if(verbose>1) printf("writing %s\n", cvfile);
356 FILE *fp; fp=fopen(cvfile, "w");
357 if(fp==NULL) {
358 fprintf(stderr, "Error: cannot open file for writing.\n");
359 tacFree(&tac); tacFree(&mtac); return(13);
360 }
361 int cunit=mtac.cunit; mtac.cunit=UNIT_UNITLESS; // CV has no unit
362 ret=tacWrite(&mtac, fp, TAC_FORMAT_UNKNOWN, 1, &status);
363 fclose(fp); mtac.cunit=cunit; // ... but we may need original unit later
364 if(ret!=TPCERROR_OK) {
365 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
366 tacFree(&tac); tacFree(&mtac); return(13);
367 }
368 }
369
370 /* If weighting was not requested, or mean TAC was not requested,
371 then we are done here */
372 if(weightMode==0 || !avgfile[0]) {
373 tacFree(&tac); tacFree(&mtac);
374 return(0);
375 }
376
377 /*
378 * Try to compute weighted mean TAC
379 */
380 /* Proceed one time frame at a time */
381 for(int j=0; j<tac.sampleNr; j++) {
382 double sum=0.0, wsum=0.0;
383 for(int i=0; i<tac.tacNr; i++)
384 if(!isnan(tac.c[i].y[j]) && !isnan(tac.c[i].size)) {
385 sum+=tac.c[i].size*tac.c[i].y[j];
386 wsum+=tac.c[i].size;
387 }
388 if(wsum<1.0E-030) {
389 fprintf(stderr, "Error: data does not contain valid weights.\n");
390 tacFree(&tac); tacFree(&mtac);
391 return(8);
392 }
393 mtac.c[0].y[j]=sum/wsum;
394 } // next time frame
395
396 /* Write weighted mean TAC */
397 {
398 mtac.tacNr=1;
399 TAC *otac;
400 if(strcasecmp(tacfile, avgfile)!=0) { // Save into separate file
401 if(verbose>1) printf("writing %s\n", avgfile);
402 otac=&mtac;
403 } else { // Add into input TAC file
404 strcpy(avgfile, tacfile); // to prevent problems with upper/lower case characters
405 if(verbose>1) printf("adding mean to %s\n", avgfile);
406 ret=tacAllocateMore(&tac, 1);
407 if(ret==TPCERROR_OK) ret=tacCopyTacc(&mtac.c[0], &tac.c[tac.tacNr], tac.sampleNr);
408 if(ret!=TPCERROR_OK) {
409 fprintf(stderr, "Error: cannot add mean TAC.\n");
410 tacFree(&tac); tacFree(&mtac); return(15);
411 }
412 tac.tacNr++;
413 otac=&tac;
414 }
415 FILE *fp; fp=fopen(avgfile, "w");
416 if(fp==NULL) {
417 fprintf(stderr, "Error: cannot open file for writing.\n");
418 tacFree(&tac); tacFree(&mtac); return(15);
419 }
420 ret=tacWrite(otac, fp, TAC_FORMAT_UNKNOWN, 1, &status);
421 fclose(fp);
422 if(ret!=TPCERROR_OK) {
423 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
424 tacFree(&tac); tacFree(&mtac); return(15);
425 }
426 }
427
428 tacFree(&tac); tacFree(&mtac);
429
430 return(0);
431}
432/*****************************************************************************/
433
434/*****************************************************************************/
void parFree(PAR *par)
Definition par.c:75
void parInit(PAR *par)
Definition par.c:25
char * parFormattxt(parformat c)
Definition pario.c:59
int parWrite(PAR *par, FILE *fp, parformat format, int extra, TPCSTATUS *status)
Definition pario.c:148
int parRead(PAR *par, const char *fname, TPCSTATUS *status)
Definition pario.c:232
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
int roinameMatch(const char *roiname, const char *test_str, TPCSTATUS *status)
Definition roiname.c:183
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
Definition tpcpar.h:100
int format
Definition tpcpar.h:102
int parNr
Definition tpcpar.h:108
int tacNr
Definition tpcpar.h:104
PARR * r
Definition tpcpar.h:114
PARN * n
Definition tpcpar.h:112
char name[MAX_PARNAME_LEN+1]
Definition tpcpar.h:82
char name[MAX_TACNAME_LEN+1]
Definition tpcpar.h:50
char sw
Definition tpcpar.h:74
double * p
Definition tpcpar.h:64
char name[MAX_TACNAME_LEN+1]
Definition tpctac.h:81
double * y
Definition tpctac.h:75
double size
Definition tpctac.h:71
Definition tpctac.h:87
unit cunit
Definition tpctac.h:105
tacformat format
Definition tpctac.h:93
int sampleNr
Definition tpctac.h:89
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 tacIsSize(TAC *d)
Definition tac.c:335
int tacAllocate(TAC *tac, int sampleNr, int tacNr)
Definition tac.c:130
void tacInit(TAC *tac)
Definition tac.c:24
int tacAllocateMore(TAC *tac, int tacNr)
Definition tac.c:178
int tacCopyTacc(TACC *d1, TACC *d2, int sampleNr)
Definition tac.c:233
int tacCopyHdr(TAC *tac1, TAC *tac2)
Copy TAC header data from tac1 to tac2.
Definition tac.c:310
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 tacXCopy(TAC *tac1, TAC *tac2, int i1, int i2)
Definition tacx.c:24
Header file for library libtpcextensions.
@ WEIGHTING_OFF
Not weighted or weights not available (weights for all included samples are 1.0).
@ UNIT_UNITLESS
Unitless.
@ TPCERROR_OK
No error.
Header file for library libtpcift.
Header file for libtpcpar.
@ PAR_FORMAT_CSV_UK
UK CSV.
Definition tpcpar.h:33
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
Definition tpctac.h:28