/**********************************************************/ /* */ /* Modified by Ryan From */ /* */ /* PXI SCAN CODE -- J.M. Allmond (ORNL) -- July 2016 */ /* */ /**********************************************************/ #include #include #include #include #include #include "TFile.h" #include "TTree.h" #include "TMath.h" #include "TBenchmark.h" #define RAND ((float) rand() / ((unsigned int) RAND_MAX + 1)) // random number in interval (0,1) #define MAX_CRATES 2 #define MAX_BOARDS_PER_CRATE 13 #define MAX_CHANNELS_PER_BOARD 16 #define BOARD_START 2 #define MAX_ID MAX_CRATES*MAX_BOARDS_PER_CRATE*MAX_CHANNELS_PER_BOARD #define HEADER_LENGTH 4 //unit = words with 4 bytes per word #define MAX_SUB_LENGTH 2016 //unit = words with 4 bytes per word ; 2004 --> 40 micro-second trace + 4 word header #define RAWE_REBIN_FACTOR 2.0 // Rebin 32k pixie16 spectra to something smaller to fit better into 8k. #include "mapping.h" ///////////////////// // RAW EVENT TYPES // ///////////////////// struct subevent { int chn; int sln; int crn; int id; int hlen; int elen; int trlen; //number of samples int trwlen; //number of words (two samples per word) int fcode; //pileup flag long long int time; int ctime; int ctimef; int energy; int extra; short tr[4096]; int esum[4]; int qsum[8]; }; struct subevent subevt[MAX_ID]={0}; int sevtmult=0; unsigned long long int sevtcount=0; unsigned long long int pileupcount=0; unsigned long long int evtcount=0; int mult[1][4096]={0}; int tdifid[MAX_ID][8192]={0}; /**** int overwrite = 1; /////////////////////// // Write 2-byte data // /////////////////////// void write_data2(char *filename, short *data, int xdim, int ydim, int overwrite) { //2byte per channel Write / Add to previous FILE *FP; int i; short *previous; if(!overwrite) { //allocate memory for 1d-array for reading in rows of 2d Radware matrix if ( ( previous = (short *)malloc(xdim * ydim * sizeof(short)) ) == NULL ) { printf("\nError, memory not allocated.\n"); exit(1); } //open previous spectra file if( (FP=fopen(filename, "r")) != NULL ){ fread(previous, sizeof(short)*xdim*ydim, 1, FP); fclose(FP); //update spectra for (i=0; i root ===\n"); printf("=====================================\n"); //CERN ROOT things TString inFileName = argv[1]; TString outFileName = inFileName; int EVENT_BUILD_TIME = 100; if( argc >= 3 ){ EVENT_BUILD_TIME = atoi(argv[2]); } outFileName.Remove(inFileName.First('.')); outFileName.Append(".root"); printf(" in file : %s \n", inFileName.Data()); printf(" our file : %s \n", outFileName.Data()); printf(" number of detector channal: %d \n", MAX_ID); printf("------------------------ Event building time window : %d tics = %d nsec \n", EVENT_BUILD_TIME, EVENT_BUILD_TIME*10); TFile * outRootFile = new TFile(outFileName, "recreate"); outRootFile->cd(); TTree * tree = new TTree("tree", "tree"); unsigned long long evID = -1; double energy[NCRYSTAL]; unsigned long long etimestamp[NCRYSTAL]; double bgo[NBGO]; double other[NOTHER]; unsigned short pileup[NCRYSTAL]; //const int maxMulti = 40; //double energy[maxMulti]; //unsigned timestamp[maxMulti]; //short detID[maxMulti]; int multi; tree->Branch("evID", &evID, "event_ID/l"); ///tree->Branch("detID", detID, Form("det ID[%d]/B", NCRYSTAL)); tree->Branch("e", energy, Form("energy[%d]/D", NCRYSTAL)); tree->Branch("t", etimestamp, Form("energy_time_stamp[%d]/l", NCRYSTAL)); tree->Branch("p", pileup, Form("pile_up_flag[%d]/s", NCRYSTAL)); tree->Branch("bgo", bgo, Form("BGO_energy[%d]/D", NBGO)); tree->Branch("other", other, Form("other_energy[%d]/D", NOTHER)); tree->Branch("multi", &multi, "multiplicity/I"); //open list-mode data file from PXI digitizer FILE *fpr; long int fprsize,fprpos; if ((fpr = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "Error, cannot open input file %s\n", argv[2]); return 1; } //get file size fseek(fpr, 0L, SEEK_END); fprsize = ftell(fpr); rewind(fpr); TBenchmark gClock; gClock.Reset(); gClock.Start("timer"); ///////////////////// // MAIN WHILE LOOP // ///////////////////// while (1) { //main while loop ///////////////////////////////// // UNPACK DATA AND EVENT BUILD // ///////////////////////////////// //CERN data clear for( int haha = 0; haha < NCRYSTAL; haha++){ energy[haha] = TMath::QuietNaN(); etimestamp[haha] = 0; pileup[haha] = 0; } for( int haha = 0; haha < NBGO; haha++) bgo[haha] = TMath::QuietNaN(); for( int haha = 0; haha < NOTHER; haha++) other[haha] = TMath::QuietNaN(); multi = 0; evID++; etime=-1; tdif=-1; sevtmult=0; //memset(&subevt, 0, sizeof(subevt)); //not needed since everything is redefined (except maybe trace on pileup evts) while (1) { //get subevents and event build for one "event" // memset(&subevt[sevtmult], 0, sizeof(subevt[sevtmult])); //not needed since everything is redefined (except maybe trace on pileup evts) //read 4-byte header if (fread(sub, sizeof(int)*HEADER_LENGTH, 1, fpr) != 1) break; subevt[sevtmult].chn = sub[0] & 0xF; /// channel in digitizer subevt[sevtmult].sln = (sub[0] & 0xF0) >> 4; /// digitizer ID subevt[sevtmult].crn = (sub[0] & 0xF00) >> 8; /// crate subevt[sevtmult].id = subevt[sevtmult].crn*MAX_BOARDS_PER_CRATE*MAX_CHANNELS_PER_BOARD + (subevt[sevtmult].sln-BOARD_START)*MAX_CHANNELS_PER_BOARD + subevt[sevtmult].chn; subevt[sevtmult].hlen = (sub[0] & 0x1F000) >> 12; subevt[sevtmult].elen = (sub[0] & 0x7FFE0000) >> 17; subevt[sevtmult].fcode = (sub[0] & 0x80000000) >> 31; subevt[sevtmult].time = ( (long long int)(sub[2] & 0xFFFF) << 32) + sub[1]; subevt[sevtmult].ctime = (sub[2] & 0x7FFF0000) >> 16; subevt[sevtmult].ctimef = (sub[2] & 0x80000000) >> 31; subevt[sevtmult].energy = (sub[3] & 0xFFFF); subevt[sevtmult].trlen = (sub[3] & 0x7FFF0000) >> 16; subevt[sevtmult].trwlen = subevt[sevtmult].trlen / 2; subevt[sevtmult].extra = (sub[3] & 0x80000000) >> 31; //rebin raw trap energy from 32k to .... tempf = (float)subevt[sevtmult].energy/RAWE_REBIN_FACTOR;// + RAND; subevt[sevtmult].energy = (int)tempf; //check lengths (sometimes all of the bits for trace length are turned on ...) /* if (subevt[sevtmult].elen - subevt[sevtmult].hlen != subevt[sevtmult].trwlen) { printf("SEVERE ERROR: event, header, and trace length inconsistencies found\n"); printf("event length = %d\n", subevt[sevtmult].elen); printf("header length = %d\n", subevt[sevtmult].hlen); printf("trace length = %d\n", subevt[sevtmult].trwlen); printf("Extra = %d\n", subevt[sevtmult].extra); printf("fcode = %d\n", subevt[sevtmult].fcode); //sleep(1); //return 0; } */ //CERN fill tree ///========== need a mapping, can reduce the array size, speed up. int ch = map[subevt[sevtmult].id]; if ( 0 <= ch && ch < NCRYSTAL ){ energy[ch] = subevt[sevtmult].energy; etimestamp[ch] = subevt[sevtmult].time; pileup[ch] = subevt[sevtmult].fcode; multi++; } if ( 100 <= ch && ch < 100 + NBGO ){ bgo[ch-100] = subevt[sevtmult].energy; } if ( 200 <= ch && ch < 200 + NOTHER){ other[ch-200] = subevt[sevtmult].energy; } //Set reference time for event building if (etime == -1) { etime = subevt[sevtmult].time; tdif = 0; } else { tdif = subevt[sevtmult].time - etime; if (tdif < 0) { printf("SEVERE ERROR: tdiff < 0, file must be time sorted\n"); printf("etime = %lld, time = %lld, and tdif = %lld\n", etime, subevt[sevtmult].time, tdif); return 0; } } //Check for end of event, rewind, and break out of while loop if (tdif > EVENT_BUILD_TIME) { fseek(fpr, -sizeof(int)*HEADER_LENGTH, SEEK_CUR); //fwrite/fread is buffered by system ; storing this in local buffer is no faster! break; } //time between sequential events for a single channel ; useful for determining optimal event building time temptime = (subevt[sevtmult].time - idtime[subevt[sevtmult].id])/100; //rebin to 1 micro-second if ( temptime >= 0 && temptime < 8192) { tdifid[subevt[sevtmult].id][temptime]++; } idtime[subevt[sevtmult].id]=subevt[sevtmult].time; //store time for next subevent of channel // total pileups if (subevt[sevtmult].fcode==1) { pileupcount++; } //more data than just the header; read entire sub event fseek(fpr, -sizeof(int)*HEADER_LENGTH, SEEK_CUR); if (fread(sub, sizeof(int)*subevt[sevtmult].elen, 1, fpr) != 1) break; /* //trace k=0; for (i = subevt[sevtmult].hlen; i < subevt[sevtmult].elen; i++) { subevt[sevtmult].tr[i - subevt[sevtmult].hlen + k] = sub[i] & 0x3FFF; subevt[sevtmult].tr[i - subevt[sevtmult].hlen + k + 1] = (sub[i]>>16) & 0x3FFF; k=k+1; } // if (subevt[sevtmult].id == 4 && subevt[sevtmult].fcode == 1) DB(subevt[sevtmult].tr); //continue if no esum or qsum if (subevt[sevtmult].hlen==HEADER_LENGTH) { sevtmult++; continue; } //esum if (subevt[sevtmult].hlen==8 || subevt[sevtmult].hlen==16) { for (i=4; i < 8; i++) { subevt[sevtmult].esum[i-4] = sub[i]; } } //qsum if (subevt[sevtmult].hlen==12) { for (i=4; i < 12; i++) { subevt[sevtmult].qsum[i-4] = sub[i]; } } //qsum if (subevt[sevtmult].hlen==16) { for (i=8; i < 16; i++) { subevt[sevtmult].qsum[i-8] = sub[i]; } } */ sevtmult++; } //end while loop for unpacking sub events and event building for one "event" if (sevtmult==0) break; //end main WHILE LOOP when out of events mult[0][sevtmult]++; //Histogram raw sub event multiplicity sevtcount += sevtmult; evtcount++; //event-built number ///////////////////////////////////// // END UNPACK DATA AND EVENT BUILD // ///////////////////////////////////// //event stats, print status every 10000 events lle_div=lldiv(evtcount,10000); if ( lle_div.rem == 0 ) { fprpos = ftell(fpr); tempf = (float)fprsize/(1024.*1024.*1024.); gClock.Stop("timer"); double time = gClock.GetRealTime("timer"); gClock.Start("timer"); printf("Total SubEvents: \x1B[32m%llu \x1B[31m(%d%% pileup)\x1B[0m\nTotal Events: \x1B[32m%llu (%.1f )\x1B[0m\nPercent Complete: \x1B[32m%ld%% of %.3f GB\x1B[0m\nTime used:%3.0f min %5.2f sec\033[3A\r", sevtcount, (int)((100*pileupcount)/sevtcount), evtcount, (float)sevtcount/(float)evtcount, (100*fprpos/fprsize), tempf, TMath::Floor(time/60.), time - TMath::Floor(time/60.)*60.); } //cern fill tree outRootFile->cd(); tree->Fill(); } // end main while loop ///////////////////////// // END MAIN WHILE LOOP // ///////////////////////// fprpos = ftell(fpr); tempf = (float)fprsize/(1024.*1024.*1024.); printf("Total SubEvents: \x1B[32m%llu \x1B[31m(%d%% pileup)\x1B[0m\nTotal Events: \x1B[32m%llu (%.1f )\x1B[0m\nPercent Complete: \x1B[32m%ld%% of %.3f GB\x1B[0m\n\033[3A\n", sevtcount, (int)((100*pileupcount)/sevtcount), evtcount, (float)sevtcount/(float)evtcount, (100*fprpos/fprsize), tempf); //cern save root outRootFile->cd(); tree->Write(); outRootFile->Close(); fclose(fpr); gClock.Stop("timer"); double time = gClock.GetRealTime("timer"); printf("\n==================== finished.\r\n"); printf("Total time spend : %3.0f min %5.2f sec\n", TMath::Floor(time/60.), time - TMath::Floor(time/60.)*60.); return 0; }