8#include "tpcclibConfig.h"
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.",
27 "Usage: @P [Options] ABSS_file [BTAC_file]",
31 " Calibration coefficients for ABSS and well-counter should be specified",
32 " with calibration file (2), given with option -c.",
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, ...",
38 " Blood data is corrected for radioactive decay (on, default), or not",
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.",
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.",
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.",
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.",
76 " @P -i=O-15 -c=S:/Lab/plasma/bsampler_calibration/pump_cal.dat sr452_blo.bld",
83 "1. https://www.turkupetcentre.net/petanalysis/input_abss.html",
84 "2. https://www.turkupetcentre.net/petanalysis/input_abss_calibration.html",
86 "See also: absszero, absstime, abssexam, abssfch, taccat, disp4dft, fitdelay",
88 "Keywords: blood, input, ABSS, calibration",
95#define BLOOD_DENSITY 1.06
96typedef enum {SCANDITRONICS,ALLOGG,ALLOGG2} Format;
97static int both_cols=0;
100char isotope[10]=
"UNKNOWN";
111 struct BDataResults results;
113 double time_since_start;
114 double meas_interval;
126 struct BDataResults results;
127 double time_since_start;
128 double meas_interval;
134 struct BDataS scanditronics;
135 struct BDataA allogg;
136 struct BDataResults results;
138 struct DataList *prev, *next;
151 struct DataList *data;
155int read_scanditronics_data(
156 const char *inputfile,
struct Blood *blood,
int verbose);
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);
186int main(
int argc,
char *argv[])
188 int ai, help=0, version=0, verbose=1;
190 double startTime=0.0, density=1.0, wc_factor=-1.0, pump_factor=-1.0;
192 char pumpfile[FILENAME_MAX], calfile[FILENAME_MAX], outfile[FILENAME_MAX];
193 char tmp[FILENAME_MAX];
195 Format format=SCANDITRONICS;
196 struct DataList *ptr;
204 int zero1=1, zero2=1;
205 time_t t_injection, t_samp;
206 struct tm tm_injection, tm_samp;
212 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
213 pumpfile[0]=calfile[0]=outfile[0]=(char)0;
217 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
219 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
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) {
224 strlcpy(outfile, cptr+2, FILENAME_MAX);
continue;
225 }
else if(strncasecmp(cptr,
"I=", 2)==0 && strlen(cptr)>2) {
231 printf(
"Error: Incorrect isotope code '%s'\n", cptr+2);
233 }
else if(strncasecmp(cptr,
"DECAY=", 6)==0 && strlen(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) {
249 }
else if(strncasecmp(cptr,
"RIGHT", 1)==0) {
251 }
else if(strcasecmp(cptr,
"BOTH")==0) {
252 both_cols=1;
continue;
253 }
else if(strncasecmp(cptr,
"PUMP=", 5)==0 && strlen(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;}
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;
266 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
271 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
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);}
282 fprintf(stderr,
"Error: missing ABSS file name.\n");
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);
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;}
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");
315 printf(
"pump := %d\n", pump);
316 printf(
"format := %d\n", format);
323 if(verbose>0) printf(
"reading %s\n", pumpfile);
326 if(read_scanditronics_data(pumpfile, &blood, verbose-2))
return 2;
329 if(read_allogg_data(pumpfile, &blood, verbose-2))
return 2;
332 if(read_allogg2_data(pumpfile, &blood, verbose-2, tmp)) {
333 fprintf(stderr,
"Error in reading %s: %s.\n", pumpfile, tmp);
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");
346 if(calfile[0] && strcasecmp(isotope,
"UNKNOWN")==0) {
347 fprintf(stderr,
"Error: isotope must be specified for calibration.\n");
352 if(verbose>0) printf(
"processing the data\n");
355 correct_scanditronics(&blood, verbose-2);
358 if(correct_allogg(&blood) == 1)
return 3;
361 if(correct_allogg2(&blood, verbose-2) == 1)
return 3;
366 if(verbose>1) printf(
"verifying that data is not all zeroes\n");
368 if(format==SCANDITRONICS) {
371 if(fabs(ptr->results.ch1) > 1.0e-10) zero1=0;
372 if(fabs(ptr->results.ch2) > 1.0e-10) zero2=0;
376 fprintf(stderr,
"Error: All values from channel 1 are zeros. Contact the physicist!\n");
377 if(column!=2)
return 4;
380 fprintf(stderr,
"Error: All values from channel 2 are zeros. Contact the physicist!\n");
381 if(column!=1)
return 4;
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) {
392 fprintf(stderr,
"Error: %s does not contain background.\n", pumpfile);
395 fprintf(stderr,
"Warning: %s does not contain background.\n", pumpfile);
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");
413 if(verbose>0) printf(
"calibrating\n");
415 if(get_calfactors(calfile,
timegm(&blood.date), &wc_factor, &pump_factor,
416 pump, isotope, caldate, verbose-1))
421 printf(
" PC := %g\n WC/BR := %g\n calibration_date := %s\n",
422 pump_factor, wc_factor, caldate);
424 ptr->results.ch1*=wc_factor*pump_factor;
425 ptr->results.ch2*=wc_factor*pump_factor;
428 }
else if(verbose>=0) {
429 printf(
"Warning: no calibration file was entered; data is not calibrated.\n");
437 if(verbose>1) printf(
"correcting the start time\n");
440 ptr->results.t+=startTime;
441 if(format==SCANDITRONICS)
442 ptr->scanditronics.time_since_start+=startTime;
444 ptr->allogg.time_since_start+=startTime;
445 if(ptr->results.t<0.0) {
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");
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;
465 fprintf(stderr,
"Warning: invalid sample time.\n");
467 fprintf(stdout,
"Time point of the first sample is: %s\n", buf);
473 if(decay_correct!=0) {
478 if(verbose>=0) printf(
"decay correction with half-life %.2f min.\n", halflife);
481 if(format==SCANDITRONICS) {
482 if(ptr->scanditronics.time_since_start>=0.0) {
484 ptr->scanditronics.time_since_start, ptr->scanditronics.meas_interval);
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);
492 ptr->results.ch1*=dc;
493 ptr->results.ch2*=dc;
503 ptr->results.t-=startTime;
512 printf(
"kBq/mL to kBq/g correction with blood density of %.2f g/mL.\n", density);
515 ptr->results.ch1/=density;
516 ptr->results.ch2/=density;
522 ptr=blood.data; sum1=sum2=0.0;
524 if(format==ALLOGG || format==ALLOGG2) {
525 if(ptr->results.ch1 < -2.0)
526 printf(
"Warning: channel below zero:%lf\n", ptr->results.ch1);
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);
533 sum1+=ptr->results.ch1;
534 sum2+=ptr->results.ch2;
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");
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);
555 fprintf(stderr,
"Error: %s\n", tmp);
558 if(verbose>=0) printf(
"writing output in file %s\n", outfile);
559 fp=fopen(outfile,
"w");
561 fprintf(stderr,
"Error: cannot write %s\n", outfile);
569 if(verbose>2) printf(
"writing 'header'\n");
572 if(
gmtime_r(&t_injection, &tm_samp)==NULL) {
573 fprintf(stderr,
"Warning: invalid measurement start time.\n");
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;
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);
588 fprintf(fp,
"# detector := %d\n", pump);
590 if(timeInMinutes==1) fprintf(fp,
"# time_unit := min\n");
591 else fprintf(fp,
"# time_unit := sec\n");
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);
601 fprintf(fp,
"# calibrated := no\n");
602 fprintf(fp,
"# unit := cps\n");
605 fprintf(fp,
"# isotope := %s\n", isotope);
607 if(decay_correct!=0) {
608 fprintf(fp,
"# decay_correction := yes\n");
609 fprintf(fp,
"# halflife := %g [min]\n", halflife);
611 fprintf(fp,
"# decay_correction := no\n");
614 r=3600*blood.date.tm_hour + 60*blood.date.tm_min + blood.date.tm_sec;
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);
620 fprintf(fp,
"# injection_time := %g [sec]\n", startTime);
622 t_injection=
timegm(&blood.date);
623 if(t_injection==-1) {
624 fprintf(stderr,
"Error: invalid injection time.\n");
625 fclose(fp);
return(12);
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);
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);
638 if(blood.background>0.0) {
640 fprintf(fp,
"# background_date := %s\n", blood.bgdate);
641 fprintf(fp,
"# background := %g [cps]\n", blood.background);
645 fprintf(fp,
"# studynr := %s\n", studynr);
651 if(verbose>2) printf(
"Writing data lines\n");
655 if(ptr->results.t<0.0) {ptr=ptr->next;
continue;}
657 if(timeInMinutes) fprintf(fp,
"%12.4f", ptr->results.t/60.0);
658 else fprintf(fp,
"%12.3f", ptr->results.t);
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);
667 fprintf(fp,
" %12.3f\n", 0.5*(ptr->results.ch1+ptr->results.ch2));
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);
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;
703 printf(
"find_date(): %04d-%02d-%02d %02d:%02d:%02d\n", yyyy, MM, dd, hh, mm, ss);
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");
759 while(isspace((
int)*str) || *str==
'#') str++;
761 if(strncasecmp(str,
"Background:", 11)==0) {
763 if(sscanf(str,
"%f", &blood->background) == 1) {
766 }
else if(strncasecmp(str,
"Background on", 13)==0) {
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);
771 }
else if(sscanf(str,
"%10s: %f", blood->bgdate, &blood->background)==2) {
784int read_scanditronics_data(
786 const char *inputfile,
793 struct DataList *points;
794 struct BDataS *bdata;
801 if(verbose>0) printf(
"%s(%s)\n", __func__, inputfile);
802 blood->bgdate[0]=
'\0';
803 blood->background = 0.0;
805 fp=fopen(inputfile,
"r");
807 fprintf(stderr,
"Error: cannot open \"%s\".\n",inputfile);
814 points=malloc(
sizeof(
struct DataList));
815 points->prev=NULL; points->next=NULL;
816 bdata=&points->scanditronics;
817 memset(bdata,0,
sizeof(
struct BDataS));
820 while(fgets(line,
sizeof(line),fp)) {
822 while(*str && isspace((
unsigned char)*str)) str++;
824 if(datenotfound) datenotfound=find_date(str, blood, verbose);
825 if(hlnotfound) hlnotfound=find_halflife(str, verbose);
829 fprintf(stderr,
"Error: valid measurement date was not found in header.\n");
830 fclose(fp);
return 5;
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,
839 points->next=malloc(
sizeof(
struct DataList));
840 points->next->prev=points;
843 bdata=&points->scanditronics;
844 memset(bdata,0,
sizeof(
struct BDataS));
846 if(n>0 && n!=7) fprintf(stderr,
"Warning: malformed line!:{%s}\n",str);
851 if(bdata->time_of_day==0 && bdata->meas_interval==0) {
853 struct DataList *prev=points->prev;
874 const char *inputfile,
881 struct DataList *points;
882 struct BDataA *bdata;
883 int datenotfound=1, bgnotfound=1, timenotfound=1;
888 if(verbose>0) printf(
"%s(%s)\n", __func__, inputfile);
890 blood->bgdate[0] =
'\0';
891 blood->background = -1.0E20;
893 fp=fopen(inputfile,
"r");
895 fprintf(stderr,
"Error: cannot open \"%s\".\n",inputfile);
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));
909 while(fgets(line,
sizeof(line),fp)) {
911 while(isspace((
unsigned char)*str)) str++;
913 if(datenotfound) datenotfound=find_date(str, blood, verbose-2);
914 if(bgnotfound) bgnotfound=find_background(str, blood);
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;
925 fprintf(stderr,
"Error: malformed line %sCorrect syntax is hhmmss.\n",str);
928 points->next=malloc(
sizeof(
struct DataList));
929 points->next->prev=points;
932 bdata=&points->allogg;
933 memset(bdata,0,
sizeof(
struct BDataA));
937 if(bdata->time_since_start==0) {
938 struct DataList *prev=points->prev;
956int read_allogg2_data(
968 int singles, coincidents;
972 struct DataList *points;
973 struct BDataA *bdata;
976 if(verbose>0) printf(
"%s(%s)\n", __func__, inputfile);
978 if(inputfile==NULL || blood==NULL || strlen(inputfile)<1) {
979 if(msg!=NULL) strcpy(msg,
"program error");
982 blood->bgdate[0] =
'\0';
983 blood->background = -1.0E20;
987 if(ret) {
if(msg!=NULL) strcpy(msg, ift.
status);
iftEmpty(&ift);
return(2);}
988 if(verbose>=12) {
iftWrite(&ift,
"stdout", 0); fflush(stdout);}
991 strcpy(tmp,
"System ID"); ii=
iftGet(&ift, tmp, 0);
993 if(msg!=NULL) strcpy(msg,
"wrong format");
996 if(strcmp(ift.
item[ii].
value,
"ABSS09282")!=0) {
997 if(msg!=NULL) strcpy(msg,
"wrong sampler ID");
1002 strcpy(tmp,
"//Average background counts"); ii=
iftFindNthKey(&ift, tmp, 1, 0);
1004 if(verbose>3) printf(
"key := '%s'\n", ift.
item[ii].
key);
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");
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");
1019 strcpy(tmp,
"HalfTime"); ii=
iftGet(&ift, tmp, 0);
1024 if(strcmp(isotope,
"UNKNOWN")==0) {
1027 if(verbose) printf(
"half-life := %g min\n", halflife);
1032 strcpy(tmp,
"Run number"); ii=
iftGet(&ift, tmp, 0);
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;}
1047 if(verbose>0) printf(
"studynr := %s\n", studynr);
1053 for(ii=0; ii<ift.
keyNr; ii++)
if(!ift.
item[ii].
key[0]) {
1055 if(verbose>7) printf(
"%s\n", ift.
item[ii].
value);
1065 if(ret!=0 && verbose>1) {
1066 fprintf(stderr,
"Error %d in reading date and time in %s\n", ret, inputfile);
1070 if(verbose>1) printf(
"reading count data\n");
1072 points=malloc(
sizeof(
struct DataList));
1073 points->prev=NULL; points->next=NULL;
1074 bdata=&points->allogg;
1075 memset(bdata,0,
sizeof(
struct BDataA));
1078 for(; ii<ift.
keyNr; ii++) {
1080 if(ift.
item[ii].
key[0])
break;
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;
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);
1093 points->next=malloc(
sizeof(
struct DataList));
1094 points->next->prev=points;
1095 points=points->next;
1097 bdata=&points->allogg;
1098 memset(bdata,0,
sizeof(
struct BDataA));
1101 bdata->time_since_start=tas;
1102 bdata->data[0]=coincidents;
1108 if(n<1) {
if(msg!=NULL) strcpy(msg,
"no valid count data");
return(9);}
1109 if(msg!=NULL) strcpy(msg,
"ok");
1117void correct_scanditronics(
1119 struct Blood *blood,
1123 struct DataList *data;
1127 if(verbose>0) printf(
"%s()\n", __func__);
1130 tim=data->scanditronics.time_of_day;
1133 if(!
ctime_r_int(&tim, tmp)) strcpy(tmp,
"1900-01-01 00:00:00");
1134 printf(
" %s\n", tmp);
1138 strftime(buf, 32,
"%Y-%m-%d %H:%M:%S", &blood->date);
1139 printf(
" blood->date: %s\n", buf);
1142 if(pump==2 || (blood->date.tm_hour==0 && blood->date.tm_min==0 && blood->date.tm_sec==0)) {
1145 blood->date.tm_hour=date.tm_hour;
1146 blood->date.tm_min=date.tm_min;
1147 blood->date.tm_sec=date.tm_sec;
1149 fprintf(stderr,
"Warning: invalid date in file.\n");
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;
1174 struct DataList *data;
1175 double meas_interval=0.0;
1179 meas_interval=data->next->allogg.time_since_start-data->allogg.time_since_start;
1181 printf(
"Error: Only one blood data line found, cannot calculate frame time.\n");
1185 struct BDataA *d=&data->allogg;
1186 d->meas_interval=meas_interval;
1187 d->results.t=d->time_since_start-0.5*meas_interval;
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;
1192 if(meas_interval == 0) {
1193 printf(
"Error: zero measuring interval found, would lead to divide by zero\n");
1196 d->results.ch1=d->data[1]/d->meas_interval;
1197 d->results.ch2=d->data[1]/d->meas_interval;
1211 struct Blood *blood,
1215 if(verbose>0) printf(
"%s()\n", __func__);
1217 struct DataList *data;
1218 double meas_interval=0.0;
1222 meas_interval=data->next->allogg.time_since_start-data->allogg.time_since_start;
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]);
1230 printf(
"Error: Only one blood data line found, cannot calculate frame time.\n");
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");
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);
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;
1255void subtract_background(
1259 struct DataList *data=blood->data;
1261 struct BDataResults *res=&data->results;
1263 res->ch1 -= blood->background;
1264 res->ch2 -= blood->background;
1294 if(verbose>0) printf(
"%s(%s, ..., %d, %s, ...)\n", __func__, file, pump, isotope);
1296 const time_t too_old = 60*60*24*31*6;
1297 struct tm calibrdate;
1298 char line[512],*str;
1300 time_t calibrt, last_date=0;
1306 fprintf(stderr,
"Warning: pump number %d too low, set to 1\n",pump);
1308 }
else if(pump>MAX_PUMPS) {
1309 fprintf(stderr,
"Warning: pump number %d too high, set to %d\n", pump, MAX_PUMPS);
1315 fprintf(stderr,
"Error: cannot open file %s\n",file);
1319 while(fgets(line,
sizeof(line),fp)) {
1321 while(*str && isspace((
unsigned char)*str)) str++;
1322 if(*str==
'#' || *str==
'\0')
continue;
1324 double p[MAX_PUMPS];
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);
1329 printf(
"Error: Malformed line in calibration file, cannot continue\n");
1330 fclose(fp);
return 1;
1333 printf(
"Error: no calibration for this blood sampler in %s\n", file);
1334 fclose(fp);
return 2;
1336 if(i==5) {w=p[1];}
else if(i==6) {w=p[2];}
else if(i==7) {w=p[3];}
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;
1355 if(calibrt>bloodt)
break;
1357 strftime(sdate, 24,
"%Y-%m-%d", &calibrdate);
1365 printf(
" pump_factor: %g\n", *pumpf);
1366 printf(
" wc_factor: %g\n", *wcf);
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;
1376 else fprintf(stderr,
"Warning: branching factor not included in calibration.\n");
1379 printf(
" wc_factor_including_branching_correction: %g\n", *wcf);
1384 if(bloodt>last_date && bloodt-last_date > too_old) {
1385 fprintf(stderr,
"Warning: check that %s contains the latest calibration coefficients.\n", file);
1389 if(caldate!=NULL) strcpy(caldate, sdate);
int backupExistingFile(char *filename, char *backup_ext, char *status)
int get_datetime(char *str, struct tm *date, int verbose)
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,...
int isdate2(char *str, char *intdate)
time_t timegm(struct tm *tm)
Inverse of gmtime, converting struct tm to time_t.
int isdatetime(char *str, char *intdate)
struct tm * gmtime_r(const time_t *t, struct tm *tm)
Convert time_t to GMT struct tm.
int isdate3(char *str, char *intdate)
double atof_dpi(char *str)
int doubleMatch(const double v1, const double v2, const double lim)
double hl2lambda(double halflife)
char * hlIsotopeCode(int isotope)
double hlLambda2factor(double lambda, double frametime, double framedur)
char * hlCorrectIsotopeCode(char *isocode)
double hlFromIsotope(char *isocode)
int hlIsotopeFromHalflife(double halflife)
int iftRead(IFT *ift, char *filename, int is_key_required, int verbose)
int iftWrite(IFT *ift, char *filename, int verbose)
int iftFindNthKey(IFT *ift, char *str, int n, int verbose)
int iftGet(IFT *ift, char *key, int verbose)
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
int studynr_from_fname2(char *fname, char *studynr, int force)
int studynr_validity_check2(char *studynr, int zero_ok)
size_t strlcpy(char *dst, const char *src, size_t dstsize)
char * strcasestr(const char *haystack, const char *needle)
int tpcHtmlUsage(const char *program, char *text[], const char *path)
void tpcPrintBuild(const char *program, FILE *fp)
void tpcPrintUsage(const char *program, char *text[], FILE *fp)