TPCCLIB
Loading...
Searching...
No Matches
absscal.c
Go to the documentation of this file.
1
7/*****************************************************************************/
8#include "tpcclibConfig.h"
9/*****************************************************************************/
10#include <stdio.h>
11#include <stdlib.h>
12#include <unistd.h>
13#include <string.h>
14#include <ctype.h>
15#include <time.h>
16#include <math.h>
17/*****************************************************************************/
18#include "libtpcmisc.h"
19/*****************************************************************************/
20
21/*****************************************************************************/
22static char *info[] = {
23 "Extraction and calibration of blood TACs measured using",
24 "automatic blood sampling systems (ABSS, \"blood pump\") (1).",
25 "Application name was previously blo2kbq, version 3.8.1.",
26 " ",
27 "Usage: @P [Options] ABSS_file [BTAC_file]",
28 " ",
29 "Options:",
30 " -c=<filename>",
31 " Calibration coefficients for ABSS and well-counter should be specified",
32 " with calibration file (2), given with option -c.",
33 " -i=<isotope>",
34 " If ABSS data file does not contain the isotope code or halflife, then",
35 " it can be given with this option, using codes",
36 " C-11, F-18, Ga-68, Ge-68, O-15, ...",
37 " -decay=<on|off>",
38 " Blood data is corrected for radioactive decay (on, default), or not",
39 " corrected (off).",
40//" Possible background subtraction is done before decay correction.",
41 " -start=<t>",
42 " If ABSS measurement was not started at the time of injection,",
43 " the delay t (sec) must be entered with option -start=<t>. If data",
44 " collection was started before injection, enter a negative value for t;",
45 " activities before that time are removed from the output data.",
46 " -density[=<blood density>]",
47 " With this option blood radioactivity concentrations (kBq/mL) are",
48 " divided by the given blood density (by default 1.06)",
49 " to get concentrations in units kBq/g.",
50 " -min",
51 " Sample times are written in minutes (in seconds by default).",
52 " -mean, -left, -right, -both",
53 " The counts or radioactivity concentrations are by default calculated",
54 " as the mean of the channels (-mean). With options -left and -right ",
55 " only the left (ch2) or right (ch1) channel is used.",
56 " With option -both the results from both channels are saved.",
57 " Only applicable to Scanditronics and GEMS data.",
58/*
59 " -z",
60 " For reading of the measurement date, local time zone can be used with",
61 " option -z instead of Greenwich main time (default).",
62*/
63 " -abss=<device>",
64 " ABSS produces device-specific file formats, and detectors have",
65 " calibration factors. This option is needed if ABSS can not be correctly",
66 " determined from the filename (*.lis, *.bld, *.alg, or *.txt).",
67 " Accepted devices are Scanditronics, GEMS, Allogg1, and Allogg2, or",
68 " numbers 1-4, accordingly.",
69 " -stdoptions", // List standard options like --help, -v, etc
70 " ",
71 "Filename for corrected blood TAC data can be entered as the last command-line",
72 "argument. If not given, then file is written to the directory where ABSS file",
73 "is; calibrated file is named *.kbq and non-calibrated *.dat by default.",
74 " ",
75 "Example:",
76 " @P -i=O-15 -c=S:/Lab/plasma/bsampler_calibration/pump_cal.dat sr452_blo.bld",
77 " ",
78//"In case of the GEMS online sampler (GE Advange/PET CT), the injection",
79//"time is always taken from the first sample time in the *.bld file,",
80//"not from the header of the file, like with Scanditronics data.",
81//" ",
82 "References:",
83 "1. https://www.turkupetcentre.net/petanalysis/input_abss.html",
84 "2. https://www.turkupetcentre.net/petanalysis/input_abss_calibration.html",
85 " ",
86 "See also: absszero, absstime, abssexam, abssfch, taccat, disp4dft, fitdelay",
87 " ",
88 "Keywords: blood, input, ABSS, calibration",
89 0};
90/*****************************************************************************/
91
92/*****************************************************************************/
93/* Types and defaults */
94#define MAX_PUMPS 4
95#define BLOOD_DENSITY 1.06
96typedef enum {SCANDITRONICS,ALLOGG,ALLOGG2} Format;
97static int both_cols=0;
98static int gm_timez=1; /*time zone = Greenwich main time*/
99static int pump=0;
100char isotope[10]="UNKNOWN";
101double halflife=-1.0;
102char studynr[MAX_STUDYNR_LEN+1];
103/*****************************************************************************/
104/* Results data */
105struct BDataResults {
106 double t, ch1, ch2;
107};
108/*****************************************************************************/
109/* Scanditronics data */
110struct BDataS {
111 struct BDataResults results;
112 double time_of_day;
113 double time_since_start;
114 double meas_interval;
115 int pair1_coincid;
116 int pair1_det1_cnts;
117 int pair1_det2_cnts;
118 int pair2_coincid;
119 int pair2_det1_cnts;
120 int pair2_det2_cnts;
121 int aux_cnts;
122};
123
124/* Allogg data */
125struct BDataA {
126 struct BDataResults results;
127 double time_since_start;
128 double meas_interval; /* This is calculated from the data */
129 int data[2];
130};
131
132struct DataList {
133 union {
134 struct BDataS scanditronics;
135 struct BDataA allogg;
136 struct BDataResults results;
137 };
138 struct DataList *prev, *next;
139};
140
141struct Blood {
143 struct tm date;
145 time_t time;
147 char bgdate[11];
149 float background;
151 struct DataList *data;
152};
153/*****************************************************************************/
154/* Local functions */
155int read_scanditronics_data(
156 const char *inputfile, struct Blood *blood, int verbose);
157int read_allogg_data(
158 const char *inputfile, struct Blood *blood, int verbose);
159int read_allogg2_data(
160 char *inputfile, struct Blood *blood, int verbose, char *msg);
161void correct_scanditronics(struct Blood *blood, int verbose);
162int correct_allogg(struct Blood *blood);
163int correct_allogg2(struct Blood *blood, int verbose);
164void subtract_background(struct Blood *blood);
165int get_calfactors(const char *file,time_t bloodt, double *wcf,
166 double *pumpf, int pump, char *isotope, char *caldate, int verbose);
167int find_date(char *str, struct Blood *blood, int verbose);
168int find_halflife(char *str, int verbose);
169/*****************************************************************************/
170
171/*****************************************************************************/
172/* Turn on the globbing of the command line, since it is disabled by default in
173 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
174 In Unix&Linux wildcard command line processing is enabled by default. */
175/*
176#undef _CRT_glob
177#define _CRT_glob -1
178*/
179int _dowildcard = -1;
180/*****************************************************************************/
181
182/*****************************************************************************/
186int main(int argc, char *argv[])
187{
188 int ai, help=0, version=0, verbose=1;
189
190 double startTime=0.0, density=1.0, wc_factor=-1.0, pump_factor=-1.0;
191 int decay_correct=1; // 0=no, 1=yes
192 char pumpfile[FILENAME_MAX], calfile[FILENAME_MAX], outfile[FILENAME_MAX];
193 char tmp[FILENAME_MAX];
194 float sum1, sum2;
195 Format format=SCANDITRONICS;
196 struct DataList *ptr;
197 int timeInMinutes=0;
198 struct Blood blood;
199 char caldate[25];
200 int column=0; // use mean (0), left (1), or right (2) channel
201 char *cptr;
202 FILE *fp;
203 int r;
204 int zero1=1, zero2=1;
205 time_t t_injection, t_samp;
206 struct tm tm_injection, tm_samp;
207
208
209 /*
210 * Get arguments
211 */
212 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
213 pumpfile[0]=calfile[0]=outfile[0]=(char)0;
214 studynr[0]=(char)0;
215
216 /* Options */
217 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
218 //printf("argv[%d] := '%s'\n", ai, argv[ai]);
219 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
220 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
221 if(strncasecmp(cptr, "C=", 2)==0 && strlen(cptr)>2) {
222 strlcpy(calfile, cptr+2, FILENAME_MAX); continue;
223 } else if(strncasecmp(cptr, "O=", 2)==0 && strlen(cptr)>2) { // deprecated
224 strlcpy(outfile, cptr+2, FILENAME_MAX); continue;
225 } else if(strncasecmp(cptr, "I=", 2)==0 && strlen(cptr)>2) {
226 if(hlCorrectIsotopeCode(cptr+2)!=NULL) {
227 strcpy(isotope, hlCorrectIsotopeCode(cptr+2));
228 halflife=hlFromIsotope(isotope);
229 continue;
230 }
231 printf("Error: Incorrect isotope code '%s'\n", cptr+2);
232 return(1);
233 } else if(strncasecmp(cptr, "DECAY=", 6)==0 && strlen(cptr)>6) {
234 cptr+=6;
235 if(strcasecmp(cptr, "OFF")==0) {decay_correct=0; continue;}
236 if(strcasecmp(cptr, "ON")==0) {decay_correct=1; continue;}
237 } else if(strcasecmp(cptr, "DENSITY")==0) {
238 density=BLOOD_DENSITY; continue;
239 } else if(strncasecmp(cptr, "DENSITY=", 8)==0) {
240 cptr+=8; density=atof_dpi(cptr); if(density>0.0) continue;
241 } else if(strncasecmp(cptr, "MIN", 1)==0) {
242 timeInMinutes=1; continue;
243 } else if(strcasecmp(cptr, "SEC")==0) {
244 timeInMinutes=0; continue;
245 } else if(strncasecmp(cptr, "Z", 1)==0) {
246 gm_timez=0; continue;
247 } else if(strncasecmp(cptr, "LEFT", 1)==0) {
248 column=1; continue;
249 } else if(strncasecmp(cptr, "RIGHT", 1)==0) {
250 column=2; continue;
251 } else if(strcasecmp(cptr, "BOTH")==0) {
252 both_cols=1; continue;
253 } else if(strncasecmp(cptr, "PUMP=", 5)==0 && strlen(cptr)>5) {
254 cptr+=5;
255 if(strncasecmp(cptr, "SCANDITRONICS", 1)==0) {format=SCANDITRONICS; pump=1; continue;}
256 if(strncasecmp(cptr, "GEMS", 1)==0) {format=SCANDITRONICS; pump=2; continue;}
257 if(strncasecmp(cptr, "ALLOGG1", 1)==0) {format=ALLOGG; pump=3; continue;}
258 if(strcasecmp(cptr, "ALLOGG2")==0) {format=ALLOGG2; pump=4; continue;}
259 pump=atoi(cptr);
260 if(pump==1 || pump==2) {format=SCANDITRONICS; continue;}
261 if(pump==3) {format=ALLOGG; continue;}
262 if(pump==4) {format=ALLOGG2; continue;}
263 } else if(strncasecmp(cptr, "START=", 6)==0 && strlen(cptr)>6) {
264 startTime=atof_dpi(cptr+6); continue;
265 }
266 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
267 return(1);
268 } else break;
269
270 /* Print help or version? */
271 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
272 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
273 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
274
275 /* Process other arguments, starting from the first non-option */
276 if(ai<argc) strlcpy(pumpfile, argv[ai++], FILENAME_MAX);
277 if(ai<argc) strlcpy(outfile, argv[ai++], FILENAME_MAX);
278 if(ai<argc) {fprintf(stderr, "Error: too many arguments: '%s'.\n", argv[ai]); return(1);}
279
280 /* Is something missing? */
281 if(!pumpfile[0]) {
282 fprintf(stderr, "Error: missing ABSS file name.\n");
283 return(1);
284 }
285
286 /* In verbose mode print arguments and options */
287 if(verbose>1) {
288 printf("pumpfile := %s\n", pumpfile);
289 printf("isotope := %s\n", isotope);
290 printf("halflife := %g\n", halflife);
291 printf("decay_correct := %d\n", decay_correct);
292 printf("startTime := %g\n", startTime);
293 printf("density := %g\n", density);
294 printf("timeInMinutes := %d\n", timeInMinutes);
295 printf("column := %d\n", column);
296 printf("both_cols := %d\n", both_cols);
297 fflush(stdout);
298 }
299
300 /* Decide which pump we are dealing with, if not given by user */
301 if(pump==0) {
302 cptr=pumpfile+strlen(pumpfile)-4;
303 if(strcasecmp(cptr, ".lis")==0) {pump=1; format=SCANDITRONICS;}
304 else if(strcasecmp(cptr, ".bld")==0) {pump=2; format=SCANDITRONICS;}
305 else if(strcmp(cptr, ".alg")==0) {pump=3; format=ALLOGG;}
306 else if(strcmp(cptr, ".txt")==0) {pump=4; format=ALLOGG2;}
307 else {
308 fprintf(stderr, "Error: cannot identify the pump;\n");
309 fprintf(stderr, "please rename the file to *.lis, *.bld, *.alg or *.txt\n");
310 fprintf(stderr, "or use option -abss=<id>.\n");
311 return(1);
312 }
313 }
314 if(verbose>1) {
315 printf("pump := %d\n", pump);
316 printf("format := %d\n", format);
317 }
318
319
320 /*
321 * Read in data
322 */
323 if(verbose>0) printf("reading %s\n", pumpfile);
324 switch(format) {
325 case SCANDITRONICS:
326 if(read_scanditronics_data(pumpfile, &blood, verbose-2)) return 2;
327 break;
328 case ALLOGG:
329 if(read_allogg_data(pumpfile, &blood, verbose-2)) return 2;
330 break;
331 case ALLOGG2:
332 if(read_allogg2_data(pumpfile, &blood, verbose-2, tmp)) {
333 fprintf(stderr, "Error in reading %s: %s.\n", pumpfile, tmp);
334 return 2;
335 }
336 break;
337 }
338 /* Check that isotope is specified with decay correction */
339 if(decay_correct!=0) {
340 if(halflife<=0.0 || strcasecmp(isotope, "UNKNOWN")==0) {
341 fprintf(stderr,"Error: isotope must be specified for decay correction.\n");
342 return 1;
343 }
344 }
345 /* Check that isotope is specified with calfile */
346 if(calfile[0] && strcasecmp(isotope, "UNKNOWN")==0) {
347 fprintf(stderr,"Error: isotope must be specified for calibration.\n");
348 return 1;
349 }
350
351 /* Process the data */
352 if(verbose>0) printf("processing the data\n");
353 switch(format) {
354 case SCANDITRONICS:
355 correct_scanditronics(&blood, verbose-2);
356 break;
357 case ALLOGG:
358 if(correct_allogg(&blood) == 1) return 3;
359 break;
360 case ALLOGG2:
361 if(correct_allogg2(&blood, verbose-2) == 1) return 3;
362 break;
363 }
364
365 /* Check that neither of the channels has all values zero*/
366 if(verbose>1) printf("verifying that data is not all zeroes\n");
367 zero1=zero2=1;
368 if(format==SCANDITRONICS) {
369 ptr=blood.data;
370 while(ptr) {
371 if(fabs(ptr->results.ch1) > 1.0e-10) zero1=0;
372 if(fabs(ptr->results.ch2) > 1.0e-10) zero2=0;
373 ptr=ptr->next;
374 }
375 if(zero1){
376 fprintf(stderr, "Error: All values from channel 1 are zeros. Contact the physicist!\n");
377 if(column!=2) return 4;
378 }
379 if(zero2){
380 fprintf(stderr, "Error: All values from channel 2 are zeros. Contact the physicist!\n");
381 if(column!=1) return 4;
382 }
383 }
384
385 /* Subtract background radiation; must be done before decay correction */
386 if(blood.background>0.0) {
387 if(verbose>=0) printf("subtracting background\n");
388 subtract_background(&blood);
389 } else if(blood.background<-1.0) {
390 if(format==ALLOGG || format==ALLOGG2) {
391 if(calfile[0]) {
392 fprintf(stderr, "Error: %s does not contain background.\n", pumpfile);
393 return(5);
394 } else
395 fprintf(stderr, "Warning: %s does not contain background.\n", pumpfile);
396 }
397 }
398
399
400 /*
401 * Calibration
402 */
403 if(calfile[0]) {
404
405 /* Check that we have the measurement date */
406 if(blood.date.tm_year==0) {
407 fprintf(stderr, "\nError: Blood file must contain the measurement date!\n");
408 fprintf(stderr, "Open the blood file in a text editor and add the date to\n");
409 fprintf(stderr, "the beginning as its own comment line, e.g. # 1999-11-31\n\n");
410 return(6);
411 }
412
413 if(verbose>0) printf("calibrating\n");
414 ptr=blood.data;
415 if(get_calfactors(calfile, timegm(&blood.date), &wc_factor, &pump_factor,
416 pump, isotope, caldate, verbose-1))
417// if(get_calfactors(calfile,mktime(&blood.date),&wc_factor,&pump_factor,
418// pump,isotope,caldate))
419 return 7;
420 if(verbose>=0)
421 printf(" PC := %g\n WC/BR := %g\n calibration_date := %s\n",
422 pump_factor, wc_factor, caldate);
423 while(ptr) {
424 ptr->results.ch1*=wc_factor*pump_factor;
425 ptr->results.ch2*=wc_factor*pump_factor;
426 ptr=ptr->next;
427 }
428 } else if(verbose>=0) {
429 printf("Warning: no calibration file was entered; data is not calibrated.\n");
430 }
431
432
433 /* Correct the start time for decay correction */
434 /* If negative, then correct them back again later */
435 /* Set earlier activities to 0 */
436 if(startTime!=0.0) {
437 if(verbose>1) printf("correcting the start time\n");
438 ptr=blood.data;
439 while(ptr) {
440 ptr->results.t+=startTime;
441 if(format==SCANDITRONICS)
442 ptr->scanditronics.time_since_start+=startTime;
443 else
444 ptr->allogg.time_since_start+=startTime;
445 if(ptr->results.t<0.0) {
446 ptr->results.ch1=0;
447 ptr->results.ch2=0;
448 }
449 ptr=ptr->next;
450 }
451 }
452
453 /* Print the time of the first sample */
454 if(format==SCANDITRONICS) {
455 ptr=blood.data; t_samp=ptr->scanditronics.time_of_day;
456 if(gmtime_r(&t_samp, &tm_samp)==NULL) {
457 fprintf(stderr, "Warning: invalid sample time.\n");
458 } else {
459 tm_samp.tm_year=blood.date.tm_year;
460 tm_samp.tm_mon=blood.date.tm_mon;
461 tm_samp.tm_mday=blood.date.tm_mday;
462 t_samp=timegm(&tm_samp);
463 char buf[32];
464 if(!ctime_r_int(&t_samp, buf)) {
465 fprintf(stderr, "Warning: invalid sample time.\n");
466 } else {
467 fprintf(stdout, "Time point of the first sample is: %s\n", buf);
468 }
469 }
470 }
471
472 /* Decay correction */
473 if(decay_correct!=0) {
474 double lambda=hl2lambda(halflife*60.0);
475 double dc=0;
476
477 ptr=blood.data;
478 if(verbose>=0) printf("decay correction with half-life %.2f min.\n", halflife);
479 while(ptr) {
480 dc=1.0;
481 if(format==SCANDITRONICS) {
482 if(ptr->scanditronics.time_since_start>=0.0) {
483 dc = hlLambda2factor(lambda,
484 ptr->scanditronics.time_since_start, ptr->scanditronics.meas_interval);
485 }
486 } else {
487 if(ptr->allogg.time_since_start>=0.0) {
488 dc = hlLambda2factor(lambda, ptr->allogg.time_since_start, ptr->allogg.meas_interval);
489 if(verbose>5) printf("dc:%f %f\n",dc,ptr->allogg.time_since_start);
490 }
491 }
492 ptr->results.ch1*=dc;
493 ptr->results.ch2*=dc;
494 ptr=ptr->next;
495 }
496 }
497
498#if(0) // REMOVED IN BLO2KBQ VERSION 3.4.3
499 /* If start time is negative, then set orig times */
500 if(startTime<0.0) {
501 ptr=blood.data;
502 while(ptr) {
503 ptr->results.t-=startTime;
504 ptr=ptr->next;
505 }
506 }
507#endif
508
509 /* Blood density correction */
510 if(density!=1.0) {
511 if(verbose>0)
512 printf("kBq/mL to kBq/g correction with blood density of %.2f g/mL.\n", density);
513 ptr=blood.data;
514 while(ptr) {
515 ptr->results.ch1/=density;
516 ptr->results.ch2/=density;
517 ptr=ptr->next;
518 }
519 }
520
521 /* Check that channels are not too different */
522 ptr=blood.data; sum1=sum2=0.0;
523 while(ptr) {
524 if(format==ALLOGG || format==ALLOGG2) {
525 if(ptr->results.ch1 < -2.0)
526 printf("Warning: channel below zero:%lf\n", ptr->results.ch1);
527 } else {
528 if(ptr->results.ch1 < 0)
529 printf("Warning: channel one below zero:%lf\n", ptr->results.ch1);
530 if(ptr->results.ch2 < 0)
531 printf("Warning: channel two below zero:%lf\n", ptr->results.ch2);
532 }
533 sum1+=ptr->results.ch1;
534 sum2+=ptr->results.ch2;
535 ptr=ptr->next;
536 }
537 if(column!=1 && column!=2 && (fabs(sum1-sum2)/(1.0+sum1+sum2))>0.3)
538 fprintf(stderr, "Warning: Large difference between channels of online blood sampler!\n");
539
540
541 /*
542 * Write output
543 */
544
545 /* Create output filename, if not given */
546 if(!outfile[0]) {
547 if(studynr_validity_check2(studynr, 1)) strcpy(outfile, studynr);
548 else strcpy(outfile, pumpfile);
549 cptr=strrchr(outfile,'.'); if(cptr!=NULL) *cptr='\0';
550 if(calfile[0]) strcat(outfile,".kbq"); else strcat(outfile,".dat");
551 if(verbose>1) printf("outputfile := %s\n", outfile);
552 }
553 /* Check if output file exists; backup, if necessary */
554 if(backupExistingFile(outfile, NULL, tmp)) {
555 fprintf(stderr, "Error: %s\n", tmp);
556 }
557 /* Open the file */
558 if(verbose>=0) printf("writing output in file %s\n", outfile);
559 fp=fopen(outfile, "w");
560 if(fp==NULL) {
561 fprintf(stderr, "Error: cannot write %s\n", outfile);
562 perror("fopen");
563 return 11;
564 }
565
566 /*
567 * Write header information
568 */
569 if(verbose>2) printf("writing 'header'\n");
570
571 /* measurement start time */
572 if(gmtime_r(&t_injection, &tm_samp)==NULL) {
573 fprintf(stderr, "Warning: invalid measurement start time.\n");
574 }
575#if(0)
576 } else {
577 /* Greenwich main time->Hki time zone*/
578 if(blood.date.tm_hour==tm_samp.tm_hour-2)
579 blood.date.tm_hour+=2;
580 else if(blood.date.tm_hour==tm_samp.tm_hour-3)
581 blood.date.tm_hour+=3;
582 }
583#endif
584 fprintf(fp, "# measurement_start_time := %.4d-%.2d-%.2d %.2d:%.2d:%.2d\n",
585 blood.date.tm_year+1900,blood.date.tm_mon+1,blood.date.tm_mday,
586 blood.date.tm_hour,blood.date.tm_min,blood.date.tm_sec);
587 /* detector id */
588 fprintf(fp, "# detector := %d\n", pump);
589 /* sample time unit */
590 if(timeInMinutes==1) fprintf(fp, "# time_unit := min\n");
591 else fprintf(fp, "# time_unit := sec\n");
592 /* calibration */
593 if(calfile[0]) {
594 fprintf(fp, "# calibrated := yes\n");
595 fprintf(fp, "# unit := kBq/ml\n");
596 fprintf(fp, "# calibration_date := %s\n", caldate);
597 fprintf(fp, "# pump_calibration_factor := %g\n", pump_factor);
598 fprintf(fp, "# wc_calibration_factor_per_br := %g\n", wc_factor);
599 fprintf(fp, "# calibration_file := %s\n", calfile);
600 } else {
601 fprintf(fp, "# calibrated := no\n");
602 fprintf(fp, "# unit := cps\n");
603 }
604 /* isotope */
605 fprintf(fp, "# isotope := %s\n", isotope);
606 /* decay correction */
607 if(decay_correct!=0) {
608 fprintf(fp, "# decay_correction := yes\n");
609 fprintf(fp, "# halflife := %g [min]\n", halflife);
610 } else {
611 fprintf(fp, "# decay_correction := no\n");
612 }
613 /* injection time */
614 r=3600*blood.date.tm_hour + 60*blood.date.tm_min + blood.date.tm_sec;
615 if(startTime==0.0) { /* injection time = measurement start time */
616 fprintf(fp, "# injection_time := %.4d-%.2d-%.2d %.2d:%.2d:%.2d\n",
617 blood.date.tm_year+1900, blood.date.tm_mon+1, blood.date.tm_mday,
618 blood.date.tm_hour, blood.date.tm_min, blood.date.tm_sec);
619 } else if(r==0) {
620 fprintf(fp, "# injection_time := %g [sec]\n", startTime);
621 } else {
622 t_injection=timegm(&blood.date);
623 if(t_injection==-1) {
624 fprintf(stderr, "Error: invalid injection time.\n");
625 fclose(fp); return(12);
626 } else {
627 t_injection-=startTime;
628 if(gmtime_r(&t_injection, &tm_injection)==NULL) {
629 fprintf(stderr, "Error: invalid injection time.\n");
630 fclose(fp); return(12);
631 }
632 }
633 fprintf(fp, "# injection_time := %.4d-%.2d-%.2d %.2d:%.2d:%.2d\n",
634 tm_injection.tm_year+1900, tm_injection.tm_mon+1, tm_injection.tm_mday,
635 tm_injection.tm_hour, tm_injection.tm_min, tm_injection.tm_sec);
636 }
637 /* background activity */
638 if(blood.background>0.0) {
639 if(blood.bgdate[0])
640 fprintf(fp,"# background_date := %s\n", blood.bgdate);
641 fprintf(fp,"# background := %g [cps]\n", blood.background);
642 }
643 /* Study number */
644 if(studynr_validity_check2(studynr, 1)) {
645 fprintf(fp, "# studynr := %s\n", studynr);
646 }
647
648 /*
649 * Write the data lines
650 */
651 if(verbose>2) printf("Writing data lines\n");
652 ptr=blood.data;
653 while(ptr) {
654 /* Don't print if sample time is negative */
655 if(ptr->results.t<0.0) {ptr=ptr->next; continue;}
656 /* Write the sample time */
657 if(timeInMinutes) fprintf(fp, "%12.4f", ptr->results.t/60.0);
658 else fprintf(fp, "%12.3f", ptr->results.t);
659 /* Write the channel avg, or both separately, or only one */
660 if(both_cols) {
661 fprintf(fp, " %12.3f %12.3f\n", ptr->results.ch1, ptr->results.ch2);
662 } else if(column==1) {
663 fprintf(fp, " %12.3f\n", ptr->results.ch1);
664 } else if(column==2) {
665 fprintf(fp, " %12.3f\n", ptr->results.ch2);
666 } else {
667 fprintf(fp, " %12.3f\n", 0.5*(ptr->results.ch1+ptr->results.ch2));
668 }
669 ptr=ptr->next;
670 }
671
672 return 0;
673}
674/*****************************************************************************/
675
676/*****************************************************************************/
682int find_date(
684 char *str,
686 struct Blood *blood,
688 int verbose
689) {
690 int c,yyyy,MM,dd,hh=0,mm=0,ss=0;
691 if(str[6]=='-' && (str[8]=='-'||str[9]=='-')) {
692 c=sscanf(str,"# %d-%d-%d %d:%d:%d",&yyyy,&MM,&dd,&hh,&mm,&ss);
693 /* Found all fields */
694 if(c==6 || c==3) {
695 blood->date.tm_year=yyyy-1900;
696 blood->date.tm_mday=dd;
697 blood->date.tm_mon=MM-1;
698 blood->date.tm_hour=hh;
699 blood->date.tm_min=mm;
700 blood->date.tm_sec=ss;
701 blood->date.tm_isdst=-1;
702 if(verbose>0)
703 printf("find_date(): %04d-%02d-%02d %02d:%02d:%02d\n", yyyy, MM, dd, hh, mm, ss);
704 return 0;
705 }
706 }
707 return 1;
708}
709/*****************************************************************************/
710
711/*****************************************************************************/
717int find_halflife(
719 char *str,
721 int verbose
722) {
723 char *cptr=strcasestr(str, "half-life: ");
724 if(cptr!=NULL) {
725 cptr+=11;
726 } else {
727 cptr=strcasestr(str, "halflife: ");
728 if(cptr!=NULL) {
729 cptr+=10;
730 } else {
731 return(1);
732 }
733 }
734 if(verbose>0) printf("%s(): %s\n", __func__, cptr);
735 double f=atof_dpi(cptr); if(!isnormal(f)) return(1);
736 if(!isnan(halflife) && halflife>0.0 && !doubleMatch(halflife, f, 0.1)) {
737 fprintf(stderr, "Error: different isotope in file and given by user.\n");
738 exit(1);
739 }
740 halflife=f;
741 int c=hlIsotopeFromHalflife(halflife); if(c<0) return(1);
742 strcpy(isotope, hlIsotopeCode(c));
743 return(1);
744}
745/*****************************************************************************/
746
747/*****************************************************************************/
751int find_background(
753 const char *str,
755 struct Blood *blood
756) {
757 char tmp[11];
758
759 while(isspace((int)*str) || *str=='#') str++;
760 if(*str) {
761 if(strncasecmp(str, "Background:", 11)==0) {
762 str+=11;
763 if(sscanf(str, "%f", &blood->background) == 1) {
764 return 0;
765 }
766 } else if(strncasecmp(str, "Background on", 13)==0) {
767 str+=13;
768 if(sscanf(str,"%8s: %f", tmp, &blood->background) == 2) {
769 sprintf(blood->bgdate, "%4.4s-%2.2s-%2.2s", tmp, tmp+4, tmp+6);
770 return 0;
771 } else if(sscanf(str, "%10s: %f", blood->bgdate, &blood->background)==2) {
772 return 0;
773 }
774 }
775 }
776 return 1;
777}
778/*****************************************************************************/
779
780/*****************************************************************************/
784int read_scanditronics_data(
786 const char *inputfile,
788 struct Blood *blood,
790 int verbose
791) {
792 char line[512],*str;
793 struct DataList *points;
794 struct BDataS *bdata;
795 int datenotfound=1;
796 int hlnotfound=1;
797 FILE *fp;
798 int n;
799 //time_t t;
800
801 if(verbose>0) printf("%s(%s)\n", __func__, inputfile);
802 blood->bgdate[0]='\0';
803 blood->background = 0.0;
804
805 fp=fopen(inputfile,"r");
806 if(!fp) {
807 fprintf(stderr,"Error: cannot open \"%s\".\n",inputfile);
808 perror("fopen");
809 return 1;
810 }
811 /*
812 t=0; if(gm_timez) blood->date=*gmtime(&t); else blood->date=*localtime(&t);
813 */
814 points=malloc(sizeof(struct DataList));
815 points->prev=NULL; points->next=NULL;
816 bdata=&points->scanditronics;
817 memset(bdata,0,sizeof(struct BDataS));
818 blood->data=points;
819 /* Read data */
820 while(fgets(line,sizeof(line),fp)) {
821 str=line;
822 while(*str && isspace((unsigned char)*str)) str++;
823 if(*str=='#') { /* Comment line; find date */
824 if(datenotfound) datenotfound=find_date(str, blood, verbose);
825 if(hlnotfound) hlnotfound=find_halflife(str, verbose);
826 continue;
827 }
828 if(datenotfound) {
829 fprintf(stderr, "Error: valid measurement date was not found in header.\n");
830 fclose(fp); return 5;
831 }
832 if(*str=='*' || *str=='\0') continue;
833 n=sscanf(str, "%lf %lf %lf %i %i %i %i %i %i %i",
834 &bdata->time_of_day, &bdata->time_since_start, &bdata->meas_interval,
835 &bdata->pair1_coincid, &bdata->pair1_det1_cnts, &bdata->pair1_det2_cnts,
836 &bdata->pair2_coincid, &bdata->pair2_det1_cnts, &bdata->pair2_det2_cnts,
837 &bdata->aux_cnts);
838 if(n==10) {
839 points->next=malloc(sizeof(struct DataList));
840 points->next->prev=points;
841 points=points->next;
842 points->next=NULL;
843 bdata=&points->scanditronics;
844 memset(bdata,0,sizeof(struct BDataS));
845 } else {
846 if(n>0 && n!=7) fprintf(stderr,"Warning: malformed line!:{%s}\n",str);
847 }
848 }
849 fclose(fp);
850
851 if(bdata->time_of_day==0 && bdata->meas_interval==0) {
852 /* Remove extra entry if any */
853 struct DataList *prev=points->prev;
854 free(points);
855 points=prev;
856 if(points) {
857 points->next=NULL;
858 } else {
859 blood->data=NULL;
860 }
861 }
862 return 0;
863}
864/*****************************************************************************/
865
866/*****************************************************************************/
872int read_allogg_data(
874 const char *inputfile,
876 struct Blood *blood,
878 int verbose
879) {
880 char line[512],*str;
881 struct DataList *points;
882 struct BDataA *bdata;
883 int datenotfound=1, bgnotfound=1, timenotfound=1;
884 FILE *fp;
885 int n;
886 //time_t t;
887
888 if(verbose>0) printf("%s(%s)\n", __func__, inputfile);
889
890 blood->bgdate[0] = '\0';
891 blood->background = -1.0E20;
892
893 fp=fopen(inputfile,"r");
894 if(!fp) {
895 fprintf(stderr,"Error: cannot open \"%s\".\n",inputfile);
896 perror("fopen");
897 return 1;
898 }
899 /*
900 t=0; if(gm_timez) blood->date=*gmtime(&t); else blood->date=*localtime(&t);
901 */
902 memset(&blood->date,0,sizeof(struct tm));
903 points=malloc(sizeof(struct DataList));
904 points->prev=NULL; points->next=NULL;
905 bdata=&points->allogg;
906 memset(bdata,0,sizeof(struct BDataA));
907 blood->data=points;
908 /* Read data */
909 while(fgets(line,sizeof(line),fp)) {
910 str=line;
911 while(isspace((unsigned char)*str)) str++;
912 if(*str=='#') { /* Comment line; find date */
913 if(datenotfound) datenotfound=find_date(str, blood, verbose-2);
914 if(bgnotfound) bgnotfound=find_background(str, blood);
915 continue;
916 }
917 if(*str=='\0') continue;
918 n=sscanf(str,"%lf %d %d", &bdata->time_since_start,&bdata->data[0],&bdata->data[1]);
919 if(timenotfound && strlen(str)>6&&strlen(str)<9) {
920 blood->date.tm_hour=(str[0]-'0')*10+(str[1]-'0');
921 blood->date.tm_min=(str[2]-'0')*10+(str[3]-'0');
922 blood->date.tm_sec=(str[4]-'0')*10+(str[5]-'0');
923 blood->date.tm_isdst=-1; timenotfound=0;
924 } else if(n<2) {
925 fprintf(stderr,"Error: malformed line %sCorrect syntax is hhmmss.\n",str);
926 return 2;
927 } else {
928 points->next=malloc(sizeof(struct DataList));
929 points->next->prev=points;
930 points=points->next;
931 points->next=NULL;
932 bdata=&points->allogg;
933 memset(bdata,0,sizeof(struct BDataA));
934 }
935 }
936 fclose(fp);
937 if(bdata->time_since_start==0) { /* Remove extra entry if any */
938 struct DataList *prev=points->prev;
939 free(points);
940 points=prev;
941 if(points) {
942 points->next=NULL;
943 } else {
944 blood->data=NULL;
945 }
946 }
947
948 return 0;
949}
950/*****************************************************************************/
951
952/*****************************************************************************/
956int read_allogg2_data(
958 char *inputfile,
960 struct Blood *blood,
962 int verbose,
964 char *msg
965) {
966 IFT ift;
967 int ii, n, ret;
968 int singles, coincidents;
969 char tmp[1024];
970 double f, tas;
971 //time_t t;
972 struct DataList *points;
973 struct BDataA *bdata;
974
975
976 if(verbose>0) printf("%s(%s)\n", __func__, inputfile);
977 /* Check the arguments */
978 if(inputfile==NULL || blood==NULL || strlen(inputfile)<1) {
979 if(msg!=NULL) strcpy(msg, "program error");
980 return(1);
981 }
982 blood->bgdate[0] = '\0';
983 blood->background = -1.0E20;
984
985 /* Read Allogg2 file into IFT struct */
986 iftInit(&ift); ret=iftRead(&ift, inputfile, 0, 0);
987 if(ret) {if(msg!=NULL) strcpy(msg, ift.status); iftEmpty(&ift); return(2);}
988 if(verbose>=12) {iftWrite(&ift, "stdout", 0); fflush(stdout);}
989
990 /* Check that this is TPC Allogg2 */
991 strcpy(tmp, "System ID"); ii=iftGet(&ift, tmp, 0);
992 if(ii<0) {
993 if(msg!=NULL) strcpy(msg, "wrong format");
994 iftEmpty(&ift); return(3);
995 }
996 if(strcmp(ift.item[ii].value, "ABSS09282")!=0) {
997 if(msg!=NULL) strcpy(msg, "wrong sampler ID");
998 iftEmpty(&ift); return(4);
999 }
1000
1001 /* Read the background */
1002 strcpy(tmp, "//Average background counts"); ii=iftFindNthKey(&ift, tmp, 1, 0);
1003 if(ii>=0) {
1004 if(verbose>3) printf("key := '%s'\n", ift.item[ii].key);
1005 /* Get background date from the key */
1006 ret=isdate(ift.item[ii].key+28);
1007 if(ret!=0) ret=isdate2(ift.item[ii].key+28, tmp);
1008 if(ret!=0) ret=isdate3(ift.item[ii].key+28, tmp);
1009 if(ret==0) {
1010 if(verbose>1) printf("background_date := %s\n", tmp);
1011 strcpy(blood->bgdate, tmp);
1012 } else if(verbose>0) printf("background_date not valid\n");
1013 /* Get background counts/sec from value */
1014 if(verbose>1) printf("background_value := %s\n", ift.item[ii].value);
1015 blood->background=atof(ift.item[ii].value);
1016 } else if(verbose>0) printf("background not found\n");
1017
1018 /* Read the isotope (half-life) */
1019 strcpy(tmp, "HalfTime"); ii=iftGet(&ift, tmp, 0);
1020 if(ii>=0) {
1021 f=atof(ift.item[ii].value);
1023 /* Use it only if user did not specify the isotope */
1024 if(strcmp(isotope, "UNKNOWN")==0) {
1025 strcpy(isotope, hlIsotopeCode(ii));
1026 halflife=hlFromIsotope(isotope);
1027 if(verbose) printf("half-life := %g min\n", halflife);
1028 }
1029 }
1030
1031 /* Read study number */
1032 strcpy(tmp, "Run number"); ii=iftGet(&ift, tmp, 0);
1033 if(ii>=0) {
1034#if(1)
1035 studynr_from_fname2(ift.item[ii].value, studynr, 0);
1036#else
1037 int len, i, j;
1038 strncpy(studynr, ift.item[ii].value, MAX_STUDYNR_LEN);
1039 /* Remove possible extra tail */
1040 len=strlen(studynr);
1041 for(i=0; i<len; i++) if(!isalnum((int)studynr[i])) {strcpy(studynr, ""); len=0;}
1042 for(i=0; i<len; i++) if(!isalpha((int)studynr[i])) break;
1043 if(i<1 || i>5) {strcpy(studynr, ""); len=0;}
1044 for(j=0; (i+j)<len; j++) if(!isdigit((int)studynr[i+j])) {studynr[i+j]=(char)0; break;}
1045 if(j<1 || j>5) {strcpy(studynr, ""); len=0;}
1046#endif
1047 if(verbose>0) printf("studynr := %s\n", studynr);
1048 }
1049
1050
1051 /* Find the first line which starts with date and time, that is, */
1052 /* the first count data line */
1053 for(ii=0; ii<ift.keyNr; ii++) if(!ift.item[ii].key[0]) {
1054 if(isdatetime(ift.item[ii].value, NULL)!=0) continue;
1055 if(verbose>7) printf("%s\n", ift.item[ii].value);
1056 break;
1057 }
1058 /* Get start time from it */
1059 /*
1060 t=0; if(gm_timez) blood->date=*gmtime(&t); else blood->date=*localtime(&t);
1061 */
1062 //memset(&blood->date,0,sizeof(struct tm));
1063 //find_date(ift.item[ii].value, blood);
1064 ret=get_datetime(ift.item[ii].value, &(blood->date), verbose-4);
1065 if(ret!=0 && verbose>1) {
1066 fprintf(stderr, "Error %d in reading date and time in %s\n", ret, inputfile);
1067 }
1068
1069 /* Read the count data lines */
1070 if(verbose>1) printf("reading count data\n");
1071 /* Initiate the list */
1072 points=malloc(sizeof(struct DataList));
1073 points->prev=NULL; points->next=NULL;
1074 bdata=&points->allogg;
1075 memset(bdata,0,sizeof(struct BDataA));
1076 blood->data=points;
1077 n=0;
1078 for(; ii<ift.keyNr; ii++) {
1079 /* Stop if item key is found */
1080 if(ift.item[ii].key[0]) break;
1081 /* Ignore comment lines */
1082 if(strncmp(ift.item[ii].value, "//", 2)==0) continue;
1083 if(strncmp(ift.item[ii].value, "#", 1)==0) continue;
1084 if(strncmp(ift.item[ii].value, ";", 1)==0) continue;
1085 /* Stop if line does not start with valid date and time */
1086 if(isdatetime(ift.item[ii].value, NULL)!=0) break;
1087 /* Read time after start, singles and coincidents */
1088 ret=sscanf(ift.item[ii].value+19, "%lf %d %d", &tas, &singles, &coincidents);
1089 if(ret!=3) continue;
1090 if(verbose>10 && n<4) printf(" %f %d\n", tas, coincidents);
1091 /* Increase the list */
1092 if(n>0) {
1093 points->next=malloc(sizeof(struct DataList));
1094 points->next->prev=points;
1095 points=points->next;
1096 points->next=NULL;
1097 bdata=&points->allogg;
1098 memset(bdata,0,sizeof(struct BDataA));
1099 }
1100 /* Copy to list */
1101 bdata->time_since_start=tas;
1102 bdata->data[0]=coincidents;
1103 bdata->data[1]=0;
1104 n++;
1105 }
1106
1107 iftEmpty(&ift);
1108 if(n<1) {if(msg!=NULL) strcpy(msg, "no valid count data"); return(9);}
1109 if(msg!=NULL) strcpy(msg, "ok");
1110 return 0;
1111}
1112/*****************************************************************************/
1113
1114/*****************************************************************************/
1117void correct_scanditronics(
1119 struct Blood *blood,
1121 int verbose
1122) {
1123 struct DataList *data;
1124 struct tm date; //*date;
1125 time_t tim;
1126
1127 if(verbose>0) printf("%s()\n", __func__);
1128
1129 data=blood->data;
1130 tim=data->scanditronics.time_of_day;
1131 if(verbose>2) {
1132 char tmp[32];
1133 if(!ctime_r_int(&tim, tmp)) strcpy(tmp, "1900-01-01 00:00:00");
1134 printf(" %s\n", tmp);
1135 }
1136 if(verbose>3) {
1137 char buf[32];
1138 strftime(buf, 32, "%Y-%m-%d %H:%M:%S", &blood->date);
1139 printf(" blood->date: %s\n", buf);
1140 }
1141 /* Set time if it was not properly set in the comments */
1142 if(pump==2 || (blood->date.tm_hour==0 && blood->date.tm_min==0 && blood->date.tm_sec==0)) {
1143 //if(gm_timez) date=gmtime(&tim); else date=localtime(&tim);
1144 if(gmtime_r(&tim, &date)!=NULL) {
1145 blood->date.tm_hour=date.tm_hour;
1146 blood->date.tm_min=date.tm_min;
1147 blood->date.tm_sec=date.tm_sec;
1148 } else {
1149 fprintf(stderr, "Warning: invalid date in file.\n");
1150 }
1151 }
1152 while(data) {
1153 struct BDataS *d=&data->scanditronics;
1154 d->results.t=d->time_since_start+0.5*d->meas_interval;
1155 d->results.ch1=(double)d->pair1_coincid;
1156 d->results.ch2=(double)d->pair2_coincid;
1157 if(d->meas_interval>0) {
1158 d->results.ch1/=(double)d->meas_interval;
1159 d->results.ch2/=(double)d->meas_interval;
1160 }
1161 data=data->next;
1162 }
1163}
1164/*****************************************************************************/
1165
1166/*****************************************************************************/
1170int correct_allogg(
1172 struct Blood *blood
1173) {
1174 struct DataList *data;
1175 double meas_interval=0.0;
1176
1177 data=blood->data;
1178 if(data->next)
1179 meas_interval=data->next->allogg.time_since_start-data->allogg.time_since_start;
1180 else {
1181 printf("Error: Only one blood data line found, cannot calculate frame time.\n");
1182 return 1;
1183 }
1184 while(data) {
1185 struct BDataA *d=&data->allogg;
1186 d->meas_interval=meas_interval;
1187 d->results.t=d->time_since_start-0.5*meas_interval; /* '+'->'-' by VO */
1188#if 0
1189 d->results.ch1=(d->data[0]-d->data[1])/d->meas_interval;
1190 d->results.ch2=(d->data[0]-d->data[1])/d->meas_interval;
1191#else /* Use only second discriminator */
1192 if(meas_interval == 0) {
1193 printf("Error: zero measuring interval found, would lead to divide by zero\n");
1194 return 1;
1195 }
1196 d->results.ch1=d->data[1]/d->meas_interval;
1197 d->results.ch2=d->data[1]/d->meas_interval;
1198#endif
1199 data=data->next;
1200 }
1201 return 0;
1202}
1203/*****************************************************************************/
1204
1205/*****************************************************************************/
1209int correct_allogg2(
1211 struct Blood *blood,
1213 int verbose
1214) {
1215 if(verbose>0) printf("%s()\n", __func__);
1216
1217 struct DataList *data;
1218 double meas_interval=0.0;
1219
1220 data=blood->data;
1221 if(data->next) {
1222 meas_interval=data->next->allogg.time_since_start-data->allogg.time_since_start;
1223 if(verbose>1) {
1224 printf("time_since_start := %g\n", data->allogg.time_since_start);
1225 printf("time_since_start_next := %g\n", data->next->allogg.time_since_start);
1226 printf("data0 := %d\n", data->allogg.data[0]);
1227 printf("data0 next := %d\n", data->next->allogg.data[0]);
1228 }
1229 } else {
1230 printf("Error: Only one blood data line found, cannot calculate frame time.\n");
1231 return 1;
1232 }
1233 while(data) {
1234 struct BDataA *d=&data->allogg;
1235 d->meas_interval=meas_interval;
1236 if(meas_interval == 0) {
1237 printf("Error: zero measuring interval found, would lead to divide by zero\n");
1238 if(verbose>1) {
1239 printf("time_since_start := %g\n", data->allogg.time_since_start);
1240 printf("time_since_start_next := %g\n", data->next->allogg.time_since_start);
1241 }
1242 return 1;
1243 }
1244 d->results.t=d->time_since_start+0.5*meas_interval;
1245 d->results.ch1=d->data[0]/d->meas_interval;
1246 d->results.ch2=d->data[0]/d->meas_interval;
1247 data=data->next;
1248 }
1249 return 0;
1250}
1251/*****************************************************************************/
1252
1253/*****************************************************************************/
1255void subtract_background(
1257 struct Blood *blood
1258) {
1259 struct DataList *data=blood->data;
1260 while(data) {
1261 struct BDataResults *res=&data->results;
1262
1263 res->ch1 -= blood->background;
1264 res->ch2 -= blood->background;
1265 data=data->next;
1266 }
1267}
1268/*****************************************************************************/
1269
1270/*****************************************************************************/
1284int get_calfactors(
1285 const char *file,
1286 time_t bloodt,
1287 double *wcf,
1288 double *pumpf,
1289 int pump,
1290 char *isotope,
1291 char *caldate,
1292 int verbose
1293) {
1294 if(verbose>0) printf("%s(%s, ..., %d, %s, ...)\n", __func__, file, pump, isotope);
1295
1296 const time_t too_old = 60*60*24*31*6; /* 6 months */
1297 struct tm calibrdate; //*calibrdate;
1298 char line[512],*str;
1299 int i,yyyy,mm,dd;
1300 time_t calibrt, last_date=0;
1301 char sdate[25];
1302 FILE *fp;
1303
1304 strcpy(sdate, "");
1305 if(pump<1) {
1306 fprintf(stderr,"Warning: pump number %d too low, set to 1\n",pump);
1307 pump=1;
1308 } else if(pump>MAX_PUMPS) {
1309 fprintf(stderr,"Warning: pump number %d too high, set to %d\n", pump, MAX_PUMPS);
1310 pump=MAX_PUMPS;
1311 }
1312
1313 fp=fopen(file,"r");
1314 if(!fp) {
1315 fprintf(stderr,"Error: cannot open file %s\n",file);
1316 perror("fopen");
1317 return 1;
1318 }
1319 while(fgets(line,sizeof(line),fp)) {
1320 str=line;
1321 while(*str && isspace((unsigned char)*str)) str++;
1322 if(*str=='#' || *str=='\0') continue;
1323
1324 double p[MAX_PUMPS]; /* Pumps */
1325 double w; /* Well-counter */
1326 i=sscanf(str,"%d-%d-%d %lf %lf %lf %lf %lf",
1327 &yyyy, &mm, &dd, &p[0], &p[1], &p[2], &p[3], &w);
1328 if(i<5) {
1329 printf("Error: Malformed line in calibration file, cannot continue\n");
1330 fclose(fp); return 1;
1331 }
1332 if(pump>i-4) {
1333 printf("Error: no calibration for this blood sampler in %s\n", file);
1334 fclose(fp); return 2;
1335 }
1336 if(i==5) {w=p[1];} else if(i==6) {w=p[2];} else if(i==7) {w=p[3];}
1337
1338 calibrdate.tm_mday=dd; calibrdate.tm_mon=mm-1;
1339 calibrdate.tm_year=yyyy-1900;
1340 calibrdate.tm_hour=calibrdate.tm_min=calibrdate.tm_sec=0;
1341 calibrdate.tm_isdst=-1;
1342 calibrt=timegm(&calibrdate);
1343 if(calibrt==-1) calibrt=0;
1344 if(calibrt>=last_date) last_date=calibrt;
1345/*
1346 calibrt=time(NULL); calibrdate=localtime(&calibrt);
1347 calibrdate->tm_mday=dd; calibrdate->tm_mon=mm-1;
1348 calibrdate->tm_year=yyyy-1900;
1349 calibrdate->tm_isdst=-1;
1350 calibrt=mktime(calibrdate);
1351 if(calibrt>last_date) last_date=calibrt;
1352*/
1353
1354 /* Check that calibration date is not later than measurement date */
1355 if(calibrt>bloodt) break;
1356 //if(calibrt!=(time_t)-1 && difftime(bloodt, calibrt)<0.0) break;
1357 strftime(sdate, 24, "%Y-%m-%d", &calibrdate);
1358
1359 /* It was not, so set calibration factors and try the next line */
1360 *pumpf=p[pump-1];
1361 *wcf=w;
1362 }
1363
1364 if(verbose>1) {
1365 printf(" pump_factor: %g\n", *pumpf);
1366 printf(" wc_factor: %g\n", *wcf);
1367 }
1368
1369 /* Correct for branching ratio */
1370 if(strcasecmp(isotope, "C-11")==0) *wcf/=BRANCHING_C;
1371 else if(strcasecmp(isotope, "F-18")==0) *wcf/=BRANCHING_F;
1372 else if(strcasecmp(isotope, "O-15")==0) *wcf/=BRANCHING_O;
1373 else if(strcasecmp(isotope, "GE-68")==0) *wcf/=BRANCHING_Ge;
1374 else if(strcasecmp(isotope, "GA-68")==0) *wcf/=BRANCHING_Ga;
1375 else if(strcasecmp(isotope, "Cu-64")==0) *wcf/=BRANCHING_Cu64;
1376 else fprintf(stderr, "Warning: branching factor not included in calibration.\n");
1377
1378 if(verbose>1) {
1379 printf(" wc_factor_including_branching_correction: %g\n", *wcf);
1380 }
1381
1382 fclose(fp);
1383 /* Warn user if latest calibration date is older than 6 months */
1384 if(bloodt>last_date && bloodt-last_date > too_old) {
1385 fprintf(stderr, "Warning: check that %s contains the latest calibration coefficients.\n", file);
1386 }
1387
1388 /* Set return value for calibration date */
1389 if(caldate!=NULL) strcpy(caldate, sdate);
1390 return 0;
1391}
1392/*****************************************************************************/
1393
1394/*****************************************************************************/
int backupExistingFile(char *filename, char *backup_ext, char *status)
Definition backup.c:14
int get_datetime(char *str, struct tm *date, int verbose)
Definition datetime.c:322
char * ctime_r_int(const time_t *t, char *buf)
Convert calendard time t into a null-terminated string of the form YYYY-MM-DD hh:mm:ss,...
Definition datetime.c:110
int isdate2(char *str, char *intdate)
Definition datetime.c:168
time_t timegm(struct tm *tm)
Inverse of gmtime, converting struct tm to time_t.
Definition datetime.c:69
int isdate(char *str)
Definition datetime.c:146
int isdatetime(char *str, char *intdate)
Definition datetime.c:280
struct tm * gmtime_r(const time_t *t, struct tm *tm)
Convert time_t to GMT struct tm.
Definition datetime.c:22
int isdate3(char *str, char *intdate)
Definition datetime.c:199
double atof_dpi(char *str)
Definition decpoint.c:59
int doubleMatch(const double v1, const double v2, const double lim)
Definition doubleutil.c:28
double hl2lambda(double halflife)
Definition halflife.c:84
char * hlIsotopeCode(int isotope)
Definition halflife.c:36
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
int hlIsotopeFromHalflife(double halflife)
Definition halflife.c:195
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 iftWrite(IFT *ift, char *filename, int verbose)
Definition iftfile.c:282
int iftFindNthKey(IFT *ift, char *str, int n, int verbose)
Definition iftsrch.c:84
int iftGet(IFT *ift, char *key, int verbose)
Definition iftsrch.c:15
Header file for libtpcmisc.
#define BRANCHING_O
Definition libtpcmisc.h:26
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
int studynr_from_fname2(char *fname, char *studynr, int force)
Definition studynr.c:67
int studynr_validity_check2(char *studynr, int zero_ok)
Definition studynr.c:166
#define BRANCHING_C
Definition libtpcmisc.h:28
#define BRANCHING_F
Definition libtpcmisc.h:34
#define BRANCHING_Cu64
Definition libtpcmisc.h:30
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition strext.c:245
#define BRANCHING_Ge
Definition libtpcmisc.h:36
#define MAX_STUDYNR_LEN
Definition libtpcmisc.h:163
char * strcasestr(const char *haystack, const char *needle)
Definition strext.c:279
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
#define BRANCHING_Ga
Definition libtpcmisc.h:38
int keyNr
Definition libtpcmisc.h:270
const char * status
Definition libtpcmisc.h:277
IFT_KEY_AND_VALUE * item
Definition libtpcmisc.h:279