TPCCLIB
Loading...
Searching...
No Matches
tacdecay.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 <string.h>
14#include <math.h>
15/*****************************************************************************/
16#include "tpcextensions.h"
17#include "tpcift.h"
18#include "tpccsv.h"
19#include "tpcisotope.h"
20#include "tpctac.h"
21/*****************************************************************************/
22
23/*****************************************************************************/
24static char *info[] = {
25 "Correction of PET TAC files for physical decay, or removing decay correction.",
26 " ",
27 "Usage: @P [Options] tacfile [outputfile]",
28 " ",
29 "Options:",
30 " -decay=<on|off>",
31 " Correct the data for radioactive decay (on, default), or remove",
32 " decay correction (off).",
33 " -i=<Isotope code>",
34 " Most TAC files do not contain the isotope code, thus it can be",
35 " specified with this option.",
36 " Accepted isotope codes are for example F-18, C-11, and O-15.",
37 " -sec or -min",
38 " Sample times are known to be in seconds or minutes, but is not",
39 " specified or is wrong in TAC file.",
40 " -stdoptions", // List standard options like --help, -v, etc
41 " ",
42 "Example 1: remove the correction for physical decay from a F-18 study,",
43 " writing non-corrected data into a new file.",
44 " @P -decay=off -i=F-18 a123ap.bld a123ap_nodecay.bld",
45 " ",
46 "Example 2: correct the TAC data for radioactive decay, overwriting the data.",
47 " @P -decay=on -i=C-11 ia456dy1.tac",
48 " ",
49 "See also: tactime, tacframe, tacunit, tacformat, imgdecay, dcftime",
50 " ",
51 "Keywords: TAC, physical decay, halflife, isotopes, simulation",
52 0};
53/*****************************************************************************/
54
55/*****************************************************************************/
56/* Turn on the globbing of the command line, since it is disabled by default in
57 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
58 In Unix&Linux wildcard command line processing is enabled by default. */
59/*
60#undef _CRT_glob
61#define _CRT_glob -1
62*/
63int _dowildcard = -1;
64/*****************************************************************************/
65
66/*****************************************************************************/
70int main(int argc, char **argv)
71{
72 int ai, help=0, version=0, verbose=1;
74 int correct=1; // 1=correct for decay, 0=remove decay correction
75 unit knownTimeunit=UNIT_UNKNOWN;
76 char tacfile1[FILENAME_MAX], tacfile2[FILENAME_MAX];
77
78
79 /*
80 * Get arguments
81 */
82 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
83 tacfile1[0]=tacfile2[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 char *cptr=argv[ai]+1;
88 if(strncasecmp(cptr, "I=", 2)==0) {
89 cptr+=2;
90 if((isot=isotopeIdentify(cptr))==ISOTOPE_UNKNOWN) {
91 fprintf(stderr, "Error: invalid isotope '%s'.\n", cptr);
92 return(1);
93 }
94 continue;
95 } else if(strncasecmp(cptr, "DECAY=", 6)==0) {
96 if((correct=tpcYesNo(cptr+6))==-1) {
97 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
98 return(1);
99 }
100 continue;
101 } else if(strncasecmp(cptr, "MINUTES", 3)==0) {
102 knownTimeunit=UNIT_MIN; continue;
103 } else if(strncasecmp(cptr, "SECONDS", 3)==0) {
104 knownTimeunit=UNIT_SEC; continue;
105 }
106 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
107 return(1);
108 } else break; // tac name argument may start with '-'
109
110
111 TPCSTATUS status; statusInit(&status);
112 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
113 status.verbose=verbose-1;
114
115 /* Print help or version? */
116 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
117 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
118 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
119
120 /* Process other arguments, starting from the first non-option */
121 if(ai<argc) strlcpy(tacfile1, argv[ai++], FILENAME_MAX);
122 if(ai<argc) strlcpy(tacfile2, argv[ai++], FILENAME_MAX);
123 if(ai<argc) {
124 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
125 return(1);
126 }
127
128 /* Is something missing? */
129 if(!tacfile1[0]) {
130 fprintf(stderr, "Error: missing file name; use option --help\n");
131 return(1);
132 }
133 /* If output filename was not given, use input filename */
134 if(!tacfile2[0]) strcpy(tacfile2, tacfile1);
135
136
137 /* In verbose mode print arguments and options */
138 if(verbose>1) {
139 printf("tacfile1 := %s\n", tacfile1);
140 printf("tacfile2 := %s\n", tacfile2);
141 printf("correct := %d\n", correct);
142 if(isot!=ISOTOPE_UNKNOWN) printf("isotope := %s\n", isotopeName(isot));
143 if(knownTimeunit!=UNIT_UNKNOWN) printf("knownTimeunit := %s\n", unitName(knownTimeunit));
144 fflush(stdout);
145 }
146
147
148
149 /*
150 * Read TAC data
151 */
152 if(verbose>1) {fprintf(stdout, "reading %s\n", tacfile1); fflush(stdout);}
153 TAC tac; tacInit(&tac);
154 if(tacRead(&tac, tacfile1, &status)!=TPCERROR_OK) {
155 fprintf(stderr, "Error: %s (%s)\n", errorMsg(status.error), tacfile1);
156 tacFree(&tac); return(2);
157 }
158 if(verbose>2) {
159 printf("fileformat := %s\n", tacFormattxt(tac.format));
160 printf("tacNr := %d\n", tac.tacNr);
161 printf("sampleNr := %d\n", tac.sampleNr);
162 if(tac.isframe) printf("frames := yes\n"); else printf("frames := no\n");
163 fflush(stdout);
164 }
165 /* Correct the time unit, if given by user */
166 if(knownTimeunit!=UNIT_UNKNOWN) {
167 tac.tunit=knownTimeunit;
168 } else if(!unitIsTime(tac.tunit)) {
169 double xmin, xmax;
170 if(tacXRange(&tac, &xmin, &xmax)) {
171 fprintf(stderr, "Error: invalid sample times.\n");
172 tacFree(&tac); return(2);
173 }
174 if(xmax>30.0 && lambdaFromIsotope(isot)>0.3) {
175 tac.tunit=UNIT_SEC;
176 fprintf(stderr, "Warning: assuming that sample times are in seconds.\n");
177 } else {
178 tac.tunit=UNIT_MIN;
179 fprintf(stderr, "Warning: assuming that sample times are in minutes.\n");
180 }
181 }
182 if(verbose>2) {
183 printf("xunit := %s\n", unitName(tac.tunit));
184 printf("yunit := %s\n", unitName(tac.cunit));
185 fflush(stdout);
186 }
187
188 /* If datafile contains valid isotope, then check that it is the same as given by user */
189 {
190 isotope fisot=tacGetIsotope(&tac);
191 if(verbose>3) {printf("tac.isotope := %s\n", isotopeName(fisot)); fflush(stdout);}
192 if(isot==ISOTOPE_UNKNOWN && fisot==ISOTOPE_UNKNOWN) {
193 fprintf(stderr, "Error: valid isotope not specified.\n");
194 tacFree(&tac); return(3);
195 }
196 if(isot==ISOTOPE_UNKNOWN && fisot!=ISOTOPE_UNKNOWN) {
197 isot=fisot;
198 if(verbose>1) printf("isotope := %s\n", isotopeName(isot));
199 } else if(isot!=ISOTOPE_UNKNOWN && fisot==ISOTOPE_UNKNOWN) {
200 fisot=isot;
201 tacSetIsotope(&tac, fisot);
202 if(verbose>1) printf("isotope := %s\n", isotopeName(isot));
203 }
204 if(isot!=fisot) {
205 fprintf(stderr, "Error: different isotope in %s\n", tacfile1);
206 tacFree(&tac); return(3);
207 }
208 }
209
210 /* If datafile contains information on decay correction, then check that to prevent
211 user from decay correcting data twice, or removing non-existing decay correction */
213 if(fdc==DECAY_UNKNOWN) {
214 if(verbose>1) printf("Note: status of current decay correction is not known.\n");
215 } else if(fdc==DECAY_CORRECTED && correct==1) {
216 fprintf(stderr, "Error: physical decay is already corrected in %s.\n", tacfile1);
217 tacFree(&tac); return(4);
218 } else if(fdc==DECAY_NOTCORRECTED && correct==0) {
219 fprintf(stderr, "Error: physical decay is not corrected in %s.\n", tacfile1);
220 tacFree(&tac); return(4);
221 }
222
223
224 /*
225 * Decay correction / removal
226 */
227 if(tacDecayCorrection(&tac, isot, correct, &status)!=TPCERROR_OK) {
228 fprintf(stderr, "Error: %s (%s)\n", errorMsg(status.error), tacfile1);
229 tacFree(&tac); return(5);
230 }
231 /* Set also header */
234
235
236
237 /*
238 * Save corrected file
239 */
240 if(verbose>1) printf("saving %s\n", tacfile2);
241 {
242 FILE *fp; fp=fopen(tacfile2, "w");
243 if(fp==NULL) {
244 fprintf(stderr, "Error: cannot open file for writing\n");
245 tacFree(&tac); return(11);
246 }
247 int ret=tacWrite(&tac, fp, TAC_FORMAT_UNKNOWN, 1, &status);
248 fclose(fp);
249 if(ret!=TPCERROR_OK) {
250 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
251 tacFree(&tac); return(12);
252 }
253
254 /* Tell user what we did */
255 if(verbose>=0) {
256 if(correct) printf(" data was corrected for decay with half-life of");
257 else printf(" decay correction was removed from data with half-life of");
258 printf(" %s\n", isotopeName(isot));
259 fflush(stdout);
260 }
261 }
262 tacFree(&tac);
263
264 return(0);
265}
266/*****************************************************************************/
267
268/*****************************************************************************/
double lambdaFromIsotope(int isotope)
Definition decay.c:63
char * isotopeName(int isotope_code)
Definition isotope.c:101
int isotopeIdentify(const char *isotope)
Definition isotope.c:145
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:47
int tpcYesNo(const char *s)
Definition proginfo.c:459
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
Definition tpctac.h:87
unit cunit
Definition tpctac.h:105
tacformat format
Definition tpctac.h:93
int sampleNr
Definition tpctac.h:89
IFT h
Optional (but often useful) header information.
Definition tpctac.h:141
int isframe
Definition tpctac.h:95
unit tunit
Definition tpctac.h:109
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
void tacInit(TAC *tac)
Definition tac.c:24
int tacGetIsotope(TAC *tac)
Definition tacdc.c:25
int tacDecayCorrection(TAC *tac, int isotope, int mode, TPCSTATUS *status)
Definition tacdc.c:59
void tacSetIsotope(TAC *tac, int isotope)
Definition tacdc.c:41
decaycorrection tacGetHeaderDecayCorrection(IFT *h)
Definition tacift.c:548
int tacSetHeaderDecayCorrection(IFT *h, decaycorrection dc)
Definition tacift.c:578
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 tacXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
Definition tacx.c:124
Header file for library libtpccsv.
Header file for library libtpcextensions.
unit
@ UNIT_MIN
minutes
@ UNIT_UNKNOWN
Unknown unit.
@ UNIT_SEC
seconds
@ TPCERROR_OK
No error.
char * unitName(int unit_code)
Definition units.c:143
int unitIsTime(int u)
Definition units.c:359
Header file for library libtpcift.
Header file for library libtpcisotope.
decaycorrection
Definition tpcisotope.h:78
@ DECAY_UNKNOWN
Not known; usually assumed that data is corrected.
Definition tpcisotope.h:79
@ DECAY_NOTCORRECTED
Data is not corrected for physical decay.
Definition tpcisotope.h:80
@ DECAY_CORRECTED
Data is corrected for physical decay.
Definition tpcisotope.h:81
isotope
Definition tpcisotope.h:50
@ ISOTOPE_UNKNOWN
Unknown.
Definition tpcisotope.h:51
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
Definition tpctac.h:28