From e3aa858ff0f0017cbac0cb5ed106f3e17c6456b9 Mon Sep 17 00:00:00 2001 From: "ryan@pauli" Date: Tue, 24 May 2022 18:21:12 -0400 Subject: [PATCH] initial commit --- .gitignore | 8 + Cali_gamma_histogram.C | 267 +++ DecayFinder.C | 246 +++ DecayFinder.h | 136 ++ PIDCutChecker.C | 54 + PIDCutCreator.C | 90 + armory/AnalysisLibrary.h | 296 +++ armory/Analyzer_Utili.c | 195 ++ armory/AutoFit.C | 2787 +++++++++++++++++++++++++++++ armory/DataBlock.h | 110 ++ armory/EventBuilder_evt | Bin 0 -> 41392 bytes armory/EventBuilder_evt.cpp | 270 +++ armory/EventBuilder_seperated.cpp | 206 +++ armory/LoadCorrection.h | 111 ++ armory/MergeEVT | Bin 0 -> 26224 bytes armory/MergeEVT.cpp | 135 ++ armory/ev22txt | Bin 0 -> 16516 bytes armory/ev22txt.cpp | 81 + armory/evt2hist | Bin 0 -> 158952 bytes armory/evt2hist.cpp | 344 ++++ armory/evtReader.h | 373 ++++ armory/makefile | 25 + convertPixie.sh | 87 + correction_Clover.dat | 52 + correction_e.dat | 1 + degai.cal | 64 + mapping.h | 56 + nscl2pixie.c | 288 +++ peachCake.C | 380 ++++ peachCake.h | 201 +++ pixie_evt | 1 + rawdata | 1 + rootlogon.C | 42 + script.C | 10 + 34 files changed, 6917 insertions(+) create mode 100644 .gitignore create mode 100644 Cali_gamma_histogram.C create mode 100644 DecayFinder.C create mode 100644 DecayFinder.h create mode 100644 PIDCutChecker.C create mode 100644 PIDCutCreator.C create mode 100644 armory/AnalysisLibrary.h create mode 100644 armory/Analyzer_Utili.c create mode 100644 armory/AutoFit.C create mode 100644 armory/DataBlock.h create mode 100755 armory/EventBuilder_evt create mode 100644 armory/EventBuilder_evt.cpp create mode 100644 armory/EventBuilder_seperated.cpp create mode 100644 armory/LoadCorrection.h create mode 100755 armory/MergeEVT create mode 100644 armory/MergeEVT.cpp create mode 100755 armory/ev22txt create mode 100644 armory/ev22txt.cpp create mode 100755 armory/evt2hist create mode 100644 armory/evt2hist.cpp create mode 100644 armory/evtReader.h create mode 100644 armory/makefile create mode 100755 convertPixie.sh create mode 100644 correction_Clover.dat create mode 120000 correction_e.dat create mode 100644 degai.cal create mode 100644 mapping.h create mode 100644 nscl2pixie.c create mode 100644 peachCake.C create mode 100644 peachCake.h create mode 120000 pixie_evt create mode 120000 rawdata create mode 100644 rootlogon.C create mode 100644 script.C diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8f7a6fb --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.pcm +*.d +*.so +*.root + +legacy_code +nscl2pixie +nscl2pixie_haha diff --git a/Cali_gamma_histogram.C b/Cali_gamma_histogram.C new file mode 100644 index 0000000..534b933 --- /dev/null +++ b/Cali_gamma_histogram.C @@ -0,0 +1,267 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "armory/AnalysisLibrary.h" + +vector Cali_gamma_histogram(TH1F * hist, int opt = 0, float threshold = 0.1, int peakDensity = 10){ + /**///======================================================== load tree + + printf("============================================================= \n"); + printf("====================== Cali_gamma.C ========================= \n"); + printf("============================================================= \n"); + + /**///======================================================== Browser or Canvas + + vector sol; + + if( hist->GetEntries() < 100 ){ + sol.push_back(0); + sol.push_back(1); + return sol; + } + + Int_t Div[2] = {2,2}; //x,y + Int_t size[2] = {600,300}; //x,y + + TCanvas * cAlpha = (TCanvas *) gROOT->FindObjectAny("cAlpha"); + if( cAlpha == NULL ){ + cAlpha = new TCanvas("cAlpha", "cAlpha", 0, 0, size[0]*Div[0], size[1]*Div[1]); + } + cAlpha->Clear(); + cAlpha->Divide(Div[0],Div[1]); + + for( int i = 1; i <= Div[0]*Div[1] ; i++){ + cAlpha->cd(i)->SetGrid(); + } + + gStyle->SetOptStat(0); + gStyle->SetStatY(1.0); + gStyle->SetStatX(0.99); + gStyle->SetStatW(0.2); + gStyle->SetStatH(0.1); + + if(cAlpha->GetShowEditor() )cAlpha->ToggleEditor(); + if(cAlpha->GetShowToolBar() )cAlpha->ToggleToolBar(); + + /**///========================================================= Analysis + + cAlpha->cd(1); + hist->Draw(); + cAlpha->Update(); + gSystem->ProcessEvents(); + + int dummy = 0; + int temp = 0; + + int nPeaks = 10; + vector energy; + vector refEnergy; + vector fitEnergy; + + + printf("---- finding peak using TSepctrum Class...\n"); + + TSpectrum * spec = new TSpectrum(20); + nPeaks = spec->Search(hist, peakDensity, "", threshold); + printf("---- found %2d peaks | ", nPeaks); + + double * xpos = spec->GetPositionX(); + double * ypos = spec->GetPositionY(); + + cAlpha->Update(); + gSystem->ProcessEvents(); + + vector height; + + int * inX = new int[nPeaks]; + TMath::Sort(nPeaks, xpos, inX, 0 ); + for( int j = 0; j < nPeaks; j++){ + energy.push_back(xpos[inX[j]]); + height.push_back(ypos[inX[j]]); + } + + for( int j = 0; j < nPeaks; j++) printf("%7.2f, ", energy[j]); + printf("\n"); + + + //------------ 3, correction + int option = 0; + if ( opt == 0 ) { + printf("========== which detector to be the reference?\n"); + printf("-1 = manual reference\n"); + printf("-2 = use 228Th, first 5 strongest peaks \n"); + printf("-3 = use 207Bi, 3 peaks \n"); + printf("-4 = use 152Eu, 11 peaks \n"); + printf("-9 = stop \n"); + printf("your choice = "); + temp = scanf("%d", &option); + }else{ + option = opt; + } + + if( option == -9 ) { + printf("------ stopped by user.\n"); + return sol; + } + + + + //======== fill reference energy + if(option == -1){ + for( int i = 0; i < nPeaks; i++){ + float eng; + printf("%2d-th peak energy %f ch (-1 to skip, -2 to skip all):", i, energy[i]); + temp = scanf("%f", &eng); + if( eng >= 0 ) { + refEnergy.push_back(eng); + fitEnergy.push_back(energy[i]); + printf(" input: %f \n", eng); + }else if ( eng == -1 ){ + printf(" input: skipped \n"); + }else if ( eng == -2 ){ + break; + } + }; + } + + if( option == -2 ){ + fitEnergy = energy; + + refEnergy.clear(); + refEnergy.push_back(5.423); + refEnergy.push_back(5.685); + refEnergy.push_back(6.288); + refEnergy.push_back(6.778); + refEnergy.push_back(8.785); + } + + if( option == -3 ){ + + fitEnergy = energy; + + refEnergy.clear(); + refEnergy.push_back(0.569702); + refEnergy.push_back(1.063662); + refEnergy.push_back(1.770237); + } + + if( option == -4 ){ + fitEnergy = energy; + + refEnergy.clear(); + refEnergy.push_back( 121.783); + refEnergy.push_back( 244.699); + refEnergy.push_back( 344.281); + refEnergy.push_back( 411.115); + refEnergy.push_back( 443.965); + refEnergy.push_back( 778.903); + refEnergy.push_back( 867.390); + refEnergy.push_back( 964.055); + refEnergy.push_back(1085.842); + refEnergy.push_back(1112.087); + refEnergy.push_back(1408.022); + } + + //==================== adjusting energy + int n = refEnergy.size(); + for( int k = 0; k < n; k++) printf("%2d-th peak : %f \n", k, refEnergy[k]); + + nPeaks = energy.size(); + + vector k1 = fitEnergy; + vector k2 = refEnergy; + //===== when nPeaks != refEnergy.size(), need to matching the two vector size by checking the r-squared. + if( option != -1 ){ + vector> haha = FindMatchingPair(fitEnergy, refEnergy); + k1 = haha[0]; + k2 = haha[1]; + } + + TGraph * graph = new TGraph(min(n, nPeaks), &k1[0], &k2[0] ); + cAlpha->cd(2); + graph->Draw("A*"); + gSystem->ProcessEvents(); + + TF1 * fit = new TF1("fit", "pol1" ); + graph->Fit("fit", "q"); + + double a0 = fit->GetParameter(0); + double a1 = fit->GetParameter(1); + double a2 = 0.0 ; //fit->GetParameter(2); + + printf("----- a0: %9.6f, a1: %9.6f (%14.8f) \n", a0, a1, 1./a1); + printf(" %13.10f\t %13.10f \n", a0, a1); + + sol.clear(); + sol.push_back(a0); + sol.push_back(a1); + + //====== Plot residue + vector resi; + for( int i = 0 ; i < min(n, nPeaks); i++){ + resi.push_back(k2[i] - fit->Eval(k1[i])); + } + TGraph * graphResi = new TGraph(min(n, nPeaks), &k2[0], &resi[0] ); + + cAlpha->cd(4); + graphResi->Draw("A*"); + graphResi->GetYaxis()->SetTitle("residue [keV]"); + graphResi->GetXaxis()->SetTitle("cali energy [keV]"); + gSystem->ProcessEvents(); + + //====== Plot adjusted spectrum + + cAlpha->cd(3); + + int bin = hist->GetNbinsX(); + double xMin = hist->GetXaxis()->GetXmin(); + double xMax = hist->GetXaxis()->GetXmax(); + + double xMinC, xMaxC; + if( a1 > 0 ) { + xMinC = xMin*xMin*a2 + xMin*a1 + a0; + xMaxC = xMax*xMax*a2 + xMax*a1 + a0; + }else{ + xMaxC = xMin*xMin*a2 + xMin*a1 + a0; + xMinC = xMax*xMax*a2 + xMax*a1 + a0; + } + + + TH1F * calH = new TH1F("calH", "calibrated energy", bin, xMinC, xMaxC); + + /* + FILE * paraOut; + TString filename; + filename.Form("hist%s.dat", hist->GetName()); + paraOut = fopen (filename.Data(), "w+"); + */ + for( int i = 1; i <= bin; i ++){ + int y = hist->GetBinContent(i); + int x = hist->GetBinCenter(i); + + calH->Fill(x*x*a2 + x*a1+a0, y); + + //fprintf(paraOut, "%9.6f, %9d\n", x*x*a2 + x*a1+a0, y); + + } + + // fflush(paraOut); + // fclose(paraOut); + + calH->Draw(); + gSystem->ProcessEvents(); + + return sol; + +} diff --git a/DecayFinder.C b/DecayFinder.C new file mode 100644 index 0000000..139ba6e --- /dev/null +++ b/DecayFinder.C @@ -0,0 +1,246 @@ +#define DecayFinder_cxx + +#include "DecayFinder.h" +#include +#include +#include +#include +#include +#include +#include +#include + +//===================== Settings +Bool_t debug = false; + +TString pidCutFileName = "PIDCuts.root"; + +double distThreshold = 0.2; +double forwardTime = 250; //ms +double backwardTime = 100; //ms + +//===================== histograms + +TH2F * hPID; +TH1F ** hDecay ; +TH2F * hDist; +TH1F ** hvetoF; + +TH2F * hIonsPos; +TH2F * hBetaPos; + +//===================== Parameters + +int tick2ns = 8; +double tick2ms = tick2ns / 1e6; + +TFile * cutFile; +TCutG * cut = NULL; +TObjArray * cutList; +int numCut = 0; + +int numMatch = 0; + +//===================== Begins +void DecayFinder::Begin(TTree * /*tree*/){ + + TString option = GetOption(); + + hPID = new TH2F("hPID", "PID; TOF; dE", 400, -260, -220, 400, 0, 6500); + + hDist = new TH2F("hDist", "dist; dx; dy", 100, -distThreshold, distThreshold, 100, -distThreshold, distThreshold); + + hIonsPos = new TH2F("hIonsPos", "Ions Pos; x; y", 200, 0, 1, 200, 0, 1); + hBetaPos = new TH2F("hBetaPos", "Beta Pos; x; y", 200, 0, 1, 200, 0, 1); + + //-------------- GetCut; + cutFile = new TFile(pidCutFileName, "UPDATE"); + bool listExist = cutFile->GetListOfKeys()->Contains("cutList"); + if( !listExist ) { + cutList = new TObjArray(); + }else{ + cutList = (TObjArray*) cutFile->FindObjectAny("cutList"); + numCut = cutList->GetLast()+1; + printf("------------ found %d cuts in %s \n", numCut, pidCutFileName.Data()); + for( int k = 0; k < numCut; k++){ + if( cutList->At(k) != NULL ){ + printf("found a cut at %2d \n", k); + }else{ + printf(" No cut at %2d \n", k); + } + } + } + + hDecay = new TH1F *[numCut]; + hvetoF = new TH1F *[numCut]; + + for( int i = 0; i < numCut; i++){ + hDecay[i] = new TH1F(Form("hDecay%02d",i), Form("Decay cut-%02d ; [ms]; count", i), 50, -backwardTime, forwardTime); + hvetoF[i] = new TH1F(Form("hvetoF%02d",i), Form("veto-F cut-%02d ; [ms]; count", i), 100, 0, 6000); + } + + printf("=====================================\n"); + +} + +double dist(double x1, double x2, double y1, double y2){ + return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)); +} + +//===================== Process +Bool_t DecayFinder::Process(Long64_t entry){ + + if( entry > (Long64_t)1e6 ) return kTRUE; + + b_TOF->GetEntry(entry); + b_energy->GetEntry(entry); + b_crossTime->GetEntry(entry); + b_crossEnergy->GetEntry(entry); + b_flag->GetEntry(entry); + b_vetoFlag->GetEntry(entry); + b_xIons->GetEntry(entry); + b_yIons->GetEntry(entry); + b_dyIonsTime->GetEntry(entry); + b_veto_r->GetEntry(entry); + b_veto_f->GetEntry(entry); + + ULong64_t ImplantEntry = 0; + ULong64_t ImplantTime = 0; + double ImplantX = TMath::QuietNaN(); + double ImplantY = TMath::QuietNaN(); + + if( debug && entry % 10 == 0 ) printf("------------- %llu\n", entry); + + if( flag & 1 ) hPID->Fill(TOF, energy); + + int cutID = -1; + for(int i = 0; i < numCut; i++){ + cut = (TCutG*) cutList->At(i); + if( cut->IsInside(TOF, energy) ) cutID = i; + } + + if( cutID == -1 ) return kTRUE; + if( (flag & 1) == 0 ) return kTRUE; /// no beam + //if( (flag & 2) == 0 ) return kTRUE; /// no Ions + if( (flag & 4) == 0 ) return kTRUE; /// no beta + + //if( veto_f > 0 ) return kTRUE; + if( veto_r > 0 ) return kTRUE; + if( dyIonsTime[0] == 0 ) return kTRUE; + + ImplantEntry = entry; + ImplantTime = dyIonsTime[0]; + ImplantX = xIons; + ImplantY = yIons; + + hIonsPos->Fill( xIons, yIons); + + if( debug ) printf("===========%8lld, %13llu, %f, %f\n", ImplantEntry, ImplantTime, ImplantX, ImplantY); + + for( ULong64_t k = ImplantEntry - 10000; k < totNumEntry ; k++){ + b_flag->GetEntry(k); + b_vetoFlag->GetEntry(k); + b_dyBetaTime->GetEntry(k); + b_crossTime->GetEntry(k); + b_crossEnergy->GetEntry(k); + b_veto_f->GetEntry(k); + b_veto_r->GetEntry(k); + b_xBeta->GetEntry(k); + b_yBeta->GetEntry(k); + + if ( k == ImplantEntry ) continue; + + //if( crossTime > 0 ) continue; + if( crossEnergy > 0 ) continue; + //if( (flag & 2) == 2 ) continue; /// has Ions + if( (flag & 4) == 0 ) continue; /// no Beta + if( !TMath::IsNaN(veto_f) ) continue; + if( !TMath::IsNaN(veto_r) ) continue; + if( dyBetaTime[0] == 0) continue; + if( dist(ImplantX, xBeta, ImplantY, yBeta) > distThreshold ) continue; + + if( k < ImplantEntry && ( ImplantTime - dyBetaTime[0] ) * tick2ms > backwardTime) continue; + if( k > ImplantEntry && ( dyBetaTime[0] - ImplantTime ) * tick2ms > forwardTime ) break; + + clock.Stop("timer"); + Double_t time = clock.GetRealTime("timer"); + clock.Start("timer"); + printf(" %llu[%.2f%%], searched next %lld events | match case %d | expect : %5.2f min\r", + ImplantEntry, ImplantEntry*100./totNumEntry, k - ImplantEntry, + numMatch, totNumEntry*time/(ImplantEntry+1.)/60.); + + if( debug ) printf(" %8lld, %13llu, %f, %f\n", k, dyBetaTime[0], xBeta, yBeta); + if( debug ) printf("+++++++++++%8s, %13llu | %.f ms\n", "+", dyBetaTime[0], (dyBetaTime[0] - ImplantTime)*tick2ms); + + hDist->Fill(ImplantX - xBeta, ImplantY - yBeta); + + numMatch ++; + double dT = 0; + if( dyBetaTime[0] > ImplantTime ){ + dT = (dyBetaTime[0] - ImplantTime)*tick2ms; + }else{ + dT = (ImplantTime - dyBetaTime[0])*tick2ms; + dT = -dT; + } + + hDecay[cutID]->Fill(dT); + hvetoF[cutID]->Fill(crossEnergy); + hBetaPos->Fill(xBeta, yBeta); + + } + + return kTRUE; +} + + +void DecayFinder::Terminate(){ + + //============== Save the results + TFile * haha = new TFile("results.root", "recreate"); + haha->cd(); + for( int i = 0; i < numCut; i++){ + hDecay[i]->Write(); + } + hPID->Write(); + haha->Close(); + + //============== Plot result + gStyle->SetOptStat("neiou"); + TCanvas * cDecay = new TCanvas("cDecay", "Decay", 1000, 1000); + cDecay->Divide(2,2); + + int padID = 1; cDecay->cd(padID); + hPID->Draw("colz"); + for( int i = 0; i < numCut; i++){ + cut = (TCutG*) cutList->At(i); + cut->SetLineColor(i+2); + cut->Draw("same"); + } + + padID++; cDecay->cd(padID); //cDecay->cd(padID)->SetLogy(); + double yMax = 0; + for( int i = 0; i < numCut; i++){ + if( hDecay[i]->GetMaximum() > yMax ) yMax = hDecay[i]->GetMaximum(); + } + for( int i = 0; i < numCut; i++){ + hDecay[i]->SetLineColor(i+2); + hDecay[i]->SetMaximum(yMax *1.2); + hDecay[i]->Draw(i == 0 ? "" : "same"); + } + + //padID++; cDecay->cd(padID); + //hDist->Draw("colz"); + // + //padID++; cDecay->cd(padID); + //for( int i = 0; i < numCut; i++){ + // hvetoF[i]->SetLineColor(i+2); + // hvetoF[i]->Draw(i == 0 ? "" : "same"); + //} + + padID++; cDecay->cd(padID); + hIonsPos->Draw("colz"); + + padID++; cDecay->cd(padID); + hBetaPos->Draw("colz"); + +} diff --git a/DecayFinder.h b/DecayFinder.h new file mode 100644 index 0000000..93aee38 --- /dev/null +++ b/DecayFinder.h @@ -0,0 +1,136 @@ +////////////////////////////////////////////////////////// +// This class has been automatically generated on +// Mon May 16 17:09:53 2022 by ROOT version 6.24/06 +// from TTree tree/tree +// found on file: run-0238_00_02.root +////////////////////////////////////////////////////////// + +#ifndef DecayFinder_h +#define DecayFinder_h + +#include +#include +#include +#include +#include + +// Header file for the classes stored in the TTree if any. + +class DecayFinder : public TSelector { +public : + TTree *fChain; //!pointer to the analyzed TTree or TChain + +// Fixed size dimensions of array or collections stored in the TTree if any. + + // Declaration of leaf types + ULong64_t eventID; + //Int_t runID; + Double_t TOF; + Double_t energy; + UInt_t crossEnergy; + ULong64_t crossTime; + Short_t flag; + Short_t vetoFlag; + Double_t xIons; + Double_t yIons; + Double_t xBeta; + Double_t yBeta; + ULong64_t dyIonsTime[4]; + ULong64_t dyBetaTime[4]; + Double_t veto_f; + Double_t veto_r; + + // List of branches + TBranch *b_eventID; //! + //TBranch *b_runID; //! + TBranch *b_TOF; //! + TBranch *b_energy; //! + TBranch *b_crossTime; //! + TBranch *b_crossEnergy; //! + TBranch *b_flag; //! + TBranch *b_vetoFlag; //! + TBranch *b_xIons; //! + TBranch *b_yIons; //! + TBranch *b_xBeta; //! + TBranch *b_yBeta; //! + TBranch *b_dyIonsTime; //! + TBranch *b_dyBetaTime; //! + TBranch *b_veto_f; //! + TBranch *b_veto_r; //! + + DecayFinder(TTree * /*tree*/ =0) : fChain(0) { } + virtual ~DecayFinder() { } + virtual Int_t Version() const { return 2; } + virtual void Begin(TTree *tree); + virtual void SlaveBegin(TTree *tree); + virtual void Init(TTree *tree); + virtual Bool_t Notify(); + virtual Bool_t Process(Long64_t entry); + virtual Int_t GetEntry(Long64_t entry, Int_t getall = 0) { return fChain ? fChain->GetTree()->GetEntry(entry, getall) : 0; } + virtual void SetOption(const char *option) { fOption = option; } + virtual void SetObject(TObject *obj) { fObject = obj; } + virtual void SetInputList(TList *input) { fInput = input; } + virtual TList *GetOutputList() const { return fOutput; } + virtual void SlaveTerminate(); + virtual void Terminate(); + + ClassDef(DecayFinder,0); + + ULong64_t totNumEntry; + + //clock + TBenchmark clock; + +}; + +#endif + +#ifdef DecayFinder_cxx +void DecayFinder::Init(TTree *tree){ + + // Set branch addresses and branch pointers + if (!tree) return; + fChain = tree; + fChain->SetMakeClass(1); + + fChain->SetBranchAddress("eventID", &eventID, &b_eventID); + //fChain->SetBranchAddress("runID", &runID, &b_runID); + fChain->SetBranchAddress("TOF", &TOF, &b_TOF); + fChain->SetBranchAddress("energy", &energy, &b_energy); + fChain->SetBranchAddress("crossTime", &crossTime, &b_crossTime); + fChain->SetBranchAddress("crossEnergy", &crossEnergy, &b_crossEnergy); + fChain->SetBranchAddress("flag", &flag, &b_flag); + fChain->SetBranchAddress("vetoFlag", &vetoFlag, &b_vetoFlag); + fChain->SetBranchAddress("xIons", &xIons, &b_xIons); + fChain->SetBranchAddress("yIons", &yIons, &b_yIons); + fChain->SetBranchAddress("xBeta", &xBeta, &b_xBeta); + fChain->SetBranchAddress("yBeta", &yBeta, &b_yBeta); + fChain->SetBranchAddress("dyIonsTime", dyIonsTime, &b_dyIonsTime); + fChain->SetBranchAddress("dyBetaTime", dyBetaTime, &b_dyBetaTime); + fChain->SetBranchAddress("veto_f", &veto_f, &b_veto_f); + fChain->SetBranchAddress("veto_r", &veto_r, &b_veto_r); + + totNumEntry = fChain->GetEntries(); + + //==== clock + clock.Reset(); + clock.Start("timer"); + +} + +Bool_t DecayFinder::Notify(){ + + return kTRUE; +} + +void DecayFinder::SlaveTerminate(){ + +} + + +void DecayFinder::SlaveBegin(TTree * /*tree*/){ + TString option = GetOption(); +} + + +#endif // #ifdef DecayFinder_cxx diff --git a/PIDCutChecker.C b/PIDCutChecker.C new file mode 100644 index 0000000..137754b --- /dev/null +++ b/PIDCutChecker.C @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void PIDCutChecker(TH2F* hist, + TString saveFileName = "PIDCuts.root", + bool isLogz = false + ){ + + printf("================ Graphic Cut Checker for PID ============== \n"); + + gStyle->SetOptStat("neiou"); + + TCanvas * cCutCreator = new TCanvas("cCutCreator", "PID Cut Creator", 100, 100, 800, 800); + if( !cCutCreator->GetShowToolBar() ) cCutCreator->ToggleToolBar(); + + cCutCreator->Update(); + if( isLogz ) cCutCreator->cd()->SetLogz(); + hist->Draw("colz"); + + TFile * cutFile; + TCutG * cut = NULL; + TObjArray * cutList; + + ///===================== load the cutFile and load the cutList + + int numCut = 0; + cutFile = new TFile(saveFileName, "UPDATE"); + bool listExist = cutFile->GetListOfKeys()->Contains("cutList"); + if( !listExist ) { + cutList = new TObjArray(); + }else{ + cutList = (TObjArray*) cutFile->FindObjectAny("cutList"); + numCut = cutList->GetLast()+1; + printf("----- found %d cuts \n", numCut); + for( int k = 0; k < numCut; k++){ + if( cutList->At(k) != NULL ){ + printf("found a cut at %2d \n", k); + cut = (TCutG*) cutList->At(k); + cut->Draw("same"); + }else{ + printf(" No cut at %2d \n", k); + } + } + } + cCutCreator->Modified(); cCutCreator->Update(); + +} diff --git a/PIDCutCreator.C b/PIDCutCreator.C new file mode 100644 index 0000000..bc29cdf --- /dev/null +++ b/PIDCutCreator.C @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void PIDCutCreator(TH2F* hist, + TString saveFileName = "PIDCuts.root", + bool isLogz = false + ){ + + printf("================ Graphic Cut Creator for PID ============== \n"); + + gStyle->SetOptStat("neiou"); + + TCanvas * cCutCreator = new TCanvas("cCutCreator", "PID Cut Creator", 100, 100, 800, 800); + if( !cCutCreator->GetShowToolBar() ) cCutCreator->ToggleToolBar(); + + cCutCreator->Update(); + if( isLogz ) cCutCreator->cd()->SetLogz(); + hist->Draw("colz"); + + TFile * cutFile; + TCutG * cut = NULL; + TObjArray * cutList; + + ///===================== load the cutFile and load the cutList + + int numCut = 0; + cutFile = new TFile(saveFileName, "UPDATE"); + if( cutFile == NULL ){ + cutFile = new TFile(saveFileName, "recreate"); + } + bool listExist = cutFile->GetListOfKeys()->Contains("cutList"); + if( !listExist ) { + cutList = new TObjArray(); + }else{ + cutList = (TObjArray*) cutFile->FindObjectAny("cutList"); + numCut = cutList->GetLast()+1; + printf("----- found %d cuts \n", numCut); + for( int k = 0; k < numCut; k++){ + if( cutList->At(k) != NULL ){ + printf("found a cut at %2d \n", k); + cut = (TCutG*) cutList->At(k); + cut->Draw("same"); + }else{ + printf(" No cut at %2d \n", k); + } + } + } + cCutCreator->Modified(); cCutCreator->Update(); + + int countCut = 0; + while (true){ + + printf("======== make a graphic cut on the plot (double click to stop), %2d-th cut: ", countCut ); + + gPad->WaitPrimitive(); + + cut = (TCutG*) gROOT->FindObject("CUTG"); + + if( cut == NULL ){ + printf(" stopped by user.\n"); + break; + } + + TString name; name.Form("cut%dd", countCut); + cut->SetName(name); + cut->SetVarX("TOF"); + cut->SetVarY("dE"); + cut->SetTitle(Form("cut%2d", countCut)); + cut->SetLineColor(countCut+1); + printf(" cut-%d \n", countCut); + + cutList->AddAtAndExpand(cut, countCut); + countCut ++; + + } + + ///================= Summary + + cutList->Write("cutList", TObject::kSingleKey); + printf("====> saved %d cuts into %s\n", countCut, saveFileName.Data()); + gROOT->ProcessLine(".q"); + +} diff --git a/armory/AnalysisLibrary.h b/armory/AnalysisLibrary.h new file mode 100644 index 0000000..b4f7eb8 --- /dev/null +++ b/armory/AnalysisLibrary.h @@ -0,0 +1,296 @@ +#ifndef Analysis_Library_h +#define Analysis_Library_h + +#include +#include +#include +#include +#include +#include +#include +#include + +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> combination(std::vector arr, int r){ + + std::vector> output; + + int n = arr.size(); + std::vector v(n); + std::fill(v.begin(), v.begin()+r, 1); + do { + //for( int i = 0; i < n; i++) { printf("%d ", v[i]); }; printf("\n"); + + std::vector temp; + for (int i = 0; i < n; ++i) { + if (v[i]) { + //printf("%.1f, ", arr[i]); + temp.push_back(arr[i]); + } + } + //printf("\n"); + + output.push_back(temp); + + } while (std::prev_permutation(v.begin(), v.end())); + + return output; +} + +double* sumMeanVar(std::vector data){ + + int n = data.size(); + double sum = 0; + for( int k = 0; k < n; k++) sum += data[k]; + double mean = sum/n; + double var = 0; + for( int k = 0; k < n; k++) var += pow(data[k] - mean,2); + + static double output[3]; + output[0] = sum; + output[1] = mean; + output[2] = var; + + return output; +} + +double* fitSlopeIntercept(std::vector dataX, std::vector dataY){ + + double * smvY = sumMeanVar(dataY); + double sumY = smvY[0]; + double meanY = smvY[1]; + + double * smvX = sumMeanVar(dataX); + double sumX = smvX[0]; + double meanX = smvX[1]; + double varX = smvX[2]; + + int n = dataX.size(); + double sumXY = 0; + for( int j = 0; j < n; j++) sumXY += dataX[j] * dataY[j]; + + double slope = ( sumXY - sumX * sumY/n ) / varX; + double intercept = meanY - slope * meanX; + + static double output[2]; + output[0] = slope; + output[1] = intercept; + + return output; + +} + + + +std::vector> FindMatchingPair(std::vector enX, std::vector enY){ + + //output[0] = fitEnergy; + //output[1] = refEnergy; + + int nX = enX.size(); + int nY = enY.size(); + + std::vector fitEnergy; + std::vector refEnergy; + + if( nX > nY ){ + + std::vector> output = combination(enX, nY); + + double * smvY = sumMeanVar(enY); + double sumY = smvY[0]; + double meanY = smvY[1]; + double varY = smvY[2]; + + double optRSquared = 0; + double absRSqMinusOne = 1; + int maxID = 0; + + for( int k = 0; k < (int) output.size(); k++){ + + double * smvX = sumMeanVar(output[k]); + double sumX = smvX[0]; + double meanX = smvX[1]; + double varX = smvX[2]; + + double sumXY = 0; + for( int j = 0; j < nY; j++) sumXY += output[k][j] * enY[j]; + + double rSq = abs(sumXY - sumX*sumY/nY)/sqrt(varX*varY); + + //for( int j = 0; j < nY ; j++){ printf("%.1f, ", output[k][j]); }; printf("| %.10f\n", rSq); + + if( abs(rSq-1) < absRSqMinusOne ) { + absRSqMinusOne = abs(rSq-1); + optRSquared = rSq; + maxID = k; + } + } + + fitEnergy = output[maxID]; + refEnergy = enY; + + printf(" R^2 : %.20f\n", optRSquared); + + //calculation fitting coefficient + //double * si = fitSlopeIntercept(fitEnergy, refEnergy); + //printf( " y = %.4f x + %.4f\n", si[0], si[1]); + + }else if( nX < nY ){ + + std::vector> output = combination(enY, nX); + + + double * smvX = sumMeanVar(enX); + double sumX = smvX[0]; + double meanX = smvX[1]; + double varX = smvX[2]; + + double optRSquared = 0; + double absRSqMinusOne = 1; + int maxID = 0; + + for( int k = 0; k < (int) output.size(); k++){ + + double * smvY = sumMeanVar(output[k]); + double sumY = smvY[0]; + double meanY = smvY[1]; + double varY = smvY[2]; + + double sumXY = 0; + for( int j = 0; j < nX; j++) sumXY += output[k][j] * enX[j]; + + double rSq = abs(sumXY - sumX*sumY/nX)/sqrt(varX*varY); + + //for( int j = 0; j < nX ; j++){ printf("%.1f, ", output[k][j]); }; printf("| %.10f\n", rSq); + + if( abs(rSq-1) < absRSqMinusOne ) { + absRSqMinusOne = abs(rSq-1); + optRSquared = rSq; + maxID = k; + } + } + + fitEnergy = enX; + refEnergy = output[maxID]; + printf(" R^2 : %.20f\n", optRSquared); + + }else{ + fitEnergy = enX; + refEnergy = enY; + + //if nX == nY, ther could be cases that only partial enX and enY are matched. + + } + + + printf("fitEnergy = ");for( int k = 0; k < (int) fitEnergy.size() ; k++){ printf("%7.2f, ", fitEnergy[k]); }; printf("\n"); + printf("refEnergy = ");for( int k = 0; k < (int) refEnergy.size() ; k++){ printf("%7.2f, ", refEnergy[k]); }; printf("\n"); + + std::vector> haha; + haha.push_back(fitEnergy); + haha.push_back(refEnergy); + + return haha; + +} + + +std::vector> LoadCorrectionParameters(TString corrFile, bool show=false){ + + 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; + + //printf("%s\n", line.c_str()); + 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"); + if( show ){ + 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("%14.6f, ", corr[i][j]); + } + printf("%14.6f\n", corr[i][len-1]); + } + } + + }else{ + printf(".... fail\n"); + std::vector temp = {0, 1}; + for( int i = 0; i < 36; i++){ + corr.push_back(temp); + } + } + + return corr; +} + +#endif + diff --git a/armory/Analyzer_Utili.c b/armory/Analyzer_Utili.c new file mode 100644 index 0000000..4549f22 --- /dev/null +++ b/armory/Analyzer_Utili.c @@ -0,0 +1,195 @@ +void listDraws(void) { + printf("------------------- List of Plots -------------------\n"); + printf(" newCanvas() - Create a new Canvas\n"); + printf("-----------------------------------------------------\n"); + printf(" eVID() - e vs ID\n"); + printf(" drawE() - e for all %d detectors\n", NCRYSTAL); + //printf(" drawGG() - Gamma - Gamma Coincident for all %d detectors\n", NCRYSTAL); + printf("-----------------------------------------------------\n"); + printf(" energyCalibration() - Calibrate energy \n"); + printf("-----------------------------------------------------\n"); +} + +int nCanvas=0; +void newCanvas(int sizeX = 800, int sizeY = 600, int posX = 0, int posY = 0){ + TString name; name.Form("cNewCanvas%d", nCanvas); + TCanvas * cNewCanvas = new TCanvas(name, name, posX, posY, sizeX, sizeY); + nCanvas++; + cNewCanvas->cd(); +} + +void eVID(bool cal = false, bool logz = false){ + TCanvas * cRawID = (TCanvas *) gROOT->FindObjectAny("cRawID"); + if( cRawID == NULL ) cRawID = new TCanvas("cRawID", "raw ID", 1000, 800); + + if( cRawID->GetShowEventStatus() == 0 ) cRawID->ToggleEventStatus(); + + cRawID->cd(1)->SetGrid(); + if( logz ) cRawID->cd(1)->SetLogz(); + cal ? heCalVID->Draw("colz") : heVID->Draw("colz"); +} + +void drawE(int CloverID = -1, bool cali = false, bool isLogy = false, double xMin = 0, double xMax = 0){ + + int nCrystalPerClover = 4; + int nClover = NCRYSTAL / nCrystalPerClover; + + if( CloverID >= nClover ) { + printf("Clover-ID > nClover = %d. \n", nClover); + return; + } + + int size = 300; + + TCanvas *cRawE = (TCanvas *) gROOT->FindObjectAny("cRawE"); + if( cRawE == NULL ) cRawE = new TCanvas("cRawE", cali ? "Cal e" : "Raw e", size * nClover, size * nCrystalPerClover); + + if( cRawE->GetShowEventStatus() == 0 ) cRawE->ToggleEventStatus(); + + cRawE->Clear(); + if( CloverID >= 0 ) { + nClover = 1; + cRawE->Divide(nClover, 1); + }else{ + cRawE->Divide(nClover, nCrystalPerClover, 0); + } + + ///find max y + double maxY = 0; + int nDet = nClover*nCrystalPerClover; + for( int i = (CloverID < 0 ? 0 : nCrystalPerClover*CloverID) ; i < (CloverID < 0 ? nDet : nCrystalPerClover*CloverID + nDet) ; i++){ + int mBin = cali ? heCal[i]->GetMaximumBin() : he[i]->GetMaximumBin(); + double max = cali ? heCal[i]->GetBinContent(mBin) : he[i]->GetBinContent(mBin); + if( max > maxY ) maxY = max; + } + maxY = maxY * 1.1; + ///printf("max Y : %f \n", maxY); + + for (Int_t i = 0; i < nClover; i++) { + + int hID = nCrystalPerClover * CloverID + i ; + if( cali ) { + heCal[hID]->SetMaximum(maxY); + heCal[hID]->Draw("same"); + }else{ + he[hID]->SetMaximum(maxY); + he[hID]->Draw("same"); + } + + + + ///for( Int_t j = 0; j < nCrystalPerClover; j++){ + /// int canvasID = CloverID < 0 ? nClover*j+ i + 1 : j + 1; + /// cRawE->cd(canvasID); + /// cRawE->cd(canvasID)->SetGrid(); + /// cRawE->cd(canvasID)->SetTickx(2); + /// cRawE->cd(canvasID)->SetTicky(2); + /// cRawE->cd(canvasID)->SetBottomMargin(0.06); + /// if ( i == nClover -1 ) cRawE->cd(canvasID)->SetRightMargin(0.002); + /// if( isLogy ) cRawE->cd(canvasID)->SetLogy(); + /// int hID = CloverID < 0 ? nCrystalPerClover*i+ j : nCrystalPerClover * CloverID + j ; + /// if( cali ) { + /// if ( xMin != 0 || xMax != 0 ) heCal[hID]->GetXaxis()->SetRangeUser(xMin, xMax); + /// heCal[hID]->SetMaximum(maxY); + /// heCal[hID]->Draw(""); + /// }else{ + /// if ( xMin != 0 || xMax != 0 ) he[hID]->GetXaxis()->SetRangeUser(xMin, xMax); + /// he[hID]->SetMaximum(maxY); + /// he[hID]->Draw(""); + /// } + ///} + } + + cRawE->SetCrosshair(1); + +} + +/** +void drawGG(){ + + int nCrystal = 4; + int numCol = NCRYSTAL / nCrystal; + + int size = 300; + + TCanvas *cGG = (TCanvas *) gROOT->FindObjectAny("cGG"); + if( cGG == NULL ) cGG = new TCanvas("cGG", "Gamma - Gamma Coin.", size * NCRYSTAL, size * NCRYSTAL); + cGG->Clear();cGG->Divide(NCRYSTAL, NCRYSTAL); + + for( int i = 0; i < NCRYSTAL; i ++){ + for( int j = i+1; j < NCRYSTAL; j ++){ + cGG->cd( NCRYSTAL * i + j +1 ); + hgg[i][j]->Draw("colz"); + } + } + +} +*/ + +void energyCalibration(int detID = -1, int BG = 10, double threshold = 0.1, double sigmaMax = 5, int peakDensity = 10){ + + TCanvas *cCal = (TCanvas *) gROOT->FindObjectAny("cCal"); + if( cCal == NULL ) cCal = new TCanvas("cCal", "Energy Calibration", 1000, 0, 1000, 600); + cCal->Clear(); + + cCal->Divide(2,1); + cCal->SetGrid(); + + vector refEnergy = {121.738, + 244.699, + 344.281, + 411.115, + 443.965, + 778.903, + 867.390, + 964.055, + 1085.842, + ///1089.700, + 1112.087, + 1408.022}; + + double a0[NCRYSTAL]; + double a1[NCRYSTAL]; + + for( int i = 0 ; i < NCRYSTAL; i++){ + if( detID >= 0 && i != detID ) continue; + + cCal->cd(1); + he[i]->Draw(); + vector peaks = fitAuto(he[i], BG, threshold, sigmaMax, peakDensity); + vector> output = FindMatchingPair(peaks, refEnergy); + + vector haha1 = output[0]; + vector haha2 = output[1]; + + TGraph * graph = new TGraph(haha1.size(), &haha1[0], &haha2[0] ); + cCal->cd(2); + graph->Draw("A*"); + + TF1 * fit = new TF1("fit", "pol1" ); + graph->Fit("fit", ""); + + a0[i] = fit->GetParameter(0); + a1[i] = fit->GetParameter(1); + + if( detID < 0 ) { + printf("%2d | a0: %14.10f, a1: %14.10f\n", i, a0[i], a1[i]); + }else{ + printf("%2d | a0, a1 = %14.10f\t%14.10f\n", i, a0[i], a1[i]); + } + } + + if( detID < 0 ){ + FILE * paraOut; + TString filename; + filename.Form("correction_e_auto.dat"); + paraOut = fopen (filename.Data(), "w+"); + printf("=========== save e-correction parameters to %s \n", filename.Data()); + for( int i = 0; i < NCRYSTAL; i++){ + fprintf(paraOut, "%14.10f\t%14.10f\n", a0[i], a1[i]); + } + fflush(paraOut); + fclose(paraOut); + } + +} diff --git a/armory/AutoFit.C b/armory/AutoFit.C new file mode 100644 index 0000000..70cb7fe --- /dev/null +++ b/armory/AutoFit.C @@ -0,0 +1,2787 @@ +/************************************************************ +# +# Created by Tsz Leung (Ryan) Tang +# goluckyryan@gmail.com +# rtang@fsu.edu +# +*************************************************************/ + +#ifndef AutoFit_C +#define AutoFit_C + +#include +#include +#include +#include +#include +#include + +void showFitMethod(){ + printf("----------------------- Method of Fitting ---------------\n"); + printf("---------------------------------------------------------\n"); + printf(" fitAuto() - estimate BG, find peak, and fit n-Gauss \n"); + printf(" fitGaussPol() - fit 1 Gauss + pol-n BG\n"); + printf(" fit2GaussP1() - fit 2 Gauss + pol-1 BG \n"); + printf(" fitGF3Pol() - fit GF3 + pol-n BG \n"); + //printf(" fitNGF3() - fit n-GF3, estimated BG \n"); + printf(" fitNGauss() - fit n-Gauss, estimated BG, need input\n"); + printf(" fitNGaussSub() - fit estimated BG with Pol, subtract, fit n-Guass\n"); + printf(" fitNGaussPol() - fit n-Gauss + pol-n BG \n"); + printf(" fitNGaussPolSub() - subtract Pol-n BG, fit n-Gauss \n"); + printf("\n"); + printf(" fitDecay() - fit A * Exp(-t/T) + B\n"); + printf("\n"); + printf("------- Mouse click Fit : \n"); + printf(" clickFitNGaussPol() - fit n-Gauss + pol-n BG \n"); + printf(" clickFitNGaussPolSub() - Fit Pol-n BG, subtract, fit n-Gauss\n"); + printf(" saveFitPara() - Save the initial guess parameters.\n"); + printf("---------------------------------------------------------\n"); +} + +std::vector SplitStrAF(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 + if( secStr.substr(0, 1) == " "){ + secStr = secStr.substr(1); + } + + output.push_back(secStr); + //printf(" |%s---\n", secStr.c_str()); + + }while(pos != std::string::npos ); + + return output; +} + +TColor RGBWheel(double ang){ + + ang = ang * TMath::DegToRad(); + + double r = max(0., (1+2*cos(ang))/3.); + double g = max(0., (1 - cos(ang) + sqrt(3)* sin(ang))/3.); + double b = max(0., (1 - cos(ang) - sqrt(3)* sin(ang))/3.); + + TColor col(r,g,b); + + return col; + +} + +int nPeaks = 16; +Double_t nGauss(Double_t *x, Double_t *par) { + Double_t result = 0; + for (Int_t p=0;pGetNpar(); + int count = totPar/numParPerPeak; + printf("ID "); + for( int i = 0; i < numParPerPeak; i++){ + printf("par%d ", i); + } + printf("\n"); + + for( int i = 0; i < count ; i++){ + printf("%3d ", i); + for( int j = 0; j < numParPerPeak; j++){ + int parID = numParPerPeak * i + j; + printf("%.3f(%.3f) ", fit->GetParameter(parID), fit->GetParError(parID)); + } + printf("\n"); + } +} + +void GoodnessofFit(TH1F * hist, TF1 * fit){ + + int nBin = hist->GetNbinsX(); + int effBin = 0; + double mean = 0; + double ysq = 0; + double SSR = 0; + double chisq = 0; //with estimated error be sqrt(y) + double Xsq = 0; // for Pearson's chi-sq test + for( int i = 1; i <= nBin; i++){ + + double e = hist->GetBinError(i); + if( e > 0 ) { + effBin ++; + double y = hist->GetBinContent(i); + double x = hist->GetBinCenter(i); + double ybar = fit->Eval(x); + ysq += y*y; + mean + y; + SSR += (y - ybar)*(y-ybar); + chisq += (y - ybar)*(y-ybar)/e/e; + + + if( ybar > e ) { + Xsq += (y - ybar)*(y-ybar)/ybar; + }else{ + Xsq += (y - ybar)*(y-ybar)/e; + } + //printf(" %d | x : %f, y : %f, ybar : %f , X-sq : %f\n", i, x, y, ybar, Xsq); + } + } + mean = mean / nBin; + double SSTotal = ysq + mean*mean; + + int npar = fit->GetNpar(); + int ndf = effBin - npar; + printf("#################################################\n"); + printf("## Goodness of Fit. ##\n"); + printf("#################################################\n"); + printf(" eff. Bin(%d) - numPar(%d) = ndf = %d \n", effBin, npar, ndf); + + printf("============== Regression analysis\n"); + printf("----------------- R-sq \n"); + printf(" SSTotal = %f \n", SSTotal); + printf(" SSR = %f \n", SSR); + printf(" MSR = %f <-- is it similar to sample variance?\n", SSR/ndf); + double Rsq = 1 - SSR/SSTotal; + printf(" R-sq = %f \n", Rsq ); + + printf("----------------- Chi-sq \n"); + printf(" Chi-sq = %f \n", chisq); + printf(" rd. Chi-sq = %f \n", chisq/ndf); + printf("ROOT Chi-Sq = %f , NDF = %d \n", fit->GetChisquare(), fit->GetNDF()); + //================ chi-sq test + printf("============== Hypothesis testing\n"); + printf(" Null Hypothesis : the fitting model is truth. \n"); + printf(" * p-value = prob. that Null Hypo. is truth. \n"); + printf(" * the Pearson's test in here only for background free data \n"); + printf(" Pearson's X-sq = %.2f \n", Xsq); + double p = 1 - TMath::Prob(Xsq, ndf); + printf(" Pearson's p-value = %.2f %s 0.05 | %s\n", p, p < 0.05 ? "<": ">", p < 0.05 ? "reject" : "cannot reject"); + double pchi = 1 - TMath::Prob(chisq, ndf); + printf(" Chi-sq p-value = %.2f %s 0.05 | %s\n", pchi, pchi < 0.05 ? "<": ">", pchi < 0.05 ? "reject" : "cannot reject"); + double pRoot = 1- fit->GetProb(); + printf("ROOT Chi-sq p-value = %.2f %s 0.05 | %s\n", pRoot, pRoot < 0.05 ? "<": ">", pRoot < 0.05 ? "reject" : "cannot reject"); + printf("################################################\n"); +} + +vector energy, height, sigma, lowE, highE ; +vector energyFlag, sigmaFlag; + +bool loadFitParameters(TString fitParaFile){ + + energy.clear(); energyFlag.clear(); + sigma.clear(); sigmaFlag.clear(); + + lowE.clear(); highE.clear(); + + height.clear(); + + bool paraRead = false; + + printf("====================================================================== \n"); + printf("----- loading fit parameters from : %s", fitParaFile.Data()); + ifstream file; + file.open(fitParaFile.Data()); + + if( !file){ + printf("\ncannot read file : %s \n", fitParaFile.Data()); + return 0; + } + + while( file.good()) { + string tempLine; + getline(file, tempLine); + + if( tempLine.substr(0, 1) == "#" ) continue; + if( tempLine.substr(0, 2) == "//" ) continue; + if( tempLine.size() < 5 ) continue; + + ///printf("%s\n", tempLine.c_str()); + + vector temp = SplitStrAF(tempLine, " "); + + if( temp.size() < 7 ) continue; + + energy.push_back( atof(temp[0].c_str())); + lowE.push_back( atof(temp[1].c_str())); + highE.push_back( atof(temp[2].c_str())); + energyFlag.push_back(atoi(temp[3].c_str())); + sigma.push_back( atof(temp[4].c_str())); + sigmaFlag.push_back( atoi(temp[5].c_str())); + height.push_back( atof(temp[6].c_str())); + + } + + printf("... done.\n"); + + int n = energy.size(); + TString limStr = "(fixed)"; + printf("%2s| %34s | %10s \n", "ID", "Peak [MeV]", "Sigma [MeV]"); + for( int j = 0; j < n; j ++){ + if( energyFlag[j] == 0 ) limStr.Form("(limited, %6.3f - %6.3f)", lowE[j], highE[j]); + printf("%2d| %7.4f %-26s | %7.4f (%5s) \n", j, energy[j], limStr.Data(), sigma[j], sigmaFlag[j] == 1 ? "fixed" : "free"); + } + + paraRead = true; + + printf("====================================================================== \n"); + + return paraRead; + +} + +TCanvas * NewCanvas(TString name, TString title, int divX, int divY, int padSizeX, int padSizeY){ + TCanvas * output = NULL; + if( gROOT->FindObjectAny(name) == NULL ){ + output = new TCanvas(name, title, divX * padSizeX, divY * padSizeY); + }else{ + output = (TCanvas *) gROOT->FindObjectAny(name) ; + output->Clear(); + } + output->Divide(divX, divY); + return output; +} + +void ScaleAndDrawHist(TH1F * hist, double xMin, double xMax){ + + if ( xMin != xMax ) hist->GetXaxis()->SetRangeUser(xMin, xMax); + int maxBin = hist->GetMaximumBin(); + double ymax = hist->GetBinContent(maxBin); + hist->GetYaxis()->SetRangeUser(0, 1.1 * ymax); + hist->Draw(); + +} + +void PlotResidual(TH1F * hist, TF1 * fit){ + + TH1F * hRes = (TH1F*) hist->Clone(); + hRes->GetListOfFunctions()->Clear(); + hRes->SetTitle("Residual"); + hRes->SetName("hRes"); + hRes->SetYTitle("Hist - fit"); + hRes->Sumw2(0); + hRes->Sumw2(1); + double xMin = hRes->GetXaxis()->GetXmin(); + double xMax = hRes->GetXaxis()->GetXmax(); + fit->SetRange(xMin, xMax); + hRes->Add(fit, -1); + hRes->Draw(); + +} + + +//######################################## +//### Fit a Gauss + Pol-n +//######################################## +void fitGaussPol(TH1F * hist, double mean, double sigmaMax, int degPol, double xMin, double xMax, TString optStat = ""){ + + printf("=========================================================\n"); + printf("================ fit 1-Gauss + Pol-%d BG ================\n", degPol); + printf(" * mean Range +- 5 sigmaMax \n"); + printf(" * inital parameters of the polynomial is random/pow(10, i) \n"); + printf("==========================================================\n"); + + gStyle->SetOptStat(optStat); + TCanvas * cFitGaussPol = NewCanvas("cFitGaussPol", Form("fit Gauss & Pol-%d | fitGaussPol", degPol), 1, 2, 800, 350); + cFitGaussPol->cd(1); + + ScaleAndDrawHist(hist, xMin, xMax); + + const int nPar = 3 + degPol + 1; + + TString funcExp = "[0] * TMath::Gaus(x, [1], [2], 1)"; + for( int i = 0; i < degPol+1 ; i++){ + funcExp += Form(" + [%d]*TMath::Power(x,%d)", i+3 , i); + } + TF1 * fit = new TF1("fit", funcExp.Data(), xMin, xMax); + + double * para = new double[nPar]; + para[0] = 100 * 0.05 * TMath::Sqrt(TMath::TwoPi()); + para[1] = mean; + para[2] = sigmaMax/2.; + for( int i = 0 ; i < degPol+1; i++){ + para[3 + i ] = gRandom->Rndm()/TMath::Power(10, i); + } + + fit->SetLineWidth(2); + fit->SetLineColor(1); + fit->SetNpx(1000); + fit->SetParameters(para); + + fit->SetParLimits(0, 0, 1e9); + fit->SetParLimits(1, mean - 5*sigmaMax, mean + 5 * sigmaMax); + fit->SetParLimits(2, 0, sigmaMax); + + hist->Fit("fit", "Rq"); + + const Double_t* paraE = fit->GetParErrors(); + const Double_t* paraA = fit->GetParameters(); + + double bw = hist->GetBinWidth(1); + + printf("histogram name : %s \n====== Gaussian:\ncount: %8.0f(%3.0f)\nmean : %8.4f(%8.4f)\nsigma: %8.4f(%8.4f) \n", + hist->GetName(), + paraA[0] / bw, paraE[0] /bw, + paraA[1], paraE[1], + paraA[2], paraE[2]); + + printf("------- the polnomail BG:\n"); + for(int i = 0 ; i < degPol+1; i++){ + printf("%2d | %8.4f(%8.4f) \n", i, paraA[3+i], paraE[3+i]); + } + + TLatex text; + text.SetNDC(); + text.SetTextFont(82); + text.SetTextSize(0.04); + + double chi2 = fit->GetChisquare(); + int ndf = fit->GetNDF(); + text.DrawLatex(0.12, 0.8, Form("#bar{#chi^{2}} : %5.3f", chi2/ndf)); + text.DrawLatex(0.12, 0.75,Form("count: %4.0f(%3.0f)", paraA[0] / bw, paraE[0] /bw)); + text.DrawLatex(0.12, 0.70,Form("E_{x}: %6.3f(%5.3f) MeV", paraA[1], paraE[1])); + text.DrawLatex(0.12, 0.65,Form("#sigma: %3.0f(%3.0f) keV", paraA[2] * 1000., paraE[2] * 1000.)); + + for( int i = 0; i < degPol + 1; i++){ + text.DrawLatex(0.60, 0.85 - 0.05*i ,Form("%3s: %8.3f(%8.3f)", Form("p%d", i), paraA[3+i], paraE[3+i])); + } + + TString expression = "[0] "; + for( int j = 1; j < degPol + 1; j++){ + expression += Form(" + [%d]*TMath::Power(x, %d)", j, j); + } + TF1 * g0 = new TF1("g0", expression.Data(), xMin, xMax); + for( int j = 0; j < degPol + 1 ; j++){ + g0->SetParameter(j, paraA[3+j]); + } + g0->SetLineColor(4); + g0->Draw("same"); + + TF1* f0 = new TF1("f0", "[0] * TMath::Gaus(x, [1], [2], 1)", xMin, xMax); + f0->SetParameter(0, paraA[0]); + f0->SetParameter(1, paraA[1]); + f0->SetParameter(2, paraA[2]); + f0->SetLineColor(2); + f0->SetNpx(1000); + f0->Draw("same"); + +// GoodnessofFit(hist, fit); + + cFitGaussPol->cd(2); + PlotResidual(hist, fit); + +} + +//######################################## +//#### fit 2 gauss + pol-1 // not updated +//######################################## +vector fit2GaussP1(TH1F * hist, double mean1, double sigma1, + double mean2, double sigma2, + double xMin, double xMax, TString optStat = "", bool newCanvas = false){ + + + printf("=========================================================\n"); + printf("================ fit 2-Gauss + Pol-1 BG ================\n" ); + printf(" NOT updated. It works, but the code is old \n"); + printf("==========================================================\n"); + + + vector output; + output.clear(); + + gStyle->SetOptStat(optStat); + TCanvas * cFit2GaussP1 = NewCanvas("cFit2GaussP1", "fit Gauss & P1 | fit2GaussP1", 1, 1, 800, 350); + cFit2GaussP1->cd(1); + + ScaleAndDrawHist(hist, xMin, xMax); + + TF1 * fit = new TF1("fit", "[0] * TMath::Gaus(x, [1], [2], 1) + [3] * TMath::Gaus(x, [4], [5], 1) + [6] + [7]*x", xMin, xMax); + + double * para = new double[8]; + para[0] = 20 * 0.05 * TMath::Sqrt(TMath::TwoPi()); + para[1] = mean1; + para[2] = sigma1; + para[3] = 100 * 0.05 * TMath::Sqrt(TMath::TwoPi()); + para[4] = mean2; + para[5] = sigma2; + para[6] = 1; + para[7] = 0; + + fit->SetLineWidth(2); + fit->SetLineColor(2); + fit->SetNpx(1000); + fit->SetParameters(para); + + hist->Fit("fit", "Rq"); + + const Double_t* paraE = fit->GetParErrors(); + const Double_t* paraA = fit->GetParameters(); + + double bw = hist->GetBinWidth(1); + + printf("%7s ====== count: %8.0f(%3.0f), mean: %8.4f(%8.4f), sigma: %8.4f(%8.4f) \n", + hist->GetName(), + paraA[0] / bw, paraE[0] /bw, + paraA[1], paraE[1], + paraA[2], paraE[2]); + printf("%7s ====== count: %8.0f(%3.0f), mean: %8.4f(%8.4f), sigma: %8.4f(%8.4f) \n", + "", + paraA[3] / bw, paraE[3] /bw, + paraA[4], paraE[4], + paraA[5], paraE[5]); + + output.push_back( paraA[0]/bw); + output.push_back( paraE[0]/bw); + output.push_back( paraA[1]); + output.push_back( paraE[1]); + output.push_back( paraA[2]); + output.push_back( paraE[2]); + + output.push_back( paraA[3]/bw); + output.push_back( paraE[3]/bw); + output.push_back( paraA[4]); + output.push_back( paraE[4]); + output.push_back( paraA[5]); + output.push_back( paraE[5]); + + + TLatex text; + text.SetNDC(); + text.SetTextFont(82); + text.SetTextSize(0.04); + + double chi2 = fit->GetChisquare(); + int ndf = fit->GetNDF(); + text.DrawLatex(0.15, 0.8, Form("#bar{#chi^{2}} : %5.3f", chi2/ndf)); + + text.DrawLatex(0.15, 0.75,Form("count: %4.0f(%3.0f), E_{x}: %6.3f(%5.3f) MeV, #sigma: %3.0f(%3.0f) keV ", + paraA[0] / bw, paraE[0] /bw, + paraA[1], paraE[1], + paraA[2] * 1000., paraE[2] * 1000.)); + text.DrawLatex(0.15, 0.7, Form("count: %4.0f(%3.0f), E_{x}: %6.3f(%5.3f) MeV, #sigma: %3.0f(%3.0f) keV ", + paraA[3] / bw, paraE[3] /bw, + paraA[4], paraE[4], + paraA[5] * 1000., paraE[5] * 1000.)); + + text.DrawLatex(0.15, 0.6, Form("Line : %6.3f(%5.3f) + %6.3f(%5.3f)x ", + paraA[6], paraE[6], + paraA[7], paraE[7])); + + GoodnessofFit(hist, fit); + return output; +} + + +//######################################## +//#### fit for gamma + pol-n BG +//######################################## +void fitGF3Pol(TH1F * hist, double mean, double sigmaMax, double ratio, double beta, double step, int degPol, double xMin, double xMax, TString optStat = ""){ + + printf("=========================================================\n"); + printf("================ fit GF1 + Pol-%d BG ================\n", degPol); + printf(" * mean Range = xMin, xMax \n"); + printf(" * inital parameters of the polynomial is random/pow(10, i) \n"); + printf("==========================================================\n"); + + + gStyle->SetOptStat(optStat); + + gStyle->SetOptStat(optStat); + TCanvas * cFitGF3Pol = NewCanvas("cFitGF3Pol", Form("fit GF3 + pol-%d | fitGF3Pol", degPol), 1, 2, 800, 350); + cFitGF3Pol->cd(1); + + ScaleAndDrawHist(hist, xMin, xMax); + + nPeaks = 1; + nPols = degPol; + int nPar = 6*nPeaks + degPol + 1; + + TF1 * fit = new TF1("fit", nGF3Pol, xMin, xMax, nPar); + + fit->Print(); + + double * para = new double[nPar]; + para[0] = hist->GetMaximum() *4; + para[1] = mean; + para[2] = sigmaMax/2.; + para[3] = ratio ; + para[4] = beta ; + para[5] = step ; + for( int i = 0 ; i < degPol + 1; i++){ + para[6+i] = gRandom->Rndm()/TMath::Power(10, i); + } + + fit->SetLineWidth(2); + fit->SetLineColor(1); + fit->SetNpx(1000); + fit->SetParameters(para); + + fit->SetParLimits(0, 0, 1e9); + fit->SetParLimits(1, xMin, xMax); + fit->SetParLimits(2, 0.00000001, sigmaMax); + fit->SetParLimits(3, 0, 0.5); + fit->SetParLimits(4, 1, 400); + fit->SetParLimits(5, 0, 0.5); + + hist->Fit("fit", "Rq"); + + const Double_t* paraE = fit->GetParErrors(); + const Double_t* paraA = fit->GetParameters(); + + double chisquare = fit->GetChisquare(); + int ndf = fit->GetNDF(); + double bw = hist->GetBinWidth(1); + + printf("histogram : %s \n", hist->GetName()); + printf("========= The Gaussian \n"); + printf("count: %8.0f(%3.0f)\n", paraA[0] / bw, paraE[0] /bw); + printf("mean : %8.4f(%8.4f)\n", paraA[1], paraE[1]); + printf("sigma: %8.4f(%8.4f)\n", paraA[2], paraE[2]); + + TLatex text; + text.SetNDC(); + text.SetTextFont(82); + text.SetTextSize(0.04); + text.SetTextColor(1); + + text.DrawLatex(0.12, 0.65, Form("count : %5.0f(%5.0f)", paraA[0]/bw, paraE[0]/bw)); + text.DrawLatex(0.12, 0.60, Form(" mean : %5.3f(%5.3f) keV", paraA[1], paraE[1])); + text.DrawLatex(0.12, 0.55, Form("sigma : %5.3f(%5.3f) keV", paraA[2], paraE[2])); + text.DrawLatex(0.12, 0.50, Form(" FWHM : %5.3f(%5.3f) keV", paraA[2] *2.355, paraE[2]*2.355)); + + text.DrawLatex(0.12, 0.40, Form("#chi^2/ndf : %5.3f", chisquare/ndf)); + + //GoodnessofFit(hist, fit); + + /// 0 1 2 3 4 5 + string label[8] = {"Area", "mean", "sigma", "ratio", "beta", "step"}; + printf("---------- The detail\n"); + for(int i = 0 ; i < 6 ; i++){ + printf("%d | %8s | %f (%f) \n", i, label[i].c_str(), paraA[i], paraE[i]); + text.DrawLatex(0.65, 0.85-0.05*i, Form("%6s: %5.3f(%5.3f)", label[i].c_str(), paraA[i], paraE[i])); + } + for(int i = 6 ; i < nPar; i++){ + printf("%d | %8s | %f (%f) \n", i, Form("p%d", i-6), paraA[i], paraE[i]); + text.DrawLatex(0.65, 0.85-0.05*i, Form("%6s: %5.3f (%5.3f) \n", Form("p%d", i-6), paraA[i], paraE[i])); + } + + /// norm * (1-ratio)* TMath::Gaus(x[0], mean, sigma, 1) + TF1 * g0 = new TF1("g0", "[0] * (1.0-[3]) * TMath::Gaus(x, [1], [2], 1)", xMin, xMax); + g0->SetParameter(0, paraA[0]); + g0->SetParameter(1, paraA[1]); + g0->SetParameter(2, paraA[2]); + g0->SetParameter(3, paraA[3]); + g0->SetNpx(1000); + g0->SetLineColor(kRed); + + /// norm * ratio * exp( sigma * sigma/2/beta/beta)* exp((x[0]-mean)/beta) * TMath::Erfc( (x[0]-mean)/(sigma * sqrt(2)) + sigma/beta/sqrt(2)) ; + TF1 * g1 = new TF1("g1", "[0] * [3] * exp( [2] * [2]/2/[4]/[4]) / (2* [4])* exp((x-[1])/[4]) * TMath::Erfc( (x-[1])/([2] * sqrt(2)) + [2]/[4]/sqrt(2)) ", xMin, xMax); + g1->SetParameter(0, paraA[0]); + g1->SetParameter(1, paraA[1]); + g1->SetParameter(2, paraA[2]); + g1->SetParameter(3, paraA[3]); + g1->SetParameter(4, paraA[4]); + g1->SetNpx(1000); + g1->SetLineColor(kGreen +3); + + /// norm * step * TMath::Erfc( (x[0]-mean)/(sigma * sqrt(2)) ); + TF1 * g2 = new TF1("g2", "[0] * [3] * TMath::Erfc( (x-[1])/([2] * sqrt(2)) );", xMin, xMax); + g2->SetParameter(0, paraA[0]); + g2->SetParameter(1, paraA[1]); + g2->SetParameter(2, paraA[2]); + g2->SetParameter(3, paraA[5]); + g2->SetNpx(1000); + g2->SetLineColor(kViolet); + + + TString expression = "[0] "; + for( int j = 1; j < degPol + 1; j++){ + expression += Form(" + [%d]*TMath::Power(x, %d)", j, j); + } + TF1 * g3 = new TF1("g3", expression.Data(), xMin, xMax); + for( int j = 0; j < degPol + 1 ; j++){ + g3->SetParameter(j, paraA[6+j]); + } + g3->SetLineColor(kBlue); + g3->Draw("same"); + + + g0->Draw("same"); + g1->Draw("same"); + g2->Draw("same"); + g3->Draw("same"); + + cFitGF3Pol->cd(2); + PlotResidual(hist, fit); + +} + +//############################################## +//##### Auto Fit n-Gauss with estimated BG +//############################################## +vector fitAuto(TH1F * hist, int bgEst = 10, + double peakThreshold = 0.05, + double sigmaMax = 0, + int peakDensity = 4, + TString optStat = ""){ + + printf("================================================================\n"); + printf("========== Auto Fit n-Gauss with estimated BG ==================\n"); + printf(" * bgEst = parameter of BG estimation, larger BG, more linear \n"); + printf(" * peakThreshold = precentage of the highest peak that will count \n"); + printf(" * sigmaMax = maximum sigma, if -1, program try to find the sigma \n"); + printf(" * peakDensity = peak will closer when the number is larger "); + printf(" \n"); + printf(" after peaks found, the i-th peaks will be limited by the mid-point\n"); + printf(" by the (i-1)-th peak and the i-th peak, and the mid-point of the\n"); + printf(" i-th peak and (i+1)-th peak \n"); + printf(" i.e. [peak(i-1)+peak(i)]/2 < limit of peak(i) < [peak(i)+peak(i+1)]/2 \n"); + printf("================================================================\n"); + + gStyle->SetOptStat(optStat); + TCanvas *cFitAuto = NewCanvas("cFitAuto","Auto Fitting | fitAuto", 1, 4, 800, 300); + cFitAuto->cd(1); + + ScaleAndDrawHist(hist, 0, 0); + + TH1F * specS = (TH1F*) hist->Clone(); + double xMin = hist->GetXaxis()->GetXmin(); + double xMax = hist->GetXaxis()->GetXmax(); + int xBin = hist->GetXaxis()->GetNbins(); + + TString titleH; + titleH.Form("fitted spectrum (BG=%d); Ex [MeV]; Count / %4.0f keV", bgEst, (xMax-xMin)*1000./xBin ); + specS->SetTitle(titleH); + specS->SetName("specS"); + ///specS->GetXaxis()->SetTitleSize(0.06); + ///specS->GetYaxis()->SetTitleSize(0.06); + ///specS->GetXaxis()->SetTitleOffset(0.7); + ///specS->GetYaxis()->SetTitleOffset(0.6); + + //=================== find peak and fit + gStyle->SetOptFit(0); + TSpectrum * peak = new TSpectrum(50); + nPeaks = peak->Search(hist, peakDensity, "", peakThreshold); + + if( bgEst > 0 ) { + printf("============= estimating background...\n"); + TH1 * h1 = peak->Background(hist, bgEst); + h1->Draw("same"); + printf("============= substracting the linear background...\n"); + specS->Sumw2(); + specS->Add(h1, -1.); + } + + cFitAuto->cd(2)->SetGrid(); + cFitAuto->cd(2); + specS->Draw("hist"); + + //========== Fitting + printf("============= Fitting....."); + printf(" found %d peaks \n", nPeaks); + + double * xpos = peak->GetPositionX(); + double * ypos = peak->GetPositionY(); + + int * inX = new int[nPeaks]; + TMath::Sort(nPeaks, xpos, inX, 0 ); + vector energy, height; + for( int j = 0; j < nPeaks; j++){ + energy.push_back(xpos[inX[j]]); + height.push_back(ypos[inX[j]]); + } + for( int j = 0; j < nPeaks; j++){ + printf(" energy : %f , %f \n", energy[j], height[j]); + } + + + if( sigmaMax == 0 ){ + printf("------------- Estimate sigma for each peak \n"); + sigma.clear(); + int binMin = hist->FindBin(xMin); + int binMax = hist->FindBin(xMax); + for( int i = 0; i < nPeaks ; i++){ + int b0 = hist->FindBin(energy[i]); + double sMin = (xMax-xMin)/5., sMax = (xMax-xMin)/5.; + //---- backward search, stop when + for( int b = b0-1 ; b > binMin ; b-- ){ + double y = hist->GetBinContent(b); + double x = hist->GetBinCenter(b); + if( y < (height[i])/2. ) { + sMin = energy[i] - hist->GetBinCenter(b); + break; + } + } + //---- forward search, stop when + for( int b = b0+1 ; b < binMax ; b++ ){ + double y = hist->GetBinContent(b); + double x = hist->GetBinCenter(b); + if( y < (height[i])/2. ) { + sMax = hist->GetBinCenter(b) - energy[i]; + break; + } + } + + double temp = TMath::Min(sMin, sMax); + /// When there are multiple peaks closely packed : + if( i > 0 && temp > 2.5 * sigma.back() ) temp = sigma.back(); + sigma.push_back(temp); + + printf("%2d | x : %8.2f | sigma(est) %f \n", i, energy[i], sigma[i]); + } + }else if( sigmaMax < 0 ){ + printf("========== use user input sigma : %f (fixed)\n", abs(sigmaMax)); + sigma.clear(); + for( int i = 0; i < nPeaks ; i++) sigma.push_back(abs(sigmaMax)); + }else if( sigmaMax > 0 ){ + printf("========== use user input sigma : %f/2. \n", sigmaMax/2.); + sigma.clear(); + for( int i = 0; i < nPeaks ; i++) sigma.push_back(sigmaMax/2.); + } + + + + int numParPerPeak = 3; + const int n = numParPerPeak * nPeaks; + double * para = new double[n]; + for(int i = 0; i < nPeaks ; i++){ + para[numParPerPeak*i+0] = height[i] * 0.05 * TMath::Sqrt(TMath::TwoPi()); + para[numParPerPeak*i+1] = energy[i]; + if( sigmaMax == 0 ){ + para[numParPerPeak*i+2] = sigma[i]; + }else if(sigmaMax < 0 ){ + para[numParPerPeak*i+2] = abs(sigmaMax); + }else if(sigmaMax > 0 ){ + para[numParPerPeak*i+2] = sigmaMax/2.; + } + } + + TF1 * fit = new TF1("fit", nGauss, xMin, xMax, 3 * nPeaks ); + fit->SetLineWidth(2); + fit->SetLineColor(2); + fit->SetNpx(1000); + fit->SetParameters(para); + + if( nPeaks > 1 ){ + for( int i = 0; i < nPeaks; i++){ + fit->SetParLimits(numParPerPeak*i+0, 0, 1e+9); + double de1 = 1, de2 = 1; + if( i == 0 ){ + de2 = (energy[i+1] - energy[i])/2.; + de1 = de2; + }else if( i < nPeaks -1 ){ + de1 = (energy[i] - energy[i-1])/2.; + de2 = (energy[i+1] - energy[i])/2.; + }else{ + de1 = (energy[i] - energy[i-1])/2.; + de2 = de1; + } + + fit->SetParLimits(numParPerPeak*i+1, energy[i] - de1 , energy[i] + de2); + if( sigmaMax== 0 ) fit->SetParLimits(numParPerPeak*i+2, 0, 1.5*sigma[i]); // add 50% margin of sigma + if( sigmaMax < 0 ) fit->FixParameter(numParPerPeak*i+2, abs(sigmaMax)); + if( sigmaMax > 0 ) fit->SetParLimits(numParPerPeak*i+2, 0, sigmaMax); + } + }else{ + fit->SetParLimits(0, 0, 1e+9); + fit->SetParLimits(2, 0, sigmaMax); + } + + specS->Fit("fit", "q"); + + + const Double_t* paraE = fit->GetParErrors(); + const Double_t* paraA = fit->GetParameters(); + + //======== calculate reduce chi-squared + //GoodnessofFit(specS, fit); + + double bw = specS->GetBinWidth(1); + + vector exPos; + for(int i = 0; i < nPeaks ; i++){ + exPos.push_back(paraA[numParPerPeak*i+1]); + printf("%2d , count: %8.0f(%3.0f), mean: %8.4f(%8.4f), sigma: %8.4f(%8.4f) \n", + i, + paraA[numParPerPeak*i] / bw, paraE[numParPerPeak*i] /bw, + paraA[numParPerPeak*i+1], paraE[numParPerPeak*i+1], + paraA[numParPerPeak*i+2], paraE[numParPerPeak*i+2]); + + } + cFitAuto->Update(); + + //draw the indivual fit + fit->Draw("same"); + + const int nn = nPeaks; + TF1 ** gFit = new TF1 *[nn]; + for( int i = 0; i < nPeaks; i++){ + gFit[i] = new TF1(Form("gFit%d", i), "[0] * TMath::Gaus(x,[1],[2], 1)", xMin, xMax); + gFit[i]->SetParameter(0, paraA[numParPerPeak*i]); + gFit[i]->SetParameter(1, paraA[numParPerPeak*i+1]); + gFit[i]->SetParameter(2, paraA[numParPerPeak*i+2]); + gFit[i]->SetLineColor(i+1); + gFit[i]->SetNpx(1000); + gFit[i]->SetLineWidth(1); + gFit[i]->Draw("same"); + } + + specS->Draw("hist same"); + + //======== print text on plot + TLatex text; + text.SetNDC(); + text.SetTextFont(82); + text.SetTextSize(0.04); + + double chi2 = fit->GetChisquare(); + int ndf = fit->GetNDF(); + text.SetTextSize(0.06); + text.DrawLatex(0.15, 0.8, Form("#bar{#chi^{2}} : %5.3f", chi2/ndf)); + + cFitAuto->cd(3); + PlotResidual(specS, fit); + + cFitAuto->cd(4); + text.SetTextSize(0.05); + text.SetTextColor(2); + + text.DrawLatex(0.1, 0.9, Form(" %13s, %18s, %18s", "count", "mean", "sigma")); + + for( int i = 0; i < nPeaks; i++){ + text.DrawLatex(0.1, 0.8-0.05*i, Form(" %2d, %8.0f(%3.0f), %8.4f(%8.4f), %8.4f(%8.4f)\n", + i, + paraA[3*i] / bw, paraE[3*i] /bw, + paraA[3*i+1], paraE[3*i+1], + paraA[3*i+2], paraE[3*i+2])); + } + + return exPos; + +} + + +//######################################## +//###### NOT tested +//######################################## +vector fitNGF3(TH1 * hist, int bgEst = 10, + double peakThreshold = 0.1, + double sigmaMax = 20, + int peakDensity = 4, + TString optStat = "", bool newPlot = true){ + + TCanvas *cFitAuto = NULL; + if( newPlot ){ + cFitAuto = new TCanvas("cFitAuto","Auto Fitting", 100, 100, 800,800); + cFitAuto->Divide(1,2); + + gStyle->SetOptStat(optStat); + cFitAuto->cd(1); + hist->Draw(); + } + + TH1F * specS = (TH1F*) hist->Clone(); + double xMin = hist->GetXaxis()->GetXmin(); + double xMax = hist->GetXaxis()->GetXmax(); + int xBin = hist->GetXaxis()->GetNbins(); + + TString titleH; + titleH.Form("fitted spectrum (BG=%d); Ex [MeV]; Count / %4.0f keV", bgEst, (xMax-xMin)*1000./xBin ); + specS->SetTitle(titleH); + specS->SetName("specS"); + ///specS->GetXaxis()->SetTitleSize(0.06); + ///specS->GetYaxis()->SetTitleSize(0.06); + ///specS->GetXaxis()->SetTitleOffset(0.7); + ///specS->GetYaxis()->SetTitleOffset(0.6); + + //=================== find peak and fit + gStyle->SetOptFit(0); + TSpectrum * peak = new TSpectrum(50); + nPeaks = peak->Search(hist, peakDensity, "", peakThreshold); + + if( bgEst > 0 ) { + printf("============= estimating background...\n"); + TH1 * h1 = peak->Background(hist, bgEst); + h1->Draw("same"); + printf("============= substracting the linear background...\n"); + specS->Sumw2(); + specS->Add(h1, -1.); + } + + if( newPlot ){ + cFitAuto->cd(2)->SetGrid(); + cFitAuto->cd(2); + } + specS->Draw("hist"); + + + //========== Fitting + if( newPlot ){ + printf("============= Fitting....."); + printf(" found %d peaks \n", nPeaks); + } + double * xpos = peak->GetPositionX(); + double * ypos = peak->GetPositionY(); + + int * inX = new int[nPeaks]; + TMath::Sort(nPeaks, xpos, inX, 0 ); + vector energy, height; + for( int j = 0; j < nPeaks; j++){ + energy.push_back(xpos[inX[j]]); + height.push_back(ypos[inX[j]]); + } + if( newPlot ){ + for( int j = 0; j < nPeaks; j++){ + printf(" energy : %f , %f \n", energy[j], height[j]); + } + } + + int numParPerPeak = 6; + const int n = numParPerPeak * nPeaks; + double * para = new double[n]; + for(int i = 0; i < nPeaks ; i++){ + para[numParPerPeak*i+0] = height[i] * 0.05 * TMath::Sqrt(TMath::TwoPi()); + para[numParPerPeak*i+1] = energy[i]; + para[numParPerPeak*i+2] = sigmaMax; + para[numParPerPeak*i+3] = height[i] * 0.05 * TMath::Sqrt(TMath::TwoPi()) * 0.1; + para[numParPerPeak*i+4] = sigmaMax; + para[numParPerPeak*i+5] = -4; + } + + TF1 * fit = new TF1("fit", nGF3, xMin, xMax, numParPerPeak * nPeaks ); + fit->SetLineWidth(2); + fit->SetLineColor(2); + fit->SetNpx(1000); + fit->SetParameters(para); + + if( nPeaks > 1 ){ + for( int i = 0; i < nPeaks; i++){ + fit->SetParLimits(numParPerPeak*i+0, 0, 1e+9); + double de1 = 1, de2 = 1; + if( i == 0 ){ + de2 = (energy[i+1] - energy[i])/2.; + de1 = de2; + }else if( i < nPeaks -1 ){ + de1 = (energy[i] - energy[i-1])/2.; + de2 = (energy[i+1] - energy[i])/2.; + }else{ + de1 = (energy[i] - energy[i-1])/2.; + de2 = de1; + } + + fit->SetParLimits(numParPerPeak*i+1, energy[i] - de1 , energy[i] + de2); + fit->SetParLimits(numParPerPeak*i+2, 0, sigmaMax * 5); + + fit->SetParLimits(numParPerPeak*i+3, 0, 1e+9); + fit->SetParLimits(numParPerPeak*i+4, 0, sigmaMax); + fit->SetParLimits(numParPerPeak*i+5, -10, -2); + + } + }else{ + fit->SetParLimits(0, 0, 1e+9); + fit->SetParLimits(2, 0, sigmaMax); + fit->SetParLimits(3, 0, 1e+9); + fit->SetParLimits(4, 0, sigmaMax); + fit->SetParLimits(5, -10, -2); + } + specS->Fit("fit", "q"); + + + const Double_t* paraE = fit->GetParErrors(); + const Double_t* paraA = fit->GetParameters(); + + //======== calculate reduce chi-squared + if( newPlot ) GoodnessofFit(specS, fit); + + double bw = specS->GetBinWidth(1); + + vector exPos; + for(int i = 0; i < nPeaks ; i++){ + exPos.push_back(paraA[numParPerPeak*i+1]); + double totCount = paraA[numParPerPeak*i] + paraA[numParPerPeak*i+3]; + double totCountErr = sqrt(paraE[numParPerPeak*i]*paraE[numParPerPeak*i] + paraE[numParPerPeak*i+3]*paraE[numParPerPeak*i+3]); + printf("%2d , count: %8.0f(%3.0f)+%8.0f(%3.0f)=%8.0f(%3.0f), mean: %8.4f(%8.4f), sigma: %8.4f(%8.4f), skewneww: %4.1f(%4.1f) \n", + i, + paraA[numParPerPeak*i] / bw, paraE[numParPerPeak*i] /bw, + paraA[numParPerPeak*i+3] / bw, paraE[numParPerPeak*i+3] /bw, + totCount / bw, totCountErr /bw, + paraA[numParPerPeak*i+1], paraE[numParPerPeak*i+1], + paraA[numParPerPeak*i+2], paraE[numParPerPeak*i+2], + paraA[numParPerPeak*i+5], paraE[numParPerPeak*i+5]); + + //PrintPar(fit, numParPerPeak); + } + if( newPlot ) cFitAuto->Update(); + + //draw the indivual fit + fit->Draw("same"); + + const int nn = nPeaks; + TF1 ** gFit = new TF1 *[nn]; + TF1 ** kFit = new TF1 *[nn]; + TF1 ** zFit = new TF1 *[nn]; + for( int i = 0; i < nPeaks; i++){ + gFit[i] = new TF1(Form("gFit%d", i), "[0] * TMath::Gaus(x,[1],[2], 1) + [3] * TMath::Gaus(x,[1],[4], 1) * ( 1 + TMath::Erf( [5]*(x-[1])/sqrt(2)/[4] ))", xMin, xMax); + gFit[i]->SetParameter(0, paraA[numParPerPeak*i]); + gFit[i]->SetParameter(1, paraA[numParPerPeak*i+1]); + gFit[i]->SetParameter(2, paraA[numParPerPeak*i+2]); + gFit[i]->SetParameter(3, paraA[numParPerPeak*i+3]); + gFit[i]->SetParameter(4, paraA[numParPerPeak*i+4]); + gFit[i]->SetParameter(5, paraA[numParPerPeak*i+5]); + gFit[i]->SetLineColor(i+1); + gFit[i]->SetNpx(1000); + gFit[i]->SetLineWidth(1); + gFit[i]->Draw("same"); + + kFit[i] = new TF1(Form("kFit%d", i), "[0] * TMath::Gaus(x,[1],[2], 1) * ( 1 + TMath::Erf( [3]*(x-[1])/sqrt(2)/[2] ))", xMin, xMax); + kFit[i]->SetParameter(0, paraA[numParPerPeak*i+3]); + kFit[i]->SetParameter(1, paraA[numParPerPeak*i+1]); + kFit[i]->SetParameter(2, paraA[numParPerPeak*i+4]); + kFit[i]->SetParameter(3, paraA[numParPerPeak*i+5]); + kFit[i]->SetLineColor(i+1); + kFit[i]->SetNpx(1000); + kFit[i]->SetLineWidth(1); + kFit[i]->Draw("same"); + + zFit[i] = new TF1(Form("zFit%d", i), "[0] * TMath::Gaus(x,[1],[2], 1)", xMin, xMax); + zFit[i]->SetParameter(0, paraA[numParPerPeak*i]); + zFit[i]->SetParameter(1, paraA[numParPerPeak*i+1]); + zFit[i]->SetParameter(2, paraA[numParPerPeak*i+2]); + zFit[i]->SetLineColor(i+1); + zFit[i]->SetNpx(1000); + zFit[i]->SetLineWidth(1); + zFit[i]->Draw("same"); + + } + + specS->Draw("hist same"); + + return exPos; + +} + +//######################################## +//###### fir N Gauss with estimated BG +//######################################## +void fitNGauss(TH1F * hist, int bgEst = 10, TString fitFile = "AutoFit_para.txt", TString optStat = ""){ + + printf("================================================================\n"); + printf("================ fit N-Gauss with estimated BG ================\n"); + printf(" * bgEst = larger of bgEst, more linear the estimated BG \n"); + printf(" * need the file input \n"); + printf(" \n"); + printf(" 1) The histogram will be subtracted by the estimated BG. \n"); + printf(" 2) n-Gauss will then be fitted the BG subtracted histogram \n"); + printf("================================================================\n"); + + + bool isParaRead = loadFitParameters(fitFile); + if( !isParaRead ) { + printf("Please provide a valid input file\n"); + return; + } + + nPeaks = energy.size(); + + gStyle->SetOptStat(optStat); + TCanvas *cFitNGauss = NewCanvas("cFitNGauss","Fit n-Gauss | fitNGauss", 1,4, 800, 300);; + cFitNGauss->cd(1); + + ScaleAndDrawHist(hist, 0, 0); + + TH1F * specS = (TH1F*) hist->Clone(); + double xMin = hist->GetXaxis()->GetXmin(); + double xMax = hist->GetXaxis()->GetXmax(); + int xBin = hist->GetXaxis()->GetNbins(); + + TString titleH; + titleH.Form("fitNGauss (BG = %2d); Ex [MeV]; Count / %4.0f keV", bgEst, (xMax-xMin)*1000./xBin ); + specS->SetTitle(titleH); + specS->SetName("specS"); + + //=================== find peak and fi + + gStyle->SetOptFit(0); + //cFitNGauss->cd(2)->SetGrid(); + cFitNGauss->cd(2); + + if( bgEst > 0 ) { + printf("============= estimating background...\n"); + TSpectrum * peak = new TSpectrum(50); + TH1 * h1 = peak->Background(hist, bgEst); + cFitNGauss->cd(1); + h1->Draw("same"); + cFitNGauss->cd(2); + printf("============= substracting the estimated background...\n"); + specS->Sumw2(); + specS->Add(h1, -1.); + } + + specS->Draw("hist"); + + //========== Fitting + printf("============= Fitting %d-Gauss..... \n", nPeaks); + + const int n = 3 * nPeaks; + double * para = new double[n]; + for(int i = 0; i < nPeaks ; i++){ + para[3*i+0] = height[i] * 0.05 * TMath::Sqrt(TMath::TwoPi()); + para[3*i+1] = energy[i]; + para[3*i+2] = sigma[i]/2.; + } + + TF1 * fit = new TF1("fit", nGauss, xMin, xMax, 3* nPeaks ); + fit->SetLineWidth(3); + fit->SetLineColor(1); + fit->SetNpx(1000); + fit->SetParameters(para); + + //fixing parameters + for( int i = 0; i < nPeaks; i++){ + fit->SetParLimits(3*i , 0, 1e9); + + if( energyFlag[i] == 1 ) { + fit->FixParameter(3*i+1, energy[i]); + }else{ + fit->SetParLimits(3*i+1, lowE[i], highE[i]); + } + if( sigmaFlag[i] == 1 ) { + fit->FixParameter(3*i+2, sigma[i]); + }else{ + fit->SetParLimits(3*i+2, 0, sigma[i]); + } + } + + specS->Fit("fit", "q"); + + const Double_t* paraE = fit->GetParErrors(); + const Double_t* paraA = fit->GetParameters(); + + //======== calculate reduce chi-squared + //GoodnessofFit(specS, fit); + + double bw = specS->GetBinWidth(1); + + for(int i = 0; i < nPeaks ; i++){ + printf(" %2d , count: %8.0f(%3.0f), mean: %8.4f(%8.4f), sigma: %8.4f(%8.4f) \n", + i, + paraA[3*i] / bw, paraE[3*i] /bw, + paraA[3*i+1], paraE[3*i+1], + paraA[3*i+2], paraE[3*i+2]); + } + printf("\n"); + + //draw the indivual fit + specS->Draw("hist"); + fit->Draw("same"); + + const int nn = nPeaks; + TF1 ** gFit = new TF1 *[nn]; + for( int i = 0; i < nPeaks; i++){ + gFit[i] = new TF1(Form("gFit%d", i), "[0] * TMath::Gaus(x,[1],[2], 1)", xMin, xMax); + gFit[i]->SetParameter(0, paraA[3*i]); + gFit[i]->SetParameter(1, paraA[3*i+1]); + gFit[i]->SetParameter(2, paraA[3*i+2]); + gFit[i]->SetLineColor(i+1); + gFit[i]->SetNpx(1000); + gFit[i]->SetLineWidth(1); + gFit[i]->Draw("same"); + } + + specS->Draw("hist same"); + //specS->Draw("E same"); + + + //======== print text on plot + TLatex text; + text.SetNDC(); + text.SetTextFont(82); + text.SetTextSize(0.06); + + double chi2 = fit->GetChisquare(); + int ndf = fit->GetNDF(); + text.DrawLatex(0.15, 0.8, Form("#bar{#chi^{2}} : %5.3f", chi2/ndf)); + + cFitNGauss->cd(3); + PlotResidual(specS, fit); + + cFitNGauss->cd(4); + + text.SetTextSize(0.05); + text.SetTextColor(2); + + text.DrawLatex(0.1, 0.9, Form(" %13s, %18s, %18s", "count", "mean", "sigma")); + + for( int i = 0; i < nPeaks; i++){ + text.DrawLatex(0.1, 0.8-0.05*i, Form(" %2d, %8.0f(%3.0f), %8.4f(%8.4f), %8.4f(%8.4f)\n", + i, + paraA[3*i] / bw, paraE[3*i] /bw, + paraA[3*i+1], paraE[3*i+1], + paraA[3*i+2], paraE[3*i+2])); + } + + cFitNGauss->Update(); +} + + +//######################################## +//#### not updated +//######################################## +void fitNGaussSub(TH1F * hist, int bgEst = 10, int degPol = 1, TString fitFile = "AutoFit_para.txt", TString optStat = ""){ + + + printf("==================================================================\n"); + printf("======== fit N-Gauss with estimated BG (method-2) ================\n"); + printf(" * bgEst = larger of bgEst, more linear the estimated BG \n"); + printf(" * degPol = degree of polynomial \n"); + printf(" * need the file input \n"); + printf(" \n"); + printf(" 1) A BG is estimated, and then the BG is fitted by a polynomial. \n"); + printf(" 2) The histogram will be subtracted by the polynomial. \n"); + printf(" 3) n-Gauss will then be fitted the subtracted histogram \n"); + printf("================================================================\n"); + + + bool isParaRead = loadFitParameters(fitFile); + if( !isParaRead ) { + printf("Please provide a valid input file\n"); + return; + } + + nPeaks = energy.size(); + nPols = degPol; + + gStyle->SetOptStat(optStat); + TCanvas *cFitNGaussSub = NewCanvas("cFitNGaussSub","Fit n-Gauss, replace estimated BG with Pol-n | fitNGauss2", 1, 4, 800, 300 ); + //if(! cFitNGaussSub->GetShowEventStatus() ) cFitNGaussSub->ToggleEventStatus(); + + cFitNGaussSub->cd(1); + ScaleAndDrawHist(hist, 0, 0); + + TH1F * specS = (TH1F*) hist->Clone(); + double xMin = hist->GetXaxis()->GetXmin(); + double xMax = hist->GetXaxis()->GetXmax(); + int xBin = hist->GetXaxis()->GetNbins(); + + TString titleH; + titleH.Form("fitNGauss2 (replace Est. BG with Pol-%d) (BG = %2d); Ex [MeV]; Count / %4.0f keV", degPol, bgEst, (xMax-xMin)*1000./xBin ); + specS->SetTitle(titleH); + specS->SetName("specS"); + + printf("============= estimating background...\n"); + TSpectrum * peak = new TSpectrum(50); + TH1 * h1 = peak->Background(hist, bgEst); + + printf("============= fit the est-background with a polynomial function...\n"); + + TString polExp = "[0]"; + for( int i = 1; i < degPol + 1; i++){ + polExp += Form("+[%d]*TMath::Power(x,%d)", i, i ); + } + TF1 * bg = new TF1("bg", polExp.Data(), xMin, xMax); + + bg->SetParameter(0, 50); + bg->SetParameter(0, 0); + bg->SetLineColor(2); + bg->SetNpx(1000); + h1->Fit("bg", "R", ""); + + hist->Draw(); + bg->Draw("same"); + + + //======== print text on plot + TLatex text; + text.SetNDC(); + text.SetTextFont(82); + text.SetTextSize(0.04); + + const Double_t * paraAt = bg->GetParameters(); + const Double_t * paraEt = bg->GetParErrors(); + + for( int i = 0; i < degPol + 1; i++){ + text.DrawLatex(0.6, 0.85 - 0.05*i, Form("%4s : %8.4e(%8.4e)\n", Form("p%d", i), paraAt[i], paraEt[i])); + } + + gStyle->SetOptFit(0); +// cFitNGaussSub->cd(2)->SetGrid(); + cFitNGaussSub->cd(2); + + printf("============= substracting the polynomial background...\n"); + specS->Sumw2(); + specS->Add(bg, -1.); + specS->Draw("hist"); + + //========== Fitting + printf("============= Fitting..... \n"); + + const int n = 3 * nPeaks; + double * para = new double[n]; + for(int i = 0; i < nPeaks ; i++){ + para[3*i+0] = height[i] * 0.05 * TMath::Sqrt(TMath::TwoPi()); + para[3*i+1] = energy[i]; + para[3*i+2] = sigma[i]/2.; + } + + TF1 * fit = new TF1("fit", nGauss, xMin, xMax, 3* nPeaks ); + fit->SetLineWidth(3); + fit->SetLineColor(1); + fit->SetNpx(1000); + fit->SetParameters(para); + + //fixing parameters + for( int i = 0; i < nPeaks; i++){ + fit->SetParLimits(3*i , 0, 1e9); + + if( energyFlag[i] == 1 ) { + fit->FixParameter(3*i+1, energy[i]); + }else{ + fit->SetParLimits(3*i+1, lowE[i], highE[i]); + } + if( sigmaFlag[i] == 1 ) { + fit->FixParameter(3*i+2, sigma[i]); + }else{ + fit->SetParLimits(3*i+2, 0, sigma[i]); + } + } + + specS->Fit("fit", "q"); + + const Double_t* paraE = fit->GetParErrors(); + const Double_t* paraA = fit->GetParameters(); + + GoodnessofFit(specS, fit); + + double bw = specS->GetBinWidth(1); + + for(int i = 0; i < nPeaks ; i++){ + printf(" %2d , count: %8.0f(%3.0f), mean: %8.4f(%8.4f), sigma: %8.4f(%8.4f) \n", + i, + paraA[3*i] / bw, paraE[3*i] /bw, + paraA[3*i+1], paraE[3*i+1], + paraA[3*i+2], paraE[3*i+2]); + } + printf("\n"); + + + //draw the indivual fit + specS->Draw("hist"); + fit->Draw("same"); + + const int nn = nPeaks; + TF1 ** gFit = new TF1 *[nn]; + for( int i = 0; i < nPeaks; i++){ + gFit[i] = new TF1(Form("gFit%d", i), "[0] * TMath::Gaus(x,[1],[2], 1)", xMin, xMax); + gFit[i]->SetParameter(0, paraA[3*i]); + gFit[i]->SetParameter(1, paraA[3*i+1]); + gFit[i]->SetParameter(2, paraA[3*i+2]); + gFit[i]->SetLineColor(i+1); + gFit[i]->SetNpx(1000); + gFit[i]->SetLineWidth(1); + gFit[i]->Draw("same"); + } + + specS->Draw("hist same"); + //specS->Draw("E same"); + + double chi2 = fit->GetChisquare(); + int ndf = fit->GetNDF(); + text.SetTextSize(0.06); + text.DrawLatex(0.15, 0.8, Form("#bar{#chi^{2}} : %5.3f", chi2/ndf)); + + + cFitNGaussSub->cd(3); + PlotResidual(specS, fit); + + cFitNGaussSub->cd(4); + + text.SetTextSize(0.05); + text.SetTextColor(2); + + text.DrawLatex(0.1, 0.9, Form(" %13s, %18s, %18s", "count", "mean", "sigma")); + + for( int i = 0; i < nPeaks; i++){ + text.DrawLatex(0.1, 0.8-0.05*i, Form(" %2d, %8.0f(%3.0f), %8.4f(%8.4f), %8.4f(%8.4f)\n", + i, + paraA[3*i] / bw, paraE[3*i] /bw, + paraA[3*i+1], paraE[3*i+1], + paraA[3*i+2], paraE[3*i+2])); + } + +} + + +//######################################## +//#### fit N-Gauss with pol-n BG +//######################################## +void fitNGaussPol(TH1F * hist, int degPol, TString fitFile = "AutoFit_para.txt",double xMin = 0, double xMax = 0, TString optStat = ""){ + + printf("================================================================\n"); + printf("================ fit N-Gauss with Pol-%1d BG ==================\n", degPol); + printf(" * degPol = degree of polynomial \n"); + printf(" * need the file input \n"); + printf(" * xMin, xMax = if left empty, full range will be used\n"); + printf(" \n"); + printf(" 1) The histogram will be fitted by n-Gauss + Pol \n"); + printf("================================================================\n"); + + + bool isParaRead = loadFitParameters(fitFile); + if( !isParaRead ) { + printf("Please provide a valid input file\n"); + return; + } + + gStyle->SetOptStat(optStat); + nPeaks = energy.size(); + nPols = degPol; + + TCanvas * cFitNGaussPol = NewCanvas("cFitNGaussPol", Form("Fitting with n-Gauss + pol-%d | fitNGaussPol", degPol), 1, 3, 800, 300); + //if(! cFitNGaussPol->GetShowEventStatus() ) cFitNGaussPol->ToggleEventStatus(); + cFitNGaussPol->cd(1); + + ScaleAndDrawHist(hist, xMin, xMax); + + if( xMin == xMax){ + xMin = hist->GetXaxis()->GetXmin(); + xMax = hist->GetXaxis()->GetXmax(); + } + int xBin = hist->GetXaxis()->GetNbins(); + + + printf("============= find the polynomial background ..... \n"); + + int nPar = 3 * nPeaks + nPols + 1; + double * para = new double[nPar]; + for(int i = 0; i < nPeaks ; i++){ + para[3*i+0] = height[i] * 0.05 * TMath::Sqrt(TMath::TwoPi()); + para[3*i+1] = energy[i]; + para[3*i+2] = sigma[i]/2.; + } + + for(int i = 0; i < nPols + 1; i++){ + //if( ggg == NULL ){ + para[3*nPeaks+i] = gRandom->Rndm()/TMath::Power(10, 3*i); + //}else{ + // para[3*nPeaks+i] = gPara[i]; + //} + } + + TF1 * fit = new TF1("fit", nGaussPol, xMin, xMax, nPar ); + fit->SetLineWidth(3); + fit->SetLineColor(1); + fit->SetNpx(1000); + fit->SetParameters(para); + + //fixing parameters + for( int i = 0; i < nPeaks; i++){ + fit->SetParLimits(3*i , 0, 1e9); + if( energyFlag[i] == 1 ) { + fit->FixParameter(3*i+1, energy[i]); + }else{ + fit->SetParLimits(3*i+1, lowE[i], highE[i]); + } + if( sigmaFlag[i] == 1 ) { + fit->FixParameter(3*i+2, sigma[i]); + }else{ + fit->SetParLimits(3*i+2, 0, sigma[i]); + } + } + + hist->Fit("fit", "Rq"); + + //=========== get the polynomial part + const Double_t* paraA = fit->GetParameters(); + const Double_t* paraE = fit->GetParErrors(); + + TString polExp = "[0]"; + for( int i = 1; i < degPol + 1; i++){ + polExp += Form("+[%d]*TMath::Power(x,%d)", i, i ); + } + + TF1 * bg = new TF1("bg", polExp.Data(), xMin, xMax); + for( int i = 0; i < degPol + 1; i++){ + bg->SetParameter(i, paraA[3*nPeaks+i]); + } + bg->SetNpx(1000); + + for( int i = 0; i < degPol + 1; i++){ + printf("%4s : %8.4e(%8.4e)\n", Form("p%d", i), paraA[3*nPeaks+i], paraE[3*nPeaks+i]); + } + printf("====================================\n"); + + cFitNGaussPol->cd(1); + bg->Draw("same"); + + TLatex text; + text.SetNDC(); + text.SetTextFont(82); + text.SetTextSize(0.04); + text.SetTextColor(1); + + for( int i = 0; i < degPol + 1; i++){ + text.DrawLatex(0.6, 0.85 - 0.05*i, Form("%4s : %8.4e(%8.4e)\n", Form("p%d", i), paraA[3*nPeaks+i], paraE[3*nPeaks+i])); + } + + double chi2 = fit->GetChisquare(); + int ndf = fit->GetNDF(); + text.SetTextSize(0.06); + text.DrawLatex(0.15, 0.8, Form("#bar{#chi^{2}} : %5.3f", chi2/ndf)); + + + //GoodnessofFit(specS, fit); + + double bw = hist->GetBinWidth(1); + + for(int i = 0; i < nPeaks ; i++){ + printf(" %2d , count: %8.0f(%3.0f), mean: %8.4f(%8.4f), sigma: %8.4f(%8.4f) \n", + i, + paraA[3*i] / bw, paraE[3*i] /bw, + paraA[3*i+1], paraE[3*i+1], + paraA[3*i+2], paraE[3*i+2]); + } + printf("\n"); + + + const int nn = nPeaks; + TF1 ** gFit = new TF1 *[nn]; + for( int i = 0; i < nPeaks; i++){ + gFit[i] = new TF1(Form("gFit%d", i), "[0] * TMath::Gaus(x,[1],[2], 1)", xMin, xMax); + gFit[i]->SetParameter(0, paraA[3*i]); + gFit[i]->SetParameter(1, paraA[3*i+1]); + gFit[i]->SetParameter(2, paraA[3*i+2]); + gFit[i]->SetLineColor(i+1); + gFit[i]->SetNpx(1000); + gFit[i]->SetLineWidth(1); + gFit[i]->Draw("same"); + } + + cFitNGaussPol->Update(); + + cFitNGaussPol->cd(2); + PlotResidual(hist, fit); + + cFitNGaussPol->cd(3); + + text.SetNDC(); + text.SetTextFont(82); + text.SetTextSize(0.05); + text.SetTextColor(2); + + text.DrawLatex(0.1, 0.9, Form(" %13s, %18s, %18s", "count", "mean", "sigma")); + + for( int i = 0; i < nPeaks; i++){ + text.DrawLatex(0.1, 0.8-0.05*i, Form(" %2d, %8.0f(%3.0f), %8.4f(%8.4f), %8.4f(%8.4f)\n", + i, + paraA[3*i] / bw, paraE[3*i] /bw, + paraA[3*i+1], paraE[3*i+1], + paraA[3*i+2], paraE[3*i+2])); + } + +} + + + + +//######################################## +//#### fit N-Gauss with pol-n BG +//######################################## +void fitNGaussPolSub(TH1F * hist, int degPol, TString fitFile = "AutoFit_para.txt",double xMin = 0, double xMax = 0, TString optStat = ""){ + + printf("================================================================\n"); + printf("========= fit N-Gauss with Pol-%1d BG / 2nd method ============\n", degPol); + printf(" * degPol = degree of polynomial \n"); + printf(" * need the file input \n"); + printf(" * xMin, xMax = if left empty, full range will be used\n"); + printf(" \n"); + printf(" 1) The histogram will be fitted by n-Gauss + Pol -> to get the estimated BG \n"); + printf(" 2) The histogram will be subtracted by the Pol BG. \n"); + printf(" 3) n-Gauss will then be fitted the BG subtracted histogram \n"); + printf("================================================================\n"); + + + bool isParaRead = loadFitParameters(fitFile); + if( !isParaRead ) { + printf("Please provide a valid input file\n"); + return; + } + + gStyle->SetOptStat(optStat); + nPeaks = energy.size(); + nPols = degPol; + + TCanvas * cFitNGaussPolSub = NewCanvas("cFitNGaussPolSub", Form("Fitting with n-Gauss + pol-%d (method-2) | fitGaussPol2", degPol), 1, 4, 800, 300); + //if(! cFitNGaussPol->GetShowEventStatus() ) cFitNGaussPol->ToggleEventStatus(); + cFitNGaussPolSub->cd(1); + + ScaleAndDrawHist(hist, xMin, xMax); + + if( xMin == xMax){ + xMin = hist->GetXaxis()->GetXmin(); + xMax = hist->GetXaxis()->GetXmax(); + } + int xBin = hist->GetXaxis()->GetNbins(); + + printf("============= find the polynomial background ..... \n"); + + int nPar = 3 * nPeaks + nPols + 1; + double * para = new double[nPar]; + for(int i = 0; i < nPeaks ; i++){ + para[3*i+0] = height[i] * 0.05 * TMath::Sqrt(TMath::TwoPi()); + para[3*i+1] = energy[i]; + para[3*i+2] = sigma[i]/2.; + } + + for(int i = 0; i < nPols + 1; i++){ + para[3*nPeaks+i] = gRandom->Rndm()/TMath::Power(10, 3*i); + } + + TF1 * fit = new TF1("fit", nGaussPol, xMin, xMax, nPar ); + fit->SetLineWidth(3); + fit->SetLineColor(1); + fit->SetNpx(1000); + fit->SetParameters(para); + + //fixing parameters + for( int i = 0; i < nPeaks; i++){ + fit->SetParLimits(3*i , 0, 1e9); + if( energyFlag[i] == 1 ) { + fit->FixParameter(3*i+1, energy[i]); + }else{ + fit->SetParLimits(3*i+1, lowE[i], highE[i]); + } + if( sigmaFlag[i] == 1 ) { + fit->FixParameter(3*i+2, sigma[i]); + }else{ + fit->SetParLimits(3*i+2, 0, sigma[i]); + } + } + + hist->Fit("fit", "nq"); + + //=========== get the polynomial part and substract + const Double_t* paraAt = fit->GetParameters(); + const Double_t* paraEt = fit->GetParErrors(); + + TString polExp = "[0]"; + for( int i = 1; i < degPol + 1; i++){ + polExp += Form("+[%d]*TMath::Power(x,%d)", i, i ); + } + + TF1 * bg = new TF1("bg", polExp.Data(), xMin, xMax); + for( int i = 0; i < degPol + 1; i++){ + bg->SetParameter(i, paraAt[3*nPeaks+i]); + } + bg->SetNpx(1000); + + for( int i = 0; i < degPol + 1; i++){ + printf("%4s : %8.4e(%8.4e)\n", Form("p%d", i), paraAt[3*nPeaks+i], paraEt[3*nPeaks+i]); + } + printf("====================================\n"); + + cFitNGaussPolSub->cd(1); + bg->Draw("same"); + + TH1F * specS = (TH1F*) hist->Clone(); + TString titleH; + titleH.Form("pol-%d BG Subtracted spectrum (fitNGaussPol-2); Ex [MeV]; Count / %4.0f keV", degPol, (xMax-xMin)*1000./xBin ); + specS->SetTitle(titleH); + specS->SetName("specS"); + + //=================== find peak and fit + + gStyle->SetOptFit(0); + ///cFitNGaussPol->cd(2)->SetGrid(); + cFitNGaussPolSub->cd(2); + + printf("============= substracting the polynomial background...\n"); + specS->Sumw2(); + specS->Add(bg, -1.); + specS->Draw("hist"); + + //======= fit again + printf("============= fitting the subtracted spectrum.... \n"); + + nPar = 3* nPeaks; + TF1 * fita = new TF1("fita", nGauss, xMin, xMax, nPar ); + fita->SetLineWidth(3); + fita->SetLineColor(1); + fita->SetNpx(1000); + fita->SetParameters(para); + + //fixing parameters + for( int i = 0; i < nPeaks; i++){ + fita->SetParLimits(3*i , 0, 1e9); + + if( energyFlag[i] == 1 ) { + fita->FixParameter(3*i+1, energy[i]); + }else{ + fita->SetParLimits(3*i+1, lowE[i], highE[i]); + } + if( sigmaFlag[i] == 1 ) { + fita->FixParameter(3*i+2, sigma[i]); + }else{ + fita->SetParLimits(3*i+2, 0, sigma[i]); + } + } + + specS->Fit("fita", "q"); + + const Double_t* paraE = fita->GetParErrors(); + const Double_t* paraA = fita->GetParameters(); + + //GoodnessofFit(specS, fit); + + double bw = specS->GetBinWidth(1); + + for(int i = 0; i < nPeaks ; i++){ + printf(" %2d , count: %8.0f(%3.0f), mean: %8.4f(%8.4f), sigma: %8.4f(%8.4f) \n", + i, + paraA[3*i] / bw, paraE[3*i] /bw, + paraA[3*i+1], paraE[3*i+1], + paraA[3*i+2], paraE[3*i+2]); + } + printf("\n"); + + + //draw the indivual fit + specS->Draw("hist"); + fita->Draw("same"); + + const int nn = nPeaks; + TF1 ** gFit = new TF1 *[nn]; + for( int i = 0; i < nPeaks; i++){ + gFit[i] = new TF1(Form("gFit%d", i), "[0] * TMath::Gaus(x,[1],[2], 1)", xMin, xMax); + gFit[i]->SetParameter(0, paraA[3*i]); + gFit[i]->SetParameter(1, paraA[3*i+1]); + gFit[i]->SetParameter(2, paraA[3*i+2]); + gFit[i]->SetLineColor(i+1); + gFit[i]->SetNpx(1000); + gFit[i]->SetLineWidth(1); + gFit[i]->Draw("same"); + } + + specS->Draw("hist same"); + //specS->Draw("E same"); + + + TLatex text; + text.SetNDC(); + text.SetTextFont(82); + text.SetTextSize(0.04); + text.SetTextColor(1); + + for( int i = 0; i < degPol + 1; i++){ + text.DrawLatex(0.6, 0.85 - 0.05*i, Form("%4s : %8.4e(%8.4e)\n", Form("p%d", i), paraA[3*nPeaks+i], paraE[3*nPeaks+i])); + } + + double chi2 = fita->GetChisquare(); + int ndf = fita->GetNDF(); + text.SetTextSize(0.06); + text.DrawLatex(0.15, 0.8, Form("#bar{#chi^{2}} : %5.3f", chi2/ndf)); + + + cFitNGaussPolSub->cd(3); + PlotResidual(specS, fita); + + cFitNGaussPolSub->cd(4); + + text.SetNDC(); + text.SetTextFont(82); + text.SetTextSize(0.05); + text.SetTextColor(2); + + text.DrawLatex(0.1, 0.9, Form(" %13s, %18s, %18s", "count", "mean", "sigma")); + + for( int i = 0; i < nPeaks; i++){ + text.DrawLatex(0.1, 0.8-0.05*i, Form(" %2d, %8.0f(%3.0f), %8.4f(%8.4f), %8.4f(%8.4f)\n", + i, + paraA[3*i] / bw, paraE[3*i] /bw, + paraA[3*i+1], paraE[3*i+1], + paraA[3*i+2], paraE[3*i+2])); + } + +} + +//######################################## +//###### fit A * Exp(-t/T) + B +//######################################## +void fitDecay(TH1F * hist){ + + gStyle->SetOptStat(""); + TCanvas * cFitDecay = NULL; + if( gROOT->FindObjectAny("cFitDecay") == NULL ){ + cFitDecay = new TCanvas("cFitDecay", Form("fit A * Exp(-t/T) + B | fitDecay"), 800, 1000); + }else{ + delete gROOT->FindObjectAny("cFitDecay") ; + cFitDecay = new TCanvas("cFitDecay", Form("fit A * Exp(-t/T) + B | fitDecay"), 800, 1000); + } + + cFitDecay->Divide(1, 2); + + double yMax = hist->GetBinContent(hist->GetMaximumBin()); + hist->SetMaximum(yMax*1.2); + cFitDecay->cd(1); hist->Draw(); + double estHalf = hist->GetBinCenter(hist->FindLastBinAbove(yMax/2.)) *1.3; + + //printf("estimator : A = %.2f, T = %.2f \n", yMax, estHalf); + + TF1 * fit = new TF1("fit", "[0]*TMath::Exp(-x/[1]/TMath::Log(2))+[2]"); + fit->SetLineWidth(3); + fit->SetLineColor(1); + fit->SetNpx(1000); + + fit->SetParameter(0, yMax ); + fit->SetParameter(1, estHalf ); + fit->SetParameter(2, 1); + + fit->SetParLimits(0, 0, 1e9); + fit->SetParLimits(1, 0, 1e9); + fit->SetParLimits(2, 0, 1e9); + + gStyle->SetOptFit(000000); + hist->Fit("fit", "q"); + + const Double_t* paraE = fit->GetParErrors(); + const Double_t* paraA = fit->GetParameters(); + + TLatex text; + text.SetNDC(); + text.SetTextFont(82); + text.SetTextSize(0.04); + text.SetTextColor(1); + + text.DrawLatex(0.6, 0.8, "A e^{#left(-#frac{t}{T Ln(2)}#right)}+B"); + text.DrawLatex(0.6, 0.75, Form("A : %.f(%.f)", paraA[0], paraE[0])); + text.DrawLatex(0.6, 0.7, Form("T : %.f(%.f)", paraA[1], paraE[1])); + text.DrawLatex(0.6, 0.65, Form("B : %.f(%.f)", paraA[2], paraE[2])); + + double chi2 = fit->GetChisquare(); + int ndf = fit->GetNDF(); + text.DrawLatex(0.6, 0.6, Form("#bar{#chi^{2}} : %5.3f", chi2/ndf)); + + + TF1 * fite = new TF1("fite", "[0]*TMath::Exp(-x/[1])" ); + fite->SetParameter(0, paraA[0]); + fite->SetParameter(1, paraA[1]); + fite->Draw("same"); + + TF1 * fitbg = new TF1("fitbg", "pol0" ); + fitbg->SetParameter(0, paraA[2]); + fitbg->Draw("same"); + + cFitDecay->cd(2); + PlotResidual(hist, fit); + + +} + +//################################################# +//#### fit N-Gauss with pol-n BG using mouse click +//################################################# + +int nClick = 0; +bool peakFlag = 1; +vector xPeakList; +vector yPeakList; +vector xBGList; +vector yBGList; + +TH1F * tempHist; +int markerStyle = 23; +int markerColor = 2; +int markerBGColor = 4; + +void Clicked() { + int event = gPad->GetEvent(); + if (event != 11) return; + TObject *select = gPad->GetSelected(); + if (!select) return; + + TH1F *h = (TH1F*)select; + int px = gPad->GetEventX(); + double xd = gPad->AbsPixeltoX(px); + float x = gPad->PadtoX(xd); + + if( peakFlag ) { + xPeakList.push_back(x); + }else{ + xBGList.push_back(x); + } + int b = tempHist->FindBin(x); + double y = tempHist->GetBinContent(b); + if( peakFlag ){ + yPeakList.push_back(y); + }else{ + yBGList.push_back(y); + } + // add marker in the histogram + TMarker * mark = new TMarker(x,y, markerStyle); + mark->SetMarkerColor(markerColor); + tempHist->GetListOfFunctions()->Add(mark); + + printf("%2d | x : %8.2f , y : %.0f \n", nClick, x, y); + + nClick ++; + +} + + +void saveFitPara(TString fileName = "AutoFit_para.txt"){ + printf("Save to : %s \n", fileName.Data()); + FILE * file_out; + file_out = fopen (fileName.Data(), "w+"); + + 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 < xPeakList.size() ; i++){ + fprintf(file_out, "%.3f %.3f %.3f 0 %.3f 0 %.0f\n", + xPeakList[i], + xPeakList[i] - 5*sigma[i], + xPeakList[i] + 5*sigma[i], + sigma[i], + yPeakList[i]); + } + fclose(file_out); +} + +void clickFitNGaussPol(TH1F * hist, int degPol, double sigmaMax = 0){ + + printf("=========================================================\n"); + printf("======== fit n-Gauss + Pol-%d BG using mouse click =====\n", degPol ); + printf("==========================================================\n"); + + gStyle->SetOptStat(""); + gStyle->SetOptFit(0); + + TCanvas * cClickFitNGaussPol = NULL; + if( gROOT->FindObjectAny("cClickFitGaussPol") == NULL ){ + cClickFitNGaussPol = new TCanvas("cClickFitNGaussPol", Form("fit Gauss & Pol-%d by mouse click | clickFitGaussPol", degPol), 1400, 1200); + }else{ + delete gROOT->FindObjectAny("cClickFitNGaussPol") ; + cClickFitNGaussPol = new TCanvas("cClickFitNGaussPol", Form("fit Gauss & Pol-%d by mouse click | clickFitGaussPol", degPol), 1400, 1200); + } + cClickFitNGaussPol->Divide(1, 4); + for(int i = 1; i <= 4 ; i++){ + cClickFitNGaussPol->cd(i)->SetGrid(0,0); + } + + if(! cClickFitNGaussPol->GetShowEventStatus() ) cClickFitNGaussPol->ToggleEventStatus(); + cClickFitNGaussPol->cd(1); + + + hist->GetListOfFunctions()->Clear(); + ScaleAndDrawHist(hist, 0, 0); + TH1F* hspec = (TH1F*) hist->Clone(); + hspec->Sumw2(); + cClickFitNGaussPol->Update(); + cClickFitNGaussPol->Draw(); + + TLatex helpMsg; + helpMsg.SetNDC(); + helpMsg.SetTextFont(82); + helpMsg.SetTextSize(0.06); + helpMsg.SetTextColor(kRed); + helpMsg.DrawLatex(0.15, 0.8, "Click for peaks: (Double-click / x / Ctrl to end) "); + + printf("--------- Click the histogram for peaks: (Double-click / x / Ctrl to end) \n"); + nClick = 0; + xPeakList.clear(); + yPeakList.clear(); + markerColor = 2; + markerStyle = 23; + peakFlag = 1; + cClickFitNGaussPol->cd(1)->SetCrosshair(1); + cClickFitNGaussPol->cd(1)->AddExec("ex", "Clicked()"); + tempHist = hist; + TObject * obj ; + do{ + obj = gPad->WaitPrimitive(); + if( obj == NULL ) break; + }while( obj != NULL); + + if( degPol >= 0 ){ + printf("--------- Click the histogram for Background: (Double-click / x / Ctrl to end) \n"); + printf(" * when no input, program will estimate \n"); + + cClickFitNGaussPol->cd(1)->Clear(); + hist->Draw(); + helpMsg.SetTextColor(markerBGColor); + helpMsg.DrawLatex(0.15, 0.8, "Click for BG: (Double-click / x / Ctrl to end) "); + helpMsg.DrawLatex(0.15, 0.75, "* when no input, program will estimate"); + cClickFitNGaussPol->Update(); + cClickFitNGaussPol->Draw(); + + nClick = 0; + xBGList.clear(); + yBGList.clear(); + markerColor = markerBGColor; + markerStyle = 33; + peakFlag = 0; + cClickFitNGaussPol->cd(1)->AddExec("ex", "Clicked()"); + do{ + obj = gPad->WaitPrimitive(); + if( obj == NULL ) break; + }while( obj != NULL); + + } + + cClickFitNGaussPol->cd(1)->DeleteExec("ex"); + cClickFitNGaussPol->cd(1)->SetCrosshair(0); + cClickFitNGaussPol->cd(1)->Clear(); + hist->Draw(); + + tempHist = NULL; + + cClickFitNGaussPol->Update(); + cClickFitNGaussPol->Draw(); + + nPols = degPol; + double xMin = hspec->GetXaxis()->GetXmin(); + double xMax = hspec->GetXaxis()->GetXmax(); + + TString polExp = "[0]"; + for( int i = 1; i < degPol + 1; i++) polExp += Form("+[%d]*TMath::Power(x,%d)", i, i ); + TF1 *bg = new TF1("bg", polExp.Data(), xMin, xMax); + bg->SetNpx(1000); + bg->SetLineColor(markerBGColor); + bg->SetLineWidth(1); + if( xBGList.size() > 0 ) { + printf("---------------- fit the BG with Pol-%d \n", nPols); + TGraph * gBG = new TGraph((int) xBGList.size(), &xBGList[0], &yBGList[0]); + for( int i = 0; i < degPol + 1; i++) bg->SetParameter(i, gRandom->Rndm()/TMath::Power(10, 3*i)); + gBG->Fit("bg", "Rq"); + bg->Draw("same"); + //printf("--------------- Subtracting the BG \n"); + //hspec->Add(bg, -1); + }else{ + for( int i = 0; i < nPols+1; i++) bg->SetParameter(i, 0.); + } + + nPeaks = (int) xPeakList.size(); + if( sigmaMax == 0 ){ + printf("------------- Estimate sigma for each peak \n"); + sigma.clear(); + int binMin = hist->FindBin(xMin); + int binMax = hist->FindBin(xMax); + for( int i = 0; i < nPeaks ; i++){ + int b0 = hist->FindBin(xPeakList[i]); + double estBG = bg->Eval(xPeakList[i]); + double sMin = (xMax-xMin)/5., sMax = (xMax-xMin)/5.; + //---- backward search, stop when + for( int b = b0-1 ; b > binMin ; b-- ){ + double y = hist->GetBinContent(b); + double x = hist->GetBinCenter(b); + if( y - (bg->Eval(x)) < (yPeakList[i]-estBG)/2. ) { + sMin = xPeakList[i] - hist->GetBinCenter(b); + break; + } + } + //---- forward search, stop when + for( int b = b0+1 ; b < binMax ; b++ ){ + double y = hist->GetBinContent(b); + double x = hist->GetBinCenter(b); + if( y - (bg->Eval(x)) < (yPeakList[i]-estBG)/2. ) { + sMax = hist->GetBinCenter(b) - xPeakList[i]; + break; + } + } + + double temp = TMath::Min(sMin, sMax); + /// When there are multiple peaks closely packed : + if( i > 0 && temp > 2.5 * sigma.back() ) temp = sigma.back(); + sigma.push_back(temp); + + printf("%2d | x : %8.2f | sigma(est) %f \n", i, xPeakList[i], sigma[i]); + + } + + //---- use the mean of the sigma + double sigma0 = 0; + for( int i = 0; i < nPeaks ; i++) sigma0 += sigma[i]; + sigma0 = sigma0/(nPeaks+1); + for( int i = 0; i < nPeaks ; i++) sigma[i] = sigma0; + printf("========== use the mean sigma : %f \n", sigma0); + }else if( sigmaMax < 0 ){ + printf("========== use user input sigma : %f (fixed)\n", abs(sigmaMax)); + sigma.clear(); + for( int i = 0; i < nPeaks ; i++) sigma.push_back(abs(sigmaMax)); + }else if( sigmaMax > 0 ){ + printf("========== use user input sigma : %f/2. \n", sigmaMax/2.); + sigma.clear(); + for( int i = 0; i < nPeaks ; i++) sigma.push_back(sigmaMax/2.); + } + + printf("-------------- Fit the spectrum with %d-Gauss + Pol-%d\n", nPeaks, nPols ); + cClickFitNGaussPol->cd(2); + hspec->Draw("hist"); + + int nPar = 3 * nPeaks + nPols + 1; + double * para = new double[nPar]; + for(int i = 0; i < nPeaks ; i++){ + para[3*i+0] = yPeakList[i] * 0.05 * TMath::Sqrt(TMath::TwoPi()); + para[3*i+1] = xPeakList[i]; + if( sigmaMax == 0){ + para[3*i+2] = sigma[i]; + }else if(sigmaMax < 0 ){ + para[3*i+2] = abs(sigmaMax); + }else if(sigmaMax > 0 ){ + para[3*i+2] = sigmaMax/2.; + } + } + for(int i = 0; i < nPols+1 ; i++){ + para[3*nPeaks+i] = bg->GetParameter(i); + } + + TF1 * fit = new TF1("fit", nGaussPol, xMin, xMax, nPar ); + fit->SetLineWidth(3); + fit->SetLineColor(1); + fit->SetNpx(1000); + fit->SetParameters(para); + + //limit parameters + for( int i = 0; i < nPeaks; i++){ + fit->SetParLimits(3*i , 0, 1e9); + + double dE1, dE2; + if( i == 0 ){ + dE2 = xPeakList[i+1] - xPeakList[i]; + dE1 = dE2; + }else if ( i == nPeaks-1 ){ + dE1 = xPeakList[i] - xPeakList[i-1]; + dE2 = dE1; + }else{ + dE1 = xPeakList[i] - xPeakList[i-1]; + dE2 = xPeakList[i+1] - xPeakList[i]; + } + + fit->SetParLimits(3*i+1, xPeakList[i] - dE1 , xPeakList[i] + dE2 ); + if( sigmaMax== 0 ) fit->SetParLimits(3*i+2, 0, 1.5*sigma[i]); // add 50% margin of sigma + if( sigmaMax < 0 ) fit->FixParameter(3*i+2, abs(sigmaMax)); + if( sigmaMax > 0 ) fit->SetParLimits(3*i+2, 0, sigmaMax); + } + + hspec->Fit("fit", "Rq"); + fit->Draw("same"); + + //=========== get the polynomial part + const Double_t* paraA = fit->GetParameters(); + const Double_t* paraE = fit->GetParErrors(); + + double chi2 = fit->GetChisquare(); + int ndf = fit->GetNDF(); + double bw = hspec->GetBinWidth(1); + + for(int i = 0; i < nPeaks ; i++){ + printf(" %2d , count: %8.0f(%3.0f), mean: %8.4f(%8.4f), sigma: %8.4f(%8.4f) \n", + i, + paraA[3*i] / bw, paraE[3*i] /bw, + paraA[3*i+1], paraE[3*i+1], + paraA[3*i+2], paraE[3*i+2]); + } + printf("\n"); + + TLatex text; + text.SetNDC(); + text.SetTextFont(82); + text.SetTextSize(0.06); + text.DrawLatex(0.15, 0.8, Form("#bar{#chi^{2}} : %5.3f", chi2/ndf)); + + for( int i = 0; i < degPol + 1; i++){ + text.DrawLatex(0.6, 0.85 - 0.05*i, Form("%4s : %8.4e(%8.4e)\n", Form("p%d", i), paraA[3*nPeaks+i], paraE[3*nPeaks+i])); + } + + TF1 ** gFit = new TF1 *[nPeaks]; + for( int i = 0; i < nPeaks; i++){ + gFit[i] = new TF1(Form("gFit%d", i), "[0] * TMath::Gaus(x,[1],[2], 1)", xMin, xMax); + gFit[i]->SetParameter(0, paraA[3*i]); + gFit[i]->SetParameter(1, paraA[3*i+1]); + gFit[i]->SetParameter(2, paraA[3*i+2]); + gFit[i]->SetLineColor(i+1); + gFit[i]->SetNpx(1000); + gFit[i]->SetLineWidth(1); + gFit[i]->Draw("same"); + } + + if( degPol >= 0 ){ + TF1 *bg2 = new TF1("bg", polExp.Data(), xMin, xMax); + bg2->SetNpx(1000); + bg2->SetLineColor(markerBGColor); + bg2->SetLineWidth(1); + for( int i = 0; i < nPols + 1; i++){ + bg2->SetParameter(i, paraA[3*nPeaks+i]); + } + bg2->Draw("same"); + } + + cClickFitNGaussPol->cd(3); + PlotResidual(hspec, fit); + + cClickFitNGaussPol->cd(4); + + text.SetTextSize(0.05); + text.SetTextColor(2); + text.DrawLatex(0.1, 0.9, Form(" %13s, %18s, %18s", "count", "mean", "sigma")); + + for( int i = 0; i < nPeaks; i++){ + text.DrawLatex(0.1, 0.8-0.05*i, Form(" %2d, %8.0f(%3.0f), %8.4f(%8.4f), %8.4f(%8.4f)\n", + i, + paraA[3*i] / bw, paraE[3*i] /bw, + paraA[3*i+1], paraE[3*i+1], + paraA[3*i+2], paraE[3*i+2])); + } +} + + + +void clickFitNGaussPolSub(TH1F * hist, int degPol, double sigmaMax = 0){ + + printf("=========================================================\n"); + printf("= fit n-Gauss + Pol-%d BG using mouse click (method-2) =\n", degPol ); + printf("==========================================================\n"); + + gStyle->SetOptStat(""); + gStyle->SetOptFit(0); + + TCanvas * cClickFitNGaussPolsub = NULL; + if( gROOT->FindObjectAny("cClickFitGaussPolsub") == NULL ){ + cClickFitNGaussPolsub = new TCanvas("cClickFitNGaussPol", Form("fit Gauss & Pol-%d by mouse click (sub) | clickFitGaussPolsub", degPol), 1400, 1200); + }else{ + delete gROOT->FindObjectAny("cClickFitNGaussPolsub") ; + cClickFitNGaussPolsub = new TCanvas("cClickFitNGaussPolsub", Form("fit Gauss & Pol-%d by mouse click (sub) | clickFitGaussPolsub", degPol), 1400, 1200); + } + cClickFitNGaussPolsub->Divide(1, 4); + for(int i = 1; i <= 4 ; i++){ + cClickFitNGaussPolsub->cd(i)->SetGrid(0,0); + } + + if(! cClickFitNGaussPolsub->GetShowEventStatus() ) cClickFitNGaussPolsub->ToggleEventStatus(); + cClickFitNGaussPolsub->cd(1); + + + hist->GetListOfFunctions()->Clear(); + ScaleAndDrawHist(hist, 0, 0); + TH1F* hspec = (TH1F*) hist->Clone(); + hspec->Sumw2(); + cClickFitNGaussPolsub->Update(); + cClickFitNGaussPolsub->Draw(); + + TLatex helpMsg; + helpMsg.SetNDC(); + helpMsg.SetTextFont(82); + helpMsg.SetTextSize(0.06); + helpMsg.SetTextColor(kRed); + helpMsg.DrawLatex(0.15, 0.8, "Click for peaks: (Double-click / x / Ctrl to end) "); + + + printf("--------- Click the histogram for peaks: (Double-click / x / Ctrl to end) \n"); + nClick = 0; + xPeakList.clear(); + yPeakList.clear(); + markerColor = 2; + markerStyle = 23; + peakFlag = 1; + cClickFitNGaussPolsub->cd(1)->SetCrosshair(1); + cClickFitNGaussPolsub->cd(1)->AddExec("ex", "Clicked()"); + tempHist = hist; + TObject * obj ; + do{ + obj = gPad->WaitPrimitive(); + if( obj == NULL ) break; + }while( obj != NULL); + + if( degPol >= 0 ){ + printf("--------- Click the histogram for Background: (Double-click / x / Ctrl to end) \n"); + + cClickFitNGaussPolsub->cd(1)->Clear(); + hist->Draw(); + helpMsg.SetTextColor(markerBGColor); + helpMsg.DrawLatex(0.15, 0.8, "Click for BG: (Double-click / x / Ctrl to end) "); + cClickFitNGaussPolsub->Update(); + cClickFitNGaussPolsub->Draw(); + + nClick = 0; + xBGList.clear(); + yBGList.clear(); + markerColor = markerBGColor; + markerStyle = 33; + peakFlag = 0; + do{ + obj = gPad->WaitPrimitive(); + if( obj == NULL ) break; + }while( obj != NULL); + } + cClickFitNGaussPolsub->cd(1)->DeleteExec("ex"); + cClickFitNGaussPolsub->cd(1)->SetCrosshair(0); + cClickFitNGaussPolsub->cd(1)->Clear(); + hist->Draw(); + + tempHist = NULL; + + if( xBGList.size() == 0 ) helpMsg.DrawLatex(0.15, 0.75, " No BG defined ! fitting could be problematics. "); + + cClickFitNGaussPolsub->Update(); + cClickFitNGaussPolsub->Draw(); + + nPols = degPol; + double xMin = hspec->GetXaxis()->GetXmin(); + double xMax = hspec->GetXaxis()->GetXmax(); + + TString polExp = "[0]"; + for( int i = 1; i < degPol + 1; i++) polExp += Form("+[%d]*TMath::Power(x,%d)", i, i ); + TF1 *bg = new TF1("bg", polExp.Data(), xMin, xMax); + bg->SetNpx(1000); + bg->SetLineColor(markerBGColor); + bg->SetLineWidth(1); + if( xBGList.size() > 0 ) { + printf("---------------- fit the BG with Pol-%d \n", nPols); + + TGraph * gBG = new TGraph((int) xBGList.size(), &xBGList[0], &yBGList[0]); + + for( int i = 0; i < degPol + 1; i++) bg->SetParameter(i, gRandom->Rndm()/TMath::Power(10, 3*i)); + + gBG->Fit("bg", "Rq"); + bg->Draw("same"); + + printf("--------------- Subtracting the BG \n"); + hspec->Add(bg, -1); + }else{ + for( int i = 0; i < nPols+1; i++) bg->SetParameter(i, 0.); + } + + + TLatex text; + text.SetNDC(); + text.SetTextFont(82); + text.SetTextSize(0.06); + + double chi2BG = bg->GetChisquare(); + int ndfBG = bg->GetNDF(); + + text.DrawLatex(0.15, 0.8, Form("#bar{#chi^{2}} : %5.3f", chi2BG/ndfBG)); + + //=========== get the polynomial BG + const Double_t* paraAt = bg->GetParameters(); + const Double_t* paraEt = bg->GetParErrors(); + + for( int i = 0; i < degPol + 1; i++){ + text.DrawLatex(0.6, 0.85 - 0.05*i, Form("%4s : %8.2f(%8.2f)\n", Form("p%d", i), paraAt[i], paraEt[i])); + } + + nPeaks = (int) xPeakList.size(); + if( sigmaMax == 0 ){ + printf("------------- Estimate sigma for each peak \n"); + sigma.clear(); + int binMin = hist->FindBin(xMin); + int binMax = hist->FindBin(xMax); + + for( int i = 0; i < nPeaks ; i++){ + int b0 = hist->FindBin(xPeakList[i]); + double estBG = bg->Eval(xPeakList[i]); + double sMin = (xMax-xMin)/5., sMax = (xMax-xMin)/5.; + //---- backward search, stop when + for( int b = b0-1 ; b > binMin ; b-- ){ + double y = hist->GetBinContent(b); + double x = hist->GetBinCenter(b); + if( y - (bg->Eval(x)) < (yPeakList[i]-estBG)/2. ) { + sMin = xPeakList[i] - hist->GetBinCenter(b); + break; + } + } + //---- forward search, stop when + for( int b = b0+1 ; b < binMax ; b++ ){ + double y = hist->GetBinContent(b); + double x = hist->GetBinCenter(b); + if( y - (bg->Eval(x)) < (yPeakList[i]-estBG)/2. ) { + sMax = hist->GetBinCenter(b) - xPeakList[i]; + break; + } + } + + double temp = TMath::Min(sMin, sMax); + /// When there are multiple peaks closely packed : + if( i > 0 && temp > 2.5 * sigma.back() ) temp = sigma.back(); + sigma.push_back(temp); + + printf("%2d | x : %8.2f | sigma(est) %f \n", i, xPeakList[i], sigma[i]); + + } + }else if( sigmaMax < 0 ){ + printf("========== use user input sigma : %f (fixed)\n", abs(sigmaMax)); + sigma.clear(); + for( int i = 0; i < nPeaks ; i++) sigma.push_back(abs(sigmaMax)); + }else if( sigmaMax > 0 ){ + printf("========== use user input sigma : %f/2. \n", sigmaMax/2.); + sigma.clear(); + for( int i = 0; i < nPeaks ; i++) sigma.push_back(sigmaMax/2.); + } + + printf("-------------- Fit the subtracted spectrum with %d-Gauss\n", nPeaks ); + cClickFitNGaussPolsub->cd(2); + hspec->Draw("hist"); + + int nPar = 3 * nPeaks; + double * para = new double[nPar]; + for(int i = 0; i < nPeaks ; i++){ + para[3*i+0] = yPeakList[i] * 0.05 * TMath::Sqrt(TMath::TwoPi()); + para[3*i+1] = xPeakList[i]; + if( sigmaMax == 0){ + para[3*i+2] = sigma[i]; + }else if(sigmaMax < 0 ){ + para[3*i+2] = abs(sigmaMax); + }else if(sigmaMax > 0 ){ + para[3*i+2] = sigmaMax/2.; + } + } + + TF1 * fit = new TF1("fit", nGauss, xMin, xMax, nPar ); + fit->SetLineWidth(3); + fit->SetLineColor(1); + fit->SetNpx(1000); + fit->SetParameters(para); + + //limit parameters + for( int i = 0; i < nPeaks; i++){ + fit->SetParLimits(3*i , 0, 1e9); + + double dE1, dE2; + if( i == 0 ){ + dE2 = xPeakList[i+1] - xPeakList[i]; + dE1 = dE2; + }else if ( i == nPeaks-1 ){ + dE1 = xPeakList[i] - xPeakList[i-1]; + dE2 = dE1; + }else{ + dE1 = xPeakList[i] - xPeakList[i-1]; + dE2 = xPeakList[i+1] - xPeakList[i]; + } + + fit->SetParLimits(3*i+1, xPeakList[i] - dE1 , xPeakList[i] + dE2 ); + if( sigmaMax== 0 ) fit->SetParLimits(3*i+2, 0, 1.5*sigma[i]); // add 50% margin of sigma + if( sigmaMax < 0 ) fit->FixParameter(3*i+2, abs(sigmaMax)); + if( sigmaMax > 0 ) fit->SetParLimits(3*i+2, 0, sigmaMax); + } + + hspec->Fit("fit", "Rq"); + fit->Draw("same"); + + //=========== get the fit parameters + const Double_t* paraA = fit->GetParameters(); + const Double_t* paraE = fit->GetParErrors(); + + double chi2 = fit->GetChisquare(); + int ndf = fit->GetNDF(); + double bw = hspec->GetBinWidth(1); + + text.DrawLatex(0.15, 0.8, Form("#bar{#chi^{2}} : %5.3f", chi2/ndf)); + + for(int i = 0; i < nPeaks ; i++){ + printf(" %2d , count: %8.0f(%3.0f), mean: %8.4f(%8.4f), sigma: %8.4f(%8.4f) \n", + i, + paraA[3*i] / bw, paraE[3*i] /bw, + paraA[3*i+1], paraE[3*i+1], + paraA[3*i+2], paraE[3*i+2]); + } + printf("\n"); + + TF1 ** gFit = new TF1 *[nPeaks]; + for( int i = 0; i < nPeaks; i++){ + gFit[i] = new TF1(Form("gFit%d", i), "[0] * TMath::Gaus(x,[1],[2], 1)", xMin, xMax); + gFit[i]->SetParameter(0, paraA[3*i]); + gFit[i]->SetParameter(1, paraA[3*i+1]); + gFit[i]->SetParameter(2, paraA[3*i+2]); + gFit[i]->SetLineColor(i+1); + gFit[i]->SetNpx(1000); + gFit[i]->SetLineWidth(1); + gFit[i]->Draw("same"); + } + + cClickFitNGaussPolsub->cd(3); + PlotResidual(hspec, fit); + + cClickFitNGaussPolsub->cd(4); + + text.SetTextSize(0.05); + text.SetTextColor(2); + text.DrawLatex(0.1, 0.9, Form(" %13s, %18s, %18s", "count", "mean", "sigma")); + + for( int i = 0; i < nPeaks; i++){ + text.DrawLatex(0.1, 0.8-0.05*i, Form(" %2d, %8.0f(%3.0f), %8.4f(%8.4f), %8.4f(%8.4f)\n", + i, + paraA[3*i] / bw, paraE[3*i] /bw, + paraA[3*i+1], paraE[3*i+1], + paraA[3*i+2], paraE[3*i+2])); + } +} + + +//######################################## +//#### fit N-Gauss with pol-1 BG at fixed for < 0 +//######################################## +void fitSpecial(TH1F * hist, TString fitFile = "AutoFit_para.txt"){ + + printf("================================================================\n"); + printf("================ Special fit for h074_82Kr =====================\n"); + printf(" * need the file input \n"); + printf("================================================================\n"); + + + bool isParaRead = loadFitParameters(fitFile); + if( !isParaRead ) { + printf("Please provide a valid input file\n"); + return; + } + + gStyle->SetOptStat(""); + gStyle->SetOptFit(0); + nPeaks = energy.size(); + nPols = 1; + + TCanvas * cFitSpecial = NewCanvas("cFitSpecial", "Fitting for h074_82Kr", 1, 3, 800, 300); + //if(! cFitSpecial->GetShowEventStatus() ) cFitSpecial->ToggleEventStatus(); + cFitSpecial->cd(1); + + ScaleAndDrawHist(hist, 0, 0); + + double xMin = hist->GetXaxis()->GetXmin(); + double xMax = hist->GetXaxis()->GetXmax(); + int xBin = hist->GetXaxis()->GetNbins(); + + printf("============= find the pol-1 background ..... \n"); + + TF1 * fitpol1 = new TF1("fitpol1", "pol1", xMin, -0.3); + fitpol1->SetParameter(0, gRandom->Rndm()); + fitpol1->SetParameter(1, gRandom->Rndm()); + + hist->Fit("fitpol1", "Rq"); + + double x0 = fitpol1->GetParameter(0); + double x1 = fitpol1->GetParameter(1); + + + int nPar = 3 * nPeaks + nPols + 1; + double * para = new double[nPar]; + for(int i = 0; i < nPeaks ; i++){ + para[3*i+0] = height[i] * 0.05 * TMath::Sqrt(TMath::TwoPi()); + para[3*i+1] = energy[i]; + para[3*i+2] = sigma[i]/2.; + } + + para[3*nPeaks+0] = x0; + para[3*nPeaks+1] = x1; + + + TF1 * fit = new TF1("fit", nGaussPol, xMin, xMax, nPar ); + fit->SetLineWidth(3); + fit->SetLineColor(1); + fit->SetNpx(1000); + fit->SetParameters(para); + + //fixing parameters + for( int i = 0; i < nPeaks; i++){ + fit->SetParLimits(3*i , 0, 1e9); + if( energyFlag[i] == 1 ) { + fit->FixParameter(3*i+1, energy[i]); + }else{ + fit->SetParLimits(3*i+1, lowE[i], highE[i]); + } + if( sigmaFlag[i] == 1 ) { + fit->FixParameter(3*i+2, sigma[i]); + }else{ + fit->SetParLimits(3*i+2, 0, sigma[i]); + } + } + + fit->FixParameter(3*nPeaks + 0, x0); + fit->FixParameter(3*nPeaks + 1, x1); + + hist->Fit("fit", "Rq"); + + //=========== get the polynomial part + const Double_t* paraA = fit->GetParameters(); + const Double_t* paraE = fit->GetParErrors(); + + TString polExp = "[0]"; + for( int i = 1; i < nPols + 1; i++){ + polExp += Form("+[%d]*TMath::Power(x,%d)", i, i ); + } + + TF1 * bg = new TF1("bg", polExp.Data(), xMin, xMax); + for( int i = 0; i < nPols + 1; i++){ + bg->SetParameter(i, paraA[3*nPeaks+i]); + } + bg->SetNpx(1000); + + for( int i = 0; i < nPols + 1; i++){ + printf("%4s : %8.4e(%8.4e)\n", Form("p%d", i), paraA[3*nPeaks+i], paraE[3*nPeaks+i]); + } + printf("====================================\n"); + + cFitSpecial->cd(1); + bg->Draw("same"); + + TLatex text; + text.SetNDC(); + text.SetTextFont(82); + text.SetTextSize(0.04); + text.SetTextColor(1); + + for( int i = 0; i < nPols + 1; i++){ + text.DrawLatex(0.6, 0.85 - 0.05*i, Form("%4s : %8.4e(%8.4e)\n", Form("p%d", i), paraA[3*nPeaks+i], paraE[3*nPeaks+i])); + } + + double chi2 = fit->GetChisquare(); + int ndf = fit->GetNDF(); + text.SetTextSize(0.06); + text.DrawLatex(0.15, 0.8, Form("#bar{#chi^{2}} : %5.3f", chi2/ndf)); + + + //GoodnessofFit(specS, fit); + + double bw = hist->GetBinWidth(1); + + for(int i = 0; i < nPeaks ; i++){ + printf(" %2d , count: %8.0f(%3.0f), mean: %8.4f(%8.4f), sigma: %8.4f(%8.4f) \n", + i, + paraA[3*i] / bw, paraE[3*i] /bw, + paraA[3*i+1], paraE[3*i+1], + paraA[3*i+2], paraE[3*i+2]); + } + printf("\n"); + + + const int nn = nPeaks; + TF1 ** gFit = new TF1 *[nn]; + for( int i = 0; i < nPeaks; i++){ + gFit[i] = new TF1(Form("gFit%d", i), "[0] * TMath::Gaus(x,[1],[2], 1)", xMin, xMax); + gFit[i]->SetParameter(0, paraA[3*i]); + gFit[i]->SetParameter(1, paraA[3*i+1]); + gFit[i]->SetParameter(2, paraA[3*i+2]); + gFit[i]->SetLineColor(i+1); + gFit[i]->SetNpx(1000); + gFit[i]->SetLineWidth(1); + gFit[i]->Draw("same"); + } + + cFitSpecial->Update(); + + cFitSpecial->cd(2); + PlotResidual(hist, fit); + + cFitSpecial->cd(3); + + text.SetNDC(); + text.SetTextFont(82); + text.SetTextSize(0.05); + text.SetTextColor(2); + + text.DrawLatex(0.1, 0.9, Form(" %13s, %18s, %18s", "count", "mean", "sigma")); + + for( int i = 0; i < nPeaks; i++){ + text.DrawLatex(0.1, 0.8-0.05*i, Form(" %2d, %8.0f(%3.0f), %8.4f(%8.4f), %8.4f(%8.4f)\n", + i, + paraA[3*i] / bw, paraE[3*i] /bw, + paraA[3*i+1], paraE[3*i+1], + paraA[3*i+2], paraE[3*i+2])); + } + +} + + + + +#endif diff --git a/armory/DataBlock.h b/armory/DataBlock.h new file mode 100644 index 0000000..ecfe1b2 --- /dev/null +++ b/armory/DataBlock.h @@ -0,0 +1,110 @@ + +#ifndef DATABLOCK_H +#define DATABLOCK_H + +#include +#include +#include +#include +#include + +#include "TSystem.h" +#include "TObject.h" +#include "TFile.h" +#include "TTree.h" +#include "TString.h" + +#define MAX_TRACE_LENGHT 16000 + +class DataBlock{ + +public: + UShort_t ch; + UShort_t slot; + UShort_t crate; + UShort_t headerLength; /// headerLength > 4, more data except tarce. + UShort_t eventLength; /// eventLength = headerLength + trace + Bool_t pileup; + ULong64_t time; + Bool_t cfd_forced; + Bool_t cfd_source; + UShort_t cfd; + UShort_t energy; + UShort_t trace_length; + Bool_t trace_out_of_range; + + Int_t trailing; + Int_t leading; + Int_t gap; + Int_t baseline; + Int_t QDCsum[8]; + + ULong64_t eventID; + + UShort_t trace[MAX_TRACE_LENGHT]; + + DataBlock(){ + Clear(); + }; + + ~DataBlock(){}; + + void Clear(){ + ch = 0; + slot = 0; + crate = 0; + headerLength = 0; + eventLength = 0; + pileup = false; + time = 0; + cfd_forced = false; + cfd_source = false; + cfd = 0; + energy = 0; + trace_length = 0; + trace_out_of_range = 0; + eventID = 0; + ClearQDC(); + ClearTrace(); + } + + void ClearQDC(){ + trailing = 0; + leading = 0; + gap = 0; + baseline = 0; + for( int i = 0; i < 8; i++) QDCsum[i] = -1; + } + + void ClearTrace(){ + for( int i = 0 ; i < MAX_TRACE_LENGHT; i++) trace[i] = 0; + } + + + void Print(int opt = 0){ + 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); + printf("trace_length: %d, pile-up:%d\n", trace_length, pileup); + printf("CFD : %d , Forced : %d , Source : %d\n", cfd, cfd_forced, cfd_source); + if( headerLength > 4 ){ + if( headerLength > 12 ){ + printf(" trailing : %d\n", trailing); + printf(" leading : %d\n", leading); + printf(" gap : %d\n", gap); + printf(" baseLine : %d\n", baseline); + } + if( opt >= 1 ){ + printf(" QDCsum : \n"); + for( int i = 0; i < 8; i++) printf(" %-10d\n", QDCsum[i]); + } + } + if( opt >= 2 && eventLength > headerLength ){ + printf(" trace:\n"); + for( int i = 0 ; i < trace_length ; i++)printf("%3d| %-10d\n",i, trace[i]); + } + } + +}; + +#endif diff --git a/armory/EventBuilder_evt b/armory/EventBuilder_evt new file mode 100755 index 0000000000000000000000000000000000000000..5c51149ebd558ac985863e069f3af6b7efedb780 GIT binary patch literal 41392 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 PzfKj4<3gQ+4psg)-}#qR literal 0 HcmV?d00001 diff --git a/armory/EventBuilder_evt.cpp b/armory/EventBuilder_evt.cpp new file mode 100644 index 0000000..18310bf --- /dev/null +++ b/armory/EventBuilder_evt.cpp @@ -0,0 +1,270 @@ +/**********************************************************/ +/* */ +/* Modified by Ryan From */ +/* */ +/* PXI SCAN CODE -- J.M. Allmond (ORNL) -- July 2016 */ +/* */ +/**********************************************************/ + +#include +#include +#include +#include +#include + +#include "TFile.h" +#include "TTree.h" +#include "TMath.h" +#include "TBenchmark.h" + +#define RAND ((float) rand() / ((unsigned int) RAND_MAX + 1)) // random number in interval (0,1) + +#define MAX_CRATES 2 +#define MAX_BOARDS_PER_CRATE 13 +#define MAX_CHANNELS_PER_BOARD 16 +#define BOARD_START 2 + +#define MAX_ID MAX_CRATES*MAX_BOARDS_PER_CRATE*MAX_CHANNELS_PER_BOARD + +#define HEADER_LENGTH 4 //unit = words with 4 bytes per word +#define MAX_SUB_LENGTH 2016 //unit = words with 4 bytes per word ; 2004 --> 40 micro-second trace + 4 word header + +#define RAWE_REBIN_FACTOR 2.0 // Rebin 32k pixie16 spectra to something smaller to fit better into 8k. + +#include "../mapping.h" + +#include "../armory/evtReader.h" + +unsigned long long int dataCount=0; +unsigned long long int pileUpCount=0; +unsigned long long int evtCount=0; +int tick2ns = 4; + +/////////////////////////////////// +// START OF MAIN FUNCTION // +/////////////////////////////////// +int main(int argc, char **argv) { + + printf("=====================================\n"); + printf("=== evt.to --> root ===\n"); + printf("=====================================\n"); + + // Check that the corrent number of arguments were provided. + if (argc <= 3) { + printf("Incorrect number of arguments:\n"); + printf("%s [outFile] [timeWindow] [to File1] [to File2] .... \n", argv[0]); + printf(" outFile : output root file name\n"); + printf(" timeWindow : number of tick, 1 tick = %d ns. default = 100 \n", tick2ns); + return 1; + } + + TString outFileName = argv[1]; + int timeWindow = atoi(argv[2]); + int nFile = argc - 3; + TString inFileName[nFile]; + for( int i = 0 ; i < nFile ; i++){ + inFileName[i] = argv[i+3]; + } + + printf("====================================\n"); + + evtReader * evt = new evtReader(); + DataBlock * data = evt->data; + + printf(" Number of input file : %d \n", nFile); + printf(" out file : \033[1;31m%s\033[m\n", outFileName.Data()); + printf(" Event building time window : %d tics = %d nsec \n", timeWindow, timeWindow*tick2ns); + + + TFile * outRootFile = new TFile(outFileName, "recreate"); + outRootFile->cd(); + TTree * tree = new TTree("tree", outFileName); + + unsigned long long evID = 0; + int multi = 0; + int id[MAX_ID] = {0}; + double e[MAX_ID] = {TMath::QuietNaN()}; + unsigned long long e_t[MAX_ID] = {0}; + int cfd[MAX_ID] = {0}; + bool pileup[MAX_ID] = {0}; + int qdc[MAX_ID][8] = {0}; + int multiClover = 0 ; /// this is total multiplicity for all crystal + int runID = 0; // date-run-fileID + int multiBeam = 0; + //unsigned short pileup[MAXMULTI]; + + tree->Branch("evID", &evID, "event_ID/l"); + tree->Branch("multi", &multi, "multi/I"); + tree->Branch("detID", id, "detID[multi]/I"); + tree->Branch("e", e, "e[multi]/D"); + tree->Branch("e_t", e_t, "e_timestamp[multi]/l"); + //tree->Branch("pileup", pileup, "pileup[multi]/O"); + tree->Branch("cfd", cfd, "cfd[multi]/I"); + tree->Branch("qdc", qdc, "qdc[multi][8]/I"); + tree->Branch("multiClover", &multiClover, "multiplicity_Clover/I"); + tree->Branch("multiBeam", &multiBeam, "multiplicity_Beam/I"); + tree->Branch("runID", &runID, "runID/I"); + + int countGP = 0; //gamma-particle coincident + double totalDataSize = 0; + int outFileCount = 0; + + for( int i = 0; i < nFile; i++){ + + evt->OpenFile(inFileName[i], false); + if( evt->IsOpen() == false ) continue; + + printf("==================================================== %d / %d\n", i+1, nFile); + printf("\033[1;31m%s \033[m\n", inFileName[i].Data()); + + int pos = inFileName[i].Last('/'); + TString temp = inFileName[i]; + temp.Remove(0, pos+1); + pos = temp.Last('-'); + temp.Remove(0, pos+1); + pos = temp.Last('.'); + temp.Remove(pos); + runID = atoi(temp.Data()); + + long long int etime = -1; + long long int tdif = -1; + + while ( evt->IsEndOfFile() == false ) { //main while loop + + if ( evt->ReadBlock() == -1) break; + + if ( data->crate == 0 ) continue; + + //Set reference time for event building + if (etime == -1) { + etime = data->time; + tdif = 0; + multi = 0; + multiClover = 0; + multiBeam = 0; + }else { + tdif = data->time - etime; + } + + //Check for end of event, rewind, and break out of while loop + if (tdif > timeWindow) { + + //Gate + //if( multiClover > 2 && multiBeam ==0 ) { + // + outRootFile->cd(); + tree->Fill(); + //printf("------------------\n"); + // + // countGP++; + //} + + evID ++; + + //clear data + etime = data->time; + tdif = 0; + multi = 0; + multiClover = 0; + multiBeam = 0; + + int haha = data->crate*MAX_BOARDS_PER_CRATE*MAX_CHANNELS_PER_BOARD + (data->slot-BOARD_START)*MAX_CHANNELS_PER_BOARD + data->ch; + id[multi] = mapping[haha]; + e[multi] = data->energy; + e_t[multi] = data->time; + cfd[multi] = data->cfd_forced == 0 ? (data->cfd - 16384*(data->cfd_source == true ? 1 : 0))/2 : 0; + pileup[multi] = data->pileup; + for( int i = 0; i < 8; i++) qdc[multi][i] = data->QDCsum[i]; + + if( 0 <= id[multi] && id[multi] < 100 ) multiClover += 1; + if( id[multi] == 300 || id[multi] == 301 || id[multi] == 307 || id[multi] == 308 ) multiBeam += 1; + //printf("id: %d, multiBeam: %d, %llu, tdif %llu\n", id[multi], multiBeam, e_t[multi], tdif); + multi++ ; + }else{ + //if within time window, fill array; + int haha = data->crate*MAX_BOARDS_PER_CRATE*MAX_CHANNELS_PER_BOARD + (data->slot-BOARD_START)*MAX_CHANNELS_PER_BOARD + data->ch; + id[multi] = mapping[haha]; + e[multi] = data->energy; + e_t[multi] = data->time; + cfd[multi] = data->cfd_forced == 0 ? (data->cfd - 16384*(data->cfd_source == true ? 1 : 0))/2 : 0; + //printf(" %d , %d , %d, %d \n", data->cfd_forced, data->cfd_source, data->cfd, cfd[multi]); + pileup[multi] = data->pileup; + for( int i = 0; i < 8; i++) qdc[multi][i] = data->QDCsum[i]; + if( 0 <= id[multi] && id[multi] < 100 ) multiClover += 1; + if( id[multi] == 300 || id[multi] == 301 || id[multi] == 307 || id[multi] == 308 ) multiBeam += 1; + //printf("id: %d, multiBeam: %d, %llu, tdif %llu\n", id[multi], multiBeam, e_t[multi], tdif); + multi++ ; + + } + + // total pileups + if (data->pileup == 1) { + pileUpCount++; + } + + evt->PrintStatus(10000); + + } // end main while loop + + evt->PrintStatus(1); + printf("\n\n\n"); + printf(" total number of event built : %llu\n", evID); + //printf(" total number of Gamma - GAGG coincdient : %d (%.3f %%)\n", countGP, countGP*1.0/evID); + + outRootFile->cd(); + tree->Write(); + + totalDataSize += (evt->GetFileSize())/1024./1024./1024.; + + double rootFileSize = outRootFile->GetSize()/1024./1024./1024. ; // in GB + printf(" ----------- root file size : %.3f GB\n", rootFileSize); + printf(" ---------- total read size : %.3f GB\n", totalDataSize); + printf(" ----------- reduction rate : %.3f %%\n", rootFileSize*100./totalDataSize); + + evt->CloseFile(); + + /* + if( rootFileSize > 3.0 ) { + break; + }*/ + + ///try to open a new root file when file size > 2 GB + /*if( rootFileSize > 2.0 ) { + + outRootFile->Close(); + delete outRootFile; + delete tree; + outFileCount += 1; + + if( outFileCount > 5 ) break; + + TString outFileName2 = outFileName; + outFileName2.Insert(outFileName.Sizeof() - 6, Form("_%03d",outFileCount)); + outRootFile = new TFile( outFileName2, "recreate"); + + tree = new TTree("tree", "tree"); + tree->Branch("evID", &evID, "event_ID/l"); + tree->Branch("multi", &multi, "multi/I"); + tree->Branch("detID", id, "detID[multi]/I"); + tree->Branch("e", e, "e[multi]/D"); + tree->Branch("e_t", e_t, "e_timestamp[multi]/l"); + tree->Branch("qdc", qdc, "qdc[multi][8]/I"); + tree->Branch("multiClover", &multiClover, "multiplicity_crystal/I"); + tree->Branch("multiBeam", &multiBeam, "multiplicity_GAGG/I"); + tree->Branch("runID", &runID, "runID/I"); + + }*/ + + } + + + outRootFile->Close(); + + printf("\n\n\n==================== finished.\r\n"); + + //printf(" number of Gamma - GAGG coincdient : %d\n", countGP); + + return 0; +} + + 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/LoadCorrection.h b/armory/LoadCorrection.h new file mode 100644 index 0000000..a17b609 --- /dev/null +++ b/armory/LoadCorrection.h @@ -0,0 +1,111 @@ +#ifndef Analysis_Library_h +#define Analysis_Library_h + +#include +#include +#include +#include +#include +#include +#include +#include + +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, bool show=false){ + + 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; + + //printf("%s\n", line.c_str()); + 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"); + if( show ){ + 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("%14.6f, ", corr[i][j]); + } + printf("%14.6f\n", corr[i][len-1]); + } + } + + }else{ + printf(".... fail\n"); + std::vector temp = {0, 1}; + for( int i = 0; i < 36; i++){ + corr.push_back(temp); + } + } + + return corr; +} + +#endif + diff --git a/armory/MergeEVT b/armory/MergeEVT new file mode 100755 index 0000000000000000000000000000000000000000..81c1e1093e8668b6d91fbf72753928e0e37ab2d1 GIT binary patch literal 26224 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 literal 0 HcmV?d00001 diff --git a/armory/MergeEVT.cpp b/armory/MergeEVT.cpp new file mode 100644 index 0000000..10773b7 --- /dev/null +++ b/armory/MergeEVT.cpp @@ -0,0 +1,135 @@ +#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("cfd", &data->cfd, "cfd/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(); + Long64_t nBlock = evt->GetNumberOfBlock(); + + //=============== Read File + while( evt->IsEndOfFile() == false ){ + + evt->ReadBlock(); + evt->PrintStatus(nBlock/10); + + int id = data->crate*MAX_BOARDS_PER_CRATE*MAX_CHANNELS_PER_BOARD + (data->slot-BOARD_START)*MAX_CHANNELS_PER_BOARD + data->ch; + if( id > 352 || id < 0 ) continue; + 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/ev22txt b/armory/ev22txt new file mode 100755 index 0000000000000000000000000000000000000000..47d89166812072aad38359f5ac879409791a3ada GIT binary patch literal 16516 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 literal 0 HcmV?d00001 diff --git a/armory/ev22txt.cpp b/armory/ev22txt.cpp new file mode 100644 index 0000000..7c44366 --- /dev/null +++ b/armory/ev22txt.cpp @@ -0,0 +1,81 @@ +#include +#include +#include +#include + +using namespace std; + +int main(int argc, char **argv){ + + printf("=====================================\n"); + printf("=== ev2 --> txt ===\n"); + printf("=====================================\n"); + + if ( argc != 2 && argc != 3 ){ + printf("Usage: \n"); + printf("%10s [ev2 file] [max number of event]\n", argv[0]); + } + + string inFileName = argv[1]; + string outFileName = argv[1]; + int found = outFileName.find('.'); + int len = outFileName.length(); + outFileName.erase(found, len-found); + outFileName.append(".txt"); + + long long maxNumEvent = 0; // if maxNumEvent <= 0, all event + if( argc >= 3 ) maxNumEvent = atoi(argv[2]); + + + //open list-mode data file from PXI digitizer + FILE *inFile = fopen(argv[1], "r"); + long int inFileSize,inFilepos; + if ( inFile == NULL) { + printf("Error, cannot open input file %s\n", argv[1]); + return 1; + } + + //get file size + fseek(inFile, 0L, SEEK_END); + inFileSize = ftell(inFile); + rewind(inFile); + long int inFilePos = 0; + + printf(" in file : %s | file size : %f MB\n", inFileName.c_str(), inFileSize/1024./1024.); + //printf(" out file : %s \n", outFileName.c_str()); + if( maxNumEvent <= 0 ){ + printf(" max number of event : ALL \n"); + }else{ + printf(" max number of event : %lld \n", maxNumEvent); + } + printf("-------------------------------------\n"); + + long long nEvent = 0; + short * multi = new short[1]; + short * id = new short[1]; + short * energy = new short[1] ; + + while ( inFilePos < inFileSize || feof(inFile) ) { + + printf("------------------- %lld\n", nEvent); + + fread(multi, 1, 1, inFile); + printf(" number of det : %d \n", multi[0]); + + for( int i = 0; i < multi[0] ; i++){ + + fread(id, 1, 1, inFile); + fread(energy, 2, 1, inFile); + + printf("%2d| %3d, %8d \n", i, id[0], energy[0]); + + } + fread(multi, 1, 1, inFile); + + nEvent++; + + if( maxNumEvent > 0 && nEvent > maxNumEvent ) break; + + } + +} diff --git a/armory/evt2hist b/armory/evt2hist new file mode 100755 index 0000000000000000000000000000000000000000..51bd0ed29f9edc6936e689d3098cde9b1c764f95 GIT binary patch literal 158952 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 literal 0 HcmV?d00001 diff --git a/armory/evt2hist.cpp b/armory/evt2hist.cpp new file mode 100644 index 0000000..380fbe3 --- /dev/null +++ b/armory/evt2hist.cpp @@ -0,0 +1,344 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "TSystem.h" +#include "TObject.h" +#include "TFile.h" +#include "TTree.h" +#include "TString.h" +#include "TMath.h" +#include "TGraph.h" +#include "TLatex.h" +#include "TBenchmark.h" +#include "TH1F.h" +#include "TH2F.h" +#include "TApplication.h" +#include "TCanvas.h" +#include "TClonesArray.h" + +#include "../mapping.h" +#include "../armory/AnalysisLibrary.h" + +#include "../armory/DataBlock.h" +#include "../armory/evtReader.h" + +#define sleepTime 5000 ///sleep for 5 sec +//#############################TODO +// 1) multiple file +// 2) Change to GUI +// 4) eventBuilding +// 3) last 10% data + + +//################################## user setting +int eRange[2] = {50, 1000}; ///min, max + +bool PIDFlag = false; +int GAGGID = 209; +//############################################# +// main +//############################################### +int main(int argn, char **argv) { + + if (argn < 2 || argn > 7 ) { + printf("Usage :\n"); + printf("%s [evt File] [E corr] [raw E threshold] [Hist File] [Root File] [display data]\n", argv[0]); + printf(" [E corr] : correction file for gamma energy \n"); + printf(" [raw E threshold] : min raw E, default 10 ch \n"); + printf(" [Hist File] : if provided, saved histograms in root. if value = 1, auto fileName. \n"); + printf(" [Root File] : if provided, saved energy, timestamp, QDC, and trace in to root. if value = 1, auto fileName. \n"); + printf(" [display data] : number of event from the first one to display. default 0. \n"); + return 1; + } + + TString inFileName = argv[1]; + + TString corrFile = ""; + std::vector> eCorr; + if( argn >= 3 ){ + corrFile = argv[2]; + eCorr.clear(); + eCorr = LoadCorrectionParameters(corrFile); + } + + int rawEnergyThreshold = 10; + if( argn >= 4 ) rawEnergyThreshold = atoi(argv[3]); + + TString histFileName = ""; ///save gamma hist for calibration + if( argn >= 5 ) histFileName = argv[4]; + if( histFileName == "1" ){ + histFileName = inFileName; + histFileName.Remove(0, inFileName.Last('/')+1); + histFileName.Remove(histFileName.First('.')); + histFileName.Append("_hist.root"); + } + if( histFileName == "0" ) histFileName = ""; + + TString rootFileName = ""; ///save data into root + if( argn >= 6 ) rootFileName = argv[5]; + if( rootFileName == "1" ){ + rootFileName = inFileName; + rootFileName.Remove(0, inFileName.Last('/')+1); + rootFileName.Remove(rootFileName.First('.')); + rootFileName.Append("_raw.root"); + } + if( rootFileName == "0" ) rootFileName = ""; + + int maxDataDisplay = 0; + if( argn >= 7 ) maxDataDisplay = atoi(argv[6]); + + TBenchmark gClock; + gClock.Reset(); + gClock.Start("timer"); + + printf("====================================\n"); + + evtReader * evt = new evtReader(); + evt->OpenFile(inFileName); + if( evt->IsOpen() == false ) return -404; + DataBlock * data = evt->data; + + printf(" in file: \033[1;31m%s\033[m\n", inFileName.Data()); + printf(" Gamma energy correction file : %s\n", corrFile == "" ? "Not provided." : corrFile.Data()); + printf(" raw E threshold : %d ch\n", rawEnergyThreshold); + if( histFileName != "" ) printf(" Save histograms to %s\n", histFileName.Data()); + if( rootFileName != "" ) printf(" Save root to %s\n", rootFileName.Data()); + printf("--------------------------------\n"); + printf("Scanning the evt file... \n"); + evt->ScanNumberOfBlock(); + printf("go to 90%% of data \n"); + evt->JumptoPrecent(9); + + //================ ROOT tree + TFile * fFile = NULL; + TTree * tree = NULL; + + short detID; + + if( rootFileName != "" ){ + fFile = new TFile(rootFileName, "RECREATE"); + tree = new TTree("tree", "tree"); + + tree->Branch("headerLenght", &data->headerLength, "HeaderLength/s"); + tree->Branch("detID", &detID, "detID/s"); + tree->Branch("e", &data->energy, "energy/s"); + tree->Branch("e_t", &data->time, "timestamp/l"); + tree->Branch("p", &data->pileup, "pileup/O"); + tree->Branch("qdc", data->QDCsum, "QDC_sum[8]/I"); + tree->Branch("trace_length", &data->trace_length, "trace_length/s"); + tree->Branch("trace", data->trace, "trace[trace_length]/s"); + } + + //================ Historgrams + TH1F * he[NCRYSTAL]; + for( int i = 0 ; i < NCRYSTAL; i++){ + he[i] = new TH1F(Form("he%02d", i), Form("e-%2d", i), eRange[1]-eRange[0], eRange[0], eRange[1]); + switch (i % 4){ + case 0 : he[i]->SetLineColor(2); break; + case 1 : he[i]->SetLineColor(4); break; + case 2 : he[i]->SetLineColor(1); break; + case 3 : he[i]->SetLineColor(kGreen+3); break; + } + } + + + TH2F * hPID ; + if( PIDFlag ) hPID = new TH2F(Form("hPID%d", GAGGID), Form("GAGG - %d; tail; peak", GAGGID), 400, -10, 600, 400, -50, 1000); + + TGraph * gTrace = new TGraph(); + TLatex text; + text.SetNDC(); + text.SetTextFont(82); + text.SetTextSize(0.04); + text.SetTextColor(2); + + //================ Set Canvas + TApplication * app = new TApplication ("app", &argn, argv); + + TCanvas * canvas = new TCanvas("fCanvas", "Online Spectrum", 1800, 2000); + + canvas->Divide(3, TMath::Ceil(NCLOVER/3.), 0); + canvas->SetCrosshair(1); + for( int i = 0; i < 9 ; i++){ + canvas->cd(i+1)->SetBottomMargin(0.1); + canvas->cd(i+1)->SetRightMargin(0.002); + } + + ///TCanvas * cTrace = new TCanvas("cTrace", "Trace", 100, 100, 1000, 500); + TCanvas * cPID; + if( PIDFlag ) cPID = new TCanvas("cPID", "PID", 100, 100, 500, 500); + + //=============== Read File + int sleepCount = 0; + + while ( true ){ + + if( evt->ReadBlock()== -1 ) { + break; + //printf("\n\n\nReached the end of file, wait %d sec to see any update.\n", sleepTime); + //sleep( sleepTime ); + //evt->UpdateFileSize(); + //sleepCount ++; + //if( sleepCount > 1 ) { + // printf("waited for %d sec. exit.\n", 4* sleepTime); + // break; + //}else{ + // continue; + //} + } + sleepCount = 0; + + if( evt->GetBlockID() < maxDataDisplay ) { + printf("----------------------event Length: %u, fpos: %lu byte (%ld words)\n", data->eventLength, evt->GetFilePos(), evt->GetFilePos()/4); + data->Print(); + } + + //==== Fill Histogram + + int haha = data->crate*MAX_BOARDS_PER_CRATE*MAX_CHANNELS_PER_BOARD + (data->slot-BOARD_START)*MAX_CHANNELS_PER_BOARD + data->ch; + detID = mapping[haha]; + + if( 0 <= detID && detID < 100 && data->energy > rawEnergyThreshold ){ + if( corrFile != ""){ + ///========= apply correction + int order = (int) eCorr[detID].size(); + double eCal = 0; + for( int k = 0; k < order ; k++){ + eCal += eCorr[detID][k] * TMath::Power(data->energy, k); + } + he[detID]->Fill(eCal); + }else{ + he[detID]->Fill(data->energy); + } + } + + ///============ QDC + if( PIDFlag && detID == GAGGID && (data->headerLength < data->eventLength) ){ + double bg = (data->QDCsum[0] + data->QDCsum[1])/60.; + double peak = data->QDCsum[3]/20. - bg; + double tail = data->QDCsum[5]/55. - bg; + hPID->Fill( tail , peak); + } + + //===== Trace + ///if( data->trace_length > 0 ) { + /// gTrace->Clear(); + /// gTrace->Set(data->trace_length); + /// gTrace->SetTitle(Form("eventID : %llu, detID: %d", data->eventID, data->detID)); + /// + /// for( int i = 0; i < data->trace_length; i++) gTrace->SetPoint(i, i, data->trace[i]); + ///} + + if( rootFileName != "" ){ + fFile->cd(); + tree->Fill(); + } + + //==== event stats, print status every 10000 events + evt->PrintStatus(10000); + + //==== Plot Canvas + gClock.Stop("timer"); + int time = TMath::Floor(gClock.GetRealTime("timer")*1000); // in millisec + gClock.Start("timer"); + if( time % 1000 == 0 || time < 10){ + + ///==== for clover + for( int i = 0; i < NCLOVER; i++){ + double maxY = 0; + double y = 0; + for( int j = 0; j < 4; j++){ + int mBin = he[4*i+j]->GetMaximumBin(); + y = he[4*i+j]->GetBinContent(mBin); + if( maxY < y ) maxY = y; + } + for( int j = 0; j < 4; j++){ + canvas->cd(i+1); + he[4*i+j]->GetYaxis()->SetRangeUser(0, maxY*1.2); + if ( j == 0) { + he[4*i]->Draw(); + }else{ + he[4*i+j]->Draw("same"); + } + } + } + canvas->Modified(); + canvas->Update(); + + ///==== for trace + ///if( data->trace_length > 0 ){ + /// cTrace->cd(); + /// gTrace->Draw("AL"); + /// + /// for( int i = 0; i < 8; i++){ + /// text.DrawLatex(0.2, 0.8-0.05*i, Form("%d", data->QDCsum[i])); + /// } + /// cTrace->Modified(); + /// cTrace->Update(); + ///} + + ///=== for GAGG PID + if( PIDFlag ) { + cPID->cd(); + cPID->SetLogz(); + hPID->Draw("colz"); + cPID->Modified(); + cPID->Update(); + } + + gSystem->ProcessEvents(); + } + }//---- end of file loop + + + for( int i = 0; i < NCLOVER; i++){ + double maxY = 0; + double y = 0; + for( int j = 0; j < 4; j++){ + int mBin = he[4*i+j]->GetMaximumBin(); + y = he[4*i+j]->GetBinContent(mBin); + if( maxY < y ) maxY = y; + } + for( int j = 0; j < 4; j++){ + canvas->cd(i+1); + he[4*i+j]->GetYaxis()->SetRangeUser(0, maxY*1.2); + if ( j == 0) { + he[4*i]->Draw(); + }else{ + he[4*i+j]->Draw("same"); + } + } + } + canvas->Modified(); + canvas->Update(); + + gSystem->ProcessEvents(); + + evt->PrintStatus(1); + + printf("\n\n\n============= reached end of file\n"); + + if( histFileName != "" ) { + printf(" save gamma histograms : \033[1;3m%s\033[m\n", histFileName.Data()); + TFile * fHist = new TFile(histFileName, "RECREATE"); + for( int i = 0; i < NCRYSTAL; i++) he[i]->Write("", TObject::kOverwrite); + fHist->Close(); + } + + if( rootFileName != "" ){ + printf(" save into Root : \033[1;3m%s\033[m\n", rootFileName.Data()); + fFile->cd(); + tree->Write(); + fFile->Close(); + } + + printf("Crtl+C to end program.\n"); + + app->Run(); + +} diff --git a/armory/evtReader.h b/armory/evtReader.h new file mode 100644 index 0000000..8da3310 --- /dev/null +++ b/armory/evtReader.h @@ -0,0 +1,373 @@ +#ifndef EVTREADER_H +#define EVTREADER_H + +#include /// for FILE +#include +#include +#include +#include + +#include "TString.h" +#include "TBenchmark.h" + +#include "../armory/DataBlock.h" + +#define MAX_CRATES 2 +#define MAX_BOARDS_PER_CRATE 13 +#define MAX_CHANNELS_PER_BOARD 16 +#define BOARD_START 2 + +//TODO load the file into RAM, and read from the RAM + +class evtReader{ + + public: + DataBlock * data; + + private: + FILE * inFile; + + long int inFileSize; + long int inFilePos; + bool endOfFile; + bool isOpened; + Long64_t blockID; + long int nBlock; + + unsigned int extraHeader[14]; + unsigned int traceBlock[MAX_TRACE_LENGHT/2]; + + TBenchmark gClock; + + long int inFilePosPrecent[10]; + Long64_t blockIDPrecent[10]; + + bool fromRAM; + int * pxidata; + long nWords; + + ///============================================ Methods + public: + + evtReader(); + evtReader(TString inFileName, bool load2RAM); + ~evtReader(); + + void OpenFile(TString inFileName, bool load2RAM); + void CloseFile(); + + void UpdateFileSize(); + bool IsEndOfFile(); + + bool IsOpen() {return isOpened;} + long int GetFilePos() {return inFilePos;} + long int GetFileSize() {return inFileSize;} + Long64_t GetBlockID() {return blockID;} + Long64_t GetNumberOfBlock() {return nBlock;} + + + int ReadBlock(int opt = 0); /// 0 = default, fill data + /// 1 = no fill data + /// 2 = fill data and print + + void ScanNumberOfBlock(); + void JumptoPrecent(int precent); ///this is offset by 1 block + void PrintStatus(int mod); + +}; + + +//========================== implementation + +evtReader::evtReader(){ + inFile = 0; + data = new DataBlock(); + + inFileSize = 0; + inFilePos = 0; + + nBlock = 0; + blockID = -1; + endOfFile = false; + isOpened = false; + + fromRAM = false; + pxidata = NULL; + nWords = 0; +} + + +evtReader::~evtReader(){ + fclose(inFile); + delete inFile; + delete data; + delete pxidata; +} + + +evtReader::evtReader(TString inFileName, bool load2RAM = false){ + inFile = 0; + data = new DataBlock(); + + inFileSize = 0; + inFilePos = 0; + + nBlock = 0; + blockID = -1; + endOfFile = false; + isOpened = false; + fromRAM = false; // true until loaded to RAM + pxidata = NULL; + nWords = 0; + + OpenFile(inFileName, load2RAM); +} + +void evtReader::OpenFile(TString inFileName, bool load2RAM = false){ + inFile = fopen(inFileName, "r"); + if( inFile == NULL ){ + printf("Cannot read file : %s \n", inFileName.Data()); + }else{ + fseek(inFile, 0L, SEEK_END); + inFileSize = ftell(inFile); + rewind(inFile); ///back to the File begining + + //TODO load the evt file to RAM + if( load2RAM ) { + pxidata = (int *) malloc(inFileSize); + if( pxidata == NULL ){ + printf("\nError, memory not allocated.\n"); + }else{ + printf("Allocated %.3f GB of memory to buffer native PXI data\n", (float)inFileSize/(1024.0*1024.0*1024.0)); + printf("Now loading data to RAM\n"); + fread(pxidata, sizeof(pxidata), inFileSize/sizeof(pxidata), inFile); + fromRAM = true; + fclose(inFile); + inFilePos = 0; + } + } + + data->Clear(); + + gClock.Reset(); + gClock.Start("timer"); + + isOpened = true; + } +}; + +void evtReader::CloseFile(){ + fclose(inFile); + isOpened = false; + data->Clear(); + inFileSize = 0; + inFilePos = 0; + nBlock = 0; + blockID = -1; + endOfFile = false; +}; + +void evtReader::UpdateFileSize(){ + if( inFile == NULL ) return; + fseek(inFile, 0L, SEEK_END); + inFileSize = ftell(inFile); + fseek(inFile, inFilePos, SEEK_SET); +} + +bool evtReader::IsEndOfFile() { + int haha = feof(inFile); + return haha > 0 ? true: false; +} + + +int evtReader::ReadBlock(int opt){ + + if( feof(inFile) ) return -1; + if( endOfFile ) return -1; + + unsigned int header[4]; ///read 4 header, unsigned int = 4 byte = 32 bits. + + if( fromRAM ){ + for( int i = 0; i < 4 ; i++){ + header[i] = pxidata[nWords]; nWords += 1; + } + }else{ + if ( fread(header, sizeof(header), 1, inFile) != 1 ) { + endOfFile = true; + return -1; + } + } + blockID ++; + + + if( opt == 0 || opt == 2){ + /// see the Pixie-16 user manual, Table4-2 + data->eventID = blockID; + data->ch = header[0] & 0xF ; + data->slot = (header[0] >> 4) & 0xF; + data->crate = (header[0] >> 8) & 0xF; + data->headerLength = (header[0] >> 12) & 0x1F; + data->eventLength = (header[0] >> 17) & 0x3FFF; + data->pileup = header[0] >> 31 ; + data->time = ((ULong64_t)(header[2] & 0xFFFF) << 32) + header[1]; + data->cfd_forced = header[2] >> 16 & 0x8000; + data->cfd_source = header[2] >> 16 & 0x4000; + data->cfd = header[2] >> 16 & 0x3FFF; // 0x3FFF for 250MHz , 0x7FFF for 100MHz + data->energy = (header[3] & 0xFFFF ); + data->trace_length = (header[3] >> 16) & 0x7FFF; + data->trace_out_of_range = header[3] >> 31; + + data->ClearQDC(); + data->ClearTrace(); + + ///======== read QDCsum + if( data->headerLength >= 4 ){ + if( fromRAM ){ + for( int i = 0; i < data->headerLength - 4 ; i++){ + extraHeader[i] = pxidata[nWords]; nWords += 1; + } + }else{ + fread(extraHeader, sizeof(unsigned int) * (data->headerLength-4), 1, inFile); + } + if( data->headerLength == 8 || data->headerLength == 16){ + data->trailing = extraHeader[0]; + data->leading = extraHeader[1]; + data->gap = extraHeader[2]; + data->baseline = extraHeader[3]; + } + if( data->headerLength == 12 || data->headerLength == 16){ + for( int i = 0; i < 8; i++){ + int startID = 0; + if( data->headerLength > 12) startID = 4; ///the 1st 4 words + data->QDCsum[i] = extraHeader[i+startID]; + } + } + }else{ + for( int i = 0 ; i < 8; i++){ data->QDCsum[i] = 0;} + data->trailing = 0; + data->leading = 0; + data->gap = 0; + data->baseline = 0; + } + ///====== read trace + if( data->eventLength > data->headerLength ){ + if( fromRAM ){ + for( int i = 0; i < data->trace_length / 2 ; i++){ + traceBlock[i] = pxidata[nWords]; nWords += 1; + } + }else{ + fread(traceBlock, sizeof(unsigned int) * ( data->trace_length / 2 ), 1, inFile); + } + for( int i = 0; i < data->trace_length/2 ; i++){ + data->trace[2*i+0] = traceBlock[i] & 0xFFFF ; + data->trace[2*i+1] = (traceBlock[i] >> 16 ) & 0xFFFF ; + } + + ///make QDC by trace + /** + if( data->headerLength == 4 || data->headerLength == 8 ) { + for( int i = 0; i < 8; i++){ data->QDCsum[i] = 0;} + for( int i = 0; i < data->trace_length; i++){ + if( 0 <= i && i < 31 ) data->QDCsum[0] += data->trace[i]; + if( 31 <= i && i < 60 ) data->QDCsum[1] += data->trace[i]; + if( 60 <= i && i < 75 ) data->QDCsum[2] += data->trace[i]; + if( 75 <= i && i < 95 ) data->QDCsum[3] += data->trace[i]; + if( 95 <= i && i < 105 ) data->QDCsum[4] += data->trace[i]; + if( 105 <= i && i < 160 ) data->QDCsum[5] += data->trace[i]; + if( 160 <= i && i < 175 ) data->QDCsum[6] += data->trace[i]; + if( 175 <= i && i < 200 ) data->QDCsum[7] += data->trace[i]; + } + }*/ + } + } + + if( opt == 1 ){ + + data->headerLength = (header[0] >> 12) & 0x1F; + data->eventLength = (header[0] >> 17) & 0x3FFF; + data->trace_length = (header[3] >> 16) & 0x7FFF; + + if( data->headerLength >= 4 ){ + if( fromRAM ){ + nWords += (data->headerLength-4); + }else{ + fread(extraHeader, sizeof(unsigned int) * (data->headerLength-4), 1, inFile); + } + } + if( data->eventLength > data->headerLength ){ + if( fromRAM ){ + nWords += ( data->trace_length / 2 ); + }else{ + fread(traceBlock, sizeof(unsigned int) * ( data->trace_length / 2 ), 1, inFile); + } + } + } + + if ( fromRAM ){ + inFilePos = nWords * 32; + }else{ + inFilePos = ftell(inFile); + } + + if( opt == 2) data->Print(); + + return 1; +} + + +void evtReader::ScanNumberOfBlock(){ + + nBlock = 0; + int count = 0; + while( ReadBlock(1) != -1 ){ + nBlock ++; + int haha = (inFilePos*10/inFileSize)%10; + if( haha == count ) { + inFilePosPrecent[count] = inFilePos; + blockIDPrecent[count] = blockID; + count++; + } + + PrintStatus(10000); + } + + printf("\n\n\n"); + printf("scan complete: number of data Block : %ld\n", nBlock); + + inFilePos = 0; + blockID = -1; + + rewind(inFile); ///back to the File begining + endOfFile = false; + +} + +void evtReader::JumptoPrecent(int precent){ + + if( precent < 0 || precent > 10 ) { + printf("input precent should be 0 to 10\n"); + return; + } + + fseek(inFile, inFilePosPrecent[precent], SEEK_SET); + blockID = blockIDPrecent[precent]; + +} + +void evtReader::PrintStatus(int mod){ + + ///==== event stats, print status every 10000 events + + if ( blockID % mod == 0 ) { + + UpdateFileSize(); + gClock.Stop("timer"); + double time = gClock.GetRealTime("timer"); + gClock.Start("timer"); + printf("Total measurements: \x1B[32m%llu \x1B[0m\nReading Pos: \x1B[32m %.3f/%.3f GB\x1B[0m\nTime used:%3.0f min %5.2f sec\033[A\033[A\r", + blockID, inFilePos/(1024.*1024.*1024.), inFileSize/1024./1024./1024, TMath::Floor(time/60.), time - TMath::Floor(time/60.)*60.); + } + +} + +#endif diff --git a/armory/makefile b/armory/makefile new file mode 100644 index 0000000..29a7fe2 --- /dev/null +++ b/armory/makefile @@ -0,0 +1,25 @@ +CC=g++ + +all: EventBuilder_evt evt2hist MergeEVT ev22txt EventBuilder + +#this is for eventbuild +EventBuilder_evt: ../armory/EventBuilder_evt.cpp ../armory/DataBlock.h ../armory/evtReader.h ../mapping.h + $(CC) ../armory/EventBuilder_evt.cpp -o EventBuilder_evt `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` + +#this is for online spectrums +evt2hist: ../armory/evt2hist.cpp ../armory/DataBlock.h ../armory/evtReader.h ../mapping.h + $(CC) ../armory/evt2hist.cpp -o evt2hist `root-config --cflags --glibs` + + +ev22txt: ../armory/ev22txt.cpp + $(CC) ../armory/ev22txt.cpp -o ev22txt + +EventBuilder: ../armory/EventBuilder.cpp + $(CC) ../armory/EventBuilder.cpp -o EventBuilder `root-config --cflags --glibs` + +clean: + -rm xia2root to2root MergeEVT evt2hist pxi-time-order ev22txt EventBuilder test diff --git a/convertPixie.sh b/convertPixie.sh new file mode 100755 index 0000000..b4cd768 --- /dev/null +++ b/convertPixie.sh @@ -0,0 +1,87 @@ + +nCore=10; + +if [ $# -eq 0 ]; then + echo "Usage: " + echo " ./convertPixie.sh [RUNNUM]" + exit; +fi + +runNum=$1 + +nFile=$(ls -1 rawdata/run${runNum}/run*evt | wc -l) +files=$(ls -1 rawdata/run${runNum}/run*evt) + +nLoop=$((${nFile}/nCore+1)) + +echo "===== number of files in run-${runNum} = ${nFile}" +echo " number of loops = ${nLoop}" +echo "=================================================" + +i=0 +while [[ $i -lt ${nLoop} ]]; do + + j=0 + while [[ $j -lt ${nCore} ]]; do + SegNum=$((${nCore}*i+j)) + + if [[ ${SegNum} -ge ${nFile} ]]; then break; fi + + #patching the prefix ZERO + if [ $runNum -lt 10 ]; then + runPrefix="000" + elif [ $runNum -lt 100 ]; then + runPrefix="00" + elif [ $runNum -lt 1000 ]; then + runPrefix="0" + fi + + #patching the prefix ZERO for segment + if [ $SegNum -lt 10 ]; then + segPrefix="0" + else + segPrefix="" + fi + + fileName=rawdata/run${runNum}/run-${runPrefix}${runNum}-${segPrefix}${SegNum}.evt + outFileName=pixie_evt/pixie-${runPrefix}${runNum}-${segPrefix}${SegNum}.evt + if [[ -f ${outFileName} ]]; then + echo "${outFileName} exist. Skip." + else + echo ${fileName} + ./nscl2pixie_haha ${fileName} ${outFileName} & + fi + ((j += 1)) + done + + while true; do + nthings=`ps aux | grep "[n]scl2pixie_haha"| wc -l` + echo $(date)" || "$nthings" nscl2pixie_haha are running." + + + if [[ $nthings > 0 ]]; then + sleep 10; + else + break + fi + done + + + + ((i += 1)) +done + + + +#Pixiefiles=$(ls -1 evt_data/pixie-0${run}*.evt) + +#for a in ${Pixiefiles} +#do +# echo ${a} +# echo ${a:15:7} +# ./armory/MergeEVT root_data/run-${a:15:7}_raw.root ${a} +#done + + + + diff --git a/correction_Clover.dat b/correction_Clover.dat new file mode 100644 index 0000000..51b4fe2 --- /dev/null +++ b/correction_Clover.dat @@ -0,0 +1,52 @@ +-0.2745420387 0.1903055400 + 0.1893425548 0.1818331614 +-0.0367071701 0.1824341324 +-0.1063887098 0.1910650773 +-0.1850638424 0.1946547185 +-0.2585036758 0.1865086505 + 0.2311507914 0.1930849561 +-0.0611156448 0.1880617739 + 0.2138792456 0.1857668487 +-0.1000184518 0.1830644733 + 2.0604294051 0.1385512827 + 0.3180233659 0.1386769235 + 0.0000000000 0.0000000000 + 0.0000000000 0.0000000000 + 0.0000000000 0.0000000000 + 0.0000000000 0.0000000000 +-0.2208351518 0.1364541549 +-0.0306010261 0.1783805884 +-0.0037076212 0.1960560535 + 0.0642160243 0.1839858595 +-0.0511685756 0.1859194405 +-0.1172917454 0.1856488571 +-0.1286314737 0.1872948275 +-0.1364423663 0.1855266236 +-0.0008503082 0.1902808189 + 0.1662583256 0.1907490728 + 0.0557733175 0.1920862347 + 0.1879598992 0.1887119382 + 0.0000000000 0.0000000000 + 0.0000000000 0.0000000000 + 0.0000000000 0.0000000000 + 0.0000000000 0.0000000000 +-0.9876919208 0.4327488664 + 0.2788794959 0.4412627192 +-0.9159334953 0.4314262803 + 0.1617243872 0.1540839667 +-0.0582723977 0.2020260902 +-0.2204402251 0.1920815477 + 0.0312224501 0.1779034597 +-0.0839891831 0.1812223578 + 0.0842978355 0.1560970523 +-0.1401545082 0.1992025914 + 0.2404464347 0.1853884121 + 0.0029329553 0.1837522238 + 1.0202556280 0.1941341886 + 1.0659732514 0.1919353184 +-0.2565005696 0.1973878067 + 0.0787616555 0.1961591821 +-0.0159272801 0.1863936847 + 0.4103358572 0.1853258451 + 0.3394901400 0.1936672410 +-0.2622309571 0.1876968520 diff --git a/correction_e.dat b/correction_e.dat new file mode 120000 index 0000000..c1b58f6 --- /dev/null +++ b/correction_e.dat @@ -0,0 +1 @@ +degai.cal \ No newline at end of file diff --git a/degai.cal b/degai.cal new file mode 100644 index 0000000..1502651 --- /dev/null +++ b/degai.cal @@ -0,0 +1,64 @@ + -0.106851 0.190142 0.000000 + 0.016704 0.181833 0.000000 + -0.145046 0.182478 0.000000 + -0.249700 0.191049 0.000000 + + -0.249730 0.194651 0.000000 + -0.267311 0.186496 0.000000 + 0.203408 0.193090 0.000000 + -0.317856 0.188170 0.000000 + + 0.305632 0.185745 0.000000 + -0.230991 0.183063 0.000000 + -0.043614 0.138764 0.000000 + 0.386491 0.138711 0.000000 + + 0.000000 1.000000 0.000000 + 0.000000 1.000000 0.000000 + 0.000000 1.000000 0.000000 + 0.000000 1.000000 0.000000 + + -0.353672 0.136451 0.000000 + -0.189959 0.178413 0.000000 + -0.063779 0.195860 0.000000 + -0.134865 0.183998 0.000000 + + -0.220694 0.185943 0.000000 + -0.165269 0.185650 0.000000 + -0.205702 0.187253 0.000000 + -0.139217 0.185499 0.000000 + + -0.031178 0.191581 0.000000 + -0.023608 0.190817 0.000000 + -0.100241 0.193328 0.000000 + 0.396967 0.188671 0.000000 + + 0.000000 1.000000 0.000000 + 0.000000 1.000000 0.000000 + 0.000000 1.000000 0.000000 + 0.000000 1.000000 0.000000 + + -0.974461 0.432854 0.000000 + -0.279092 0.441360 0.000000 + -0.698628 0.431157 0.000000 + 0.148492 0.154080 0.000000 + + -0.198020 0.202018 0.000000 + -0.281912 0.192079 0.000000 + -0.012972 0.177876 0.000000 + -0.337566 0.181243 0.000000 + + 0.056818 0.156063 0.000000 + -0.248622 0.199156 0.000000 + -0.046962 0.185395 0.000000 + 0.175072 0.183612 0.000000 + + -0.111547 0.195441 0.000000 + -0.328011 0.190841 0.000000 + -0.501598 0.197271 0.000000 + -0.121546 0.196111 0.000000 + + -0.147028 0.186377 0.000000 + 0.161169 0.185324 0.000000 + 0.157357 0.193662 0.000000 + -0.348731 0.187723 0.000000 diff --git a/mapping.h b/mapping.h new file mode 100644 index 0000000..7bd1f30 --- /dev/null +++ b/mapping.h @@ -0,0 +1,56 @@ +/************************************ +Clover : 0 - 99 +LaBr : 100 - 199 +Implat : 200 - 299, 200-209 low gain, 250-259 highgain, 290 = veto front, 291 = veto rear +beam line : 300 - 399, 300-309 Image Scint, 310-319 PPAC, 320-329 cross scint, 330-339 MSX +TAC : 400 - 499 + * *********************************/ +#ifndef MAPPING +#define MAPPING + +//==================== mapping + +#define NCLOVER 13 +#define NCRYSTAL NCLOVER*4 +#define NIMPLAT 10 +#define NVETO 2 +#define NLABR 15 +#define NBEAM 15 + +// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 +int mapping[416] ={ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-0, mod-0 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-0, mod-1 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-0, mod-2 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-0, mod-3 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-0, mod-4 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-0, mod-5 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-0, mod-6 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-0, mod-7 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-0, mod-8 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-0, mod-9 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-0, mod-10 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-0, mod-11 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-0, mod-12 + + 250, 200, -1, -1, 251, 252, 253, 254, 201, 202, 203, 204, -1, -1, -1, 500, //crate-1, mod-0 + -1, -1, -1, -1, -1, -1, -1, -1, 306, 310, 300, 301, 302, 303, 304, 305, //crate-1, mod-1 + 308, 309, -1, -1, 311, 312, 313, 314, 307, -1, -1, -1, -1, -1, -1, -1, //crate-1, mod-2 + 0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -1, 11, -1, -1, -1, -1, //crate-1, mod-3 + 16, 17, 18, 19, 20, 21, 22, 23, -1, -1, -1, 27, -1, -1, -1, -1, //crate-1, mod-4 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, -1, 46, 47, //crate-1, mod-5 + 48, 49, 50, 51, 9, 10, 24, 25, 26, -1, -1, -1, -1, -1, -1, -1, //crate-1, mod-6 + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, -1, //crate-1, mod-7 + 290, 291, -1, -1, 44, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-1, mod-8 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-1, mod-9 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-1, mod-10 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //crate-1, mod-11 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; //crate-1, mod-12 + + +int mapDetID(int crate, int slot, int ch){ + int id = crate * 208 + 16*(slot-2) + ch; + //printf("id : %d, detID : %d \n", id, mapping[id]); + return mapping[id]; +} + +#endif diff --git a/nscl2pixie.c b/nscl2pixie.c new file mode 100644 index 0000000..e77800f --- /dev/null +++ b/nscl2pixie.c @@ -0,0 +1,288 @@ +#include +#include + +/* +Ring Item structure + +NSCLDAQ >= 11.0 +Ring Item Header + Size (4) + Type (4) (physics item, type=30) + +Ring Item Body + Ring Item Body Header + Size (4) + Timestamp (8) + Source ID (4) + Barrier Type (4) + + Body (for physics event) + Size (4) + Fragment #0 + Fragment Header (20) + Timestamp (8) + Source ID (4) + Payload size in bytes (4) + Barrier Type (4) + Fragment Payload + Ring Item Header (8) + Size (4) + Type (4) (physics item, type=30) + Ring Item Body Header (20) + Size (4) + Timestamp (8) + Source ID (4) + Barrier Type (4) + Ring Item Body (>8) + Body Size (4) - THIS IS IN 16-bit WORDS, NOT BYTES + Device Info (4) + Raw Data (XIA format) + Fragement #1 + Fragement Header (20) + Ring Item Header (8) + Ring Item Body Header (20) + Ring Item Body + . + . + . +*/ + +bool debug = false; + +int readRingItemHeader(FILE *file, unsigned int *ri_size) { + unsigned int ri_type; + if (fread(ri_size, (size_t)sizeof(int), 1, file) != 1) { + return -1; + } + if (fread(&ri_type, (size_t)sizeof(int), 1, file) != 1) { + return -1; + } + if (ri_type != 30 ) { + //non-physics item + if (ri_type == 1) { + if( debug) printf("\n============== BEGIN RUN ===============\n"); + } + else if (ri_type == 2) { + if( debug) printf("\n============== END RUN ===============\n"); + } + else if (ri_type == 3) { + if( debug) printf("\n============== PAUSE RUN ===============\n"); + } + else if (ri_type == 4) { + if( debug) printf("\n============== RESUME RUN ===============\n"); + } + else if (ri_type == 20) { + if( debug) printf("\nSCALERS FOUND..."); + } + else { + if( debug) printf("\nUntreated Ring item: %i %i\n", *ri_size, ri_type); + } + } + return ri_type; +} + +int readRingItemBodyHeader(FILE *file) { + unsigned int ribh_size; + unsigned long long int ribh_ts; + unsigned int ribh_sid; + unsigned int ribh_bt; + if (fread(&ribh_size, (size_t)sizeof(int), 1, file) != 1) { + return -1; + } + if (fread(&ribh_ts, (size_t)sizeof(unsigned long long int), 1, file) != 1) { + return -1; + } + if (fread(&ribh_sid, (size_t)sizeof(int), 1, file) != 1) { + return -1; + } + if (fread(&ribh_bt, (size_t)sizeof(int), 1, file) != 1) { + return -1; + } + + /* + std::cout << "Ring Item Body Header: " << std::endl; + std::cout << " size : " << ribh_size << std::endl; + std::cout << " timestamp : " << ribh_ts << std::endl; + std::cout << " source ID : " << ribh_sid << std::endl; + std::cout << " barrier type : " << ribh_bt << std::endl; + */ + return ribh_size; +} + +int readRingItemBody(FILE *file, unsigned int *rib_size) { + if (fread(rib_size, (size_t)sizeof(int), 1, file) != 1) { + return -1; + } + //std::cout << "Reading ring item body size = " << rib_size << std::endl; + *rib_size -= 4; + return *rib_size; +} + +int readNextFragment(FILE *file, unsigned int *rib_size) { + //this skips over the fragment header, the ring item header, and the ring item body header associated with the fragment + //reads the first 2 words of the ring item body (body size + device info) + //leaves the pointer right at the beginning of the actual PIXIE fragment + if (*rib_size > 48) { + //std::cout << "rib_size = " << rib_size << std::endl; + unsigned long long int frag_ts; + unsigned int frag_sid; + unsigned int frag_paysize; + unsigned int frag_bt; + + unsigned int frag_rih_size; + unsigned int frag_rih_type; + + unsigned int frag_ribh_size; + unsigned long long int frag_ribh_ts; + unsigned int frag_ribh_sid; + unsigned int frag_ribh_bt; + + if (fread(&frag_ts, (size_t)sizeof(unsigned long long int), 1, file) != 1) { return -1; } + if (fread(&frag_sid, (size_t)sizeof(int), 1, file) != 1) { return -1; } + if (fread(&frag_paysize, (size_t)sizeof(int), 1, file) != 1) { return -1; } + if (fread(&frag_bt, (size_t)sizeof(int), 1, file) != 1) { return -1; } + + if (fread(&frag_rih_size, (size_t)sizeof(int), 1, file) != 1) { return -1; } + if (fread(&frag_rih_type, (size_t)sizeof(int), 1, file) != 1) { return -1; } + + if (fread(&frag_ribh_size, (size_t)sizeof(int), 1, file) != 1) { return -1; } + if (fread(&frag_ribh_ts, (size_t)sizeof(unsigned long long int), 1, file) != 1) { return -1; } + if (fread(&frag_ribh_sid, (size_t)sizeof(int), 1, file) != 1) { return -1; } + if (fread(&frag_ribh_bt, (size_t)sizeof(int), 1, file) != 1) { return -1; } + + /* + std::cout << "Fragment Header: " << std::endl; + std::cout << " Timestamp: " << frag_ts << std::endl; + std::cout << " Source ID: " << frag_sid << std::endl; + std::cout << " Payload Size: " << frag_paysize << std::endl; + std::cout << " Barrier Type: " << frag_bt << std::endl; + + std::cout << "Fragment RIH: " << std::endl; + std::cout << " Size: " << frag_rih_size << std::endl; + std::cout << " Type: " << frag_rih_type << std::endl; + + + std::cout << "Fragment RIBH: " << std::endl; + std::cout << " Size: " << frag_ribh_size << std::endl; + std::cout << " Timestamp: " << frag_ribh_ts << std::endl; + std::cout << " Source ID: " << frag_ribh_sid << std::endl; + std::cout << " Barrier Type: " << frag_ribh_bt << std::endl; + */ + + unsigned int frag_size; //in 16 bit words not 32 bit words + unsigned int dev_info; + if (fread(&frag_size, (size_t)sizeof(int), 1, file) != 1) { + return -1; + } + if (fread(&dev_info, (size_t)sizeof(int), 1, file) != 1) { + return -1; + } + + /* + unsigned int ADC_freq = (dev_info & 0x0000ffff); + unsigned int ADC_res = (dev_info & 0xff0000) >> 16; + unsigned int mod_rev = (dev_info & 0xff000000) >> 24; + + std::cout << "dev_info = " << ADC_freq << " " << ADC_res << " " << mod_rev << std::endl; + + std::cout << "frag_size = " << frag_size << std::endl; + */ + + *rib_size -= (48 + frag_size*2); + if (*rib_size < 0 ) { + if( debug) printf("\nSEVERE ERROR, NAVIGATION THROUGH RING BUFFER BROKEN\n"); + return -1; + } + } + else if (*rib_size < 48) { + if( debug) printf("\nREMAINING DATA: \n"); + int rib_tmp = *rib_size; + int data; + while (rib_tmp > 0) { + fread(&data, (size_t)sizeof(int), 1, file); + if( debug) printf("%i\n", data); + rib_tmp -= 4; + } + } + else { + if( debug) printf("\nWarning! readNextFragment called when rib_size == 0\n"); + } + //std::cout << "readNextFragment returning " << rib_size << std::endl; + return *rib_size; +} + +int findNextFragment(FILE *file, unsigned int *rib_size) { + if (*rib_size > 0) { + return readNextFragment(file, rib_size); + } + + while (1) { + unsigned int ri_size; + int type = readRingItemHeader(file, &ri_size); + if (type == -1) { return -1; } + if (type != 30) { + fseek(file, ri_size-8, SEEK_CUR); //skip the rest of the non-physics event + continue; + } + int ribh_size = readRingItemBodyHeader(file); + if (ribh_size < 0) { return ribh_size; } + + readRingItemBody(file, rib_size); + if (*rib_size < 0) { return *rib_size; } + + return readNextFragment(file, rib_size); + } +} + +int copyPixieSubEvent(FILE *infile, FILE *outfile) { + unsigned int firstWords[4]; + if (fread(&firstWords, (size_t) sizeof(int)*4, (size_t) 1, infile) != 1) { + return -1; + } + fwrite(&firstWords, (size_t) sizeof(int)*4, (size_t) 1, outfile); + + int headerLength = (firstWords[0] & 0x1F000) >> 12; + int traceLength= (firstWords[3] & 0x7FFF0000) >> 16; + if (headerLength > 4) { + unsigned int otherWords[headerLength-4]; + if (fread(&otherWords, (size_t) 4, (size_t) headerLength-4, infile) != (size_t) headerLength-4) { + return -1; + } + fwrite(&otherWords, (size_t) 4, (size_t) headerLength-4, outfile); + } + if (traceLength > 0) { + unsigned short int trace[traceLength]; // = {0}; + if (fread(&trace[0], (size_t) 2, (size_t) traceLength, infile) != (size_t) traceLength) { + return -1; + } + fwrite(&trace[0], (size_t) 2, (size_t) traceLength, outfile); + } + return 1; +} + +int main(int argc, const char **argv) { + if (argc < 3) { + printf("usage: ./nscl2pixie [infile] [outfile] [debug=0]\n"); + return -1; + } + + FILE *infile = fopen(argv[1], "rb"); + FILE *outfile = fopen(argv[2], "wb"); + if( argc == 4 ) debug = atoi(argv[3]); + + unsigned int rib_size = 0; + long long unsigned int evts = 0; + int retval = 1; + while (1) { + retval = findNextFragment(infile, &rib_size); + if (retval < 0 ) { break; } + retval = copyPixieSubEvent(infile, outfile); + if (retval < 0 ) { break; } + ++evts; + } + + printf("%llu subevents copied\n", evts); + fclose(infile); + fclose(outfile); + +} diff --git a/peachCake.C b/peachCake.C new file mode 100644 index 0000000..5098ba0 --- /dev/null +++ b/peachCake.C @@ -0,0 +1,380 @@ +#define peachCake_cxx + +#include "peachCake.h" +#include +#include +#include +#include +#include +#include + +#include "./armory/AnalysisLibrary.h" +//============== histograms + +TH2F * hCloverID; +TH2F * hPID; +TH2F * hImplantIons; +TH2F * hImplantBeta; //high gain + +TH2F * hImplantX; +TH2F * hImplantY; + +TH2F * hImplantDyIons; +TH2F * hImplantDyBeta; + +TH1F * hDecay; +TH1F * hDecay_veto; + +TH1F * hFlag; +TH1F * hvetoFlag; + +//============ parameters +//TString cutFileName="PIDCuts.root"; +//TFile * cutFile; +//TCutG * cut = NULL; +//TObjArray * cutList; +//int numCut = 0; + +vector> eCorr; + + +void peachCake::Begin(TTree * /*tree*/){ + TString option = GetOption(); + + hCloverID = new TH2F("hCloverID", "Clover; ID; energy [keV]", 52, 0, 52, 400, 0, 2000); + hPID = new TH2F("hPID", "PID; ns; msx40", 500, -265, -220, 500, 0, 6500); + + hImplantIons = new TH2F("hImplantIons", "Implat low gain; x ; y", 400, 0, 1, 400, 0, 1); + hImplantBeta = new TH2F("hImplantBeta", "Implat high gain; x ; y", 400, 0, 1, 400, 0, 1); + + hImplantX = new TH2F("hImplantX", "Implat X; low ; high", 400, 0, 1, 400, 0, 1); + hImplantY = new TH2F("hImplantY", "Implat Y; low ; high", 400, 0, 1, 400, 0, 1); + + + hImplantDyIons = new TH2F("hImplantDyIonsow", "Implat low; sum_a; dy", 400, 0, 80000, 400, 0, 80000); + hImplantDyBeta = new TH2F("hImplantDyBetaigh", "Implat high; sum_a; dy", 400, 0, 8000, 400, 0, 8000); + + hDecay = new TH1F("hDecay", "Decay (beta.time - ion.time) ; [ticks]; counts", 100, 0, 2000); + hDecay_veto = new TH1F("hDecay_veto", "Decay (beta.time - ion.time) [veto]; [ticks]; counts", 100, 0, 2000); + + hFlag = new TH1F("hFlag", "Flag ( 1 = beam, 2 = Ions, 4 = Beta)", 8, 0, 8); + hvetoFlag = new TH1F("hvetoFlag", "vetoFlag ( 1 = front, 4 = rear)", 8, 0, 8); + + eCorr = LoadCorrectionParameters("correction_e.dat"); + + /** + cutFile = new TFile(cutFileName, "READ"); + bool listExist = cutFile->GetListOfKeys()->Contains("cutList"); + if( listExist ) { + cutList = (TObjArray*) cutFile->FindObjectAny("cutList"); + numCut = cutList->GetLast()+1; + printf("----- found %d cuts \n", numCut); + for( int k = 0; k < numCut; k++){ + if( cutList->At(k) != NULL ){ + printf("found a cut at %2d \n", k); + } + } + } + * */ + + printf("============ start \n"); + +} + + +Bool_t peachCake::Process(Long64_t entry){ + + nProcessed++; + + b_multi->GetEntry(entry); + b_detID->GetEntry(entry); + b_e->GetEntry(entry); + b_e_t->GetEntry(entry); + b_cfd->GetEntry(entry); + + energy = TMath::QuietNaN(); + Long64_t startTimeL = 0; + Long64_t startTimeR = 0; + Long64_t stopTime = 0; + double cfdL = TMath::QuietNaN(); + double cfdR = TMath::QuietNaN(); + double cfd2 = TMath::QuietNaN(); + + Long64_t startTime40 = 0; + double cfd40 = TMath::QuietNaN(); + + double a_L[5] = {TMath::QuietNaN()}; ///0 = dy, 1-4 = anode + double a_H[5] = {TMath::QuietNaN()}; + + veto_f = TMath::QuietNaN(); + veto_r = TMath::QuietNaN(); + + veto_f_time = 0; + veto_r_time = 0; + + crossEnergy = 0; /// for analog signal, cross T2 + crossTime = 0; + + for( int i = 0; i < 4 ; i++) { + dyIonsTime[i] = 0; + dyBetaTime[i] = 0; + dyIonsEnergy[i] = 0; + dyBetaEnergy[i] = 0; + } + + int multiDyBeta = 0; + int multiDyIons = 0; + + flag = 0; + vetoFlag = 0; + + //======= Scanning the event + for( int i = 0; i < multi; i++){ + + if( 0 <= detID[i] && detID[i] < 100 ){ // Clover + if( e[i] > 0 ) { + int id = detID[i]; + double eCal = 0; + for( int k = 0; k < int(eCorr[id].size()); k++){ + eCal += eCorr[id][k] * TMath::Power(e[i], k); + } + hCloverID->Fill(detID[i], eCal); + } + } + + if( detID[i] == 200 ) { //dy Beta + if ( multiDyBeta < 4 ){ + dyBetaTime[multiDyBeta] = e_t[i]; + dyBetaEnergy[multiDyBeta] = e[i]; + multiDyBeta ++; + } + } + if( 201 <= detID[i] && detID[i] < 250){ // Implant detector, high gain, Beta + a_H[detID[i] - 200] = e[i]; + } + + if( detID[i] == 250 ) { //dy Ions + if ( multiDyIons < 4 ){ + dyIonsTime[multiDyIons] = e_t[i]; + dyIonsEnergy[multiDyIons] = e[i]; + multiDyIons ++; + } + } + if( 251 <= detID[i] && detID[i] < 260){ // Implant detector, low gain, Ions + a_L[detID[i] - 250] = e[i]; + } + + if( detID[i] == 290 ) { + veto_f = e[i]; + veto_f_time = e_t[i]; + if( veto_f > 0 && (vetoFlag & 1) == 0) vetoFlag += 1; + } + if( detID[i] == 291 ) { + veto_r = e[i]; + veto_r_time = e_t[i]; + if( veto_r > 0 && (vetoFlag & 2) == 0) vetoFlag += 2; + } + + if( detID[i] == 300 ) { // image scint L + if( e[i] > 1000 ) { + startTimeL = e_t[i]; + cfdL = cfd[i]/16384.; + } + } + if( detID[i] == 301 ) { // image scint R + startTimeR = e_t[i]; + cfdR = cfd[i]/16384.; + } + if( detID[i] == 306 ) { // cross T2 analog + if( (vetoFlag & 4) == 0) vetoFlag += 4; + crossEnergy = e[i]; + crossTime = e_t[i]; + } + if( detID[i] == 307 ) { // cross B2 logic + stopTime = e_t[i]; + cfd2 = cfd[i]/16384.; + if( (vetoFlag & 4) == 0) vetoFlag += 4; + } + if( detID[i] == 308 ) energy = e[i]; //MSX40 + //if( detID[i] == 309 ) energy = e[i]; //MSX100 + + if( detID[i] == 310 ) { //MSX40 logic + startTime40 = e_t[i]; + cfd40 = cfd[i]/16384.; + } + } + + //================================== PID + Long64_t startTime = startTimeL; + double startCFD = cfdL; + + TOF = TMath::QuietNaN(); + if( startTime > 0 && stopTime > 0 ){ + if( stopTime > startTime ){ + TOF = double(stopTime - startTime) - startCFD + cfd2; + }else{ + TOF = -double(startTime - stopTime) - startCFD + cfd2 ; + } + TOF = TOF * 8; // to ns + + hPID->Fill(TOF, energy); + if( energy > 0 ) flag += 1; + } + + //================================== Implant + double sumA_L = 0; + double sumA_H = 0; + for( int i = 1; i <= 4 ; i++){ + if( a_L[i] > 0 ) sumA_L += a_L[i]; + if( a_H[i] > 0 ) sumA_H += a_H[i]; + } + + xIons = (a_L[3]+a_L[2])/sumA_L; + yIons = (a_L[1]+a_L[2])/sumA_L; + xBeta = (a_H[3]+a_H[2])/sumA_H; + yBeta = (a_H[1]+a_H[2])/sumA_H; + + + if( (flag & 1) == 0 ) { + hImplantIons->Fill(xIons, yIons); + hImplantBeta->Fill(xBeta, yBeta); + hImplantDyIons->Fill(sumA_L, dyIonsEnergy[0]); + hImplantDyBeta->Fill(sumA_H, dyBetaEnergy[0]); + + hImplantX->Fill(xIons, xBeta); + hImplantY->Fill(yIons, yBeta); + } + + if( !TMath::IsNaN(veto_f) && !TMath::IsNaN(veto_r) && crossTime == 0 ){ + //hImplantIons->Fill(xIons, yIons); + //hImplantBeta->Fill(xBeta, yBeta); + //hImplantDyIons->Fill(sumA_L, dyIonsEnergy[0]); + //hImplantDyBeta->Fill(sumA_H, dyBetaEnergy[0]); + // + //hImplantX->Fill(xIons, xBeta); + //hImplantY->Fill(yIons, yBeta); + } + + if( 0 < xIons && xIons < 1 && 0 < yIons && yIons < 1 ) flag += 2; + if( 0 < xBeta && xBeta < 1 && 0 < yBeta && yBeta < 1 ) flag += 4; + + hFlag->Fill(flag); + hvetoFlag->Fill(vetoFlag); + + + //============================== debug + if ( false ) { + + printf("################# %lld, multi:%d\n", entry, multi); + + printf("----- beam Line \n"); + printf(" MSX100 eneergy : %f \n", energy); + printf(" startTime : %llu, CFD : %f \n", startTime, startCFD); + printf(" stopTime : %llu, CFD : %f \n", stopTime, cfd2); + printf(" TOF : %f ns \n", TOF); + + printf("----- Ions, low gain \n"); + for( int i = 1; i <= 4; i++ )printf("a%d : %f\n", i, a_L[i]); + printf("sum A : %f \n", sumA_L); + printf("x : %f , y : %f \n", xIons, yIons); + for ( int i = 0; i < 4; i++ )printf("dy : %u, %llu \n", dyIonsEnergy[i], dyIonsTime[i]); + + printf("----- Beta, high gain \n"); + for( int i = 1; i <= 4; i++ )printf("a%d : %f\n", i, a_H[i]); + printf("sum A : %f \n", sumA_H); + printf("x : %f , y : %f \n", xBeta, yBeta); + for ( int i = 0; i < 4; i++ )printf("dy : %u, %llu \n", dyBetaEnergy[i], dyBetaTime[i]); + + printf("----- Veto \n"); + printf(" cross Time : %llu \n", crossTime); + printf(" cross energy : %d \n", crossEnergy); + printf("veto_f energy : %f \n", veto_f); + printf( "veto_f Time : %llu \n", veto_f_time); + printf("veto_r energy : %f \n", veto_r); + printf( "veto_r Time : %llu \n", veto_r_time); + + printf("============ flag : %d, vetoFlag : %d\n", flag, vetoFlag); + + + } + + //============================= Rejection + if ( flag == 0 ) return kTRUE; + + //============================= Progress + saveFile->cd(); + newTree->Fill(); + + + clock.Stop("timer"); + Double_t time = clock.GetRealTime("timer"); + clock.Start("timer"); + + if ( !shown ) { + if (fmod(time, 10) < 1 ){ + printf( "%12llu[%2d%%]|%3.0f min %5.2f sec | expect:%5.2f min\r", + nProcessed, + TMath::Nint((nProcessed+1)*100./totnumEntry), + TMath::Floor(time/60.), time - TMath::Floor(time/60.)*60., + totnumEntry*time/(nProcessed+1.)/60.); + shown = 1;} + }else{ + if (fmod(time, 10) > 9 ){ + shown = 0; + } + } + + return kTRUE; +} + + +void peachCake::Terminate(){ + + printf("\n===============\n"); + saveFile->cd(); + newTree->Write(); + saveFile->Close(); + + gStyle->SetOptStat("neiou"); + TCanvas * c1 = new TCanvas("c1", "c1", 1500, 1000); + c1->Divide(3,3); + + int padID=1; + + c1->cd(padID); + c1->cd(padID)->SetLogz(); + hPID->Draw("colz"); + + padID ++; + c1->cd(padID); + c1->cd(padID)->SetGrid(); + c1->cd(padID)->SetLogz(); + hCloverID->Draw("colz"); hCloverID->SetNdivisions(-13); + + padID ++; + c1->cd(padID); c1->cd(padID)->SetLogz(); hImplantIons->Draw("colz"); + + padID ++; + c1->cd(padID); c1->cd(padID)->SetLogz(); hImplantBeta->Draw("colz"); + + //padID ++; + //c1->cd(padID); c1->cd(padID)->SetLogz(); hImplantBeta_veto->Draw("colz"); + + padID ++; + c1->cd(padID); c1->cd(padID)->SetLogz(); hImplantDyIons->Draw("colz"); + + padID ++; + c1->cd(padID); c1->cd(padID)->SetLogz(); hImplantDyBeta->Draw("colz"); + + padID ++; + c1->cd(padID); c1->cd(padID)->SetLogz(); hImplantX->Draw("colz"); + + padID ++; + c1->cd(padID); c1->cd(padID)->SetLogz(); hImplantY->Draw("colz"); + + padID ++; + c1->cd(padID); hFlag->Draw(""); + hvetoFlag->SetLineColor(2); hvetoFlag->Draw("same"); + + +} diff --git a/peachCake.h b/peachCake.h new file mode 100644 index 0000000..6ca68f4 --- /dev/null +++ b/peachCake.h @@ -0,0 +1,201 @@ +////////////////////////////////////////////////////////// +// This class has been automatically generated on +// Fri May 13 17:59:58 2022 by ROOT version 6.24/06 +// from TTree tree/root_data/run-0143-00.root +// found on file: root_data/run-0143-00.root +////////////////////////////////////////////////////////// + +#ifndef peachCake_h +#define peachCake_h + +#include +#include +#include +#include +#include +#include "cmath" + +// Header file for the classes stored in the TTree if any. + +class peachCake : public TSelector { +public : + TChain *fChain; //!pointer to the analyzed TTree or TChain + +// Fixed size dimensions of array or collections stored in the TTree if any. + + // Declaration of leaf types + ULong64_t evID; + Int_t multi; + Int_t detID[416]; //[multi] + Double_t e[416]; //[multi] + ULong64_t e_t[416]; //[multi] + Int_t cfd[416]; //[multi] + Int_t qdc[416][8]; //[multi] + Int_t multiClover; + Int_t multiBeam; + Int_t runID; + + // List of branches + TBranch *b_event_ID; //! + TBranch *b_multi; //! + TBranch *b_detID; //! + TBranch *b_e; //! + TBranch *b_e_t; //! + TBranch *b_cfd; //! + TBranch *b_qdc; //! + TBranch *b_multiplicity_Clover; //! + TBranch *b_multiplicity_Beam; //! + TBranch *b_runID; //! + + peachCake(TTree * /*tree*/ =0) : fChain(0) { } + virtual ~peachCake() { } + virtual Int_t Version() const { return 2; } + virtual void Begin(TTree *tree); + virtual void SlaveBegin(TTree *tree); + virtual void Init(TTree *tree); + virtual Bool_t Notify(); + virtual Bool_t Process(Long64_t entry); + virtual Int_t GetEntry(Long64_t entry, Int_t getall = 0) { return fChain ? fChain->GetTree()->GetEntry(entry, getall) : 0; } + virtual void SetOption(const char *option) { fOption = option; } + virtual void SetObject(TObject *obj) { fObject = obj; } + virtual void SetInputList(TList *input) { fInput = input; } + virtual TList *GetOutputList() const { return fOutput; } + virtual void SlaveTerminate(); + virtual void Terminate(); + + ClassDef(peachCake,0); + + //=========== varibales in new tree + TFile * saveFile; + TTree * newTree; + TString saveFileName; + int totnumEntry; //of the original file + + //tree + Int_t eventID; + UInt_t crossEnergy; + ULong64_t crossTime; + Double_t TOF; + Double_t energy; + + Short_t flag; /// 1 = has beam, 2 = has Ions, 4 = hasBeta, default 0; + + Double_t xIons; + Double_t yIons; + Double_t xBeta; + Double_t yBeta; + UInt_t dyIonsEnergy[4]; + ULong64_t dyIonsTime[4]; + UInt_t dyBetaEnergy[4]; + ULong64_t dyBetaTime[4]; + Double_t veto_f; + ULong64_t veto_f_time; + Double_t veto_r; + ULong64_t veto_r_time; + + Short_t vetoFlag; /// default = 0, 1 = front, 2 = rear, 4 = cross + + //clock + TBenchmark clock; + Bool_t shown; + + Long64_t nProcessed; + +}; + +#endif + +#ifdef peachCake_cxx +void peachCake::Init(TTree *tree){ + + // Set branch addresses and branch pointers + if (!tree) return; + + totnumEntry = tree->GetEntries(); + printf("============= num entry : %d\n", totnumEntry); + + fChain = (TChain *)tree; + fChain->SetMakeClass(1); + + fChain->SetBranchAddress("evID", &evID, &b_event_ID); + fChain->SetBranchAddress("multi", &multi, &b_multi); + fChain->SetBranchAddress("detID", detID, &b_detID); + fChain->SetBranchAddress("e", e, &b_e); + fChain->SetBranchAddress("e_t", e_t, &b_e_t); + fChain->SetBranchAddress("cfd", cfd, &b_cfd); + fChain->SetBranchAddress("qdc", qdc, &b_qdc); + fChain->SetBranchAddress("multiClover", &multiClover, &b_multiplicity_Clover); + fChain->SetBranchAddress("multiBeam", &multiBeam, &b_multiplicity_Beam); + fChain->SetBranchAddress("runID", &runID, &b_runID); + + + //============ new tree + saveFileName = "test"; + int oldSeg = -100; + int numFile = fChain->GetListOfFiles()->GetLast()+1; + for( int i = 0; i < numFile; i++){ + TString name = fChain->GetListOfFiles()->At(i)->GetTitle(); + int pos = name.Last('/'); + name = name.Remove(0,pos+1); //this should be run-XXXX-XX.root + if( i == 0 ) { + saveFileName = name; + pos = saveFileName.Last('-'); + saveFileName = saveFileName.Remove(pos); //run-XXXX + } + pos = name.Last('-'); + int segNum = atoi(name.Remove(0, pos+1).Remove(2)); + if( oldSeg == -100 ) oldSeg = segNum; + saveFileName = saveFileName + Form("_%02d",segNum); + if( segNum == oldSeg + 1 && i != numFile -1 ){ + int len = saveFileName.Length(); + saveFileName = saveFileName.Remove(len - 3); + oldSeg = segNum; + } + } + saveFileName = saveFileName + ".root"; + + printf("=========== saveFile : %s \n", saveFileName.Data()); + + saveFile = new TFile(saveFileName, "recreate"); + newTree = new TTree("tree", "tree"); + + newTree->Branch("eventID", &eventID, "eventID/l"); + //newTree->Branch("runID", &runID, "runID/I"); + newTree->Branch("TOF", &TOF, "TOF/D"); + newTree->Branch("energy", &energy, "energy/D"); + newTree->Branch("crossTime", &crossTime, "crossTime/l"); + newTree->Branch("crossEnergy", &crossEnergy, "crossEnergy/i"); + newTree->Branch("flag", &flag, "flag/S"); + newTree->Branch("vetoFlag", &vetoFlag, "vetoFlag/S"); + newTree->Branch("xIons", &xIons, "xIons/D"); + newTree->Branch("yIons", &yIons, "yIons/D"); + newTree->Branch("xBeta", &xBeta, "xBeta/D"); + newTree->Branch("yBeta", &yBeta, "yBeta/D"); + newTree->Branch("dyIonsTime", dyIonsTime, "dyIonsTime[4]/l"); + newTree->Branch("dyBetaTime", dyBetaTime, "dyBetaTime[4]/l"); + newTree->Branch("veto_f", &veto_f, "veto_f/D"); + newTree->Branch("veto_r", &veto_r, "veto_r/D"); + + //==== clock + clock.Reset(); + clock.Start("timer"); + shown = 0; + + nProcessed = 0; + +} + +Bool_t peachCake::Notify(){ + + return kTRUE; +} + +void peachCake::SlaveBegin(TTree * /*tree*/){ + TString option = GetOption(); +} + +void peachCake::SlaveTerminate(){ +} + + +#endif // #ifdef peachCake_cxx diff --git a/pixie_evt b/pixie_evt new file mode 120000 index 0000000..2409bc7 --- /dev/null +++ b/pixie_evt @@ -0,0 +1 @@ +/mnt/data_1TB/e21062/pixie_evt \ No newline at end of file diff --git a/rawdata b/rawdata new file mode 120000 index 0000000..aa88799 --- /dev/null +++ b/rawdata @@ -0,0 +1 @@ +/mnt/data_1TB/e21062/rawdata \ No newline at end of file diff --git a/rootlogon.C b/rootlogon.C new file mode 100644 index 0000000..1c81f74 --- /dev/null +++ b/rootlogon.C @@ -0,0 +1,42 @@ +{ + printf("=================== Root v%s\n", gROOT->GetVersion()); + gStyle->SetOptStat("neiou"); + + + gStyle->SetPalette(1); + gStyle->SetLineWidth(2); + gStyle->SetStatW(0.3); + gStyle->SetStatH(0.3); + gStyle->SetTitleW(0.4); + gStyle->SetTitleH(0.1); + gStyle->SetCanvasBorderMode(0); + gStyle->SetPadBorderMode(0); + gStyle->SetPadColor(0); + gStyle->SetFrameBorderMode(0); + gStyle->SetFrameLineWidth(2); + gStyle->SetCanvasColor(0); + gStyle->SetOptDate(4); + gStyle->GetAttDate()->SetTextFont(62); + gStyle->GetAttDate()->SetTextSize(0.02); + gStyle->GetAttDate()->SetTextAngle(0); + gStyle->GetAttDate()->SetTextAlign(11); + gStyle->GetAttDate()->SetTextColor(1); + gStyle->SetDateX(0); + gStyle->SetDateY(0); + + gROOT->SetStyle("Plain"); // plain histogram style + gStyle->SetOptStat("nemruoi"); // expanded stats box + gStyle->SetPadTickX(1); // tic marks on all axes + gStyle->SetPadTickY(1); // + gStyle->SetOptFit(1111); // the results of the fits + gStyle->SetPadGridX(kTRUE); // draw horizontal and vertical grids + gStyle->SetPadGridY(kTRUE); + gStyle->SetPalette(1,0); // pretty and useful palette + gStyle->SetHistLineWidth(2); // a thicker histogram line + gStyle->SetFrameFillColor(10); // a different frame colour + gStyle->SetTitleFillColor(33); // title colour to highlight it + gStyle->SetTitleW(.76); // Title Width + gStyle->SetTitleH(.07); // Title height + gStyle->SetHistMinimumZero(true); // Suppresses Histogram Zero Supression + +} diff --git a/script.C b/script.C new file mode 100644 index 0000000..9216510 --- /dev/null +++ b/script.C @@ -0,0 +1,10 @@ +{ + TChain * chain = new TChain("tree"); + + chain->Add("root_data/run-0238-[0-4][0-9].root"); + + chain->GetListOfFiles()->Print(); + + chain->Process("peachCake.C+"); + +}