diff --git a/JakeStuff/DrawClovers b/JakeStuff/DrawClovers new file mode 100755 index 0000000..450ea02 Binary files /dev/null and b/JakeStuff/DrawClovers differ diff --git a/JakeStuff/DrawClovers.cpp b/JakeStuff/DrawClovers.cpp new file mode 100644 index 0000000..908b851 --- /dev/null +++ b/JakeStuff/DrawClovers.cpp @@ -0,0 +1,80 @@ +void DrawClovers(const char* filename = "outputs/Nov14_17_19.root", Bool_t drawCrystals = 1) { + TFile* file = TFile::Open(filename); + if (!file || file->IsZombie()) { + std::cerr << "Error: Could not open file " << filename << std::endl; + return; + } + + const int nCanvases = 11; + const int nPerCanvas = 6; + + // ROOT color codes: Blue=4, Black=1, Green=3, Red=2, Violet=6 + const int colors[nPerCanvas] = {4, 1, 3, 2, 6, 30}; + if (drawCrystals == true){ + for (int i = 0; i < nCanvases; ++i) { + TString canvasName = Form("canvas%d", i); + TCanvas* c = new TCanvas(canvasName, canvasName, 1200, 800); + c->Divide(1, nPerCanvas); + + for (int j = 0; j < nPerCanvas; ++j) { + c->cd(j + 1); + TH1F* hist = nullptr; + TString histName; + + if (j < 4) { + int index = i * 4 + j; + histName = Form("CompSupCalGeEnergy%02d", index); + } else if (j==5) { + histName = Form("AddBackGeEnergy%02d", i); + }else{ + histName = Form("SummedCloverCalGeEnergy%02d", i); + } + + std::cout << "Trying to load histogram: " << histName << std::endl; + hist = dynamic_cast(file->Get(histName)); + + if (hist) { + hist->SetTitle(histName); // Optional + hist->SetLineColor(colors[j]); + hist->Draw(); + } else { + std::cerr << "Missing histogram: " << histName << std::endl; + } + } + + c->Update(); + } + }else{ + const int nPerCanvas2 = 2; + const int colors2[nPerCanvas2] = {6, 30}; + for (int i = 0; i < nCanvases; ++i) { + TString canvasName = Form("canvas%d", i); + TCanvas* c = new TCanvas(canvasName, canvasName, 1200, 800); + c->Divide(1, nPerCanvas2); + + for (int j = 0; j < nPerCanvas2; ++j) { + c->cd(j + 1); + TH1F* hist = nullptr; + TString histName; + + if (j == 0) { + histName = Form("SummedCloverCalGeEnergy%02d", i); + }else{ + histName = Form("AddBackGeEnergy%02d", i); + } + + std::cout << "Trying to load histogram: " << histName << std::endl; + hist = dynamic_cast(file->Get(histName)); + + if (hist) { + hist->SetTitle(histName); // Optional + hist->SetLineColor(colors2[j]); + hist->Draw(); + } else { + std::cerr << "Missing histogram: " << histName << std::endl; + } + } + c->Update(); + } + } +} diff --git a/JakeStuff/JakeToDo.txt b/JakeStuff/JakeToDo.txt new file mode 100644 index 0000000..4ad0147 --- /dev/null +++ b/JakeStuff/JakeToDo.txt @@ -0,0 +1,6 @@ +figure out binning +Make the analyzer batch runable + I need to chain a bunch of files together here I think + Or sum all of the output files at the end? +Make the entire thing batch runable + Start with .evts, run one command and end up with one root file for all run files. diff --git a/JakeStuff/Jericho b/JakeStuff/Jericho new file mode 100755 index 0000000..8513a82 Binary files /dev/null and b/JakeStuff/Jericho differ diff --git a/JakeStuff/Jericho.cpp b/JakeStuff/Jericho.cpp new file mode 100644 index 0000000..9416229 --- /dev/null +++ b/JakeStuff/Jericho.cpp @@ -0,0 +1,1567 @@ +/****************************************** + * compile with this: + g++ -o JakeAnalyzer JakeAnalyzer.cpp `root-config --cflags --libs` + */ +#include +#include // for std::isfinite +#include // for TMath::QuietNaN() +#include // For file handling +#include // For string stream parsing +//some root headers +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//progress bar variables +const int barWidth = 50; +const char spinner[] = {'|', '/', '-', '\\'}; +int spinIdx = 0; + +// Detector setup +const Int_t nClovers = 11; +const Int_t nCrystals = (nClovers * 4); +const Int_t NGAGG = 64; +const Int_t nZeroDeg = 2; +const Int_t nLaBr3 = 16; +const Int_t nBEGe = 2; // we recorded both of the channels off the bege +const Int_t nCrystalPairs = 66; +const Int_t nLabrPairs = 120; + + +//calibration variables// Global calibration arrays +Double_t ge_slope[nCrystals + nBEGe]; +Double_t ge_intercept[nCrystals + nBEGe]; +Double_t geTimeGates[nCrystalPairs]; +Double_t labr_slope[nLaBr3]; +Double_t labr_intercept[nLaBr3]; + + +// PID variables +double traceSum[NGAGG]; +double peak[NGAGG]; +double tail[NGAGG]; +int PIDxSize = 4000; +int PIDySize = 150000; +int PIDnBins = 1200; +Int_t coinCounter = 0; +int gaggID = 0; +double sumAB = 0; +double pidX = 0; +double pidY = 0; + +//Comp Sup checker +bool bgoPresent = false; +Long64_t timeDiff_glob = 0; + +//Ge Timing pair map file +const char* geTimingPairFile= "hatsuneMiku.dat"; +//Labr Timing Pair Map File +const char* labrTimingPairFile= "hatsuneMiku2.dat"; + +//Global to hold the pairNum +Int_t pairNum = 0; + +//global to hold the alphaCut check +bool alphaCheck = false; + + + +Int_t makeGeTimingPairs(const char* filename, Int_t det1, Int_t det2) { + std::ifstream infile(filename); + if (!infile.is_open()) { + std::cerr << "Error: Unable to open pairing file " << filename << std::endl; + return -1; + } + + int file_det1, file_det2, pairID; + while (infile >> file_det1 >> file_det2 >> pairID) { + if ((file_det1 == det1 && file_det2 == det2) || + (file_det1 == det2 && file_det2 == det1)) { + //std::cout<<"det1: "<> file_det1 >> file_det2 >> pairID) { + if ((file_det1 == det1 && file_det2 == det2) || + (file_det1 == det2 && file_det2 == det1)) { + //std::cout<<"det1: "<= kMaxMulti || detNum[i] < 200 || detNum[i] > 399) continue; + for (int j = 0; j < multi; j++){ + if (detNum[i]<=299){ + //std::cout<<"I am an A hit first"<299){ + //std::cout<<"I am a B hit first"<= kMaxMulti || detNum[j] < 0 || detNum[j] >= nCrystals) continue; + + RawGeEnergy[detNum[j]]->Fill(e[j]); + } + +} +//Function to fill the BGOs +void makeBGO(TTree* tree, int kMaxMulti, Int_t multi, Int_t* detNum, Double_t* e, TH1F** BGOEnergy){ + for (Int_t j = 0; j < multi; ++j) { + //std::cout<<"multi"<= kMaxMulti || (detNum[j]-100) < 0 || (detNum[j]-100) >= nClovers) continue; + + BGOEnergy[(detNum[j]-100)]->Fill(e[j]); + } + +} +//Function to fill the Zero Degrees +void makeZeroDeg(TTree* tree, int kMaxMulti, Int_t multi, Int_t* detNum, Double_t* e, TH1F** ZeroDegEnergy){ + // Detector setup + const Int_t nZeroDeg = 2; + + for (Int_t j = 0; j < multi; ++j) { + //std::cout<<"multi"<= kMaxMulti || (detNum[j]-400) < 0 || (detNum[j]-400) >= nZeroDeg) continue; + + ZeroDegEnergy[(detNum[j]-400)]->Fill(e[j]); + } + +} +//This makes a a compton suppressed gamma spectrum per crystal +void makeCompSupCalGeEnergy(TTree* tree, int kMaxMulti, Int_t multi, Int_t* detNum, ULong64_t* e_t, Double_t* e, TH1F** CompSupCalGeEnergy, Int_t BGOGeTimeDiff_ns){ + //loop over each hit in the event to check if any are bgo hits + Double_t calEnergy2 = 0; + Long64_t timeDiff6 = 0; + for (Int_t j = 0; j < multi; ++j){ + if(j99 && detNum[j]<200){ + bgoPresent = true; + }else{ + bgoPresent = false; + } + } + //After that loop I know if there is a bgo hit in this event + for (Int_t j = 0; j < multi; ++j) { + //std::cout<<"multi"<= kMaxMulti || detNum[j] < 0 || detNum[j] >= nCrystals) continue; //get Ge hit + if (bgoPresent){//if there is a BGO hit in this event, loop through and find deltaTs + for (Int_t k = 0; k < multi; ++k){ + if (k >= kMaxMulti || detNum[k] < 99 || detNum[k] >= 200) continue; //make sure k is a BGO hit' + timeDiff6 = 10*(static_cast(e_t[k]) - static_cast(e_t[j])); + if(std::abs(timeDiff6)Fill(calEnergy2); + } + } + if (!bgoPresent){ + calEnergy2 = ge_slope[detNum[j]] * e[j] + ge_intercept[detNum[j]]; + CompSupCalGeEnergy[detNum[j]]->Fill(calEnergy2); + } + } +} + +//This makes a compton suppress gamma gamma matrix across all clovers +void makeCompSupCalGammaGamma(TTree* tree, int kMaxMulti, Int_t multi, Int_t* detNum, ULong64_t* e_t, Double_t* e, TH2F* CompSupGammaGamma, Int_t* cloverNum, Int_t BGOGeTimeDiff_ns){ + Double_t x = 0; + Double_t y = 0; + bool* check = new bool[kMaxMulti](); + bgoPresent = false; + + //check if event has bgo hit + for (Int_t j = 0; j < multi; ++j){ + //std::cout<<"I am here***************************** 1111111111111111111111 "<99 && detNum[j]<200){ + bgoPresent = true; + break; + } + } + + if(bgoPresent){//These first nested loops are fill check. Check is true if the timeDiff for that gamma and the BGO is out of the prompt window + for (Int_t j = 0; j < multi; ++j) { + //std::cout<<"I am here***************************** 22222222222222222 "<= kMaxMulti || detNum[j] < 0 || detNum[j] >= nCrystals) continue;//check that I have a valid Ge hit + for (Int_t i = 0; i 99 && detNum[i]<200){//i is a BGO hit + timeDiff_glob = 10*(static_cast(e_t[i]) - static_cast(e_t[j])); + if(std::abs(timeDiff_glob)>BGOGeTimeDiff_ns){//checking to see if the time diff is outside of the prompt window + check[j] = true; + } + } + } + } + + + for (Int_t j = 0; j < multi; ++j) { + if (j >= kMaxMulti || detNum[j] < 0 || detNum[j] >= nCrystals) continue; + if(check[j] == false) continue; // skip it if the time diff is in the prompt + if(e[j] <= 50) continue; //low energy threshold applied + //std::cout<<"I am here***************************** 333333333333 "<= kMaxMulti || detNum[k] < 0 || detNum[k] >= nCrystals) continue; //check for a valid Ge hit AND that it is a different hit than j + if(check[k] == false) continue; + if (e[k]<=50) continue; + y = ge_slope[detNum[k]] * e[k] + ge_intercept[detNum[k]]; + CompSupGammaGamma->Fill(x,y); + } + } + } + + if(!bgoPresent){ //if there is not a bgo hit here, we don't worry about vetoing stuff + for (Int_t j = 0; j < multi; ++j) { + if (j >= kMaxMulti || detNum[j] < 0 || detNum[j] >= nCrystals) continue; + if(e[j] <= 50) continue; //low energy threshold applied + x = ge_slope[detNum[j]] * e[j] + ge_intercept[detNum[j]]; + for (Int_t k = 0; k < multi; k++){ + if (k==j || k >= kMaxMulti || detNum[k] < 0 || detNum[k] >= nCrystals) continue; //check for a valid Ge hit AND that it is a different hit than j + if (e[k]<=50) continue; + y = ge_slope[detNum[k]] * e[k] + ge_intercept[detNum[k]]; + CompSupGammaGamma->Fill(x,y); + } + } + } + delete[] check; +} +//This will make a deltaT gated gamma gamma +void makeCalGammaGamma(TTree* tree, int kMaxMulti, Int_t multi, Int_t* detNum, ULong64_t* e_t, Double_t* e, TH2F* TotalGammaGamma, Int_t BGOGeTimeDiff_ns){ + Double_t x2 = 0; + Double_t y2 = 0; + + + for (Int_t j = 0; j < multi; ++j) {//loop over all hits + if (j < kMaxMulti && detNum[j]>=0 && detNum[j]=0 && detNum[k]50 && e[k]>50){//Enforcing an energy threshold. A lot of the thresholds were too low and messing with my timing plot + TotalGammaGamma->Fill(x2,y2); + } + } + } + } + } +} + +void makeAddBackGammaGamma(TTree* tree, int kMaxMulti, Int_t multi, Int_t* detNum, ULong64_t* e_t, Double_t* e, TH2F* AddbackGammaGamma, Int_t BGOGETimeDiff_ns, Int_t* cloverNum, Bool_t* pileup){ + /*loop over events looking for 2 gammas that happen within a prompt window (100 ns) + Add their energy as x, store their hit number (j and k), then check if multi>2. + If mult>2, loop through the rest of the events and plot the add back as x and that energy as y. But what if all three are in the time window???? + */ + + //***************I think I should fill mult 2 events!!!************************* */ + + Double_t x3 = 0; + Double_t y3 = 0; + Double_t addBackE2 = 0; + bool* BGOcheck = new bool[kMaxMulti](); + bool* addBackCheck = new bool[kMaxMulti](); + bool validAddback = false; + pairNum = 0; + Int_t germCount = 0; + + + timeDiff_glob = 0; + + //Reject pileups + for (Int_t j = 0; j < multi; ++j) { + if (j < kMaxMulti && detNum[j]>=0 && detNum[j]=0 && detNum[j]99 && detNum[k]<200){//get a BGO hit + timeDiff_glob = 10*(static_cast(e_t[k]) - static_cast(e_t[j])); + if(std::abs(timeDiff_glob)= 2){ + for (Int_t j = 0; j < multi; ++j) {//loop over all hits + if(addBackCheck[j]) continue;//this checks to see if this hit has already been used in a addback. + if (j < kMaxMulti && detNum[j]>=0 && detNum[j]=0 && detNum[k](e_t[k]) - static_cast(e_t[j])); + if(cloverNum[detNum[j]] == cloverNum[detNum[k]]){//here we want the prompt gammas and gammas from teh same clover. Not dealing with diagonals rn + pairNum = makeGeTimingPairs(geTimingPairFile, detNum[j], detNum[k]); + if(std::abs(timeDiff_glob) <= geTimeGates[pairNum]){ + addBackE2 = (ge_slope[detNum[j]] * e[j] + ge_intercept[detNum[j]]) + (ge_slope[detNum[k]] * e[k] + ge_intercept[detNum[k]]); + addBackCheck[j] = true; + addBackCheck[k] = true; + validAddback = true; + } + }// I still want to keep any gammas that are not addback but are valid gamma gammas + if(germCount >= 2 && validAddback == false){ + x3 = ge_slope[detNum[j]] * e[j] + ge_intercept[detNum[j]]; + y3 = ge_slope[detNum[k]] * e[k] + ge_intercept[detNum[k]]; + AddbackGammaGamma->Fill(x3,y3); + + } + if(multi>2 && validAddback == true){ + for(Int_t i = 0; i=0 && detNum[i]Fill(addBackE2,y3); + AddbackGammaGamma->Fill(y3,addBackE2); //making it symmetric + } + } + } + } + } + } + } + } + delete[] BGOcheck; + delete[] addBackCheck; +} + +ULong64_t makeTrueTimeStamp(Int_t detNum, Int_t cfd, ULong64_t e_t){ // Here I am only passing in the current values of these numbers. This function will NOT loop through the event. Only calculate the good timestamp for the current hit! + bool boardType100MHz = false; + bool forcedTriggerBit100 = false; + ULong64_t forcedTriggerBit500 = 0; + ULong64_t cfdFractionalTime = 0; + ULong64_t trueTimeStamp = 0; + //ULong64_t dumbBigTime = e_t*(4.294967296e9); // this is the timestamp but multiplied by 2^32 + + if(detNum>=0 && detNum<500){ + boardType100MHz = true; + } + if(detNum>=500 && detNum<600){ + boardType100MHz = false; + } + + //Now we need to split the cfd value into trigger bit and timestamp. Datablock and evtReader keep the 16 bits of cfd information together, I will split the trigger bit and the time here. + //Let's handle the split for the 100MHz boards firts. I am using the table 4-4 in the Pixie16 manual. + if(boardType100MHz){ + forcedTriggerBit100 = (cfd >> 15) & 1; //here I am pulling just the last bit in the 16 bit cfd variable. + cfdFractionalTime = (cfd) & 0x3FFF; // pulling the first 14 bits here. 0x3FFF means 0011 1111 1111 1111. + if(!forcedTriggerBit100){ + trueTimeStamp = (e_t + (cfdFractionalTime / 32768)) * 10; // calculating true time stamp from the manual page 74 + } + if(forcedTriggerBit100){ + trueTimeStamp = e_t*10; // there is a 10 ns unit on all of this + } + } + //Now the 500MHz board found in table 4-6 + if(!boardType100MHz){ + forcedTriggerBit500 = (cfd >> 13) & 0x7; + cfdFractionalTime = (cfd) & 0x1FFF; + if(forcedTriggerBit500 == 7){//According to the manual, a forced trigger bit is when these three bits are 111. This number is equal to 7 in binary + trueTimeStamp = 123456789.0;//(e_t*10); + //std::cout<<"FORCED TRIGGER BIT!!!!"<=500 && detNum[j]<600){//check for hits in the 500MHz board + forcedTriggerBit500 = (cfd[j] >> 13) & 0x7; + forcedTrigger500MHzBoard->Fill(forcedTriggerBit500); + } + } +} + +void makeGeTimeDiff(TTree* tree, int kMaxMulti, Int_t multi, Int_t* detNum, ULong64_t* e_t, Double_t* e, TH1F** GeTimeDiff, Int_t* cloverNum, Bool_t* pileup){ + Long64_t timeDiff = 0; + pairNum = 0; + + + for (Int_t j = 0; j < multi; ++j) { + if(pileup[j]) return; + } + + for (Int_t j = 0; j < multi; ++j) {//loop over all hits + //if (pileup[j] == true) return;//skipping the event if it has a pileup flag + if (j < kMaxMulti && detNum[j]>=0 && detNum[j]=0 && detNum[k](e_t[k]) - static_cast(e_t[j]));//find the time diff between them + if((ge_slope[detNum[k]] * e[k] + ge_intercept[detNum[k]])>40){ + GeTimeDiff[pairNum]->Fill(timeDiff);// fill that diff the diff hist + } + } + } + } + } + } +} +void makeTotalGeTimeDiff(TTree* tree, int kMaxMulti, Int_t multi, Int_t* detNum, ULong64_t* e_t, Double_t* e, TH1F* TotalGeTimeDiff, Int_t* cloverNum){ + Long64_t timeDiff2 = 0; + + for (Int_t j = 0; j < multi; ++j) {//loop over all hits + if (j < kMaxMulti && detNum[j]>=0 && detNum[j]=0 && detNum[k](e_t[k]) - static_cast(e_t[j]));//find the time diff between them + //std::cout<<"j timestamp: "<50 && e[k]>50){//Enforcing an energy threshold. A lot of the thresholds were too low and messing with my timing plots + TotalGeTimeDiff->Fill(timeDiff2);// fill that diff the diff hist + } + } + } + } + } +} +void makeLabrTimeDiff(TTree* tree, int kMaxMulti, Int_t multi, Int_t* detNum, TH1F** LabrTimeDiff, Bool_t* pileup, Int_t* cfd, UInt_t (*qdc)[8], ULong64_t* e_t){ + Long64_t timeDiff = 0; + pairNum = 0; + Double_t labrQDCEnergy1; + Double_t labrQDCEnergy2; + ULong64_t time1; + ULong64_t time2; + + + //for (Int_t j = 0; j < multi; ++j) { + //if(pileup[j]) return; + //} + + + for (Int_t j = 0; j < multi; ++j) {//loop over all hits + labrQDCEnergy1 = ((qdc[j][2]+qdc[j][3])-qdc[j][1])*(100.0/140.0); + labrQDCEnergy1 = labrQDCEnergy1*labr_slope[detNum[j]-500]+labr_intercept[detNum[j]-500]; + + //if (pileup[j] == true) return;//skipping the event if it has a pileup flag + if (j < kMaxMulti && detNum[j]>=500 && detNum[j]<600){//get a labr hit + if(labrQDCEnergy1>=1000 && labrQDCEnergy1<=2100){ + time1 = makeTrueTimeStamp(detNum[j], cfd[j], e_t[j]); + if(time1 == 123456789){ + //std::cout<<"Forced bit in t1*******************"<=500 && detNum[k]<600){//check that a different hit (k=!j) is a hit + if (detNum[j] == detNum[k]) continue; // check if those two hits are the same detector firing twice. + time2 = makeTrueTimeStamp(detNum[k], cfd[k], e_t[k]); + labrQDCEnergy2 = ((qdc[k][2]+qdc[k][3]) - qdc[k][1])*(100.0/140.0); + labrQDCEnergy2 = labrQDCEnergy2*labr_slope[detNum[k]-500]+labr_intercept[detNum[k]-500]; + if(time2 == 123456789){ + //std::cout<<"Forced bit in t2************"<=1000 && labrQDCEnergy2<= 2100)){ + pairNum = makeLabrTimingPairs(labrTimingPairFile, (detNum[j] - 500), (detNum[k] - 500)); + // std::cout<<"I made it through energy2 check "<Fill(abs(timeDiff));// fill that diff the diff hist + //std::cout<<"I am in labr time diff fill statement************************************"<=500 && detNum[j]<600){//get a Ge hit +// //if((labr_slope[detNum[j] - 450] * labrQDCEnergy1 + labr_intercept[detNum[j] - 450])<1) continue; //the -450 here is for the calibration read mapping. Labr start at index 50 there. Therefore 500 - 450. +// for (Int_t k = 0; k < multi; ++k) {//loop over all hits again +// if (k!=j && detNum[k]>=500 && detNum[k]<600){//check that a different hit (k=!j) is a Ge hit +// if (detNum[j] == detNum[k]) continue; // check if those two hits are the same detector firing twice. +// pairNum = makeLabrTimingPairs(labrTimingPairFile, (detNum[j] - 500), (detNum[k] - 500)); +// //std::cout<<"I made it through the same clover check pairID: "<1){ +// LabrTimeDiff[pairNum]->Fill(abs(timeDiff));// fill that diff the diff hist +// //std::cout<<"I am in labr time diff fill statement************************************"<=500 && detNum[j]<600){//get a Labr hit + //std::cout<<"I GOT IN THE FIRST LOOP"<=500 && detNum[k]<600){//check that a different hit (k=!j) is a LabR3 hit + timeDiff3 = makeTrueTimeStamp(detNum[j], cfd[j], e_t[j]) - makeTrueTimeStamp(detNum[k], cfd[k], e_t[k]); // this has already been converted to ns!! + if(timeDiff3 == 0 || std::fmod(timeDiff3,10.0) == 0){ + continue; + } + //std::cout<<"Calc'd time diff "<(e_t[k]) - static_cast(e_t[j]));//find the time diff between them + //std::cout<<"j timestamp: "<50 && e[k]>50){//Enforcing an energy threshold. A lot of the thresholds were too low and messing with my timing plots + TotalLaBr3TimeDiff->Fill(timeDiff3);// fill that diff the diff hist + //} + } + } + } + } +} + +void makeLabrTimeDiffvLabrEnergy(TTree* tree, int kMaxMulti, Int_t multi, Int_t* detNum, TH2F** LabrTimeDiffvLabrEnergy, Bool_t* pileup, Int_t* cfd, UInt_t (*qdc)[8], ULong64_t* e_t){ + Long64_t timeDiff = 0; + pairNum = 0; + Double_t labrQDCEnergy1; + Double_t labrQDCEnergy2; + ULong64_t time1; + ULong64_t time2; + + + //for (Int_t j = 0; j < multi; ++j) { + //if(pileup[j]) return; + //} + + + for (Int_t j = 0; j < multi; ++j) {//loop over all hits + labrQDCEnergy1 = ((qdc[j][2]+qdc[j][3])-qdc[j][1])*(100.0/140.0); + labrQDCEnergy1 = labrQDCEnergy1*labr_slope[detNum[j]-500]+labr_intercept[detNum[j]-500]; + + //if (pileup[j] == true) return;//skipping the event if it has a pileup flag + if (j < kMaxMulti && detNum[j]>=500 && detNum[j]<600){//get a labr hit + if(labrQDCEnergy1>=0 && labrQDCEnergy1<=5000){ + time1 = makeTrueTimeStamp(detNum[j], cfd[j], e_t[j]); + if(time1 == 123456789){ + //std::cout<<"Forced bit in t1*******************"<=500 && detNum[k]<600){//check that a different hit (k=!j) is a hit + if (detNum[j] == detNum[k]) continue; // check if those two hits are the same detector firing twice. + time2 = makeTrueTimeStamp(detNum[k], cfd[k], e_t[k]); + labrQDCEnergy2 = ((qdc[k][2]+qdc[k][3]) - qdc[k][1])*(100.0/140.0); + labrQDCEnergy2 = labrQDCEnergy2*labr_slope[detNum[k]-500]+labr_intercept[detNum[k]-500]; + if(time2 == 123456789){ + //std::cout<<"Forced bit in t2************"<=0 && labrQDCEnergy2<= 5000)){ + pairNum = makeLabrTimingPairs(labrTimingPairFile, (detNum[j] - 500), (detNum[k] - 500)); + // std::cout<<"I made it through energy2 check "<Fill(abs(timeDiff),labrQDCEnergy1);// fill that diff the diff hist + //std::cout<<"I am in labr time diff fill statement************************************"<=0 && detNum[j]=100 && detNum[k]<200){//check that a different hit (k=!j) is a BGO hit + timeDiff5 = 10*(static_cast(e_t[k]) - static_cast(e_t[j]));//find the time diff between them + if(e[j]>200){//Enforcing an energy threshold. A lot of the thresholds were too low and messing with my timing plots + if(cloverNum[detNum[j]] == (detNum[k]-100)){ + BGOGeTimeDiff[detNum[j]]->Fill(timeDiff5);//std::abs(timeDiff5));// fill that diff the diff hist + } + } + } + } + } + } +} +void readAlphaCutsFile(const char* alphaCutFile, TCutG** alphaCuts) { + // Open the ROOT file + TFile* file = TFile::Open(alphaCutFile, "READ"); + if (!file || file->IsZombie()) { + std::cerr << "Error opening cut file: " << alphaCutFile << std::endl; + return; + } + + // Regular expression to match "hPID##_alpha" + std::regex pattern("PID(\\d{2})_alpha"); + + // Loop through all keys in the file + TIter next(file->GetListOfKeys()); + TKey* key; + while ((key = (TKey*)next())) { + TObject* obj = key->ReadObj(); + + // Only proceed if object is a TCutG + if (!obj->InheritsFrom("TCutG")) continue; + + std::string name = obj->GetName(); + std::smatch match; + if (std::regex_match(name, match, pattern)) { + int idx = std::stoi(match[1]); + if (idx >= 0 && idx < 64) { + alphaCuts[idx] = (TCutG*)obj; + std::cout << "Loaded alpha cut for detector " << idx << std::endl; + } else { + std::cerr << "Warning: Cut index " << idx << " is out of bounds (0-63)" << std::endl; + } + } else { + std::cerr << "Skipping unrecognized cut: " << name << std::endl; + } + } + + file->Close(); +} + + + +void readCalFile(const char* calFile){ + std::ifstream infile(calFile); + if (!infile.is_open()) { + std::cerr << "Error: Could not open calibration file " << calFile << std::endl; + return; + } + + int detID; + double slope, intercept; + + // Initialize all entries to default values + for (int i = 0; i < nCrystals + nBEGe + nLaBr3; ++i) { + ge_slope[i] = 1.0; // default: slope=1 (no gain correction) + ge_intercept[i] = 0.0; // default: intercept=0 (no offset correction) + } + + // Read the file line by line + std::string line; + while (std::getline(infile, line)) { + std::istringstream iss(line); + if (!(iss >> detID >> slope >> intercept)) { + std::cerr << "Warning: Bad line in calibration file: " << line << std::endl; + continue; + } + if (detID >= 0 && detID < nCrystals + nBEGe) { + ge_slope[detID] = slope; + ge_intercept[detID] = intercept; + } + if (detID>nCrystals + nBEGe){ + labr_slope[detID - 50] = slope; + labr_intercept[detID- 50] = intercept; + } + + if (detID> nCrystals + nBEGe + nLaBr3 + 5) { + std::cerr << "Warning: Detector ID out of range: " << detID << std::endl; + } + } + + infile.close(); + + infile.close(); + std::cout << "Calibration loaded successfully from " << calFile << std::endl; +} + +void readGeTimeGatesFile(const char* timeGatesFile){ + std::ifstream infile(timeGatesFile); + if (!infile.is_open()) { + std::cerr << "Error: Could not open time gates file " << timeGatesFile << std::endl; + return; + } + + int detID2; + double timeGateRead; + + // Initialize all entries to default values + for (int i = 0; i < nCrystalPairs; ++i) { + geTimeGates[i] = 1.0; // default: slope=1 (no gain correction) + } + + // Read the file line by line + std::string line; + while (std::getline(infile, line)) { + std::istringstream iss(line); + if (!(iss >> detID2 >> timeGateRead)) { + std::cerr << "Warning: Bad line in time gates file: " << line << std::endl; + continue; + } + if (detID2 >= 0 && detID2 < nCrystalPairs) { + geTimeGates[detID2] = timeGateRead; + } else { + std::cerr << "Warning: Detector ID out of range: " << detID2 << std::endl; + } + } + + infile.close(); + + infile.close(); + std::cout << "Prompt time gates loaded successfully from " << timeGatesFile << std::endl; +} +void makeCalGeEnergy(TTree* tree, int kMaxMulti, Int_t multi, Int_t* detNum, Double_t* e, TH1F** CalGeEnergy){ + //Make a varible to hold the calEnergy + Double_t calEnergy = 0; + + for (Int_t j = 0; j < multi; ++j) { + //std::cout<<"multi"<= kMaxMulti || detNum[j] < 0 || detNum[j] >= nCrystals) continue; + //Apply a linear calibration + calEnergy = ge_slope[detNum[j]] * e[j] + ge_intercept[detNum[j]]; + CalGeEnergy[detNum[j]]->Fill(calEnergy); + } + +} +void makeCloverNum(Int_t* cloverNum){ + for (Int_t j = 0; j99 && detNum[j]<200) + //return; + //} + for(Int_t j = 0; j= kMaxMulti || detNum[j] < 0 || detNum[j] >= nCrystals) continue; //this was not a Ge hit + if (multi == 1){ + singleCalEnergy = (ge_slope[detNum[j]]*e[j]) + ge_intercept[detNum[j]]; + AddBackGeEnergy[cloverNum[detNum[j]]]->Fill(singleCalEnergy); + }else{ + for(Int_t k = j+1; k= kMaxMulti || detNum[k] < 0 || detNum[k] >= nCrystals || k == j) continue; //this was not a Ge hit or it is the same hit + + if (cloverNum[detNum[k]] == cloverNum[detNum[j]]){//Are the hits in the same clover + if (includeDiagonals == true){ + addBackEnergy = (ge_slope[detNum[j]]*e[j]+ge_intercept[detNum[j]])+(ge_slope[detNum[k]]*e[k]+ge_intercept[detNum[k]]); + AddBackGeEnergy[cloverNum[detNum[j]]]->Fill(addBackEnergy); + }else{ + /* + std::cout<<"Multiplicity: "<Fill(addBackEnergy); + */ + + //Below is logic for excluding the diagonals. + + if (detNum[j]%4 == 0 || detNum[j]%4 == 2){//Is the first hit a blue or green hit? + if(detNum[k]%4 == 1 || detNum[k]%4 == 3){//Is the second hit a red or black hit? I only want to add hits that happened in adjacent crystals. No diagonals + //std::cout<<"Scenario A | "<<"Multiplicity: "<Fill(addBackEnergy); + } + } + if (detNum[j]%4 == 1 || detNum[j]%4 == 3){//Vice versa of above + if(detNum[k]%4 == 0 || detNum[k]%4 == 2){ + //std::cout<<"Scenario B | "<<"Multiplicity: "<Fill(addBackEnergy); + } + } + } + } + } + } + } +} + +void makeCompSupCloverSumEnergy(TH1F** CompSupCalGeEnergy, TH1F** CompSupCloverSumEnergy){ + for (int i = 0; i < 11; ++i) { + int idx0 = i * 4; + CompSupCloverSumEnergy[i]->Reset(); // clear existing bin contents + + for (int j = 0; j < 4; ++j) { + CompSupCloverSumEnergy[i]->Add(CompSupCalGeEnergy[idx0 + j]); + } + } + +} + +void makeAlphaCutPID(TH2F** hPID, TCutG** alphaCuts, TH2F** hPID_alpha) { + for (int i = 0; i < NGAGG; ++i) { + if (!hPID[i] || !alphaCuts[i] || !hPID_alpha[i]) continue; // Skip if any pointer is null + //std::cout<<"I GOT HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"<Reset(); // Ensure we start with an empty histogram + + int nBinsX = hPID[i]->GetNbinsX(); + int nBinsY = hPID[i]->GetNbinsY(); + + for (int xBin = 1; xBin <= nBinsX; ++xBin) { + double x = hPID[i]->GetXaxis()->GetBinCenter(xBin); + for (int yBin = 1; yBin <= nBinsY; ++yBin) { + double y = hPID[i]->GetYaxis()->GetBinCenter(yBin); + if (alphaCuts[i]->IsInside(x, y)) { + double content = hPID[i]->GetBinContent(xBin, yBin); + hPID_alpha[i]->SetBinContent(xBin, yBin, content); + //std::cout<<"I GOT HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"<= kMaxMulti || detNum[j] < 200 || detNum[j] > 299) continue; //Usiung this to get a Trinity hit + //Calc pidX and Y + gaggID = detNum[j] - 200; + if (gaggID < 0 || gaggID >= NGAGG) continue; + + double sumAB2 = qdc[j][0] + qdc[j][1]; + peak[gaggID] = qdc[j][3] - (20.0 / 60.0) * sumAB2; + tail[gaggID] = qdc[j][5] - (55.0 / 60.0) * sumAB2; + traceSum[gaggID] = qdc[j][2] + qdc[j][3] + qdc[j][4] + qdc[j][5] + qdc[j][6] - (115.0 / 60.0) * sumAB2; + + if(gaggID>=0 && gaggID<14){//This is here trying to make the ring 1 and 2 PID better. In this loop I will shift the qdc over one. + peak[gaggID] = qdc[j][4] - (20.0 / 60.0) * sumAB2; + tail[gaggID] = qdc[j][6] - (55.0 / 60.0) * sumAB2; + traceSum[gaggID] = qdc[j][3] + qdc[j][4] + qdc[j][5] + qdc[j][6] + qdc[j][7] - (115.0 / 60.0) * sumAB2; + } + double pidX2 = 4000.0 * tail[gaggID] / peak[gaggID]; + double pidY2 = traceSum[gaggID]; + + //Check if it is in the cut + if(alphaCuts[gaggID] && alphaCuts[gaggID]->IsInside(pidX2,pidY2)){ + numAlphaHits = numAlphaHits + 1; + } + } + //return true if it is, false if not + if(numAlphaHits >= 1){ + return true; + }else{ + return false; + } + //std::cout<<"Trin Mult: "<=0 && detNum[j]=0 && detNum[j]99 && detNum[k]<200){//get a BGO hit + timeDiff_glob = 10*(static_cast(e_t[k]) - static_cast(e_t[j])); + if(std::abs(timeDiff_glob)= 2){ + for (Int_t j = 0; j < multi; ++j) {//loop over all hits + if(addBackCheck2[j]) continue;//this checks to see if this hit has already been used in a addback. + if (j < kMaxMulti && detNum[j]>=0 && detNum[j]=0 && detNum[k](e_t[k]) - static_cast(e_t[j])); + if(cloverNum[detNum[j]] == cloverNum[detNum[k]]){//here we want the prompt gammas and gammas from teh same clover. Not dealing with diagonals rn + pairNum = makeGeTimingPairs(geTimingPairFile, detNum[j], detNum[k]); + if(std::abs(timeDiff_glob) <= geTimeGates[pairNum]){ + addBackE3 = (ge_slope[detNum[j]] * e[j] + ge_intercept[detNum[j]]) + (ge_slope[detNum[k]] * e[k] + ge_intercept[detNum[k]]); + addBackCheck2[j] = true; + addBackCheck2[k] = true; + validAddback2 = true; + } + }// I still want to keep any gammas that are not addback but are valid gamma gammas + if(germCount2 >= 2 && validAddback2 == false){ + x4 = ge_slope[detNum[j]] * e[j] + ge_intercept[detNum[j]]; + y4 = ge_slope[detNum[k]] * e[k] + ge_intercept[detNum[k]]; + AlphaAddbackGammaGamma->Fill(x4,y4); + + } + if(multi>2 && validAddback2 == true){ + for(Int_t i = 0; i=0 && detNum[i]Fill(addBackE3,y4); + AlphaAddbackGammaGamma->Fill(y4,addBackE3); //making it symmetric + } + } + } + } + } + } + } + } + delete[] BGOcheck2; + delete[] addBackCheck2; +} + +void makeTraces(Int_t multi, Int_t* detNum, Int_t (*trace)[280], TH2F** Traces){ + for (Int_t j = 0; j < multi; ++j){ + if(detNum[j]>=500 && detNum[j]<600){//hard coding in to only look at labr traces + for(Int_t k = 0; k<280; k++){//looping over trace length hardcoded length for now + Traces[detNum[j]-500]->Fill(k, trace[j][k]); + //std::cout<<"j: "<OpenDirectory(inputDir); + if (!dirp) { + std::cerr << "Error: Cannot open directory: " << inputDir << std::endl; + return nullptr; + } + + const char* file; + while ((file = gSystem->GetDirEntry(dirp))) { + TString fname = file; + if (!fname.EndsWith(".root")) continue; + + TString fullPath = TString(inputDir) + fname; + chain->Add(fullPath); + } + + if (chain->GetEntries() == 0) { + std::cerr << "Warning: No entries found in TChain from directory: " << inputDir << std::endl; + delete chain; + return nullptr; + } + + return chain; +} + +TTree* makeOpenRootTree(const char* filename) { + TFile* file = TFile::Open(filename, "READ"); + if (!file || file->IsZombie()) { + std::cerr << "Error opening file: " << filename << std::endl; + return nullptr; + } + + TTree* tree = nullptr; + file->GetObject("tree", tree); // MUST match tree name + + if (!tree) { + std::cerr << "Error: TTree 'tree' not found in file: " + << filename << std::endl; + file->ls(); + return nullptr; + } + + // DO NOT call tree->SetDirectory(nullptr) + // DO NOT close or delete file + + return tree; +} + + + +//Function to fill the LaBr3s +void makeLaBr3(TTree* tree, int kMaxMulti, Int_t multi, Int_t* detNum, Double_t* e, TH1F** LaBr3Energy, UInt_t (*qdc)[8]){ + for (Int_t j = 0; j < multi; ++j) { + //std::cout<<"multi"<= kMaxMulti || (detNum[j] - 500) < 0 || (detNum[j] - 500) >= nLaBr3) continue; + double labr3EnergySum = (((double)qdc[j][2] + (double)qdc[j][3]) - (double)qdc[j][1]) * (100.0/140.0); + + labr3EnergySum = labr_slope[detNum[j] - 500] * labr3EnergySum + labr_intercept[detNum[j] - 500]; + //std::cout<<"DetNum - 500: "<Fill(labr3EnergySum); + } +} + +//Function to fill the BEGe channels +void makeRawBEGe(TTree* tree, int kMaxMulti, Int_t multi, Int_t* detNum, Double_t* e, TH1F** RawBEGe){ + for (Int_t j = 0; j < multi; ++j) { + //std::cout<<"multi"<= kMaxMulti || (detNum[j]) < 44 || (detNum[j]) > 45) continue; + //std::cout<<"detNum "<Fill(e[j]); + } +} + +void makeCalBEGe(TTree* tree, int kMaxMulti, Int_t multi, Int_t* detNum, Double_t* e, TH1F** calBEGe){ + //Make a varible to hold the calEnergy + Double_t calEnergy3 = 0; + + for (Int_t j = 0; j < multi; ++j) { + //std::cout<<"multi"<= kMaxMulti || detNum[j] < 44 || detNum[j] > 45) continue; + //Apply a linear calibration + calEnergy3 = ge_slope[detNum[j]] * e[j] + ge_intercept[detNum[j]]; + calBEGe[detNum[j] - 44]->Fill(calEnergy3); + } +} + +void Process_Events(const char* inputFile, + const char* calFilename, + const char* gePromptGatesFile, + const char* outputDirectory, + const char* outputFilename, + bool trinCoin, + bool includeDiagonals, + const char* alphaCutsFile, + const char* geTimeingPairFileRead, + Int_t BGOGeTimeGate_ns, + const char* labrTimeingPairFileRead) { + //Read in the calobration File + readCalFile(calFilename); + readGeTimeGatesFile(gePromptGatesFile); + geTimingPairFile = geTimeingPairFileRead; + labrTimingPairFile = labrTimeingPairFileRead; + + // Open the input ROOT file + //TChain* tree = makeTChain(inputDir, "tree"); // this chains together all of the root files in a directory + TTree* tree = makeOpenRootTree(inputFile); + if(!tree){ + std::cout<<"No Tree Found"<SetBranchAddress("multi", &multi); + tree->SetBranchAddress("detID", detNum); + tree->SetBranchAddress("e", e); + tree->SetBranchAddress("e_t", e_t); + tree->SetBranchAddress("pileup", pileup); + tree->SetBranchAddress("qdc", qdc); + tree->SetBranchAddress("cfd",cfd); + tree->SetBranchAddress("trace",trace); + + + + + //Make the cloverNum array + makeCloverNum(cloverNum); + // Initialize all elements with NaN + for (int i = 0; i < NGAGG; ++i){ + traceSum[i] = peak[i] = tail[i] = TMath::QuietNaN(); + } + // Create gamma energy histograms + TH1F* RawGeEnergy[nCrystals]; + for (int i = 0; i < nCrystals; ++i) { + RawGeEnergy[i] = new TH1F(Form("RawGeEnergy%02d", i), Form("e - %02d", i), 4000, 0, 16000); + RawGeEnergy[i]->SetDirectory(nullptr);//comment this out if you want to use this histogram + } + //Create bgo energy hists + TH1F* BGOEnergy[nClovers]; + for (int i = 0; i < nClovers; ++i) { + BGOEnergy[i] = new TH1F(Form("BGOEnergy%02d", i), Form("e - %02d", i), 20000, 0, 20000); + BGOEnergy[i]->SetDirectory(nullptr);//comment this out if you want to use this histogram + } + //Create zerodeg hists + TH1F* ZeroDegEnergy[nZeroDeg]; + for (int i = 0; i < nZeroDeg; ++i) { + ZeroDegEnergy[i] = new TH1F(Form("ZeroDegEnergy%02d", i), Form("e - %02d", i), 20000, 0, 20000); + ZeroDegEnergy[i]->SetDirectory(nullptr);//comment this out if you want to use this histogram + } + //Create the compton suppressed Ge Hists + TH1F* CompSupCalGeEnergy[nCrystals]; + for (int i = 0; i < nCrystals; ++i) { + CompSupCalGeEnergy[i] = new TH1F(Form("CompSupCalGeEnergy%02d", i), Form("e - %02d", i), 4000, 0, 4000); + CompSupCalGeEnergy[i]->SetDirectory(nullptr);//comment this out if you want to use this histogram + } + // Create calibrated gamma energy histograms + TH1F* CalGeEnergy[nCrystals]; + TH1F* BGOGeTimeDiff[nCrystals]; + for (int i = 0; i < nCrystals; ++i) { + CalGeEnergy[i] = new TH1F(Form("CalGeEnergy%02d", i),Form("Cal_e - %02d", i), 4000, 0, 4000); + BGOGeTimeDiff[i] = new TH1F(Form("BGOGeTimeDiff%02d", i),Form("BGOGeTimeDiff_Plot%02d", i),600,-3000,3000); + CalGeEnergy[i]->SetDirectory(nullptr);//comment this out if you want to use this histogram + } + // Create addback gamma energy histograms - ONE PER CLOVER + TH1F* AddBackGeEnergy[nClovers]; + for (int i = 0; i < nClovers; ++i) { + AddBackGeEnergy[i] = new TH1F(Form("AddBackGeEnergy%02d", i),Form("AddBack_e - %02d", i), 4000, 0, 4000); + } + //Create summed clover energy spectra (just summed not addback) + TH1F* CompSupCloverSumEnergy[nClovers]; + for (int i = 0; i < nClovers; ++i) { + CompSupCloverSumEnergy[i] = new TH1F(Form("SummedCloverCalGeEnergy%02d", i),Form("Summed_e - %02d", i), 4000, 0, 4000); + CompSupCloverSumEnergy[i]->SetDirectory(nullptr);//comment this out if you want to use this histogram + } + //Create Ge Time difference plot in each clover + TH1F* GeTimeDiff[nCrystalPairs]; + for (int i = 0; iSetOption("HIST"); + } + + //Create Labr Time difference plot vs labr energy + TH2F* LabrTimeDiffvLabrEnergy[nLabrPairs]; + for (int i = 0; iSetOption("COLZ"); + } + + //Create a total time diff plot Ge + TH1F* TotalGeTimeDiff = new TH1F("TotalGeTimeDiff","TotalGeTimeDiff_plot",600,-3000,3000); + + //Create a total time diff plot Ge + TH1F* TotalLaBr3TimeDiff = new TH1F("TotalLaBr3TimeDiff","TotalLaBr3TimeDiff_plot",48000,-1000,1000); + TotalLaBr3TimeDiff->SetDirectory(nullptr);//comment this out if you want to use this histogram + + //Create LaBr3 energy hists + TH1F* LaBr3Energy[nLaBr3]; + for (int i = 0; i < nLaBr3; ++i) { + LaBr3Energy[i] = new TH1F(Form("LaBr3Energy%02d", i),Form("e - %02d", i), 6000, 0, 10000); + //LaBr3Energy[i]->SetDirectory(nullptr);//comment this out if you want to use this histogram + //LaBr3Energy[i]->SetOption("HIST"); + } + + //Create Raw BEGe energy hists + TH1F* rawBEGe[nBEGe]; + for (int i = 0; i < nBEGe; ++i) { + rawBEGe[i] = new TH1F(Form("rawBEGe%02d", i),Form("e - %02d", i), 4000, 0, 16000); + rawBEGe[i]->SetDirectory(nullptr);//comment this out if you want to use this histogram + } + //Create Raw BEGe energy hists + TH1F* calBEGe[nBEGe]; + for (int i = 0; i < nBEGe; ++i) { + calBEGe[i] = new TH1F(Form("calBEGe%02d", i),Form("e - %02d", i), 4000, 0, 4000); + calBEGe[i]->SetDirectory(nullptr);//comment this out if you want to use this histogram + } + //Create the PID hists + //std::cout<<"Before PIDs"<SetDirectory(nullptr);//comment this out if you want to use this histogram + + //Create hist for time gated gamma gamma + TH2F* TotalGammaGamma = new TH2F("TotalGammaGamma","TotalGammaGamma_plot",1750,0,4000,1750,0,4000); + TotalGammaGamma->SetDirectory(nullptr);//comment this out if you want to use this histogram + + //Create hist for addback gamma gamma + TH2F* AddBackGammaGamma = new TH2F("AddBackGammaGamma","AddBackGammaGamma_plot",1750,0,4000,1750,0,4000); + + //Create hist for alphaCut addback gamma gamm + TH2F* alphaCutAddBackGammaGamma = new TH2F("alphaCutAddBackGammaGamma","alphaCutAddBackGammaGamma_plot",1750,0,4000,1750,0,4000); + + //Create a hist to hold the 500MHz cfd source bits + TH1F* forcedTrigger500MHzBoard = new TH1F("forcedTrigger500MHzBoard","forcedTrigger500MHzBoard",11,-1,10); + + //Create hists for traces from each detector + TH2F* Traces[nLaBr3]; + for (int i = 0; i < nLaBr3; ++i) { + Traces[i] = new TH2F(Form("traces%02d", i),Form("traces - %02d", i), 600, 0, 300, 10000, 0, 10000); + } + + + + + //This reads in the alphaCuts root file + readAlphaCutsFile(alphaCutsFile, alphaCuts); + + + // Fill gamma energy histograms + Long64_t nentries = tree->GetEntries(); + for (Long64_t i = 0; i < nentries; ++i) { + tree->GetEntry(i); + //This fills the Raw (and wriggling!) germanium energy histograms + makeWrigglingGerm(tree,kMaxMulti,multi,detNum,e,RawGeEnergy); + + //This fills the calibrated Ge energy + makeCalGeEnergy(tree,kMaxMulti,multi,detNum,e,CalGeEnergy); + + //This fills the AddBack calibrated Ge Energy + makeAddBackGeEnergy(tree,kMaxMulti,multi,detNum,e,cloverNum,AddBackGeEnergy, includeDiagonals); + + //This fills the PIDs + //makePID(tree,kMaxMulti,NGAGG,multi,detNum,qdc,hPID,trinCoin); + + //This fills the BGOs + //makeBGO(tree,kMaxMulti,multi,detNum,e,BGOEnergy); + + //This fills the LaBr3 energy + makeLaBr3(tree, kMaxMulti, multi, detNum,e,LaBr3Energy,qdc); + + //This fills the Raw BEGe + makeRawBEGe(tree, kMaxMulti, multi, detNum,e,rawBEGe); + + //This fills the calibrated BEGe + //makeCalBEGe(tree, kMaxMulti, multi, detNum,e,calBEGe); + + //this fills the Compton suppressed Ge Energy hists + makeCompSupCalGeEnergy(tree,kMaxMulti,multi,detNum,e_t,e,CompSupCalGeEnergy,BGOGeTimeGate_ns); + + //This fills a compton suppressed gamma gamma matrix across all clovers] + //makeCompSupCalGammaGamma(tree,kMaxMulti,multi,detNum,e_t,e,CompSupGammaGamma,cloverNum,BGOGeTimeGate_ns); + + //This fills a compton suppressed gamma gamma matrix across all clovers with a Ge time cut cats + //makeCalGammaGamma(tree,kMaxMulti,multi,detNum,e_t,e,TotalGammaGamma,BGOGeTimeGate_ns); + + //This fills an addback'ed gamma gamma + //makeAddBackGammaGamma(tree,kMaxMulti,multi,detNum,e_t,e,AddBackGammaGamma,BGOGeTimeGate_ns,cloverNum,pileup); + + //This fills a time difference plot per clover + makeGeTimeDiff(tree,kMaxMulti,multi,detNum,e_t,e,GeTimeDiff,cloverNum,pileup); + + //This filles a time difference plot per labr pair + makeLabrTimeDiff(tree, kMaxMulti, multi, detNum, LabrTimeDiff, pileup, cfd, qdc, e_t); + + //This filles a time difference plot per labr pair vs the first labr energy of the pair found in event. + makeLabrTimeDiffvLabrEnergy(tree, kMaxMulti, multi, detNum, LabrTimeDiffvLabrEnergy, pileup, cfd, qdc, e_t); + + //This fills a Ge time difference plot regardless of detector/clover. This should just be the sum of the above. + makeTotalGeTimeDiff(tree,kMaxMulti,multi,detNum,e_t,e,TotalGeTimeDiff,cloverNum); + + //This fills a LaBr3 time difference plot regardless of detector. + makeTotalLaBr3TimeDiff(tree,kMaxMulti,multi,detNum,e_t,e,TotalLaBr3TimeDiff,cloverNum,cfd); + + //This files a BGO-Ge time diff plot regardless of detector + makeBGOGeTimeDiff(tree,kMaxMulti,multi,detNum,e_t,e,BGOGeTimeDiff,cloverNum); + + //This fills the alphacut addback gamma gamma mat + //makeAlphaCutAddBackGammaGamma(tree,kMaxMulti,multi,detNum,qdc,e_t,e,alphaCutAddBackGammaGamma,BGOGeTimeGate_ns,cloverNum,pileup,alphaCuts); + + //This fills the 500MHz board cfd source bits into a hist. Diagnostic to check if code is throwing some out. + makeCFDSourceBits(multi, detNum, forcedTrigger500MHzBoard, cfd); + + //This fills the traces histograms + makeTraces(multi, detNum, trace, Traces); + + + + //Progress Bar + if (i % (nentries / 100) == 0) { + float progress = (float)i / (float)nentries; + int pos = barWidth * progress; + + std::cout << "\r["; + for (int k = 0; k < barWidth; ++k) { + if (k < pos) + std::cout << "\033[42m \033[0m"; // Green fill + else + std::cout << "\033[41m \033[0m"; // Red space + } + std::cout << "] " << int(progress * 100.0) << "% " + << "\033[31m" << spinner[spinIdx++ % 4] << "\033[0m" << std::flush; + } + } + + //This makes a singles sum energy comp sup per clover + //makeCompSupCloverSumEnergy(CompSupCalGeEnergy, CompSupCloverSumEnergy); + + //******************************************************************************Cuts Being Applied here!!!!***************************************************** */ + + //This fills the alpha cut PIDs + //makeAlphaCutPID(hPID,alphaCuts, hPID_alpha); + + + + //Progress bar + std::cout << "\r["; + for (int k = 0; k < barWidth; ++k) + std::cout << "\033[42m \033[0m"; // Full green bar + std::cout << "] 100% \033[32m✓\033[0m\n" << std::endl; // Red checkmark + std::cout <<"\033[31mPlease wait for histograms to fill!!!!\033[0m\n"<Write(); + CompSupCalGeEnergy[i]->Write(); + //CalGeEnergy[i]->Write(); + } + //for (int i = 0; i < nClovers; ++i) { + //CompSupCloverSumEnergy[i]->Write(); + //} + //for (int i = 0; i < nClovers; ++i) { + //BGOEnergy[i]->Write(); + //} + for (int i = 0; i < nClovers; ++i) { + AddBackGeEnergy[i]->Write(); + } + //for (int i = 0; i < nZeroDeg; ++i) { + //ZeroDegEnergy[i]->Write(); + //} + //for (int i = 0; i < NGAGG; ++i) { + //hPID[i]->Write(); + //} + //for (int i = 0; i < NGAGG; ++i) { + //hPID_alpha[i]->Write(); + //} + for (int i = 0; i < nLaBr3; ++i) { + LaBr3Energy[i]->Write(); + //std::cout<<"I WROTE THE LABR"<Write(); + //calBEGe[i]->Write(); + } + for(int i = 0; iWrite(); + } + for(int i = 0; iWrite(); + LabrTimeDiffvLabrEnergy[i]->Write(); + } + for(int i = 0; iWrite(); + } + for(int i =0; iWrite(); + } + + TotalGeTimeDiff->Write(); + TotalLaBr3TimeDiff->Write(); + //CompSupGammaGamma->Write(); + //TotalGammaGamma->Write(); + AddBackGammaGamma->Write(); + //alphaCutAddBackGammaGamma->Write(); + forcedTrigger500MHzBoard->Write(); + outputFile->Close(); + + // Cleanup + delete outputFile; + + std::cout << "Histograms Saved!\n"; +} + +int main(int argc, char** argv){ + if (argc<12){ + std::cerr<<"Usage: "<" + <<" " + <<" " + <<" " + <<" " + <<" " + << " " + <<" " + <<" " + <<" " + <<" " + < " + exit 1 +fi + +INPUT_DIR="$1" +PARAM_FILE="$2" + +# Check inputs +if [ ! -d "$INPUT_DIR" ]; then + echo "Error: Directory '$INPUT_DIR' not found" + exit 1 +fi + +if [ ! -f "$PARAM_FILE" ]; then + echo "Error: Parameter file '$PARAM_FILE' not found" + exit 1 +fi + +# Loop over ROOT files +shopt -s nullglob +for rootfile in "$INPUT_DIR"/*.root; do + echo "==============================================" + echo "Processing file: $rootfile" + echo "==============================================" + + # Export so runJericho.sh can see it + export inputDataFile="$rootfile" + + ./runJericho.sh "$PARAM_FILE" + + if [ $? -ne 0 ]; then + echo "❌ Error processing $rootfile" + exit 1 + fi +done + +echo "✅ All files processed successfully" + +source "$PARAM_FILE" +baseName1=$(basename "$inputDataFile" .root) +outPutFileName="${baseName1}_total.root" + +echo "Summing outputs to $outPutFileName" + +./sumOutputs $outPutDirectory $outPutFileName diff --git a/JakeStuff/calNov2025.dat b/JakeStuff/calNov2025.dat new file mode 100644 index 0000000..d90b049 --- /dev/null +++ b/JakeStuff/calNov2025.dat @@ -0,0 +1,62 @@ +0 0 0 +1 0.151622084893127 0.173443485122107 +2 0.149201243550541 0.231056683126326 +3 0.14804661589375 0.169770867217949 +4 0.154385176354815 0.27436544374234 +5 0.156996807683194 0.178323431539184 +6 0.151970593107449 0.149664715074664 +7 0.157366291176101 0.0943410767629302 +8 0.151950563195605 0.429349574565322 +9 0.152799551941885 0.450677211593302 +10 0.152909822993851 0.10583086021586 +11 0.154785176118751 0.2176540784792 +12 0.377097681276902 0.293713618342281 +13 0.369625637976828 0.0450975373187248 +14 0.360359104078422 -0.0549249250103685 +15 0.184560138822004 0.205634627700078 +16 0.129858358137908 0.288412800590095 +17 0.129734152855513 0.0842495261921385 +18 0.147244056087955 0.362215099497121 +19 0.170507193874792 0.744583721620529 +20 0 0 +21 0 0 +22 0 0 +23 0 0 +24 0.151007730564431 0.14450957772317 +25 0.152332390096443 0.012267363587398 +26 0.151628884271249 0.241210618081368 +27 0.152223382618703 -0.120606015647013 +28 0.0900641957874339 0.253536788534348 +29 0.156188829257979 0.17264297616623 +30 0.0889002779233048 0.427281373831534 +31 0.090761895382639 0.120930296684151 +32 0.150371489501676 0.191981753896812 +33 0.152813923535495 0.28903652678639 +34 0.151090215214167 0.160266523659516 +35 0.14922170475795 0.506081115341317 +36 0.155933244367767 0.214521920092466 +37 0.162959149262104 0.159756894422344 +38 0.168371264918135 0.151474673261532 +39 0.154643360568817 0.0798072610447207 +40 0 0 +41 0 0 +42 0 0 +43 0 0 +44 0.283353567841564 -0.459332495547528 +45 0 0 +50 0.0315226 -29.335 +51 0.0315039 16.556 +52 0.030819 -3.884 +53 0.035185 -15.612 +54 0.040979 3.1206 +55 0.036493 -21.233 +56 0.034558 -20.139 +57 0 0 +58 0.026014 70.562 +59 0.031718 -162.467 +60 0.027734 -1.098 +61 0.026108 -0.702 +62 0.026403 28.185 +63 0.026531 12.483 +64 0 0 +65 0 0 \ No newline at end of file diff --git a/JakeStuff/drawTimeDiffHists.cpp b/JakeStuff/drawTimeDiffHists.cpp new file mode 100644 index 0000000..c725672 --- /dev/null +++ b/JakeStuff/drawTimeDiffHists.cpp @@ -0,0 +1,70 @@ + + +// Function for GeTimeDiff histograms with 00, 01, 02, ... naming +void drawGeTimeDiffHistograms(const char* filename) { + TFile* file = TFile::Open(filename, "READ"); + if (!file || file->IsZombie()) { + std::cerr << "Error: Cannot open file " << filename << std::endl; + return; + } + + std::vector histograms; + std::vector foundIndices; + + // Look for histograms with GeTimeDiff00, GeTimeDiff01, etc. + for (int i = 0; i < 66; i++) { + TString histName = Form("GeTimeDiff%02d", i); // %02d gives 00, 01, 02, etc. + TH1* hist = (TH1*)file->Get(histName); + if (hist) { + histograms.push_back(hist); + foundIndices.push_back(i); + std::cout << "Found: " << histName << std::endl; + } + } + + if (histograms.empty()) { + std::cerr << "No GeTimeDiff histograms found!" << std::endl; + file->Close(); + return; + } + + std::cout << "Found " << histograms.size() << " GeTimeDiff histograms" << std::endl; + + // Create canvas with appropriate divisions + int nCols = 11; + int nRows = 6; + TCanvas* canvas = new TCanvas("canvas", "GeTimeDiff Histograms", 1920, 1080); + canvas->Divide(nCols, nRows); + + // Draw histograms + for (int i = 0; i < histograms.size(); i++) { + canvas->cd(i + 1); + gPad->SetLeftMargin(0.12); + gPad->SetRightMargin(0.05); + gPad->SetTopMargin(0.1); + gPad->SetBottomMargin(0.12); + + gPad->SetLogy(); + + histograms[i]->Draw(); + + // Adjust text sizes for better visibility + histograms[i]->SetTitleSize(0.06, "t"); + histograms[i]->SetTitleSize(0.05, "x"); + histograms[i]->SetTitleSize(0.05, "y"); + histograms[i]->SetLabelSize(0.04, "x"); + histograms[i]->SetLabelSize(0.04, "y"); + + // Add histogram index as subtitle + histograms[i]->SetTitle(Form("GeTimeDiff%02d", foundIndices[i])); + } + + canvas->Update(); + canvas->SaveAs("GeTimeDiff_all.pdf"); + + std::cout << "Canvas saved as GeTimeDiff_all.png and GeTimeDiff_all.pdf" << std::endl; +} + +// Usage examples: +// root -l 'drawAllHistograms("yourfile.root")' +// root -l 'drawGeTimeDiffHistograms("yourfile.root")' \ No newline at end of file diff --git a/JakeStuff/gePromptGates.dat b/JakeStuff/gePromptGates.dat new file mode 100644 index 0000000..d03484b --- /dev/null +++ b/JakeStuff/gePromptGates.dat @@ -0,0 +1,66 @@ +0 -1 +1 -1 +2 -1 +3 100 +4 100 +5 100 +6 115 +7 -1 +8 -1 +9 -1 +10 -1 +11 -1 +12 125 +13 100 +14 125 +15 125 +16 125 +17 125 +18 150 +19 150 +20 150 +21 150 +22 150 +23 150 +24 125 +25 125 +26 200 +27 200 +28 200 +29 200 +30 -1 +31 -1 +32 -1 +33 -1 +34 -1 +35 -1 +36 -1 +37 -1 +38 -1 +39 -1 +40 -1 +41 -1 +42 100 +43 175 +44 130 +45 150 +46 140 +47 150 +48 130 +49 140 +50 130 +51 160 +52 100 +53 90 +54 150 +55 150 +56 150 +57 150 +58 150 +59 150 +60 -1 +61 -1 +62 -1 +63 -1 +64 -1 +65 -1 diff --git a/JakeStuff/geTimingPairFile.dat b/JakeStuff/geTimingPairFile.dat new file mode 100644 index 0000000..751b65c --- /dev/null +++ b/JakeStuff/geTimingPairFile.dat @@ -0,0 +1,66 @@ +0 1 0 +0 2 1 +0 3 2 +1 2 3 +1 3 4 +2 3 5 +4 5 6 +4 6 7 +4 7 8 +5 6 9 +5 7 10 +6 7 11 +8 9 12 +8 10 13 +8 11 14 +9 10 15 +9 11 16 +10 11 17 +12 13 18 +12 14 19 +12 15 20 +13 14 21 +13 15 22 +14 15 23 +16 17 24 +16 18 25 +16 19 26 +17 18 27 +17 19 28 +18 19 29 +20 21 30 +20 22 31 +20 23 32 +21 22 33 +21 23 34 +22 23 35 +24 25 36 +24 26 37 +24 27 38 +25 26 39 +25 27 40 +26 27 41 +28 29 42 +28 30 43 +28 31 44 +29 30 45 +29 31 46 +30 31 47 +32 33 48 +32 34 49 +32 35 50 +33 34 51 +33 35 52 +34 35 53 +36 37 54 +36 38 55 +36 39 56 +37 38 57 +37 39 58 +38 39 59 +40 41 60 +40 42 61 +40 43 62 +41 42 63 +41 43 64 +42 43 65 diff --git a/JakeStuff/jerichoTest.par b/JakeStuff/jerichoTest.par new file mode 100644 index 0000000..5966dd6 --- /dev/null +++ b/JakeStuff/jerichoTest.par @@ -0,0 +1,9 @@ +calFile=/home/jod23/software/XIAEventBuilder/JakeStuff/calNov2025.dat +gePromptGatesFile=/home/jod23/software/XIAEventBuilder/JakeStuff/gePromptGates.dat +outPutDirectory=/home/jod23/ +trinABCoin=0 +addbackDiagonals=0 +alphaCutsFileName=/home/jod23/software/XIAEventBuilder/JakeStuff/alphaCuts.root +geTimingPairFile=/home/jod23/software/XIAEventBuilder/JakeStuff/geTimingPairFile.dat +bgoTimeGateNS=250 +labrTimingPairFile=/home/jod23/software/XIAEventBuilder/JakeStuff/labrTimingPairFile.dat \ No newline at end of file diff --git a/JakeStuff/labrTimingPairFile.dat b/JakeStuff/labrTimingPairFile.dat new file mode 100644 index 0000000..4bdcdd2 --- /dev/null +++ b/JakeStuff/labrTimingPairFile.dat @@ -0,0 +1,120 @@ +0 1 0 +0 2 1 +0 3 2 +0 4 3 +0 5 4 +0 6 5 +0 7 6 +0 8 7 +0 9 8 +0 10 9 +0 11 10 +0 12 11 +0 13 12 +0 14 13 +0 15 14 +1 2 15 +1 3 16 +1 4 17 +1 5 18 +1 6 19 +1 7 20 +1 8 21 +1 9 22 +1 10 23 +1 11 24 +1 12 25 +1 13 26 +1 14 27 +1 15 28 +2 3 29 +2 4 30 +2 5 31 +2 6 32 +2 7 33 +2 8 34 +2 9 35 +2 10 36 +2 11 37 +2 12 38 +2 13 39 +2 14 40 +2 15 41 +3 4 42 +3 5 43 +3 6 44 +3 7 45 +3 8 46 +3 9 47 +3 10 48 +3 11 49 +3 12 50 +3 13 51 +3 14 52 +3 15 53 +4 5 54 +4 6 55 +4 7 56 +4 8 57 +4 9 58 +4 10 59 +4 11 60 +4 12 61 +4 13 62 +4 14 63 +4 15 64 +5 6 65 +5 7 66 +5 8 67 +5 9 68 +5 10 69 +5 11 70 +5 12 71 +5 13 72 +5 14 73 +5 15 74 +6 7 75 +6 8 76 +6 9 77 +6 10 78 +6 11 79 +6 12 80 +6 13 81 +6 14 82 +6 15 83 +7 8 84 +7 9 85 +7 10 86 +7 11 87 +7 12 88 +7 13 89 +7 14 90 +7 15 91 +8 9 92 +8 10 93 +8 11 94 +8 12 95 +8 13 96 +8 14 97 +8 15 98 +9 10 99 +9 11 100 +9 12 101 +9 13 102 +9 14 103 +9 15 104 +10 11 105 +10 12 106 +10 13 107 +10 14 108 +10 15 109 +11 12 110 +11 13 111 +11 14 112 +11 15 113 +12 13 114 +12 14 115 +12 15 116 +13 14 117 +13 15 118 +14 15 119 \ No newline at end of file diff --git a/JakeStuff/mappingNov2025.h b/JakeStuff/mappingNov2025.h new file mode 100644 index 0000000..5ac1739 --- /dev/null +++ b/JakeStuff/mappingNov2025.h @@ -0,0 +1,53 @@ +/************************************ +Clover : 0 - 99 +BGO : 100 - 199 +GAGG A : 200 - 299 +GAGG B : 300 - 399 +ZERO DEGREE : 400 - 499 +BEGE : 44 - 45 +LaBr3 : 500 - 599 + + * *********************************/ +#ifndef MAPPING +#define MAPPING + +//==================== mapping + +#define NCLOVER 11 +#define NCRYSTAL NCLOVER*4 +#define NBGO NCLOVER +#define NGAGG 26 +#define NZEROGAGG 2 ///NZERO is used + +//Help for people looking at this mapping: +//rows are pixie slots, colomns correspond to channels. Key for the first row: +//clover1_blue, clover1_black, clover1_green, clover1_red BGO1, clover2_blue, clover2_black, clover2_green, clover2_red, BGO2, clover3_blue, clover3_black, clover3_green, clover3_red, BGO3, EMPTY_CHANNEL + +//This also does not take the missing detectors into account, it assumes a detector in each channel. +int mapping[208] ={ +//***************** <-- load indicator for EventBuidler +//-0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 0, 1, 2, 3, 100, 4, 5, 6, 7, 101, 8, 9, 10, 11, 102, 44, //slot 2 + 12, 13, 14, 15, 103, 16, 17, 18, 19, 104, 20, 21, 22, 23, 105, 45, //slot 3 + 24, 25, 26, 27, 106, 28, 29, 30, 31, 107, 32, 33, 34, 35, 108, -1, //slot 4 + 36, 37, 38, 39, 109, 40, 41, 42, 43, 110, 400, 401, -1, -1, -1, -1, //slot 5 + 200, 300, 201, 301, 202, 302, 203, 303, 204, 304, 205, 305, 206, 306, 207, 307, //slot 6 Trinity ring 1 (A and B channels alternating) crystal 1 - 8 + 208, 308, 209, 309, 210, 310, 211, 311, 212, 312, 213, 313, 214, 314, 215, 315, //slot 7 Ring 2, A and B alternating crystal 1 - 8 + 216, 316, 217, 317, 218, 318, 219, 319, 220, 320, 221, 321, 222, 322, 223, 323, //slot 8 Ring 2 first 4 channels ( crystals 9 - 10 A and B ) the rest is Ring 3 crystals 1 - 6 alternating A and B + 224, 324, 225, 325, 226, 326, 227, 327, 228, 328, 229, 329, 230, 330, 231, 331, //slot 9 Ring 3 crystal 7 - 14 A and B alternating + 232, 332, 233, 333, 234, 334, 235, 335, 236, 336, 237, 337, 238, 338, 239, 339, //slot 10 Ring 4 crystals 1 - 8 + 240, 340, 241, 341, 242, 342, 243, 343, 244, 344, 245, 345, 246, 346, 247, 347, //slot 11 Ring 4 crystals 9 - 16 + 248, 348, 249, 349, 250, 350, 251, 351, 252, 352, 253, 353, 254, 354, 255, 355, //slot 12 Ring 5 crystals 1 - 8 + 256, 356, 257, 357, 258, 358, 259, 359, 260, 360, 261, 361, 262, 362, 263, 363, //slot 13 Ring 5 crystals 9 -16 + 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, //slot 14 LaBr3 +//**************** <-- end of mapping indicator EventBuidler +}; + +//200- 209 GAGG 2A +//210- 225 GAGG 4A + +//250- 259 GAGG 2B +//260- 275 GAGG 4B + + +#endif diff --git a/JakeStuff/runJericho.sh b/JakeStuff/runJericho.sh new file mode 100755 index 0000000..82e744d --- /dev/null +++ b/JakeStuff/runJericho.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +if [ $# -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +PARAM_FILE="$1" + +if [ ! -f "$PARAM_FILE" ]; then + echo "Error: File '$PARAM_FILE' not found!" + exit 1 +fi + +source "$PARAM_FILE" + +# Construct output filename from input +baseName=$(basename "$inputDataFile" .root) +outPutFileName="${baseName}_output.root" + +./Jericho "$inputDataFile" \ + "$calFile" \ + "$gePromptGatesFile" \ + "$outPutDirectory" \ + "$outPutFileName" \ + "$trinABCoin" \ + "$addbackDiagonals" \ + "$alphaCutsFileName" \ + "$geTimingPairFile" \ + "$bgoTimeGateNS" \ + "$labrTimingPairFile" diff --git a/JakeStuff/saveCuts.cpp b/JakeStuff/saveCuts.cpp new file mode 100644 index 0000000..4ff3274 --- /dev/null +++ b/JakeStuff/saveCuts.cpp @@ -0,0 +1,16 @@ +void saveAllCuts(const char* filename = "alphaCuts.root") { + TFile* f = new TFile(filename, "UPDATE"); + TIter next(gROOT->GetListOfSpecials()); + TObject* obj; + while ((obj = next())) { + if (obj->InheritsFrom("TCutG")) { + obj->Write("", TObject::kOverwrite); + std::cout << "Saved: " << obj->GetName() << std::endl; + } + } + f->Close(); + + + // Return to the originally attached file + if (_file0) _file0->cd(); +} \ No newline at end of file diff --git a/JakeStuff/sumOutputs b/JakeStuff/sumOutputs new file mode 100755 index 0000000..d519c67 Binary files /dev/null and b/JakeStuff/sumOutputs differ diff --git a/JakeStuff/sumOutputs.cpp b/JakeStuff/sumOutputs.cpp new file mode 100755 index 0000000..9d9023c --- /dev/null +++ b/JakeStuff/sumOutputs.cpp @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include // for setw + +void AddDir(TDirectory* src, TDirectory* dest) +{ + TIter next(src->GetListOfKeys()); + TKey* key; + + while ((key = (TKey*)next())) { + TObject* obj = key->ReadObj(); + + if (obj->InheritsFrom("TDirectory")) { + TDirectory* srcSub = (TDirectory*)obj; + TDirectory* destSub = + dest->GetDirectory(srcSub->GetName()); + + if (!destSub) + destSub = dest->mkdir(srcSub->GetName()); + + AddDir(srcSub, destSub); + } + else if (obj->InheritsFrom("TH1")) { + TH1* h = (TH1*)obj; + TH1* hsum = + (TH1*)dest->Get(h->GetName()); + + if (!hsum) { + hsum = (TH1*)h->Clone(); + hsum->SetDirectory(dest); + hsum->Sumw2(kTRUE); + } else { + hsum->Add(h); + } + hsum->SetOption("HIST"); + } + } +} + +// Simple text-based progress bar +void printProgress(int current, int total, int barWidth = 50) +{ + float progress = float(current) / total; + int pos = int(barWidth * progress); + + std::cout << "["; + for (int i = 0; i < barWidth; ++i) { + if (i < pos) std::cout << "="; + else if (i == pos) std::cout << ">"; + else std::cout << " "; + } + std::cout << "] " << int(progress * 100.0) << "%\r"; + std::cout.flush(); +} + +int main(int argc, char** argv) +{ + if (argc != 3) { + std::cerr << "Usage: " << argv[0] + << " \n"; + return 1; + } + + TString dir = argv[1]; + TString outName = argv[2]; // <-- now from command-line + + void* dirp = gSystem->OpenDirectory(dir); + if (!dirp) { + std::cerr << "Cannot open directory " + << dir << std::endl; + return 1; + } + + // Gather all ROOT files in a vector + std::vector files; + const char* entry; + while ((entry = gSystem->GetDirEntry(dirp))) { + TString fname(entry); + if (!fname.EndsWith(".root")) continue; + if (fname == outName) continue; // avoid overwriting output + files.push_back(fname); + } + gSystem->FreeDirectory(dirp); + + if (files.empty()) { + std::cerr << "No ROOT files found in directory." << std::endl; + return 1; + } + + TFile* fout = new TFile(dir + "/" + outName, "RECREATE"); + + // Loop over files with progress bar + int totalFiles = files.size(); + for (int i = 0; i < totalFiles; ++i) { + TString full = dir + "/" + files[i]; + TFile f(full, "READ"); + if (!f.IsZombie()) + AddDir(&f, fout); + f.Close(); + + printProgress(i + 1, totalFiles); + } + + fout->Write(); + fout->Close(); + + std::cout << std::endl << "Output written to " << dir + "/" + outName << std::endl; + return 0; +} diff --git a/README.md b/README.md index e6811e5..970e7ac 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Codes need to be compiled are in armory/ # Function of Programs ![Alt text](armory/programs_explain.png?raw=true "program explained") + # armory/DataBlock.h this is the source file for the class DataBlock, it stored all information from a single data block from pixie16 output. @@ -17,8 +18,11 @@ this is the source file for the class evtReader. It read the *.evt file (which is same as pixie16 output) and convert each measurement (or data block) from byte into meaningful data and use DataBlock class to store the information. It can also scan the evt file. +# armory/MergeEVT +this merges all evt files into *_raw.root. + # armory/EventBuilder -This builds events from *.evt files to *.root file. It by pass the *.to file. the default BUFFERSIZE is 1 million datablock. +this builds events from *_raw,root to *.root file # armory/evt2hist this processes evt file to hstograms. @@ -30,6 +34,9 @@ this build events from *.evt.to files to *.root file (need to check the compacta this sorting the time from *evt file to *.evt.to.fsu.XXX, where XXX is the time window. It will search data within XXX time window, if non of the data is from clover, discard. +# armory/xia2root +this is old evt to root for custom pixie DAQ. + # Analyzer.C/h this is a TSelector for analysis the *.root file diff --git a/armory/AutoFit.C b/armory/AutoFit.C index 14b7731..a84d95a 100644 --- a/armory/AutoFit.C +++ b/armory/AutoFit.C @@ -15,10 +15,6 @@ #include #include #include -#include -#include -#include -#include #include void showFitMethod(){ @@ -210,7 +206,7 @@ void GoodnessofFit(TH1F * hist, TF1 * fit){ double x = hist->GetBinCenter(i); double ybar = fit->Eval(x); ysq += y*y; - mean += y; + mean + y; SSR += (y - ybar)*(y-ybar); chisq += (y - ybar)*(y-ybar)/e/e; @@ -1955,7 +1951,7 @@ void saveFitPara(TString fileName = "AutoFit_para.txt"){ fprintf(file_out, "# for n-Gauss fit, can use \"#\", or \"//\" to comment out whole line\n"); fprintf(file_out, "# peak low high fixed? sigma_Max fixed? hight\n"); - for( int i = 0 ; i < (int) xPeakList.size() ; i++){ + for( int i = 0 ; i < xPeakList.size() ; i++){ fprintf(file_out, "%.3f %.3f %.3f 0 %.3f 0 %.0f\n", xPeakList[i], xPeakList[i] - 5*sigma[i], diff --git a/armory/DataBlock.h b/armory/DataBlock.h index 887ea2b..8e2ac81 100644 --- a/armory/DataBlock.h +++ b/armory/DataBlock.h @@ -77,7 +77,7 @@ public: } - void Print(bool printTrace = true){ + void Print(){ printf("============== eventID : %llu\n", eventID); printf("Crate: %d, Slot: %d, Ch: %d \n", crate, slot, ch); printf("HeaderLength: %d, Event Length: %d, energy: %d, timeStamp: %llu\n", headerLength, eventLength, energy, time); @@ -92,7 +92,7 @@ public: printf(" QDCsum : \n"); for( int i = 0; i < 8; i++) printf(" %-10d\n", QDCsum[i]); } - if( printTrace && eventLength > headerLength ){ + if( eventLength > headerLength ){ printf(" trace:\n"); for( int i = 0 ; i < trace_length ; i++)printf("%3d| %-10d\n",i, trace[i]); } diff --git a/armory/EventBuilder.cpp b/armory/EventBuilder.cpp index 63f6910..c174946 100644 --- a/armory/EventBuilder.cpp +++ b/armory/EventBuilder.cpp @@ -1,21 +1,8 @@ -/*================== - -Thie event builder both sort and build event. skip the *.to file. - -===================*/ - #include #include #include -#include +#include #include -#include -#include -#include /** struct timeval, select() */ -#include -#include -#include // for std::remove_if -#include // for std::isspace #include "TFile.h" #include "TTree.h" @@ -24,353 +11,170 @@ Thie event builder both sort and build event. skip the *.to file. #include "TStopwatch.h" #include "TTreeIndex.h" -std::string trimSpaces(const std::string& str); -std::vector split(const std::string& str, char delimiter); -unsigned int getTime_us(); -unsigned long long getTime_ns(); - -#include "evtReader.h" +#include "../mapping.h" #define MAXMULTI 100 -#define BUFFERSIZE 1000000 // number of time and filePos in buffer -#define DEBUG 0 int main(int argn, char **argv){ printf("=====================================\n"); - printf("=== Event Builder from *.evt ===\n"); + printf("=== Event Builder from *_raw.root ===\n"); printf("=====================================\n"); - if (argn < 6 ) { + if (argn != 2 && argn != 3 && argn != 4 ) { printf("Usage :\n"); - printf("%s [timeWindows] [mapping file] [Reject Flag] [QDC Flag] [SaveFileName] [*.evt File1] [*.evt File2] ...\n", argv[0]); - printf(" timeWindows [int]: 1 unit = 10 ns \n"); - printf(" mapping file path [str]: the path of mapping file. \n"); - printf(" Reject Flag [int]: 0 = no rejection. see mapping.h\n"); - printf(" 1 = reject BGO\n"); - printf(" 2 = reject no gamma\n"); - printf(" 4 = reject no GAGG\n"); - printf(" 8 = reject zero energy data-point\n"); - printf(" 3 = reject BGO + no gamma, 5 = reject BGO + no GAGG, etc.\n"); - printf(" QDC Flag [int]: 0 = no qdc, 1 = with qdc\n"); - printf(" SaveFileName [str]: custom save file name \n"); + printf("%s [_raw.root File] \n", argv[0]); + printf(" timeWindows : default = 100 \n"); + printf(" SaveFileName : default is *.root \n"); return 1; } - - int timeWindow = atoi(argv[1]); - TString mappingFilePath = argv[2]; - unsigned short rejectFlag = atoi(argv[3]); - unsigned short qdcFlag = atoi(argv[4]); - TString outFileName = argv[5]; - - std::vector inFileList; - for( int i = 6; i < argn; i++) inFileList.push_back(argv[i]); - - printf(" Mapping file Path : %s \n", mappingFilePath.Data()); - printf(" Time window : %d ticks\n", timeWindow); - printf(" Reject Flag : %u \n", rejectFlag); - printf(" outfile Name : %s \n", outFileName.Data()); - - printf("--------------- Number of in files %ld \n", inFileList.size()); - for( size_t i = 0; i < inFileList.size(); i++){ - printf("%2ld | %s \n", i, inFileList[i].c_str()); + + TString inFileName = argv[1]; // need to check name + int timeWindow = 100; + if( argn >= 3 ) timeWindow = atoi(argv[2]); + + printf(">>> Opening input %s \n", inFileName.Data()); + TFile * inFile = new TFile(inFileName, "READ"); + if( inFile->IsOpen() == false ) { + printf("!!!! cannot open file %s \n", inFileName.Data()); + return 0; } + + TTree * tree = (TTree *) inFile->Get("tree"); + + Long64_t evID; + UShort_t detID; + UShort_t energy; + ULong64_t energy_t; - if( rejectFlag > 0 ) printf("================================== Rejection Filter Conditions\n"); - if( ( rejectFlag & 0x1 ) ) printf("\033[31m !!!! Reject event with BGO !!!! \033[0m\n"); - if( ( rejectFlag & 0x2 ) ) printf("\033[31m !!!! Reject event w/o Clover !!!! \033[0m\n"); - if( ( rejectFlag & 0x4 ) ) printf("\033[31m !!!! Reject event w/o GAGG !!!! \033[0m\n"); - if( ( rejectFlag & 0x8 ) ) printf("\033[31m !!!! Reject Zero-Energy Data Point !!!! \033[0m\n"); - if( rejectFlag > 0 ) printf(" Rejection filter does not apply to the last event when timeWindow >= 0 \n"); - printf("================================== Digesting Mapping file\n"); + TBranch *b_data_ID; //! + TBranch *b_ID; //! + TBranch *b_energy; //! + TBranch *b_energy_timestamp; //! - std::ifstream mapFile( mappingFilePath.Data() ); - - int mapping[16*12]; // fixed to be 12 digitizers - for( int i = 0; i < 16*12 ; i++ ) mapping[i] = -1; - - if( !mapFile.is_open() ){ - printf("Cannot open mapping file : %s. Skip. \n", mappingFilePath.Data()); - }else{ - - int index = 0; - bool startMap = false; - std::string line; - while( std::getline(mapFile, line) ){ - // printf("|%s|\n", line.c_str()); - if( line.find("//-") != std::string::npos ) continue; - if( line.find("<--") != std::string::npos ){ - startMap = true; - continue; - } - - if( startMap && line.find("<--") != std::string::npos ) break; - if( startMap ){ - std::vector list = split(line, ','); - for( size_t k = 0; k < list.size(); k ++ ){ - if( list[k].find("//") != std::string::npos || k >= 16 ) continue; - // printf("%ld | %s \n", k, list[k].c_str()); - mapping[index] = atoi(list[k].c_str()); - index ++; - } - - } - } - mapFile.close(); - } - - //---- print mapping; - for( int i = 0; i < 16*11; i++){ - if( i % 16 == 0 ) printf("Mod-%02d | ", i/16); - if( mapping[i] < 0 ) printf("%4d,", mapping[i]); - if( 0 <= mapping[i] && mapping[i] < 100 ) printf("\033[31m%4d\033[0m,", mapping[i]); - if( 100 <= mapping[i] && mapping[i] < 200 ) printf("\033[34m%4d\033[0m,", mapping[i]); - if( 200 <= mapping[i] && mapping[i] < 300 ) printf("\033[32m%4d\033[0m,", mapping[i]); - if( 300 <= mapping[i] && mapping[i] < 400 ) printf("\033[35m%4d\033[0m,", mapping[i]); - if( i % 16 == 15 ) printf("\n"); - } - - - printf("================================== Creating Tree\n"); + tree->SetBranchAddress("evID", &evID, &b_data_ID); + tree->SetBranchAddress("id", &detID, &b_ID); + tree->SetBranchAddress("e", &energy, &b_energy); + tree->SetBranchAddress("e_t", &energy_t, &b_energy_timestamp); + + Long64_t totnumEntry = tree->GetEntries(); + + printf(" total Entry : %lld \n", totnumEntry); + printf(" event Build window: %d tick = %d nsec \n", timeWindow, timeWindow * 10); + + printf(">>> Buidling Index using the timestamp\n"); + tree->BuildIndex("e_t"); + TTreeIndex *in = (TTreeIndex*) tree->GetTreeIndex(); + Long64_t * index = in->GetIndex(); + + ULong64_t time0; //time-0 for each event + int timeDiff; + + TString outFileName = inFileName; + outFileName.Remove(inFileName.First("_raw")); + outFileName.Append(".root"); + if( argn >=4 ) outFileName = argv[3]; + + printf(">>> out File name : \033[1;31m%s\033[m\n", outFileName.Data()); + printf(">>> Create output tree\n"); TFile * saveFile = new TFile(outFileName, "recreate"); + saveFile->cd(); TTree * newtree = new TTree("tree", outFileName); - UInt_t eventID = 0 ; - UInt_t multi = 0; /// this is total multipicilty for all detectors - newtree->Branch("multi", &multi, "multi/i"); - newtree->Branch("evID", &eventID, "event_ID/i"); + Int_t eventID = 0 ; + Int_t multi = 0; /// this is total multipicilty for all detectors + newtree->Branch("multi", &multi, "multi/I"); + + + newtree->Branch("evID", &eventID, "event_ID/l"); - // Int_t multiCry = 0 ; /// thi is total multiplicity for all crystal - // newtree->Branch("multiCry", &multiCry, "multiplicity_crystal/I"); + Int_t multiCry = 0 ; /// thi is total multiplicity for all crystal + newtree->Branch("multiCry", &multiCry, "multiplicity_crystal/I"); - UInt_t id[MAXMULTI] = {0}; - Int_t e[MAXMULTI] = {-1}; + int id[MAXMULTI] = {0}; + double e[MAXMULTI] = {TMath::QuietNaN()}; ULong64_t e_t[MAXMULTI] = {0}; - UInt_t qdc[MAXMULTI][8] = {0}; - newtree->Branch("id", id, "id[multi]/i" ); - newtree->Branch("e", e, "e[multi]/I" ); + newtree->Branch("id", id, "id[multi]/I" ); + newtree->Branch("e", e, "e[multi]/D" ); newtree->Branch("e_t", e_t, "e_timestamp[multi]/l"); - if( qdcFlag ) newtree->Branch("qdc", qdc, "qdc[multi][8]/I"); - - - saveFile->cd(); - + printf("================== Start processing....\n"); Float_t Frac = 0.05; ///Progress bar TStopwatch StpWatch; StpWatch.Start(); - std::vector hitList; - evtReader * reader = nullptr; - std::vector event; - event.clear(); - unsigned long int totalBlock; - unsigned long int blockCount = 0 ; - - unsigned long long tStart = 0; - unsigned long long tEnd = 0; - - unsigned int runStartTime = getTime_us(); - - for( size_t i = 0 ; i < inFileList.size(); i++){ - - reader = new evtReader(inFileList[i]); - reader->ScanNumberOfBlock(); - totalBlock = reader->GetNumberOfBlock(); - blockCount = 0; - - do{ - - hitList = reader->ReadBatchPos(BUFFERSIZE, DEBUG); - blockCount += hitList.size(); - // std::cout << "please wait....."; - printf("File-%ld %10lu block %10lu / %lu [%4.1f%%] | %u \r", i, hitList.size(), blockCount, totalBlock, blockCount*100./totalBlock, eventID); - fflush(stdout); - if( hitList.size() == 0 ) break; - - for( size_t k = 0; k < hitList.size(); k++ ){ - - reader->ReadBlockAtPos(hitList[k].inFilePos); - - if( eventID == 0 ) tStart = reader->data->time; - - if( event.size() == 0 ) { - - event.push_back(*(reader->data)); - - if( timeWindow < 0 ) { // no event build - multi = 1; - int index = event[0].crate*MAX_BOARDS_PER_CRATE*MAX_CHANNELS_PER_BOARD + (event[0].slot-BOARD_START)*MAX_CHANNELS_PER_BOARD + event[0].ch; - id[0] = mapping[index]; - e[0] = event[0].energy; - e_t[0] = event[0].time; - - if( qdcFlag ) for( int i = 0; i < 8; i++) qdc[0][i] = event[0].QDCsum[i]; - - if( DEBUG ){ - printf("====================== event %u, event size %u\n", eventID, multi); - printf("%6d, %12llu \n", event[0].energy, event[0].time); - } - - if( (rejectFlag & 0x8 ) && e[0] == 0 ) { - event.clear(); - continue; - } - - saveFile->cd(); - newtree->Fill(); - eventID ++; - - event.clear(); - } - - continue; - - }else{ - - if( hitList[k].time - event.front().time <= timeWindow ){ - event.push_back(*(reader->data)); - }else{ - - //save event - if( DEBUG ) printf("====================== event %u, event size %lu\n", eventID, event.size()); - - int nBGO = 0; - int nClover = 0; - int nGagg = 0; - - int count = 0 ; - for( size_t p = 0; p < event.size(); p++ ) { - if( (rejectFlag & 0x8 ) && event[p].energy == 0 ) continue; - - e[count] = event[p].energy; - e_t[count] = event[p].time; - int index = event[p].crate*MAX_BOARDS_PER_CRATE*MAX_CHANNELS_PER_BOARD + (event[p].slot-BOARD_START)*MAX_CHANNELS_PER_BOARD + event[p].ch; - id[count] = mapping[index]; - if( qdcFlag ) for( int i = 0; i < 8; i++) qdc[count][i] = event[p].QDCsum[i]; - - if( DEBUG ) printf("%u | %3d, %6d, %12llu \n", count, id[count], e[count], e_t[count]); - if( 0 <= id[count] && id[count] < 100 ) nClover ++; - if( 100 <= id[count] && id[count] < 200 ) nBGO ++; - if( 200 <= id[count] && id[count] < 400 ) nGagg ++; - count ++; - } - - multi = count; - - if( DEBUG ) printf("nBGO %d, nClover %d, nGagg %d \n", nBGO, nClover, nGagg); - - if( (rejectFlag & 0x1) && nBGO > 0 ) { - event.clear(); - event.push_back(*(reader->data)); - continue; - } - - if( (rejectFlag & 0x2) && nClover == 0 ) { - event.clear(); - event.push_back(*(reader->data)); - continue; - } - - if( (rejectFlag & 0x4) && nGagg == 0 ) { - event.clear(); - event.push_back(*(reader->data)); - continue; - } - - if( multi > 0 ){ - if( DEBUG ) printf("---------------> fill tree\n"); - saveFile->cd(); - newtree->Fill(); - eventID ++; - } - - //clear event - event.clear(); - event.push_back(*(reader->data)); - - } - } - - } - - }while(true); - - tEnd = reader->data->time; - delete reader; - } - - //save the last event - if( timeWindow >= 0 ){ - multi = event.size(); - for( size_t p = 0; p < multi; p++ ) { - if( DEBUG ) printf("%lu | %6d, %12llu \n", p, event[p].energy, event[p].time); - int index = event[p].crate*MAX_BOARDS_PER_CRATE*MAX_CHANNELS_PER_BOARD + (event[p].slot-BOARD_START)*MAX_CHANNELS_PER_BOARD + event[p].ch; - id[p] = mapping[index]; - e[p] = event[p].energy; - e_t[p] = event[p].time; - if( qdcFlag ) for( int i = 0; i < 8; i++) qdc[p][i] = event[p].QDCsum[i]; + int multiOverflow = 0; + + for( Long64_t entry = 0; entry < totnumEntry; entry++){ + + /*********** Progress Bar ******************************************/ + if (entry>totnumEntry*Frac-1) { + TString msg; msg.Form("%llu", totnumEntry/1000); + int len = msg.Sizeof(); + printf(" %3.0f%% (%*llu/%llu k) processed in %6.1f sec | expect %6.1f sec\n", + Frac*100, len, entry/1000,totnumEntry/1000,StpWatch.RealTime(), StpWatch.RealTime()/Frac); + StpWatch.Start(kFALSE); + Frac+=0.1; + } + + Long64_t ev = index[entry]; + + b_ID->GetEntry(ev, 0); + b_energy->GetEntry(ev, 0); + b_energy_timestamp->GetEntry(ev, 0); + + if( time0 == 0) { + time0 = energy_t; + multi = 0; + } + timeDiff = (int) (energy_t - time0); + + if( timeDiff < timeWindow ) { + + if( multi > MAXMULTI ){ + multiOverflow++; + }else{ + id[multi] = detID; + e[multi] = energy; + e_t[multi] = energy_t; + multi ++; + if( detID < NCRYSTAL ) multiCry++; + } + }else{ + ///---- end of event + saveFile->cd(); + newtree->Fill(); + eventID ++; + + ///---- clear data + for( int i = 0; i < MAXMULTI ; i ++){ + id[i] = 0; + e[i] = TMath::QuietNaN(); + e_t[i] = 0; + } + multi = 0; + multiCry = 0; + + + /// fill 1st data of an event + time0 = energy_t; + timeDiff = 0; + + id[multi] = detID; + e[multi] = energy; + e_t[multi] = energy_t; + multi++; + if( detID < NCRYSTAL ) multiCry++; } - saveFile->cd(); - newtree->Fill(); - eventID ++; } + printf("============================== finished.\n"); + + saveFile->cd(); newtree->Write(); - - unsigned int runEndTime = getTime_us(); - double runTime = (runEndTime - runStartTime) * 1e-6; - printf("========================================= finished.\n"); - printf(" event building time = %.2f sec = %.2f min\n", runTime, runTime/60.); - printf(" total events built = %u by event builder (%llu in tree)\n", eventID , newtree->GetEntriesFast()); - double tDuration_sec = (tEnd - tStart) * 1e-9; - printf(" first timestamp = %20llu ns\n", tStart); - printf(" last timestamp = %20llu ns\n", tEnd); - printf(" total data duration = %.2f sec = %.2f min\n", tDuration_sec, tDuration_sec/60.); - printf("==============> saved to %s \n", outFileName.Data()); - - // TMacro info; - // info.AddLine(Form("tStart= %20llu ns",tStart)); - // info.AddLine(Form(" tEnd= %20llu ns",tEnd)); - // info.Write("info"); - saveFile->Close(); - - - return 0; + + printf(" total number of event Built : %d \n", eventID); + printf(" total event has multi > %6d : %d \n", MAXMULTI, multiOverflow); } - - -unsigned int getTime_us(){ - unsigned int time_us; - struct timeval t1; - struct timezone tz; - gettimeofday(&t1, &tz); - time_us = (t1.tv_sec) * 1000 * 1000 + t1.tv_usec; - return time_us; -} - -unsigned long long getTime_ns(){ - std::chrono::high_resolution_clock::time_point currentTime = std::chrono::high_resolution_clock::now(); - std::chrono::nanoseconds nanoseconds = std::chrono::duration_cast(currentTime.time_since_epoch()); - return nanoseconds.count(); -} - -std::string trimSpaces(const std::string& str) { - std::string trimmed = str; - trimmed.erase(std::remove_if(trimmed.begin(), trimmed.end(), ::isspace), trimmed.end()); - return trimmed; -} - -std::vector split(const std::string& str, char delimiter) { - std::vector tokens; - std::stringstream ss(str); - std::string token; - - while (std::getline(ss, token, delimiter)) { - tokens.push_back(trimSpaces(token)); - } - - return tokens; -} \ No newline at end of file diff --git a/armory/EventBuilder_seperated.cpp b/armory/EventBuilder_seperated.cpp new file mode 100644 index 0000000..45fd3cf --- /dev/null +++ b/armory/EventBuilder_seperated.cpp @@ -0,0 +1,206 @@ +#include +#include +#include +#include +#include + +#include "TFile.h" +#include "TTree.h" +#include "TMath.h" +#include "TBenchmark.h" +#include "TStopwatch.h" +#include "TTreeIndex.h" + +#include "../mapping.h" + +Int_t eventID = 0 ; +double e[NCRYSTAL]; +ULong64_t e_t[NCRYSTAL]; +double bgo[NBGO]; +ULong64_t bgo_t[NBGO]; +Short_t other[NOTHER]; +Short_t multi; + +void ClearTreeData(){ + + for( int i = 0; i < NCRYSTAL; i++){ + e[i] = TMath::QuietNaN(); + e_t[i] = 0; + //pileup[i] = 0; + //hit[i] = 0; + } + for( int i = 0; i < NBGO; i++) { + bgo[i] = TMath::QuietNaN(); + bgo_t[i] = 0 ; + } + for( int i = 0; i < NOTHER; i++) { + other[i] = TMath::QuietNaN(); + } + multi = 0; +} + +int main(int argn, char **argv){ + printf("=====================================\n"); + printf("=== Event Builder ===\n"); + printf("=====================================\n"); + + if (argn != 2 && argn != 3 && argn != 4 ) { + printf("Usage :\n"); + printf("%s [_raw.root File] \n", argv[0]); + printf(" timeWindows : default = 100 \n"); + printf(" SaveFileName : default is *.root \n"); + return 1; + } + + TString inFileName = argv[1]; // need to check name + int timeWindow = 100; + if( argn >= 3 ) timeWindow = atoi(argv[2]); + + printf(">>> Opening input %s \n", inFileName.Data()); + TFile * inFile = new TFile(inFileName, "READ"); + if( inFile->IsOpen() == false ) { + printf("!!!! cannot open file %s \n", inFileName.Data()); + return 0; + } + + TTree * tree = (TTree *) inFile->Get("tree"); + + Long64_t evID; + UShort_t detID; + UShort_t energy; + ULong64_t energy_t; + + TBranch *b_data_ID; //! + TBranch *b_ID; //! + TBranch *b_energy; //! + TBranch *b_energy_timestamp; //! + + tree->SetBranchAddress("evID", &evID, &b_data_ID); + tree->SetBranchAddress("id", &detID, &b_ID); + tree->SetBranchAddress("e", &energy, &b_energy); + tree->SetBranchAddress("e_t", &energy_t, &b_energy_timestamp); + + Long64_t totnumEntry = tree->GetEntries(); + + printf( "total Entry : %lld \n", totnumEntry); + + printf(">>> Buidling Index using the timestamp\n"); + tree->BuildIndex("e_t"); + TTreeIndex *in = (TTreeIndex*) tree->GetTreeIndex(); + Long64_t * index = in->GetIndex(); + + ULong64_t time0; //time-0 for each event + int timeDiff; + + + TString outFileName = inFileName; + outFileName.Remove(inFileName.First("_raw")); + outFileName.Append(".root"); + if( argn >=4 ) outFileName = argv[3]; + + printf(">>> out File name : %s\n", outFileName.Data()); + + printf(">>> Create output tree\n"); + TFile * saveFile = new TFile(outFileName, "recreate"); + saveFile->cd(); + TTree * newtree = new TTree("tree", "tree"); + + newtree->Branch("evID", &eventID, "event_ID/l"); + newtree->Branch("e", e, Form("e[%d]/D", NCRYSTAL)); + newtree->Branch("e_t", e_t, Form("e_timestamp[%d]/l", NCRYSTAL)); + //newtree->Branch("p", pileup, Form("pile_up_flag[%d]/s", NCRYSTAL)); + //newtree->Branch("hit", hit, Form("hit[%d]/s", NCRYSTAL)); + + newtree->Branch("bgo", bgo, Form("BGO_e[%d]/D", NBGO)); + newtree->Branch("bgo_t", bgo_t, Form("BGO_timestamp[%d]/l", NBGO)); + + newtree->Branch("other", other, Form("other_e[%d]/D", NOTHER)); + + newtree->Branch("multi", &multi, "multiplicity_crystal/I"); + + ClearTreeData(); + + printf("================== Start processing....\n"); + Float_t Frac = 0.1; ///Progress bar + TStopwatch StpWatch; + StpWatch.Start(); + eventID = 0; + + for( Long64_t entry = 0; entry < totnumEntry; entry++){ + + + /*********** Progress Bar ******************************************/ + if (entry>totnumEntry*Frac-1) { + TString msg; msg.Form("%llu", totnumEntry/1000); + int len = msg.Sizeof(); + printf(" %3.0f%% (%*llu/%llu k) processed in %6.1f sec | expect %6.1f sec\n", + Frac*100, len, entry/1000,totnumEntry/1000,StpWatch.RealTime(), StpWatch.RealTime()/Frac); + StpWatch.Start(kFALSE); + Frac+=0.1; + } + + entry = index[entry]; + + b_ID->GetEntry(entry); + b_energy->GetEntry(entry); + b_energy_timestamp->GetEntry(entry); + + if( time0 == 0) time0 = energy_t; + timeDiff = (int) (energy_t - time0); + + if( timeDiff < timeWindow ) { + + if ( detID < NCRYSTAL ){ + e[detID] = energy; + e_t[detID] = energy_t; + multi++; + } + if ( 100 <= detID && detID < 100 + NBGO ){ + bgo[detID-100] = energy; + bgo_t[detID-100] = energy_t; + } + if ( 200 <= detID && detID < 200 + NOTHER){ + other[detID-200] = energy; + } + + //printf("%d | %3d %6d %10llu, %3d\n", multi, detID, energy, energy_t, timeDiff); + + }else{ + //---- end of event + eventID ++; + + saveFile->cd(); + newtree->Fill(); + + ClearTreeData(); + + /// fill 1st data of an event + time0 = energy_t; + timeDiff = 0; + + if ( detID < NCRYSTAL ){ + e[detID] = energy; + e_t[detID] = energy_t; + multi = 1; + } + if ( 100 <= detID && detID < 100 + NBGO ){ + bgo[detID-100] = energy; + bgo_t[detID-100] = energy_t; + } + if ( 200 <= detID && detID < 200 + NOTHER){ + other[detID-200] = energy; + } + + } + + } + + printf("============================== finished.\n"); + + saveFile->cd(); + newtree->Write(); + saveFile->Close(); + + printf(" total number of event Built : %d \n", eventID); + +} diff --git a/armory/MergeEVT.cpp b/armory/MergeEVT.cpp new file mode 100644 index 0000000..ae58511 --- /dev/null +++ b/armory/MergeEVT.cpp @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include "TFile.h" +#include "TTree.h" +#include "TString.h" +#include "TMath.h" +#include "TBenchmark.h" +#include + +#define MAX_CRATES 2 +#define MAX_BOARDS_PER_CRATE 13 +#define MAX_CHANNELS_PER_BOARD 16 +#define BOARD_START 2 + +#include "../mapping.h" +#include "../armory/DataBlock.h" +#include "../armory/evtReader.h" + +//############################################# +// main +//############################################# +int main(int argn, char **argv) { + + printf("=====================================\n"); + printf("=== evt --> _raw.root ===\n"); + printf("=====================================\n"); + + if (argn < 3 ) { + printf("Usage :\n"); + printf("%s [outFile] [evt1] [evt2] [evt3] ..... \n", argv[0]); + printf("e.g.: \n"); + printf("%s hahaha_raw.root haha-000.evt haha-001.evt haha-002.evt\n", argv[0]); + printf("%s hahaha_raw.root `ls haha-*.evt`\n", argv[0]); + return 1; + } + + TString outFileName = argv[1]; + int nFiles = argn-2; + TString inFileName[nFiles]; + for( int i = 0; i < nFiles ; i++){ + inFileName[i] = argv[i+2]; + printf(" in file - %2d: %s\n", i, inFileName[i].Data()); + } + + printf(" out file: %s\n", outFileName.Data()); + + + evtReader * evt = new evtReader(); + DataBlock * data = evt->data; + short detID; + printf("====================================\n"); + + //====== ROOT file + TFile * outFile = new TFile(outFileName, "recreate"); + TTree * tree = new TTree("tree", "tree"); + + tree->Branch("evID", &data->eventID, "data_ID/L"); + tree->Branch("detID", &detID, "detID/s"); + tree->Branch("e", &data->energy, "crystal_energy/s"); + tree->Branch("e_t", &data->time, "crystal_timestamp/l"); + tree->Branch("p", &data->pileup, "pileup/O"); + tree->Branch("trace_length", &data->trace_length, "trace_length/s"); + tree->Branch("trace", data->trace, "trace[trace_length]/s"); + + TBenchmark gClock; + gClock.Reset(); + gClock.Start("timer"); + + //========================================= + //========================================= + //========================================= + //========================================= + for( int i = 0; i < nFiles; i++){ + + evt->OpenFile(inFileName[i]); + if( evt->IsOpen() == false ) continue; + + Long64_t measureCount = 0; + printf("\033[1;31mProcessing file: %s\033[0m\n", inFileName[i].Data()); + TBenchmark clock2; + clock2.Reset(); + clock2.Start("timer"); + + evt->ScanNumberOfBlock(); + + //=============== Read File + while( evt->IsEndOfFile() == false ){ + + evt->ReadBlock(); + //evt->PrintStatus(10000); + + int id = data->crate*MAX_BOARDS_PER_CRATE*MAX_CHANNELS_PER_BOARD + (data->slot-BOARD_START)*MAX_CHANNELS_PER_BOARD + data->ch; + detID = mapping[id]; + + //cern fill tree + outFile->cd(); + tree->Fill(); + } + + clock2.Stop("timer"); + double time = clock2.GetRealTime("timer"); + float tempf = (float)evt->GetFilePos()/(1024.*1024.*1024.); + printf(" measurements: \x1B[32m%lld \x1B[0m | %.3f GB\n", evt->GetBlockID(), tempf); + printf(" Time used:%3.0f min %5.2f sec\n", TMath::Floor(time/60.), time - TMath::Floor(time/60.)*60.); + printf(" Root file size so far: %.4f GB\n", outFile->GetSize()/1024./1024./1024.); + + } + + gClock.Stop("timer"); + double time = gClock.GetRealTime("timer"); + gClock.Start("timer"); + float tempf = (float)evt->GetFilePos()/(1024.*1024.*1024.); + printf("Total measurements: \x1B[32m%lld \x1B[0m\nPercent Complete: \x1B[32m%ld%% of %.3f GB\x1B[0m\nTime used:%3.0f min %5.2f sec\033[A\r", + evt->GetBlockID()+1, (100*evt->GetFilePos()/evt->GetFileSize()), tempf, TMath::Floor(time/60.), time - TMath::Floor(time/60.)*60.); + + + //cern save root + outFile->cd(); + double totRootSize = outFile->GetSize()/1024./1024./1024.; + tree->Write(); + outFile->Close(); + + gClock.Stop("timer"); + 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.); + printf(" File size of %s : %.3f GB \n", outFileName.Data(), totRootSize); + +} diff --git a/armory/XIAEventBuilder.excalidraw b/armory/XIAEventBuilder.excalidraw index 42742d8..32d11dd 100644 --- a/armory/XIAEventBuilder.excalidraw +++ b/armory/XIAEventBuilder.excalidraw @@ -4,30 +4,26 @@ "source": "https://excalidraw.com", "elements": [ { - "type": "rectangle", - "version": 315, - "versionNonce": 1719979265, - "index": "a0", - "isDeleted": false, "id": "F7K7zMR1U55-x1Y0zNheF", + "type": "rectangle", + "x": 911.1777777777761, + "y": 115, + "width": 217, + "height": 49.296296296296305, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, - "angle": 0, - "x": 911.1777777777761, - "y": 115, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 217, - "height": 49.296296296296305, - "seed": 1288944801, "groupIds": [], - "frameId": null, - "roundness": { - "type": 1 - }, + "strokeSharpness": "round", + "seed": 1288944801, + "version": 313, + "versionNonce": 1380621359, + "isDeleted": false, "boundElements": [ { "type": "text", @@ -37,77 +33,74 @@ "id": "wVuMtUwvQDwX0zsvknEbS", "type": "arrow" }, + { + "id": "j2LC8-0hrLNZXTpYAtx19", + "type": "arrow" + }, { "id": "v0ZCxQCjw27_GScx0D8wJ", "type": "arrow" } ], - "updated": 1717007561924, + "updated": 1647819194534, "link": null, - "locked": false + "fontSize": 24.97113665389526, + "baseline": 30.296296296296305 }, { - "type": "text", - "version": 420, - "versionNonce": 866820495, - "index": "a1", - "isDeleted": false, "id": "a-Y-OVWiKnXczi4Nhg3-k", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, + "type": "text", "x": 916.1777777777761, "y": 124.14814814814815, - "strokeColor": "#000000", - "backgroundColor": "transparent", "width": 207, "height": 31, - "seed": 307235695, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1717007549844, - "link": null, - "locked": false, - "fontSize": 24.97113665389526, - "fontFamily": 1, - "text": "*.evt", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "F7K7zMR1U55-x1Y0zNheF", - "originalText": "*.evt", - "autoResize": true, - "lineHeight": 1.2414332767332916 - }, - { - "type": "rectangle", - "version": 274, - "versionNonce": 720716513, - "index": "a2", - "isDeleted": false, - "id": "soHz1JXys4CcGsQ3wYg0G", + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, - "angle": 0, + "groupIds": [], + "strokeSharpness": "sharp", + "seed": 307235695, + "version": 419, + "versionNonce": 111582319, + "isDeleted": false, + "boundElements": null, + "updated": 1647819196222, + "link": null, + "text": "*.evt", + "fontSize": 24.97113665389526, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 22, + "containerId": "F7K7zMR1U55-x1Y0zNheF", + "originalText": "*.evt" + }, + { + "id": "soHz1JXys4CcGsQ3wYg0G", + "type": "rectangle", "x": 725.4370370370365, "y": 291.659259259259, - "strokeColor": "#000000", - "backgroundColor": "transparent", "width": 217.79999999999995, "height": 62.7407407407408, - "seed": 784122305, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, "groupIds": [], - "frameId": null, - "roundness": { - "type": 1 - }, + "strokeSharpness": "round", + "seed": 784122305, + "version": 273, + "versionNonce": 949300495, + "isDeleted": false, "boundElements": [ { "type": "text", @@ -126,40 +119,41 @@ "type": "arrow" } ], - "updated": 1717007549844, + "updated": 1647818401509, "link": null, - "locked": false + "fontSize": 24.971673819742485, + "baseline": 43.7407407407408 }, { - "type": "rectangle", - "version": 452, - "versionNonce": 471701423, - "index": "a3", - "isDeleted": false, "id": "lVG_kdGInlSn8Z2rog8y_", + "type": "rectangle", + "x": 904.5925925925924, + "y": 489.6592592592576, + "width": 217.79999999999995, + "height": 62.7407407407408, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, - "angle": 0, - "x": 904.5925925925924, - "y": 489.6592592592576, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 217.79999999999995, - "height": 62.7407407407408, - "seed": 678994785, "groupIds": [], - "frameId": null, - "roundness": { - "type": 1 - }, + "strokeSharpness": "round", + "seed": 678994785, + "version": 451, + "versionNonce": 1100843809, + "isDeleted": false, "boundElements": [ { "id": "BrUYg7L4kzqjcJN7o7PEr", "type": "text" }, + { + "type": "text", + "id": "BrUYg7L4kzqjcJN7o7PEr" + }, { "id": "cVfBGP1caGY3pgFvecDal", "type": "arrow" @@ -177,36 +171,37 @@ "type": "arrow" } ], - "updated": 1717007549844, + "updated": 1647818401509, "link": null, - "locked": false + "fontSize": 24.971673819742485, + "baseline": 43.7407407407408 }, { - "type": "rectangle", - "version": 562, - "versionNonce": 1877753537, - "index": "a4", - "isDeleted": false, "id": "75BzEnWMBt8CyzY_59Z5z", + "type": "rectangle", + "x": 1043.5925925925924, + "y": 733.6592592592576, + "width": 218, + "height": 72, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, - "angle": 0, - "x": 1043.5925925925924, - "y": 733.6592592592576, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 218, - "height": 72, - "seed": 492968513, "groupIds": [], - "frameId": null, - "roundness": { - "type": 1 - }, + "strokeSharpness": "round", + "seed": 492968513, + "version": 561, + "versionNonce": 3329583, + "isDeleted": false, "boundElements": [ + { + "id": "MtjqdHYBc5PTU-ra8NZHg", + "type": "text" + }, { "id": "MtjqdHYBc5PTU-ra8NZHg", "type": "text" @@ -219,6 +214,10 @@ "id": "P7NpNHMmnsu-hhgwxYmo2", "type": "arrow" }, + { + "type": "text", + "id": "MtjqdHYBc5PTU-ra8NZHg" + }, { "id": "P9cZwyL3gt9n5Uc2t372O", "type": "arrow" @@ -232,156 +231,222 @@ "type": "arrow" } ], - "updated": 1717007549844, + "updated": 1647818578857, "link": null, - "locked": false + "fontSize": 24.971673819742485, + "baseline": 43.7407407407408 }, { - "type": "text", - "version": 373, - "versionNonce": 408469153, - "index": "a6", - "isDeleted": false, - "id": "B5h2e4cOtLsO2Z2nCmXUv", + "id": "N-IcJz-VgLd4G_w5IGZzo", + "type": "rectangle", + "x": 1073.2, + "y": 295.24444444444384, + "width": 217.79999999999995, + "height": 62.7407407407408, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, - "angle": 0, + "groupIds": [], + "strokeSharpness": "round", + "seed": 1768193537, + "version": 360, + "versionNonce": 1477198831, + "isDeleted": false, + "boundElements": [ + { + "id": "qh81Y2_UCqH6h6CdDOgs3", + "type": "text" + }, + { + "type": "text", + "id": "qh81Y2_UCqH6h6CdDOgs3" + }, + { + "id": "j2LC8-0hrLNZXTpYAtx19", + "type": "arrow" + }, + { + "id": "P7NpNHMmnsu-hhgwxYmo2", + "type": "arrow" + } + ], + "updated": 1647818401510, + "link": null, + "fontSize": 24.971673819742485, + "baseline": 43.7407407407408 + }, + { + "id": "B5h2e4cOtLsO2Z2nCmXUv", + "type": "text", "x": 730.4370370370365, "y": 307.52962962962937, - "strokeColor": "#000000", - "backgroundColor": "transparent", "width": 207.79999999999995, "height": 31, - "seed": 1364715503, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1717007549844, - "link": null, - "locked": false, - "fontSize": 24.971673819742485, - "fontFamily": 1, - "text": "*.evt.to.fsu.xxx", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "soHz1JXys4CcGsQ3wYg0G", - "originalText": "*.evt.to.fsu.xxx", - "autoResize": true, - "lineHeight": 1.2414065722535408 - }, - { - "type": "text", - "version": 553, - "versionNonce": 1167112175, - "index": "a7", - "isDeleted": false, - "id": "BrUYg7L4kzqjcJN7o7PEr", + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, - "angle": 0, + "groupIds": [], + "strokeSharpness": "round", + "seed": 1364715503, + "version": 372, + "versionNonce": 678113121, + "isDeleted": false, + "boundElements": null, + "updated": 1647818401509, + "link": null, + "text": "*.evt.to.fsu.xxx", + "fontSize": 24.971673819742485, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 22, + "containerId": "soHz1JXys4CcGsQ3wYg0G", + "originalText": "*.evt.to.fsu.xxx" + }, + { + "id": "BrUYg7L4kzqjcJN7o7PEr", + "type": "text", "x": 909.5925925925924, "y": 505.52962962962806, - "strokeColor": "#000000", - "backgroundColor": "transparent", "width": 207.79999999999995, "height": 31, - "seed": 1623507279, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1717007549844, - "link": null, - "locked": false, - "fontSize": 24.971673819742485, - "fontFamily": 1, - "text": "*.root", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "lVG_kdGInlSn8Z2rog8y_", - "originalText": "*.root", - "autoResize": true, - "lineHeight": 1.2414065722535408 - }, - { - "type": "text", - "version": 674, - "versionNonce": 585777793, - "index": "a8", - "isDeleted": false, - "id": "MtjqdHYBc5PTU-ra8NZHg", + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, - "angle": 0, + "groupIds": [], + "strokeSharpness": "round", + "seed": 1623507279, + "version": 552, + "versionNonce": 1496118127, + "isDeleted": false, + "boundElements": null, + "updated": 1647818401509, + "link": null, + "text": "*.root", + "fontSize": 24.971673819742485, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 22, + "containerId": "lVG_kdGInlSn8Z2rog8y_", + "originalText": "*.root" + }, + { + "id": "MtjqdHYBc5PTU-ra8NZHg", + "type": "text", "x": 1048.5925925925924, "y": 738.6592592592576, - "strokeColor": "#000000", - "backgroundColor": "transparent", "width": 208, "height": 62, - "seed": 1964271183, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1717007549844, - "link": null, - "locked": false, - "fontSize": 24.971673819742485, - "fontFamily": 1, - "text": "*.root \n(simplified)", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "75BzEnWMBt8CyzY_59Z5z", - "originalText": "*.root (simplified)", - "autoResize": true, - "lineHeight": 1.2414065722535408 - }, - { - "type": "arrow", - "version": 541, - "versionNonce": 207637089, - "index": "aA", - "isDeleted": false, - "id": "wVuMtUwvQDwX0zsvknEbS", + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 1964271183, + "version": 673, + "versionNonce": 1808511041, + "isDeleted": false, + "boundElements": null, + "updated": 1647818578857, + "link": null, + "text": "*.root \n(simplified)", + "fontSize": 24.971673819742485, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 53, + "containerId": "75BzEnWMBt8CyzY_59Z5z", + "originalText": "*.root (simplified)" + }, + { + "id": "qh81Y2_UCqH6h6CdDOgs3", + "type": "text", + "x": 1078.2, + "y": 311.1148148148142, + "width": 207.79999999999995, + "height": 31, "angle": 0, - "x": 989.7524966807964, - "y": 171.54049434487996, "strokeColor": "#000000", "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 252122593, + "version": 472, + "versionNonce": 817723009, + "isDeleted": false, + "boundElements": null, + "updated": 1647818401510, + "link": null, + "text": "*_raw.root", + "fontSize": 24.971673819742485, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 22, + "containerId": "N-IcJz-VgLd4G_w5IGZzo", + "originalText": "*_raw.root" + }, + { + "id": "wVuMtUwvQDwX0zsvknEbS", + "type": "arrow", + "x": 989.7524966807964, + "y": 171.54049434487996, "width": 119.53370984275955, "height": 111.2296296296297, - "seed": 270153423, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1717007549844, + "strokeSharpness": "round", + "seed": 270153423, + "version": 540, + "versionNonce": 202549537, + "isDeleted": false, + "boundElements": null, + "updated": 1647818401728, "link": null, - "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -119.53370984275955, + 111.2296296296297 + ] + ], + "lastCommittedPoint": null, "startBinding": { "elementId": "F7K7zMR1U55-x1Y0zNheF", "focus": -0.0325789073360154, @@ -392,49 +457,92 @@ "focus": -0.05177259320591252, "gap": 8.889135284749358 }, - "lastCommittedPoint": null, "startArrowhead": null, - "endArrowhead": "arrow", + "endArrowhead": "arrow" + }, + { + "id": "j2LC8-0hrLNZXTpYAtx19", + "type": "arrow", + "x": 1071.4586718849273, + "y": 167.96867255870347, + "width": 96.61242742710613, + "height": 120.19259259259263, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 1714358337, + "version": 556, + "versionNonce": 218291457, + "isDeleted": false, + "boundElements": null, + "updated": 1647818401729, + "link": null, "points": [ [ 0, 0 ], [ - -119.53370984275955, - 111.2296296296297 + 96.61242742710613, + 120.19259259259263 ] - ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "F7K7zMR1U55-x1Y0zNheF", + "focus": -0.22659935572522302, + "gap": 3.6723762624071696 + }, + "endBinding": { + "elementId": "N-IcJz-VgLd4G_w5IGZzo", + "focus": 0.12586559770339084, + "gap": 7.083179293147765 + }, + "startArrowhead": null, + "endArrowhead": "arrow" }, { - "type": "arrow", - "version": 654, - "versionNonce": 227169857, - "index": "aC", - "isDeleted": false, "id": "cVfBGP1caGY3pgFvecDal", + "type": "arrow", + "x": 849.5865308468354, + "y": 363.4377152877662, + "width": 110.30000188482575, + "height": 120.91851851851857, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, - "angle": 0, - "x": 849.5865308468354, - "y": 363.4377152877662, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 110.30000188482575, - "height": 120.91851851851857, - "seed": 401824335, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1717007549844, + "strokeSharpness": "round", + "seed": 401824335, + "version": 653, + "versionNonce": 226596065, + "isDeleted": false, + "boundElements": null, + "updated": 1647818401729, "link": null, - "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 110.30000188482575, + 120.91851851851857 + ] + ], + "lastCommittedPoint": null, "startBinding": { "elementId": "soHz1JXys4CcGsQ3wYg0G", "focus": 0.15714684037187934, @@ -445,74 +553,94 @@ "focus": -0.14655181276661794, "gap": 5.303025452972918 }, - "lastCommittedPoint": null, "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 110.30000188482575, - 120.91851851851857 - ] - ] + "endArrowhead": "arrow" }, { - "type": "arrow", - "version": 774, - "versionNonce": 451274863, - "index": "aD", - "isDeleted": false, "id": "P7NpNHMmnsu-hhgwxYmo2", + "type": "arrow", + "x": 1164.970878303926, + "y": 371.7773136588039, + "width": 97.11257500279567, + "height": 110.90062868698101, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, - "angle": 0, - "x": 1060.4009592684429, - "y": 181.7773136588039, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 15.625510909633476, - "height": 300.900628686981, - "seed": 340614223, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1717007567164, + "strokeSharpness": "round", + "seed": 340614223, + "version": 669, + "versionNonce": 555634881, + "isDeleted": false, + "boundElements": null, + "updated": 1647818401729, "link": null, - "locked": false, - "startBinding": null, - "endBinding": { - "elementId": "lVG_kdGInlSn8Z2rog8y_", - "focus": 0.5837873001893779, - "gap": 6.981316913472767 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", "points": [ [ 0, 0 ], [ - 15.625510909633476, - 300.900628686981 + -97.11257500279567, + 110.90062868698101 ] - ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "N-IcJz-VgLd4G_w5IGZzo", + "focus": -0.16439384322771664, + "gap": 13.792128473619215 + }, + "endBinding": { + "elementId": "lVG_kdGInlSn8Z2rog8y_", + "focus": 0.15239560394816007, + "gap": 6.981316913472767 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "kVnTUQ4sLOO3BBCX6jXhQ", + "type": "text", + "x": 1152.5222222222214, + "y": 205.5518518518516, + "width": 121, + "height": 31, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 1848809359, + "version": 176, + "versionNonce": 243225711, + "isDeleted": false, + "boundElements": null, + "updated": 1647818401510, + "link": null, + "text": "MergeEVT", + "fontSize": 25.096296296296305, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "top", + "baseline": 22, + "containerId": null, + "originalText": "MergeEVT" }, { "type": "text", - "version": 270, - "versionNonce": 1814677615, - "index": "aF", + "version": 269, + "versionNonce": 455192065, "isDeleted": false, "id": "hjpjwQjIcE6KzKaFdR-Wf", "fillStyle": "hachure", @@ -529,29 +657,23 @@ "height": 31.3703703703704, "seed": 1804472239, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, + "strokeSharpness": "round", "boundElements": [], - "updated": 1717007549844, + "updated": 1647818401510, "link": null, - "locked": false, "fontSize": 25.096296296296305, "fontFamily": 1, "text": "pxi-fsu.time-order", + "baseline": 22.3703703703704, "textAlign": "center", "verticalAlign": "top", "containerId": null, - "originalText": "pxi-fsu.time-order", - "autoResize": true, - "lineHeight": 1.2500000000000007 + "originalText": "pxi-fsu.time-order" }, { "type": "text", - "version": 321, - "versionNonce": 445151745, - "index": "aG", + "version": 320, + "versionNonce": 1670966927, "isDeleted": false, "id": "__bmlLJ8PwPTagBBqD9VN", "fillStyle": "hachure", @@ -568,29 +690,23 @@ "height": 31.3703703703704, "seed": 24381761, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, + "strokeSharpness": "round", "boundElements": [], - "updated": 1717007549844, + "updated": 1647818401510, "link": null, - "locked": false, "fontSize": 25.0962962962963, "fontFamily": 1, "text": "to2root", + "baseline": 22.3703703703704, "textAlign": "center", "verticalAlign": "top", "containerId": null, - "originalText": "to2root", - "autoResize": true, - "lineHeight": 1.250000000000001 + "originalText": "to2root" }, { "type": "text", - "version": 392, - "versionNonce": 2020050799, - "index": "aH", + "version": 378, + "versionNonce": 1906197985, "isDeleted": false, "id": "D8BUfkyxf6YqzPnGnv0Xh", "fillStyle": "hachure", @@ -599,37 +715,31 @@ "roughness": 1, "opacity": 100, "angle": 0, - "x": 1096.5629629629611, - "y": 292.78888888888935, + "x": 1130.5629629629611, + "y": 414.78888888888935, "strokeColor": "#000000", "backgroundColor": "transparent", "width": 154.16296296296298, "height": 31.3703703703704, "seed": 2079320367, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, + "strokeSharpness": "round", "boundElements": [], - "updated": 1717007563722, + "updated": 1647818401510, "link": null, - "locked": false, "fontSize": 25.096296296296305, "fontFamily": 1, "text": "EventBuilder", + "baseline": 22.3703703703704, "textAlign": "center", "verticalAlign": "top", "containerId": null, - "originalText": "EventBuilder", - "autoResize": true, - "lineHeight": 1.2500000000000007 + "originalText": "EventBuilder" }, { "type": "text", - "version": 426, - "versionNonce": 1917555169, - "index": "aI", + "version": 425, + "versionNonce": 851068079, "isDeleted": false, "id": "lDDXAL1aSoy5lFPULFt7x", "fillStyle": "hachure", @@ -646,53 +756,54 @@ "height": 31, "seed": 915951567, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, + "strokeSharpness": "round", "boundElements": [], - "updated": 1717007549844, + "updated": 1647818401510, "link": null, - "locked": false, "fontSize": 25.096296296296305, "fontFamily": 1, "text": "PreAnalyzer.C/h", + "baseline": 22, "textAlign": "center", "verticalAlign": "top", "containerId": null, - "originalText": "PreAnalyzer.C/h", - "autoResize": true, - "lineHeight": 1.2352420306965757 + "originalText": "PreAnalyzer.C/h" }, { - "type": "arrow", - "version": 237, - "versionNonce": 1465366703, - "index": "aJ", - "isDeleted": false, "id": "P9cZwyL3gt9n5Uc2t372O", + "type": "arrow", + "x": 1035.759503509729, + "y": 559, + "width": 113.19349271635019, + "height": 171, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 1, "opacity": 100, - "angle": 0, - "x": 1035.759503509729, - "y": 559, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 113.19349271635019, - "height": 171, - "seed": 1496444239, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1717007549844, + "strokeSharpness": "round", + "seed": 1496444239, + "version": 236, + "versionNonce": 1995357871, + "isDeleted": false, + "boundElements": null, + "updated": 1647818579061, "link": null, - "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 113.19349271635019, + 171 + ] + ], + "lastCommittedPoint": null, "startBinding": { "elementId": "lVG_kdGInlSn8Z2rog8y_", "focus": 0.02212915002641517, @@ -703,45 +814,30 @@ "focus": 0.17023883632050066, "gap": 3.6592592592576807 }, - "lastCommittedPoint": null, "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 113.19349271635019, - 171 - ] - ] + "endArrowhead": "arrow" }, { - "type": "ellipse", - "version": 194, - "versionNonce": 899722689, - "index": "aK", - "isDeleted": false, "id": "ZsQWjOTkWl1BHRSTW0mJ5", + "type": "ellipse", + "x": 446, + "y": 601, + "width": 232, + "height": 73, + "angle": 0, + "strokeColor": "#862e9c", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 2, "opacity": 100, - "angle": 0, - "x": 446, - "y": 601, - "strokeColor": "#862e9c", - "backgroundColor": "transparent", - "width": 232, - "height": 73, - "seed": 470581825, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, + "strokeSharpness": "round", + "seed": 470581825, + "version": 193, + "versionNonce": 1961694529, + "isDeleted": false, "boundElements": [ { "type": "text", @@ -764,78 +860,77 @@ "type": "arrow" } ], - "updated": 1717007549844, - "link": null, - "locked": false + "updated": 1647818534010, + "link": null }, { - "type": "text", - "version": 170, - "versionNonce": 1952107215, - "index": "aL", - "isDeleted": false, "id": "51dKlklstHadFKrB7n8YD", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, + "type": "text", "x": 451, "y": 620, - "strokeColor": "#862e9c", - "backgroundColor": "transparent", "width": 222, "height": 35, - "seed": 2003805697, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1717007549844, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "histograms", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "ZsQWjOTkWl1BHRSTW0mJ5", - "originalText": "histograms", - "autoResize": true, - "lineHeight": 1.25 - }, - { - "type": "arrow", - "version": 186, - "versionNonce": 732384673, - "index": "aM", - "isDeleted": false, - "id": "-k5eaNk8YWIjOcetbUfQD", + "angle": 0, + "strokeColor": "#862e9c", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 2, "opacity": 100, - "angle": 0, + "groupIds": [], + "strokeSharpness": "round", + "seed": 2003805697, + "version": 169, + "versionNonce": 1812634447, + "isDeleted": false, + "boundElements": null, + "updated": 1647818534010, + "link": null, + "text": "histograms", + "fontSize": 28, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 25, + "containerId": "ZsQWjOTkWl1BHRSTW0mJ5", + "originalText": "histograms" + }, + { + "id": "-k5eaNk8YWIjOcetbUfQD", + "type": "arrow", "x": 767.4529205935671, "y": 361, - "strokeColor": "#087f5b", - "backgroundColor": "transparent", "width": 166.43973876604423, "height": 231.250681401247, - "seed": 716854561, + "angle": 0, + "strokeColor": "#087f5b", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1717007549844, + "strokeSharpness": "round", + "seed": 716854561, + "version": 185, + "versionNonce": 2017449089, + "isDeleted": false, + "boundElements": null, + "updated": 1647818401730, "link": null, - "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -166.43973876604423, + 231.250681401247 + ] + ], + "lastCommittedPoint": null, "startBinding": { "elementId": "soHz1JXys4CcGsQ3wYg0G", "focus": 0.3008510701329823, @@ -846,49 +941,44 @@ "focus": 0.05419282065109363, "gap": 10.809776398154149 }, - "lastCommittedPoint": null, "startArrowhead": null, - "endArrowhead": "arrow", + "endArrowhead": "arrow" + }, + { + "id": "agzkYqEEC-88Vv_sngi_8", + "type": "arrow", + "x": 897, + "y": 517.4796917499153, + "width": 258.11148037057353, + "height": 84.07554502722894, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "groupIds": [], + "strokeSharpness": "round", + "seed": 1856136961, + "version": 181, + "versionNonce": 1104697711, + "isDeleted": false, + "boundElements": null, + "updated": 1647818537368, + "link": null, "points": [ [ 0, 0 ], [ - -166.43973876604423, - 231.250681401247 + -258.11148037057353, + 84.07554502722894 ] - ] - }, - { - "type": "arrow", - "version": 182, - "versionNonce": 1064737007, - "index": "aN", - "isDeleted": false, - "id": "agzkYqEEC-88Vv_sngi_8", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 897, - "y": 517.4796917499153, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 258.11148037057353, - "height": 84.07554502722894, - "seed": 1856136961, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1717007549844, - "link": null, - "locked": false, + ], + "lastCommittedPoint": null, "startBinding": { "elementId": "lVG_kdGInlSn8Z2rog8y_", "focus": 0.620792481604644, @@ -899,62 +989,33 @@ "focus": -0.20747175231881398, "gap": 8.313284858991366 }, - "lastCommittedPoint": null, "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -258.11148037057353, - 84.07554502722894 - ] - ] + "endArrowhead": "arrow" }, { - "type": "arrow", - "version": 257, - "versionNonce": 193917313, - "index": "aO", - "isDeleted": false, "id": "v0ZCxQCjw27_GScx0D8wJ", + "type": "arrow", + "x": 903, + "y": 137, + "width": 356.6226706500755, + "height": 453.59365180321606, + "angle": 0, + "strokeColor": "#087f5b", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 2, "opacity": 100, - "angle": 0, - "x": 903, - "y": 137, - "strokeColor": "#087f5b", - "backgroundColor": "transparent", - "width": 356.6226706500755, - "height": 453.59365180321606, - "seed": 1168510799, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1717007549844, + "strokeSharpness": "round", + "seed": 1168510799, + "version": 256, + "versionNonce": 1948477505, + "isDeleted": false, + "boundElements": null, + "updated": 1647818401731, "link": null, - "locked": false, - "startBinding": { - "elementId": "F7K7zMR1U55-x1Y0zNheF", - "focus": 0.5062605203705725, - "gap": 8.1777777777761 - }, - "endBinding": { - "elementId": "ZsQWjOTkWl1BHRSTW0mJ5", - "focus": -0.21950372001865495, - "gap": 10.7293622763748 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", "points": [ [ 0, @@ -968,33 +1029,42 @@ -356.6226706500755, 453.59365180321606 ] - ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "F7K7zMR1U55-x1Y0zNheF", + "focus": 0.5062605203705725, + "gap": 8.1777777777761 + }, + "endBinding": { + "elementId": "ZsQWjOTkWl1BHRSTW0mJ5", + "focus": -0.21950372001865495, + "gap": 10.7293622763748 + }, + "startArrowhead": null, + "endArrowhead": "arrow" }, { - "type": "ellipse", - "version": 105, - "versionNonce": 1848877839, - "index": "aP", - "isDeleted": false, "id": "WMRgg95DFetUO43ksQt5B", + "type": "ellipse", + "x": 751, + "y": 890, + "width": 263, + "height": 71, + "angle": 0, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 2, "opacity": 100, - "angle": 0, - "x": 751, - "y": 890, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 263, - "height": 71, - "seed": 941781135, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, + "strokeSharpness": "round", + "seed": 941781135, + "version": 104, + "versionNonce": 527404097, + "isDeleted": false, "boundElements": [ { "type": "text", @@ -1009,78 +1079,77 @@ "type": "arrow" } ], - "updated": 1717007549844, - "link": null, - "locked": false + "updated": 1647818491994, + "link": null }, { - "type": "text", - "version": 81, - "versionNonce": 2056722785, - "index": "aQ", - "isDeleted": false, "id": "zXhQXzRWuABV0jsxbzfu6", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, + "type": "text", "x": 756, "y": 913, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", "width": 253, "height": 35, - "seed": 1086239503, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1717007549844, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "PIDcuts.root", - "textAlign": "center", - "verticalAlign": "top", - "containerId": "WMRgg95DFetUO43ksQt5B", - "originalText": "PIDcuts.root", - "autoResize": true, - "lineHeight": 1.25 - }, - { - "type": "arrow", - "version": 63, - "versionNonce": 1896507695, - "index": "aR", - "isDeleted": false, - "id": "ehETUc00eCNlcTlQ6HACy", + "angle": 0, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 2, "opacity": 100, - "angle": 0, + "groupIds": [], + "strokeSharpness": "round", + "seed": 1086239503, + "version": 80, + "versionNonce": 2052002895, + "isDeleted": false, + "boundElements": null, + "updated": 1647818491995, + "link": null, + "text": "PIDcuts.root", + "fontSize": 28, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "top", + "baseline": 25, + "containerId": "WMRgg95DFetUO43ksQt5B", + "originalText": "PIDcuts.root" + }, + { + "id": "ehETUc00eCNlcTlQ6HACy", + "type": "arrow", "x": 1067.1280479269299, "y": 821.808328929171, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", "width": 91.32732084972486, "height": 77.15092278310533, - "seed": 1879927841, + "angle": 0, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1717007549844, + "strokeSharpness": "round", + "seed": 1879927841, + "version": 62, + "versionNonce": 1943037857, + "isDeleted": false, + "boundElements": null, + "updated": 1647818579062, "link": null, - "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -91.32732084972486, + 77.15092278310533 + ] + ], + "lastCommittedPoint": null, "startBinding": { "elementId": "75BzEnWMBt8CyzY_59Z5z", "focus": 0.15675849444476955, @@ -1091,62 +1160,33 @@ "focus": 0.44826161833932643, "gap": 1.690359702747088 }, - "lastCommittedPoint": null, "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -91.32732084972486, - 77.15092278310533 - ] - ] + "endArrowhead": "arrow" }, { - "type": "arrow", - "version": 228, - "versionNonce": 1242514753, - "index": "aS", - "isDeleted": false, "id": "w0d6KBM1NTHTPajgPOe6R", + "type": "arrow", + "x": 1035, + "y": 773.6182054324441, + "width": 435, + "height": 88.61820543244414, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 2, "opacity": 100, - "angle": 0, - "x": 1035, - "y": 773.6182054324441, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 435, - "height": 88.61820543244414, - "seed": 2125616111, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1717007549844, + "strokeSharpness": "round", + "seed": 2125616111, + "version": 227, + "versionNonce": 1836114159, + "isDeleted": false, + "boundElements": null, + "updated": 1647818584992, "link": null, - "locked": false, - "startBinding": { - "elementId": "75BzEnWMBt8CyzY_59Z5z", - "focus": 0.10530264507321531, - "gap": 8.592592592592268 - }, - "endBinding": { - "elementId": "ZsQWjOTkWl1BHRSTW0mJ5", - "focus": 0.37415443247287694, - "gap": 12.94027309192736 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", "points": [ [ 0, @@ -1160,81 +1200,94 @@ -435, -88.61820543244414 ] - ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "75BzEnWMBt8CyzY_59Z5z", + "focus": 0.10530264507321531, + "gap": 8.592592592592268 + }, + "endBinding": { + "elementId": "ZsQWjOTkWl1BHRSTW0mJ5", + "focus": 0.37415443247287694, + "gap": 12.94027309192736 + }, + "startArrowhead": null, + "endArrowhead": "arrow" }, { - "type": "text", - "version": 81, - "versionNonce": 358837071, - "index": "aT", - "isDeleted": false, "id": "eCLuWwIT2U3T29vZemg1y", + "type": "text", + "x": 698, + "y": 756.5, + "width": 224, + "height": 35, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 2, "opacity": 100, - "angle": 0, - "x": 698, - "y": 756.5, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 224, - "height": 35, - "seed": 410247489, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, + "strokeSharpness": "round", + "seed": 410247489, + "version": 80, + "versionNonce": 2018981967, + "isDeleted": false, "boundElements": [ { "id": "4hPuEiYm-RMAejSmybE6w", "type": "arrow" } ], - "updated": 1717007549844, + "updated": 1647818589123, "link": null, - "locked": false, + "text": "PIDAnalyzer.C/h", "fontSize": 28, "fontFamily": 1, - "text": "PIDAnalyzer.C/h", "textAlign": "center", "verticalAlign": "top", + "baseline": 25, "containerId": null, - "originalText": "PIDAnalyzer.C/h", - "autoResize": true, - "lineHeight": 1.25 + "originalText": "PIDAnalyzer.C/h" }, { - "type": "arrow", - "version": 79, - "versionNonce": 1968633121, - "index": "aU", - "isDeleted": false, "id": "4hPuEiYm-RMAejSmybE6w", + "type": "arrow", + "x": 852.040358857486, + "y": 882.8297567412599, + "width": 35.84606170772679, + "height": 79.82975674125987, + "angle": 0, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", "fillStyle": "hachure", "strokeWidth": 1, "strokeStyle": "solid", "roughness": 2, "opacity": 100, - "angle": 0, - "x": 852.040358857486, - "y": 882.8297567412599, - "strokeColor": "#1864ab", - "backgroundColor": "transparent", - "width": 35.84606170772679, - "height": 79.82975674125987, - "seed": 492766657, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1717007549844, + "strokeSharpness": "round", + "seed": 492766657, + "version": 78, + "versionNonce": 881415791, + "isDeleted": false, + "boundElements": null, + "updated": 1647818589124, "link": null, - "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -35.84606170772679, + -79.82975674125987 + ] + ], + "lastCommittedPoint": null, "startBinding": { "elementId": "WMRgg95DFetUO43ksQt5B", "focus": -0.09547986936337077, @@ -1245,25 +1298,13 @@ "focus": 0.056964146096280574, "gap": 11.5 }, - "lastCommittedPoint": null, "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -35.84606170772679, - -79.82975674125987 - ] - ] + "endArrowhead": "arrow" }, { "type": "text", - "version": 108, - "versionNonce": 1737959791, - "index": "aV", + "version": 107, + "versionNonce": 1647045825, "isDeleted": false, "id": "C5Xu4VJ1CEf58a-TdzRL1", "fillStyle": "hachure", @@ -1280,34 +1321,28 @@ "height": 35, "seed": 405206223, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, + "strokeSharpness": "round", "boundElements": [ { "id": "4hPuEiYm-RMAejSmybE6w", "type": "arrow" } ], - "updated": 1717007549844, + "updated": 1647818543962, "link": null, - "locked": false, "fontSize": 28, "fontFamily": 1, "text": "Analyzer.C/h", + "baseline": 25, "textAlign": "center", "verticalAlign": "top", "containerId": null, - "originalText": "Analyzer.C/h", - "autoResize": true, - "lineHeight": 1.25 + "originalText": "Analyzer.C/h" }, { "type": "text", - "version": 143, - "versionNonce": 1608362241, - "index": "aW", + "version": 142, + "versionNonce": 333894415, "isDeleted": false, "id": "qw9NHyRhajjjBoBiDpEXg", "fillStyle": "hachure", @@ -1324,34 +1359,28 @@ "height": 35, "seed": 2090504335, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, + "strokeSharpness": "round", "boundElements": [ { "id": "4hPuEiYm-RMAejSmybE6w", "type": "arrow" } ], - "updated": 1717007549844, + "updated": 1647818525703, "link": null, - "locked": false, "fontSize": 28, "fontFamily": 1, "text": "evt2hist", + "baseline": 25, "textAlign": "center", "verticalAlign": "top", "containerId": null, - "originalText": "evt2hist", - "autoResize": true, - "lineHeight": 1.25 + "originalText": "evt2hist" }, { "type": "text", - "version": 147, - "versionNonce": 1424892815, - "index": "aX", + "version": 146, + "versionNonce": 182333153, "isDeleted": false, "id": "yqiXgQkxg-0w8UIolLf0z", "fillStyle": "hachure", @@ -1368,28 +1397,23 @@ "height": 35, "seed": 650914657, "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, + "strokeSharpness": "round", "boundElements": [ { "id": "4hPuEiYm-RMAejSmybE6w", "type": "arrow" } ], - "updated": 1717007549844, + "updated": 1647819096455, "link": null, - "locked": false, "fontSize": 28, "fontFamily": 1, "text": "GAGGPIDCutCreator.C", + "baseline": 25, "textAlign": "center", "verticalAlign": "top", "containerId": null, - "originalText": "GAGGPIDCutCreator.C", - "autoResize": true, - "lineHeight": 1.25 + "originalText": "GAGGPIDCutCreator.C" } ], "appState": { diff --git a/armory/evtReader.h b/armory/evtReader.h index fbf6340..e7e4542 100644 --- a/armory/evtReader.h +++ b/armory/evtReader.h @@ -17,24 +17,6 @@ #define MAX_CHANNELS_PER_BOARD 16 #define BOARD_START 2 - -class timePos{ -public: - timePos(ULong64_t time, unsigned long int inFilePos){ - this->time = time; - this->inFilePos = inFilePos; - } - - ULong64_t time; - unsigned long int inFilePos; - - void Print(){ - printf("time: %16llu, filePos: %lu\n", time, inFilePos); - } - -}; - - class evtReader{ public: @@ -44,7 +26,6 @@ class evtReader{ FILE * inFile; long int inFileSize; - long int inFilePos0; long int inFilePos; bool endOfFile; bool isOpened; @@ -82,18 +63,10 @@ class evtReader{ int ReadBlock(int opt = 0); /// 0 = default, fill data /// 1 = no fill data - int ReadBlockAtPos(unsigned long int filePos); - void ScanNumberOfBlock(); void JumptoPrecent(int precent); ///this is offset by 1 block void PrintStatus(int mod); - - - std::vector timePosList; - unsigned long int filePosK; - std::vector ReadBatchPos(long batchSize, bool verbose = false); - void SortTimePos(); - + }; @@ -105,8 +78,6 @@ evtReader::evtReader(){ inFileSize = 0; inFilePos = 0; - inFilePos0 = 0; - filePosK = 0; nBlock = 0; blockID = -1; @@ -117,7 +88,8 @@ evtReader::evtReader(){ evtReader::~evtReader(){ - fclose(inFile); //already delete inFile + fclose(inFile); + delete inFile; delete data; } @@ -128,8 +100,6 @@ evtReader::evtReader(TString inFileName){ inFileSize = 0; inFilePos = 0; - inFilePos0 = 0; - filePosK = 0; nBlock = 0; blockID = -1; @@ -180,13 +150,6 @@ bool evtReader::IsEndOfFile() { return haha > 0 ? true: false; } -int evtReader::ReadBlockAtPos(unsigned long int filePos){ - - fseek( inFile, filePos, SEEK_SET); - - return ReadBlock(0); - -} int evtReader::ReadBlock(int opt){ @@ -195,8 +158,6 @@ int evtReader::ReadBlock(int opt){ unsigned int header[4]; ///read 4 header, unsigned int = 4 byte = 32 bits. - inFilePos0 = inFilePos; - if ( fread(header, sizeof(header), 1, inFile) != 1 ) { endOfFile = true; return -1; @@ -312,8 +273,6 @@ void evtReader::ScanNumberOfBlock(){ printf("scan complete: number of data Block : %ld\n", nBlock); inFilePos = 0; - inFilePos0 = 0; - filePosK = 0; blockID = -1; rewind(inFile); ///back to the File begining @@ -347,141 +306,4 @@ void evtReader::PrintStatus(int mod){ } -void evtReader::SortTimePos(){ - std::sort(timePosList.begin(), timePosList.end(), [](const timePos & a, const timePos & b) { return a.time < b.time; }); -} - -std::vector evtReader::ReadBatchPos(long batchSize, bool verbose){ - - if( verbose ) printf("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& %s / %lu / %lu\n", __func__, filePosK, inFileSize ); - - fseek( inFile, filePosK, SEEK_SET); - - std::vector timePosList_A; - if( filePosK == inFileSize ){ - timePosList_A = timePosList; - timePosList.clear(); - return timePosList_A; - } - - if( timePosList.size() == 0 ){ - int res = 0; - do{ - res = ReadBlock(); - timePosList.push_back( timePos(data->time, inFilePos0)); - }while( timePosList.size() < batchSize && res == 1); - SortTimePos(); - unsigned long long t0_B = timePosList.front().time; - unsigned long long t1_B = timePosList.back().time; - if( verbose ) { - printf(" hit in memeory : %7zu | %lu | %lu \n", timePosList.size(), inFilePos, inFileSize); - printf("t0 : %15llu\n", t0_B); - printf("t1 : %15llu\n", t1_B); - } - timePosList_A = timePosList; - timePosList.clear(); - - }else{ - timePosList_A = timePosList; - timePosList.clear(); - } - - if( feof(inFile) ) return timePosList_A; - - int res = 0; - do{ - res = ReadBlock(); - timePosList.push_back(timePos(data->time, inFilePos0)); - }while( timePosList.size() < batchSize && res == 1); - SortTimePos(); - unsigned long long t0_B = timePosList.front().time; - unsigned long long t1_B = timePosList.back().time; - if( verbose ) { - printf(" hit in memeory : %7zu | %lu | %lu \n", timePosList.size(), inFilePos, inFileSize); - printf("t0 : %15llu\n", t0_B); - printf("t1 : %15llu\n", t1_B); - } - - unsigned long long t0_A = timePosList_A.front().time; - unsigned long long t1_A = timePosList_A.back().time; - ulong ID_A = 0; - ulong ID_B = 0; - - if( t0_A >= t0_B) { - printf("\033[0;31m!!!!!!!!!!!!!!!!! %s | Need to increase the batch size. \033[0m\n", __func__); - printf("present batch size : %lu \n", batchSize); - printf("timePosList_A t0_A : %15llu\n", t0_A); - printf("timePosList t0_B : %15llu\n", t0_B); - return std::vector (); - } - - if( t1_A > t0_B) { // need to sort between two hitList - - if( verbose ) { - printf("############# need to sort \n"); - printf("=========== sume of A + B : %zu \n", timePosList_A.size() + timePosList.size()); - } - - std::vector timePosListTemp; - - // find the hit that is >= t0_B, save them to timePosListTemp - for( size_t j = 0; j < timePosList_A.size() ; j++){ - if( timePosList_A[j].time < t0_B ) continue;; - if( ID_A == 0 ) ID_A = j; - timePosListTemp.push_back(timePosList_A[j]); - } - - // remove timePosList_A element that is >= t0_B - timePosList_A.erase(timePosList_A.begin() + ID_A, timePosList_A.end() ); - - // find the hit that is <= t1_A, save them to timePosListTemp - for( size_t j = 0; j < timePosList.size(); j++){ - if( timePosList[j].time > t1_A ) { - break; - } - timePosListTemp.push_back(timePosList[j]); - ID_B = j + 1; - } - - // remove hit elements that is <= t1_A - timePosList.erase(timePosList.begin(), timePosList.begin() + ID_B ); - - // sort timePosListTemp - std::sort(timePosListTemp.begin(), timePosListTemp.end(), [](const timePos& a, const timePos& b) { - return a.time < b.time; - }); - - - if( verbose ) { - printf("----------------- ID_A : %lu, Drop\n", ID_A); - printf("----------------- ID_B : %lu, Drop\n", ID_B); - printf("=========== sume of A + B + Temp : %zu \n", timePosList_A.size() + timePosList.size() + timePosListTemp.size()); - printf("----------------- refill timePosList_A \n"); - } - - for( size_t j = 0; j < timePosListTemp.size(); j++){ - timePosList_A.push_back(timePosListTemp[j]); - } - timePosListTemp.clear(); - - if( verbose ) { - printf("=========== sume of A + B : %zu \n", timePosList_A.size() + timePosList.size()); - printf(" A in memeory : %7zu \n", timePosList_A.size()); - printf("t0 : %15llu\n", timePosList_A.front().time); - printf("t1 : %15llu\n", timePosList_A.back().time); - - printf(" B in memeory : %7zu | %lu | %lu \n", timePosList.size(), inFilePos, inFileSize); - printf("t0 : %15llu\n", timePosList.front().time); - printf("t1 : %15llu\n", timePosList.back().time); - } - - } - - filePosK = inFilePos; - - return timePosList_A; - -} - - #endif diff --git a/armory/makefile b/armory/makefile index e4e196e..c5f79b8 100644 --- a/armory/makefile +++ b/armory/makefile @@ -1,39 +1,38 @@ CC=g++ -CFLAG= -O2 -w #all: to2root evt2hist MergeEVT ev22txt EventBuilder pxi-time-order -all: to2root evt2hist ev22txt EventBuilder pxi-fsu-time-order +all: to2root evt2hist MergeEVT ev22txt EventBuilder pxi-fsu-time-order #this is FSU evt to root -# xia2root: ../armory/xia2root.cpp -# $(CC) ../armory/xia2root.cpp -o xia2root `root-config --cflags --glibs` +xia2root: ../armory/xia2root.cpp + $(CC) ../armory/xia2root.cpp -o xia2root `root-config --cflags --glibs` #xia2ev2_nopart: armory/xia2ev2_nopart.cpp # $(CC) armory/xia2ev2_nopart.cpp -o xia2ev2_nopart #this is for eventbuild to2root: ../armory/to2root.cpp ../armory/DataBlock.h ../armory/evtReader.h ../mapping.h - $(CC) $(CFLAG) ../armory/to2root.cpp -o to2root `root-config --cflags --glibs` + $(CC) ../armory/to2root.cpp -o to2root `root-config --cflags --glibs` #this is for online root -# MergeEVT: ../armory/MergeEVT.cpp ../armory/DataBlock.h ../armory/evtReader.h ../mapping.h -# $(CC) ../armory/MergeEVT.cpp -o MergeEVT `root-config --cflags --glibs` +MergeEVT: ../armory/MergeEVT.cpp ../armory/DataBlock.h ../armory/evtReader.h ../mapping.h + $(CC) ../armory/MergeEVT.cpp -o MergeEVT `root-config --cflags --glibs` #this is for online spectrums evt2hist: ../armory/evt2hist.cpp ../armory/DataBlock.h ../armory/evtReader.h ../mapping.h - $(CC) $(CFLAG) ../armory/evt2hist.cpp -o evt2hist `root-config --cflags --glibs` + $(CC) ../armory/evt2hist.cpp -o evt2hist `root-config --cflags --glibs` pxi-fsu-time-order: ../armory/pxi-fsu-time-order.cpp - $(CC) $(CFLAG) ../armory/pxi-fsu-time-order.cpp -o pxi-fsu-time-order + $(CC) ../armory/pxi-fsu-time-order.cpp -o pxi-fsu-time-order ev22txt: ../armory/ev22txt.cpp - $(CC) $(CFLAG) ../armory/ev22txt.cpp -o ev22txt + $(CC) ../armory/ev22txt.cpp -o ev22txt -EventBuilder: ../armory/EventBuilder.cpp - $(CC) $(CFLAG) ../armory/EventBuilder.cpp -o EventBuilder `root-config --cflags --glibs` +EventBuilder: ../armory/EventBuilder.cpp + $(CC) ../armory/EventBuilder.cpp -o EventBuilder `root-config --cflags --glibs` test: ../armory/test.cpp ../armory/DataBlock.h ../armory/evtReader.h ../mapping.h - $(CC) $(CFLAG) ../armory/test.cpp -o test `root-config --cflags --glibs` + $(CC) ../armory/test.cpp -o test `root-config --cflags --glibs` clean: -rm xia2root to2root MergeEVT evt2hist pxi-time-order ev22txt EventBuilder test diff --git a/armory/programs_explain.png b/armory/programs_explain.png index 8845bee..db206a6 100644 Binary files a/armory/programs_explain.png and b/armory/programs_explain.png differ diff --git a/armory/pxi-fsu-time-order.cpp b/armory/pxi-fsu-time-order.cpp index de5b12a..b3f34eb 100644 --- a/armory/pxi-fsu-time-order.cpp +++ b/armory/pxi-fsu-time-order.cpp @@ -449,11 +449,11 @@ int main(int argc, char **argv) { }else{ if( FillFlag ){ - if ( count < debugCount) printf("----------------- filled %d\n", count); + if ( count < debugCount) printf("----------------- filled \n"); for( i = 0; i < nFill; i++) fwrite(fillevents[i].data, sizeof(unsigned int)*fillevents[i].length, 1, fpw); evts_tot_write += nFill; }else{ - if ( count < debugCount) printf("----------------- dropped %d\n", count); + if ( count < debugCount) printf("----------------- dropped \n"); evts_tot_drop += nFill; } diff --git a/armory/pxi-time-order.c b/armory/pxi-time-order.c new file mode 100644 index 0000000..9bd03b4 --- /dev/null +++ b/armory/pxi-time-order.c @@ -0,0 +1,431 @@ +/*********************************************************/ +/* PXI Time Order -- J.M. Allmond (ORNL) -- v1 Jul 2016 */ +/* -- v2 Feb 2018 */ +/* -- v3 Jun 2018 */ +/* -- v4 May 2019 */ +/* */ +/* !Time Order Events from Pixie-16 digitizers */ +/* !Max of: */ +/* !IDs = static, Evts = dynamic, data = dynamic */ +/* */ +/* gcc -o pxi-time-order pxi-time-order.c */ +/* ./pxi-time-order datafile */ +/*********************************************************/ + +///////////////////////////////////////////////////////// +//Code assumes that sequential sub events for a // +//specific channel are time ordered; therefore, // +//unmerge data into circular buffers on a per // +//channel id basis and then remerge channels in // +//time order. // +///////////////////////////////////////////////////////// + + +#include +#include +#include +#include +#include + +#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 ; 2016 --> 40 micro-second trace + 4 word header + 12 extra header + + +#define DEF_SUB_EVENTS 100 //number of events for each dynamic buffer level +#define M1_SUB_EVENTS 1000 //manual input for irregular / non-linear / non-geometric progression +#define M2_SUB_EVENTS 5000 +#define M3_SUB_EVENTS 20000 +#define M4_SUB_EVENTS 50000 +#define M5_SUB_EVENTS 100000 +#define MAX_SUB_EVENTS 200000 + +#define MAX_MALLOC 4000*1024*1024L //2GB + +struct subevent +{ + long long int timestamp; + int length; //unit = words with 4 bytes per word + unsigned int *data; +}; + +struct subevent *subevents[MAX_ID]; +int nevts[MAX_ID], iptr[MAX_ID]; +int maxevts[MAX_ID]; + + +int main(int argc, char **argv) { + + FILE *fpr, *fpw; + long int fprsize=0, fprsize_orig=0, fprsize_old=-1, fprpos=0; + + int online = 0; + + unsigned int subhead[HEADER_LENGTH]; + memset(subhead, 0, sizeof(subhead)); + int pause=0; + + long long int nwords=0, evts_tot_read=0, evts_tot_write=0; + + long long int time=0,time_old=0; + int length=0; + int chn=0; + int sln=0; + int crn=0; + int id=0; + + int idmax=0; + int totmem=0; + int outoforder=0; + int evts_old=0; + int evts_new=0; + + long long int timemin=0, timemin_old=0; + int min_id = -1; + + memset(nevts, 0, sizeof(nevts)); + memset(iptr, 0, sizeof(iptr)); + + int i=0, j=0; + div_t e_div; + + + //open input event file + if ((fpr = fopen(argv[1], "r")) == NULL) { + fprintf(stderr, "Error, cannot open input file %s\n", argv[1]); + return 1; + } + + //write time order file to current location, not location of event file + char filenameto[80]; + char *filename = strrchr(argv[1], '/'); + if (filename == NULL) strcpy(filenameto,argv[1]); + else strcpy(filenameto,filename+1); + strcat(filenameto,".to"); + if ((fpw = fopen(filenameto, "w")) == NULL) { + fprintf(stderr, "Error, cannot open output file %s\n", filenameto); + return 1; + } + + + //check for lockfile, active PID, and event file for auto "online" mode detection + FILE *FPLOCK; + char lockfile[1024]; + strcpy(lockfile, getenv("HOME")); + strcat(lockfile, "/.Pixie16Lock"); + int lockpid; + + FILE *FPPATH; + char pathfile[1024]; + char line[1024]; + char onlinefile[1024]; + strcpy(pathfile, getenv("HOME")); + strcat(pathfile, "/.Pixie16Path"); + + FPLOCK = fopen(lockfile, "r"); + if (FPLOCK != NULL) { + fscanf(FPLOCK, "%d", &lockpid); + fclose(FPLOCK); + //PID from lockfile matches a running PID; run timesort in "online" mode for now + if (getpgid(lockpid) >= 0) { + FPPATH = fopen(pathfile, "r"); + if (FPPATH == NULL) { + online = 0; + } + else { + fgets(line, 1024, FPPATH); //skip first line + fgets(line, 1024, FPPATH); //need second line + sscanf(line,"%s\n", onlinefile); + fclose(FPPATH); + if (filename == NULL) { + if (strcmp(onlinefile,argv[1]) == 0) { + online = 1; + } + } + else { + if (strcmp(onlinefile,filename+1) == 0) { + online = 1; + } + } + } + } + } + if (online == 1) printf("Auto Mode: \x1B[32mOnline\x1B[0m\n"); + else printf("Auto Mode: \x1B[32mOffline\x1B[0m\n"); + + //check file size for auto "online" mode + fprpos = ftell(fpr); + fseek(fpr, 0L, SEEK_END); + fprsize = fprsize_orig = ftell(fpr); + fseek(fpr, fprpos, SEEK_SET); + + + + + //Get memory for default number of subevents per channel id + for (i=0; i= 0) { + FPPATH = fopen(pathfile, "r"); + if (FPPATH != NULL) { + fgets(line, 1024, FPPATH); //skip first line + fgets(line, 1024, FPPATH); //need second line + sscanf(line,"%s\n", onlinefile); + fclose(FPPATH); + if (filename == NULL) { + if (strcmp(onlinefile,argv[1]) == 0) online = 1; + } + else { + if (strcmp(onlinefile,filename+1) == 0) online = 1; + } + } + } + } + } //end auto online + + + //read 4-byte header + if (fread(subhead, sizeof(subhead), 1, fpr) != 1) break; + nwords = nwords + HEADER_LENGTH; + chn = subhead[0] & 0xF; + sln = (subhead[0] & 0xF0) >> 4; + crn = (subhead[0] & 0xF00) >> 8; + id = crn*MAX_BOARDS_PER_CRATE*MAX_CHANNELS_PER_BOARD + (sln-BOARD_START)*MAX_CHANNELS_PER_BOARD + chn; + length = (subhead[0] & 0x7FFE0000) >> 17; //unit = words with 4 bytes per word + time = ( (long long int)(subhead[2] & 0xFFFF) << 32) + subhead[1]; + if (id > idmax) idmax = id; + + } + + //check memory + if (totmem > MAX_MALLOC) {printf("Error: Exceeded MAX_MALLOC"); return -1;} + + //Expand memory for more events (careful when final is to left of initial in circular buffer) + if ( maxevts[id] - nevts[id] == 1 && totmem < MAX_MALLOC) { + + if (maxevts[id] == DEF_SUB_EVENTS) {evts_old = DEF_SUB_EVENTS; evts_new = M1_SUB_EVENTS;} + if (maxevts[id] == M1_SUB_EVENTS) {evts_old = M1_SUB_EVENTS; evts_new = M2_SUB_EVENTS;} + if (maxevts[id] == M2_SUB_EVENTS) {evts_old = M2_SUB_EVENTS; evts_new = M3_SUB_EVENTS;} + if (maxevts[id] == M3_SUB_EVENTS) {evts_old = M3_SUB_EVENTS; evts_new = M4_SUB_EVENTS;} + if (maxevts[id] == M4_SUB_EVENTS) {evts_old = M4_SUB_EVENTS; evts_new = M5_SUB_EVENTS;} + if (maxevts[id] == M5_SUB_EVENTS) {evts_old = M5_SUB_EVENTS; evts_new = MAX_SUB_EVENTS;} + + if (maxevts[id]==evts_old && totmem + (evts_new-evts_old)*(sizeof(struct subevent) + sizeof(unsigned int)*length) < MAX_MALLOC) { + subevents[id] = (struct subevent *) realloc(subevents[id], sizeof(struct subevent)*evts_new); + if (subevents[id] == NULL) { + printf("realloc failed\n"); + return -1; + } + totmem = totmem - sizeof(struct subevent)*evts_old + sizeof(struct subevent)*evts_new; + maxevts[id] = evts_new; + for (j=evts_old; j evts_old) { + for (j=0; j 3.5 sec) + // large gap could be from low rate or un/replug + if ( time_old == 0 || (time - time_old)/10000000 > 35 ) time_old = time; + + //fill buffers until full (online mode will stop filling buffers after 2.5 sec lag betweeen output/input) + if ( nevts[id] < maxevts[id] && ( (time - time_old)/10000000 < 25 || online == 0 ) ) { + + + j = nevts[id] + iptr[id]; + if (j >= maxevts[id]) j -= maxevts[id]; + + subevents[id][j].timestamp = time; + + if (subevents[id][j].data == NULL) { + subevents[id][j].data = (unsigned int *) malloc(sizeof(unsigned int)*length); + if (subevents[id][j].data == NULL) { + printf("malloc failed\n"); + return -1; + } + totmem += sizeof(unsigned int)*length; + } + else if (length != subevents[id][j].length) { //not needed anymore since always free data after use now. Keep for future ... + subevents[id][j].data = (unsigned int *) realloc(subevents[id][j].data, sizeof(unsigned int)*length); + if (subevents[id][j].data == NULL) { + printf("realloc failed\n"); + return -1; + } + totmem = totmem - sizeof(unsigned int)*subevents[id][j].length + sizeof(unsigned int)*length; + } + + subevents[id][j].length = length; + + if (length>HEADER_LENGTH) { + if (fread(subevents[id][j].data + HEADER_LENGTH, (length-HEADER_LENGTH)*sizeof(int), 1, fpr) != 1) break; + nwords = nwords + (length-HEADER_LENGTH); + } + + for (i=0; i < HEADER_LENGTH; i++) { + subevents[id][j].data[i] = subhead[i]; + } + + nevts[id]++; + evts_tot_read++; + + } + else { + pause = 1; + break; + } + + } // end while for fill buffers + ///////// + + + ///////// + // write event with minimum time to file + timemin_old = timemin; + timemin = -1; + for (i=0; i < idmax + 1; i++) { //could be MAX_ID but limit ourselves to current max, idmax + if (nevts[i] > 0) { + if (timemin == -1) { + timemin = subevents[i][iptr[i]].timestamp; + time_old = timemin; + min_id = i; + } + else if (subevents[i][iptr[i]].timestamp < timemin) { + timemin = subevents[i][iptr[i]].timestamp; + time_old = timemin; + min_id = i; + } + } + } + + + if (timemin > -1) { + if (timemin < timemin_old) { + printf("\nWarning!!! timemin = %lld and timemin_old = %lld and min_id = %d\n", timemin, timemin_old, min_id); + outoforder++; + } + if (subevents[min_id][iptr[min_id]].data == NULL) {printf("Error: data = NULL\n"); return -1;} + fwrite(subevents[min_id][iptr[min_id]].data, sizeof(unsigned int)*subevents[min_id][iptr[min_id]].length, 1, fpw); + + //free data memory up until it's needed again + free(subevents[min_id][iptr[min_id]].data); + subevents[min_id][iptr[min_id]].data = NULL; + totmem -= sizeof(unsigned int)*subevents[min_id][iptr[min_id]].length; + subevents[min_id][iptr[min_id]].length = 0; + subevents[min_id][iptr[min_id]].timestamp = 0; + + nevts[min_id]--; + if (++iptr[min_id] >= maxevts[min_id]) iptr[min_id] -= maxevts[min_id]; + evts_tot_write++; + } + else break; + ///////// + + + //print statistics + //e_div=div(evts_tot_read,10000); + //if ( e_div.rem == 0) + if( evts_tot_read % 10000 == 0 ) + printf("Malloc (%d MB) : evts in (\x1B[34m%lld\x1B[0m) : evts out (\x1B[32m%lld\x1B[0m) : diff (\x1B[31m%lld\x1B[0m)\r", (totmem)/1024/1024, evts_tot_read, evts_tot_write, evts_tot_read-evts_tot_write); + + } //end main while + + + //cleanup + fclose(fpr); + fclose(fpw); + for (i=0; i 0) printf("\x1B[31mWarning, there are %d events out of time order\x1B[0m\n", outoforder); + if (totmem != 0) printf("\x1B[31mError: total memory not conserved\x1B[0m\n"); + + + return 0; +} + + diff --git a/armory/to2root.cpp b/armory/to2root.cpp index e11b96a..c23baea 100644 --- a/armory/to2root.cpp +++ b/armory/to2root.cpp @@ -38,6 +38,7 @@ unsigned long long int dataCount=0; unsigned long long int pileUpCount=0; unsigned long long int evtCount=0; +int traceLength = 280; /////////////////////////////////// // START OF MAIN FUNCTION // @@ -86,9 +87,11 @@ int main(int argc, char **argv) { unsigned long long e_t[MAX_ID] = {0}; bool pileup[MAX_ID] = {0}; int qdc[MAX_ID][8] = {0}; + int cfd[MAX_ID] = {0}; //Added by jake to pull out the cfd int multiCry = 0 ; /// this is total multiplicity for all crystal int runID = 0; // date-run-fileID, Dec15-02-001 = 1502001 int multiGagg = 0; + int trace[MAX_ID][traceLength] = {0}; // added by Jake to pull out traces? //unsigned short pileup[MAXMULTI]; tree->Branch("evID", &evID, "event_ID/l"); @@ -98,9 +101,11 @@ int main(int argc, char **argv) { tree->Branch("e_t", e_t, "e_timestamp[multi]/l"); tree->Branch("pileup", pileup, "pileup[multi]/O"); tree->Branch("qdc", qdc, "qdc[multi][8]/I"); + tree->Branch("cfd", cfd, "cfd[multi]/I");//added by jake to hold the cfd info tree->Branch("multiCry", &multiCry, "multiplicity_crystal/I"); tree->Branch("multiGagg", &multiGagg, "multiplicity_GAGG/I"); - tree->Branch("runID", &runID, "runID/I"); + tree->Branch("runID", &runID, "runID/I"); + tree->Branch("trace", trace, Form("trace[multi][%d]/I",traceLength)); int countGP = 0; //gamma-particle coincident double totalDataSize = 0; @@ -166,8 +171,14 @@ int main(int argc, char **argv) { id[multi] = mapping[haha]; e[multi] = data->energy; e_t[multi] = data->time; + //cfdt[multi] = data->cfd; pileup[multi] = data->pileup; for( int i = 0; i < 8; i++) qdc[multi][i] = data->QDCsum[i]; + cfd[multi] = data->cfd; + for (int k = 0; k < 280; k++) { + trace[multi][k] = (k < data->trace_length) ? data->trace[k] : 0; + } + multi++ ; if( id[multi] < 100 ) multiCry ++; if( id[multi] >= 200 ) multiGagg ++; @@ -180,6 +191,11 @@ int main(int argc, char **argv) { e_t[multi] = data->time; pileup[multi] = data->pileup; for( int i = 0; i < 8; i++) qdc[multi][i] = data->QDCsum[i]; + cfd[multi] = data->cfd; + for (int k = 0; k < 280; k++) { + trace[multi][k] = (k < data->trace_length) ? data->trace[k] : 0; + } + multi++ ; if( id[multi] < 100 ) multiCry ++; if( id[multi] >= 200 ) multiGagg ++; diff --git a/armory/xia2root.cpp b/armory/xia2root.cpp new file mode 100644 index 0000000..20037fd --- /dev/null +++ b/armory/xia2root.cpp @@ -0,0 +1,375 @@ +#include +#include +#include +#include +#include +#include "TFile.h" +#include "TTree.h" +#include "TString.h" +#include "TMath.h" +#include + +#define NUMDET 64 /// number of detector +#define STARTDETID 15 + +std::vector SplitStr(std::string tempLine, std::string splitter, int shift = 0){ + + std::vector output; + + size_t pos; + do{ + pos = tempLine.find(splitter); /// fine splitter + if( pos == 0 ){ ///check if it is splitter again + tempLine = tempLine.substr(pos+1); + continue; + } + + std::string secStr; + if( pos == std::string::npos ){ + secStr = tempLine; + }else{ + secStr = tempLine.substr(0, pos+shift); + tempLine = tempLine.substr(pos+shift); + } + + ///check if secStr is begin with space + while( secStr.substr(0, 1) == " "){ + secStr = secStr.substr(1); + }; + + ///check if secStr is end with space + while( secStr.back() == ' '){ + secStr = secStr.substr(0, secStr.size()-1); + } + + output.push_back(secStr); + //printf(" |%s---\n", secStr.c_str()); + + }while(pos != std::string::npos ); + + return output; +} + +std::vector> LoadCorrectionParameters(TString corrFile){ + + printf("==================== load correction parameters : %s", corrFile.Data()); + std::ifstream file; + file.open(corrFile.Data()); + + std::vector> corr; + corr.clear(); + + std::vector detCorr; + detCorr.clear(); + + if( file.is_open() ){ + + while( file.good() ){ + + std::string line; + getline(file, line); + + if( line.substr(0,1) == "#" ) continue; + if( line.substr(0,2) == "//" ) continue; + if( line.size() == 0 ) continue; + + std::vector temp = SplitStr(line, " "); + + detCorr.clear(); + for( int i = 0; i < (int) temp.size() ; i++){ + detCorr.push_back(std::stod(temp[i])); + } + corr.push_back(detCorr); + } + + file.close(); + + printf(".... done\n"); + printf("===== correction parameters \n"); + for( int i = 0; i < (int) corr.size(); i++){ + printf("det : %2d | ", i ); + int len = (int) corr[i].size(); + for( int j = 0; j < len - 1 ; j++){ + printf("%6.2f, ", corr[i][j]); + } + printf("%6.2f\n", corr[i][len-1]); + } + + }else{ + printf(".... fail\n"); + } + + return corr; +} + + +//################################################################################### +//################ ########################### +//################ main ########################### +//################ ########################### +//################################################################################### +int main(int argn,char **argv) { + if ( argn == 1 ) { + printf("Usage: \n"); + printf("%s file_in.evt raw_Opt timeWidow correctionFile\n", argv[0]); + printf(" | | |\n"); + printf(" | | + correction file, row for det, col for order of correction\n"); + printf(" | |\n"); + printf(" | + when build event, event build window, 1 = 10 ns, default 100\n"); + printf(" + default 0 = raw, 1 = event build \n"); + /// std::cerr<<"Usage:\n "<= 3 ) rawOpt = atoi(argv[2]); + + int timeWindow = 100; + if ( argn >= 4 ) timeWindow = atoi(argv[3]); + + TString corrFileName = ""; + bool hasCorr = false; + if ( argn == 5 ) { + corrFileName = argv[4]; + hasCorr = true; + } + + FILE *infile=fopen(argv[1],"r"); + if (infile==NULL) { + printf("cannot open file : %s \n", argv[1]); + ///std::cerr<<"Problem opening "<> corr; + if( hasCorr ) corr = LoadCorrectionParameters(corrFileName); + + int chan,slot,chann; + int pu; /// pile up + int energy; + double cEnergy; + unsigned long long evtime; + unsigned short cfd; + + int pileupcount = 0; + int zerocount = 0; + int PileUp[64]; + + const unsigned long maskpu = 2147483648; + const unsigned long multiplier = 4294967296LL; + + double energyA[NUMDET]; + double cEnergyA[NUMDET]; + unsigned long long timeA[NUMDET]; + int puA[NUMDET]; + long long diffTimeA[NUMDET]; + unsigned short cfdA[NUMDET]; + int multi = 0; /// multipicilty in an event + int detMulti[NUMDET]; /// multiplicity in a detector in an event + + TFile * outFile = new TFile(outFileName, "RECREATE"); + outFile->cd(); + TTree * tree = new TTree("tree", "tree"); + + tree->Branch("eventID", &eventID, "event_number/l"); + + if ( rawOpt == 0 ){ /// when save raw data + tree->Branch("chan", &chan, "chan/I"); + tree->Branch("slot", &slot, "slot/I"); + tree->Branch("chann", &chann, "channel number/I"); + tree->Branch("pu", &pu, "pile-up/I"); + tree->Branch("energy", &energy, "energy/I"); + if( hasCorr) tree->Branch("cEnergy", &cEnergy, "corrected_energy/D"); + tree->Branch("time", &evtime, "timestamp/l"); + tree->Branch("cfd", &cfd, "cfd/s"); + }else{ /// when build event by time-window + tree->Branch("energy", energyA, Form("energy[%d]/D", NUMDET)); + if( hasCorr) tree->Branch("cEnergy", cEnergyA, Form("corrected_energy[%d]/D", NUMDET)); + tree->Branch("time", timeA, Form("timestamp[%d]/l", NUMDET)); + tree->Branch("dtime", diffTimeA, Form("diff_time[%d]/L", NUMDET)); + tree->Branch("pu", puA, Form("pile_up[%d]/I", NUMDET)); + tree->Branch("cfd", cfdA, Form("cfd[%d]/I", NUMDET)); + tree->Branch("multi", &multi, "multiplicity/I"); + tree->Branch("detMulti", detMulti, Form("det_multiplicity[%d]/I", NUMDET)); + } + + ///change this for 64bit compiler long *bufsam=NULL; + + //clear energy and time array + for( int i = 0; i < NUMDET; i++){ + energyA[i] = TMath::QuietNaN(); + cEnergyA[i] = TMath::QuietNaN(); + timeA[i] = 0; + diffTimeA[i] = -999; + cfdA[i] = 0; + puA[i] = -1; + detMulti[i] = 0; + } + multi = 0; + + unsigned long long startTime = 0; + long long diffTime = 0; + + int bread = 1; + int bsam = 2; + long * bufsiz=new long[bsam]; + unsigned int *bufsam = NULL; + + printf("============ Start looping events | build event ? %s", rawOpt == 0 ? "No" : "Yes"); + if( rawOpt == 1 ) { + printf(" time window : +- %d click\n", timeWindow); + }else{ + printf("\n"); + } + while ( !feof(infile) ) { + + // get buffer size + ///change long -> int for 64 bit + fread(bufsiz,sizeof(int),bread,infile); /// read 1 int (4 byte) from infile and save to bufsize + int bsize = bufsiz[0] -4 ; + if (feof(infile)) break; + blockNum ++; + + ///change for 64bit bufsam=new long[bsize/4+1]; + bufsam = new unsigned int[bsize/4+1]; + fread((char*)bufsam, 1, bsize, infile); /// read bsize of 1 byte from infile and save to char + ///printf("============ bsize : %d \n", bsize); + ///for( int i = 0; i < bsize; i++) printf("%d, ", bufsam[i]); + ///printf("\n"); + + if (bufsam[0] == 30) { + block30Num ++; + chan = (bufsam[2]) & (15); + slot = ((bufsam[2]) & (240))/16; + chann = (slot - 2)*16 + chan + 1; + pu = ((bufsam[2]) & (maskpu))/maskpu; + energy = ((bufsam[5]) & 65535); + unsigned long long evtimehi = ((bufsam[4]) & 65535); + unsigned long long evtimelo = bufsam[3]; + evtime = evtimelo + multiplier*evtimehi; + cfd = bufsam[4]/65536; + + if ( energy == 0 ) zerocount++; + if ( pu > 0 ) pileupcount++; + if ((pu > 0 ) && ( chann > 0 ) && ( chann < 65 )) PileUp[chann-1]++; + + if( blockNum % 100000 == 0 ) printf("."); + ///if( blockNum % 100000 == 0 ) printf("%llu \n", blockNum); + ///if( block30Num < 50) printf("b30: %10llu, chan: %d, slot: %d, chann: %2d, pu: %2d, energy: %5d, evtime: %13llu, cfd: %d\n", block30Num, chan, slot, chann, pu, energy, evtime, cfd); + + /// energy correction + if ( hasCorr ){ + cEnergy = 0; + int order = (int) corr[chann-1].size(); + for( int i = 0; i < order ; i++){ + cEnergy += corr[chann-1][i] * TMath::Power((double)energy, i); + } + } + + if ( rawOpt == 0 ) { + eventID++; + outFile->cd(); + tree->Fill(); + }else{ /// build event + + if ( startTime == 0 ) startTime = evtime; + + diffTime = evtime - startTime; + + if( -timeWindow < diffTime && diffTime < timeWindow ){ + + if( !TMath::IsNaN(energyA[chann-1]) ) detMulti[chann-1] ++; + energyA[chann-1] = energy; + cEnergyA[chann-1] = cEnergy; + timeA[chann-1] = evtime; + diffTimeA[chann-1] = diffTime; + puA[chann-1] = pu; + detMulti[chann-1]++; + multi++; + + + }else{ + /// fill tree + eventID++; + outFile->cd(); + tree->Fill(); + /// clear energy and time array + multi = 0; + for( int i = 0; i < NUMDET; i++){ + energyA[i] = TMath::QuietNaN(); + cEnergyA[i] = TMath::QuietNaN(); + timeA[i] = 0; + diffTimeA[i] = -999; + puA[i] = -1; + detMulti[i] = 0; + cfdA[i] = 0; + } + + /// fill the 1st data of a new event + startTime = evtime; + energyA[chann-1] = energy; + cEnergyA[chann-1] = cEnergy; + timeA[chann-1] = evtime; + diffTimeA[chann-1] = 0; + puA[chann-1] = pu; + detMulti[chann-1]++; + multi++; + } + } + + } ///end if bufsam[0]=30 + + } + + delete [] bufsiz; + delete [] bufsam; + fclose(infile); + + printf("\n============ end of event loop, totoal block read: %llu \n", blockNum); + + eventID++; + outFile->cd(); + tree->Write(); + outFile->Close(); + + + //========================= Print summary + printf("============================================\n"); + ///printf(" number of block: %llu\n", blockNum); + printf(" number of type 30 block: %llu\n", block30Num); + printf(" event built: %llu\n", eventID); + printf("============================================\n"); + + return 0; +} + diff --git a/mapping.h b/mapping.h index 4838322..5ac1739 100644 --- a/mapping.h +++ b/mapping.h @@ -1,8 +1,11 @@ /************************************ Clover : 0 - 99 BGO : 100 - 199 -GAGG : 200 - 299 -ZERO DEGREE : 300 - 399 +GAGG A : 200 - 299 +GAGG B : 300 - 399 +ZERO DEGREE : 400 - 499 +BEGE : 44 - 45 +LaBr3 : 500 - 599 * *********************************/ #ifndef MAPPING @@ -16,20 +19,27 @@ ZERO DEGREE : 300 - 399 #define NGAGG 26 #define NZEROGAGG 2 ///NZERO is used -int mapping[176] ={ +//Help for people looking at this mapping: +//rows are pixie slots, colomns correspond to channels. Key for the first row: +//clover1_blue, clover1_black, clover1_green, clover1_red BGO1, clover2_blue, clover2_black, clover2_green, clover2_red, BGO2, clover3_blue, clover3_black, clover3_green, clover3_red, BGO3, EMPTY_CHANNEL + +//This also does not take the missing detectors into account, it assumes a detector in each channel. +int mapping[208] ={ //***************** <-- load indicator for EventBuidler //-0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - 0, 1, 2, 3, 100, 4, 5, 6, 7, 101, 8, 9, 10, 11, 102, -1, //mod-0 - 12, 13, 14, 15, 103, 16, 17, 18, 19, 104, 20, 21, 22, 23, 105, -1, //mod-1 - 24, 25, 26, 27, 106, 28, 29, 30, 31, 107, 32, 33, 34, 35, 108, -1, //mod-2 - 36, 37, 38, 39, 109, 40, 41, 42, 43, 110, 300, 301, 200, 201, 202, 203, //mod-3 - 204, 205, 206, 207, 208, 209, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, //mod-4 - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, //mod-5, Ring 4A - 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, //mod-6, Ring 4B - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //mod-7 - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //mod-8 - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //mod-9 - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //mod-10 + 0, 1, 2, 3, 100, 4, 5, 6, 7, 101, 8, 9, 10, 11, 102, 44, //slot 2 + 12, 13, 14, 15, 103, 16, 17, 18, 19, 104, 20, 21, 22, 23, 105, 45, //slot 3 + 24, 25, 26, 27, 106, 28, 29, 30, 31, 107, 32, 33, 34, 35, 108, -1, //slot 4 + 36, 37, 38, 39, 109, 40, 41, 42, 43, 110, 400, 401, -1, -1, -1, -1, //slot 5 + 200, 300, 201, 301, 202, 302, 203, 303, 204, 304, 205, 305, 206, 306, 207, 307, //slot 6 Trinity ring 1 (A and B channels alternating) crystal 1 - 8 + 208, 308, 209, 309, 210, 310, 211, 311, 212, 312, 213, 313, 214, 314, 215, 315, //slot 7 Ring 2, A and B alternating crystal 1 - 8 + 216, 316, 217, 317, 218, 318, 219, 319, 220, 320, 221, 321, 222, 322, 223, 323, //slot 8 Ring 2 first 4 channels ( crystals 9 - 10 A and B ) the rest is Ring 3 crystals 1 - 6 alternating A and B + 224, 324, 225, 325, 226, 326, 227, 327, 228, 328, 229, 329, 230, 330, 231, 331, //slot 9 Ring 3 crystal 7 - 14 A and B alternating + 232, 332, 233, 333, 234, 334, 235, 335, 236, 336, 237, 337, 238, 338, 239, 339, //slot 10 Ring 4 crystals 1 - 8 + 240, 340, 241, 341, 242, 342, 243, 343, 244, 344, 245, 345, 246, 346, 247, 347, //slot 11 Ring 4 crystals 9 - 16 + 248, 348, 249, 349, 250, 350, 251, 351, 252, 352, 253, 353, 254, 354, 255, 355, //slot 12 Ring 5 crystals 1 - 8 + 256, 356, 257, 357, 258, 358, 259, 359, 260, 360, 261, 361, 262, 362, 263, 363, //slot 13 Ring 5 crystals 9 -16 + 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, //slot 14 LaBr3 //**************** <-- end of mapping indicator EventBuidler };