TPCCLIB
Loading...
Searching...
No Matches
tactime.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 <math.h>
15#include <unistd.h>
16#include <string.h>
17#include <time.h>
18/*****************************************************************************/
19#include "libtpcmisc.h"
20#include "libtpcmodel.h"
21#include "libtpccurveio.h"
22/*****************************************************************************/
23
24/*****************************************************************************/
25static char *info[] = {
26 "Increase or decrease the sample (frame) times in regional or blood/plasma",
27 "TAC files.",
28 "Samples with negative times are not saved by default.",
29 "Time must be given in the same units that are used in the datafile.",
30 " ",
31 "Usage: @P [Options] tacfile [-]time outputfile",
32 " ",
33 "Time can be given as positive or negative value directly in the command",
34 "line, or in an ASCII file which contains a line with the time change value",
35 "in the following format: 'time_difference := time'.",
36 "Alternatively, time specified in that file with 'Ta' or 'start_time' is",
37 "subtracted from sample times.",
38 " ",
39 "Options:",
40 " -decay",
41 " Physical decay correction is changed with change in sample times;",
42 " without this option, radioactivity values are not changed.",
43 " Note that this option will provide correct result only if time unit",
44 " setting in datafile is correct.",
45 " -i=<isotope>",
46 " If tacfile does not contain the isotope, then decay correction cannot",
47 " applied unless isotope is given with this option.",
48 " Accepted isotope codes are for example F-18, C-11, and O-15.",
49 " Isotope code can also be specified in input file in format",
50 " '# isotope := Isotope'.",
51 " -keepnegat",
52 " Samples with negative sample times are not removed from output.",
53 " -keeptimes",
54 " While correction for physical decay is changed with option -decay,",
55 " sample times will not be changed.",
56 " -nogap",
57 " Possible gap between time zero and first sample is filled.",
58 " -stdoptions", // List standard options like --help, -v, etc
59 " ",
60 "See also: tacframe, tacdecay, injdifft, tacunit, fitdelay, simdisp, taccut",
61 " ",
62 "Keywords: TAC, modelling, simulation, late scan, input, time delay",
63 0};
64/*****************************************************************************/
65
66/*****************************************************************************/
67/* Turn on the globbing of the command line, since it is disabled by default in
68 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
69 In Unix&Linux wildcard command line processing is enabled by default. */
70/*
71#undef _CRT_glob
72#define _CRT_glob -1
73*/
74int _dowildcard = -1;
75/*****************************************************************************/
76
77/*****************************************************************************/
81int main(int argc, char **argv)
82{
83 int ai, help=0, version=0, verbose=1;
84 int fi, fj, ri, n, ret;
85 int change_decay=0;
86 int keep_negat=0;
87 int keep_times=0;
88 int fill_gap=0;
89 int time_sign=1;
90 char *cptr, dftfile1[FILENAME_MAX], dftfile2[FILENAME_MAX], tmp[64];
91 char isotope[64];
92 double time_diff=0.0;
93 double halflife=0.0, lambda, dcf, f;
94 int time_diff_unit=TUNIT_UNKNOWN;
95 DFT dft;
96 IFT ift;
97
98
99 /*
100 * Get arguments
101 */
102 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
103 dftfile1[0]=dftfile2[0]=isotope[0]=(char)0;
104 iftInit(&ift); dftInit(&dft);
105 /* Options */
106 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
107 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
108 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
109 cptr=argv[ai]+1;
110 if(strcasecmp(cptr, "DECAY")==0) {
111 change_decay=1; continue;
112 } else if(strncasecmp(cptr, "D=", 2)==0) { // deprecated option
113 change_decay=1;
114 cptr+=2; if(!*cptr) continue;
115 halflife=hlFromIsotope(cptr);
116 if(halflife<=0.0) {
117 fprintf(stderr, "Error: invalid isotope '%s'.\n", cptr);
118 return(1);
119 }
120 strcpy(isotope, hlCorrectIsotopeCode(cptr));
121 continue;
122 } else if(strncasecmp(cptr, "I=", 2)==0) {
123 //change_decay=1;
124 cptr+=2; if(!*cptr) continue;
125 halflife=hlFromIsotope(cptr);
126 if(halflife<=0.0) {
127 fprintf(stderr, "Error: invalid isotope '%s'.\n", cptr);
128 return(1);
129 }
130 strcpy(isotope, hlCorrectIsotopeCode(cptr));
131 continue;
132 } else if(strncasecmp(cptr, "KEEPNEGATIVE", 5)==0) {
133 keep_negat=1; continue;
134 } else if(strncasecmp(cptr, "KEEPTIMES", 5)==0) {
135 keep_times=1; continue;
136 } else if(strncasecmp(cptr, "NOGAP", 5)==0) {
137 fill_gap=1; continue;
138 }
139 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
140 return(1);
141 } else break;
142
143 /* Print help or version? */
144 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
145 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
146 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
147
148 /* Process other arguments, starting from the first non-option */
149 /* get data file name */
150 if(ai<argc) {
151 if(access(argv[ai], 0) == -1) {
152 fprintf(stderr, "Error: file '%s' does not exist.\n", argv[ai]);
153 return(1);
154 }
155 strcpy(dftfile1, argv[ai]); ai++;
156 }
157 /* get time difference */
158 if(ai<argc) {
159 /* maybe time is given in a file? */
160 ret=iftRead(&ift, argv[ai], 1);
161 if(ret==0) { /* yes it seems so */
162 strcpy(tmp, "scan_start_time_difference");
163 n=iftGet(&ift, tmp); time_sign=+1;
164 if(n==-1) {
165 strcpy(tmp, "time_difference"); n=iftGet(&ift, tmp); time_sign=+1;
166 }
167 if(n==-1) {
168 strcpy(tmp, "Ta"); n=iftGet(&ift, tmp); time_sign=-1;
169 }
170 if(n==-1) {
171 strcpy(tmp, "start_time"); n=iftGet(&ift, tmp); time_sign=-1;
172 }
173 if(n<0) {
174 fprintf(stderr,
175 "Error: keyword for time difference not found in '%s'.\n", argv[ai]);
176 iftEmpty(&ift); return(2);
177 }
178 ret=atof_with_check(ift.item[n].value, &time_diff);
179 if(ret!=0) {
180 fprintf(stderr, "Error: invalid format for time in '%s'.\n", argv[ai]);
181 iftEmpty(&ift); return(2);
182 }
183 time_diff*=time_sign;
184 /* Try to get its units too */
185 if(strstr(ift.item[n].value, "[s]")!=NULL) time_diff_unit=TUNIT_SEC;
186 else if(strstr(ift.item[n].value, "[min]")!=NULL) time_diff_unit=TUNIT_MIN;
187 } else { /* probably not, try to read it directly as a value */
188 ret=atof_with_check(argv[ai], &time_diff);
189 if(ret!=0) {
190 fprintf(stderr, "Error: invalid argument for time: '%s'.\n", argv[ai]);
191 return(1);
192 }
193 }
194 if(verbose>1) printf("time_diff := %g\n", time_diff);
195 if(time_diff==0.0) {
196 fprintf(stderr, "Warning: time change is zero.\n");
197 }
198 ai++;
199 }
200 /* get output file name */
201 if(ai<argc) {
202 strcpy(dftfile2, argv[ai]);
203 ai++;
204 }
205 /* check that there are no extra arguments */
206 if(ai<argc) {
207 fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]);
208 return(1);
209 }
210
211 /* Is something missing? */
212 if(!dftfile1[0]) {
213 fprintf(stderr, "Error: missing command-line argument; try %s --help\n",
214 argv[0]);
215 return(1);
216 }
217 if(!dftfile2[0]) {
218 fprintf(stderr, "Error: undefined output file name.\n");
219 return(1);
220 }
221
222 /* Check options */
223 if(keep_times==1 && change_decay==0) {
224 fprintf(stderr,
225 "Error: change in neither sample times or decay correction were requested.\n");
226 return(1);
227 }
228 if(keep_times==1) keep_negat=1;
229
230 /* In verbose mode print arguments and options */
231 if(verbose>1) {
232 printf("dftfile1 := %s\n", dftfile1);
233 printf("dftfile2 := %s\n", dftfile2);
234 printf("time_diff := %g\n", time_diff);
235 printf("change_decay := %d\n", change_decay);
236 printf("halflife := %g\n", halflife);
237 if(isotope[0]) printf("isotope := %s\n", isotope);
238 printf("keep_times := %d\n", keep_times);
239 printf("keep_negat := %d\n", keep_negat);
240 printf("fill_gap := %d\n", fill_gap);
241 }
242
243 /*
244 * Read data
245 */
246 if(verbose>1) printf("reading %s\n", dftfile1);
247 if(dftRead(dftfile1, &dft)) {
248 fprintf(stderr, "Error in reading '%s': %s\n", dftfile1, dfterrmsg);
249 return(3);
250 }
251 if(verbose>2) {
252 printf("voiNr := %d\n", dft.voiNr);
253 printf("frameNr := %d\n", dft.frameNr);
254 }
255
256 /* Get halflife from isotope setting in data file */
257 if(change_decay && strlen(dft.isotope)>0) {
258 f=hlFromIsotope(dft.isotope);
259 if(f<=0.0) {
260 fprintf(stderr, "Error: invalid isotope '%s' in '%s'.\n",
261 dft.isotope, dftfile1);
262 dftEmpty(&dft); return(3);
263 }
264 /* check that command-line and file isotope settings are matching */
265 if(halflife>0.0) {
266 if(halflife!=f) {
267 fprintf(stderr, "Error: invalid isotope in '%s' or in command line.\n",
268 dftfile1);
269 dftEmpty(&dft); return(1);
270 }
271 } else {
272 halflife=f;
273 }
274 }
275
276 /* Check that we now have the halflife, if decay needs to be changed */
277 if(change_decay && halflife<=0.0) {
278 fprintf(stderr, "Error: isotope not specified.\n");
279 dftEmpty(&dft); return(1);
280 }
281
282 /* Set isotope code in the file, if necessary */
283 if(isotope[0] && strlen(dft.isotope)<1) {
284 strcpy(dft.isotope, isotope);
285 //strcat(dft.comments, "# isotope := "); strcat(dft.comments, isotope);
286 }
287 if(!isotope[0]) strcpy(isotope, dft.isotope);
288 if(verbose>1) printf("isotope := %s\n", isotope);
289
290 /* If necessary, change the halflife time unit based on time unit in data */
291 if(halflife>0.0 && dft.timeunit==TUNIT_SEC) {
292 halflife*=60.0;
293 }
294 if(verbose>1) printf("halflife := %g\n", halflife);
295
296
297 /* Convert time diff units to the same as in DFT file */
298 if(time_diff_unit==TUNIT_MIN && dft.timeunit==TUNIT_SEC) {
299 time_diff*=60.0; time_diff_unit=TUNIT_SEC;
300 } else if(time_diff_unit==TUNIT_SEC && dft.timeunit==TUNIT_MIN) {
301 time_diff/=60.0; time_diff_unit=TUNIT_MIN;
302 }
303 if(verbose>1) printf("final_time_diff := %g\n", time_diff);
304
305 /*
306 * Change the sample times
307 */
308 if(keep_times==0) {
309 for(fi=0; fi<dft.frameNr; fi++) {
310 dft.x[fi]+=time_diff; dft.x1[fi]+=time_diff; dft.x2[fi]+=time_diff;
311 }
312 }
313 /* Remove samples with negative times */
314 if(keep_negat==0) {
315 for(fi=0; fi<dft.frameNr; fi++) if(dft.x[fi]>=0.0) break;
316 n=fi; if(n>0) for(fj=fi; fj<dft.frameNr; fj++) {
317 for(ri=0; ri<dft.voiNr; ri++) dft.voi[ri].y[fj-n]=dft.voi[ri].y[fj];
318 dft.x[fj-n]=dft.x[fj]; dft.x1[fj-n]=dft.x1[fj]; dft.x2[fj-n]=dft.x2[fj];
319 dft.w[fj-n]=dft.w[fj];
320 }
321 dft.frameNr-=n;
322 if(dft.frameNr<=0) {
323 fprintf(stderr, "Error: No positive times left.\n");
324 dftEmpty(&dft); return(4);
325 }
326 }
327 if(verbose>10) dftPrint(&dft);
328
329
330 /*
331 * Change the correction for physical decay, if required
332 */
333 if(change_decay) {
334 lambda=hl2lambda(halflife); if(time_diff<0.0) lambda=-lambda;
335 dcf=hlLambda2factor(lambda, fabs(time_diff), -1.0);
336 if(verbose>0)
337 printf("correction factor for physical decay: %g\n", dcf);
338 for(fi=0; fi<dft.frameNr; fi++) for(ri=0; ri<dft.voiNr; ri++)
339 dft.voi[ri].y[fi]*=dcf;
340 }
341
342
343 /*
344 * If sample times were not changed, and datafile contains injection time,
345 * then change the injection time accordingly
346 */
347 if(keep_times!=0 && strlen(dft.injectionTime)>18) {
348 time_t t_injection;
349 struct tm tm_injection;
350 /* Convert time string into time_t */
351 ret=get_datetime(dft.injectionTime, &tm_injection, verbose-2);
352 if(ret==0) {
353 t_injection=timegm(&tm_injection);
354 if(t_injection<0) ret=-100;
355 }
356 if(ret!=0) {
357 fprintf(stderr, "Error: invalid injection time.\n");
358 dftEmpty(&dft); return(6);
359 }
360 /* Add time_diff in seconds */
361 if(dft.timeunit==TUNIT_SEC) tmAdd(-time_diff, &tm_injection);
362 else if(dft.timeunit==TUNIT_MIN) tmAdd(-60.0*time_diff, &tm_injection);
363 snprintf(dft.injectionTime, 20, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d",
364 tm_injection.tm_year+1900, tm_injection.tm_mon+1, tm_injection.tm_mday,
365 tm_injection.tm_hour, tm_injection.tm_min, tm_injection.tm_sec);
366 if(verbose>0) printf("updated_injectiontime := %s\n", dft.injectionTime);
367 }
368
369 /*
370 * Make sure that there is no initial gap
371 */
372 if(fill_gap!=0) {
373 if(verbose>1) printf("checking for initial gap\n");
374 ret=dftFillInitialGap(&dft); if(ret!=0) {
375 fprintf(stderr, "Error: invalid injection time.\n");
376 dftEmpty(&dft); return(9);
377 }
378 }
379
380
381 /*
382 * Save the modified data
383 */
384 if(verbose>1) printf("saving modified data in %s\n", dftfile2);
385 /* Set comments */
386 strcpy(dft.comments, ""); dftSetComments(&dft);
387 /* Write the file */
388 if(dftWrite(&dft, dftfile2)) {
389 fprintf(stderr, "Error in writing '%s': %s\n", dftfile2, dfterrmsg);
390 dftEmpty(&dft); return(11);
391 }
392 /* Quit and tell what was done */
393 dftEmpty(&dft);
394 if(verbose>=0) {
395 if(keep_times==0) fprintf(stdout, "Sample times changed by %g", time_diff);
396 else fprintf(stdout, "Injection time changed by %g", -time_diff);
397 if(change_decay) fprintf(stdout, " and values with half-life %g", halflife);
398 fprintf(stdout, " in %s\n", dftfile2);
399 }
400 return(0);
401}
402/*****************************************************************************/
403
404/*****************************************************************************/
int get_datetime(char *str, struct tm *date, int verbose)
Definition datetime.c:322
time_t timegm(struct tm *tm)
Inverse of gmtime, converting struct tm to time_t.
Definition datetime.c:69
void tmAdd(int s, struct tm *d)
Definition datetime.c:514
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
void dftInit(DFT *data)
Definition dft.c:38
char dfterrmsg[64]
Definition dft.c:6
void dftSetComments(DFT *dft)
Definition dft.c:1326
void dftEmpty(DFT *data)
Definition dft.c:20
int dftFillInitialGap(DFT *dft)
Definition dft.c:1385
int dftRead(char *filename, DFT *data)
Definition dftio.c:22
void dftPrint(DFT *data)
Definition dftio.c:538
int dftWrite(DFT *data, char *filename)
Definition dftio.c:594
double hl2lambda(double halflife)
Definition halflife.c:84
double hlLambda2factor(double lambda, double frametime, double framedur)
Definition halflife.c:98
char * hlCorrectIsotopeCode(char *isocode)
Definition halflife.c:141
double hlFromIsotope(char *isocode)
Definition halflife.c:55
void iftEmpty(IFT *ift)
Definition ift.c:60
void iftInit(IFT *ift)
Definition ift.c:45
int iftRead(IFT *ift, char *filename, int is_key_required, int verbose)
Definition iftfile.c:24
int iftGet(IFT *ift, char *key, int verbose)
Definition iftsrch.c:15
Header file for libtpccurveio.
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:213
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:383
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:158
Header file for libtpcmodel.
Voi * voi
int timeunit
double * w
double * x1
char comments[_DFT_COMMENT_LEN+1]
int voiNr
double * x2
char injectionTime[20]
int frameNr
char isotope[8]
double * x
IFT_KEY_AND_VALUE * item
Definition libtpcmisc.h:279
double * y