diff --git a/.gitignore b/.gitignore index 6856f48..73ab6e2 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ EventBuilder .gdb_history +data data_raw root_data diff --git a/.vscode/settings.json b/.vscode/settings.json index 6b63c3c..415af4f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -121,7 +121,9 @@ "Monitors_Util.C": "cpp", "Monitor_Util.C": "cpp", "script_single.C": "cpp", - "script_multi.C": "cpp" + "script_multi.C": "cpp", + "Isotope.C": "cpp", + "classisotope.h": "c" }, "better-comments.multilineComments": true, diff --git a/Armory/AnalysisLib.h b/Armory/AnalysisLib.h new file mode 100644 index 0000000..4ff335c --- /dev/null +++ b/Armory/AnalysisLib.h @@ -0,0 +1,296 @@ +#ifndef ANALYSIS_LIB_H +#define ANALYSIS_LIB_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace AnalysisLib { + +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; +}; + + +//************************************** TCutG + +TObjArray * LoadListOfTCut(TString fileName, TString cutName = "cutList"){ + + if( fileName == "" ) return nullptr; + + TObjArray * cutList = nullptr; + + TFile * fCut = new TFile(fileName); + bool isCutFileOpen = fCut->IsOpen(); + if(!isCutFileOpen) { + printf( "Failed to open rdt-cutfile 1 : %s\n" , fileName.Data()); + }else{ + cutList = (TObjArray *) fCut->FindObjectAny(cutName); + + if( cutList ){ + int numCut = cutList->GetEntries(); + printf("=========== found %d cutG in %s \n", numCut, fCut->GetName()); + + for(int i = 0; i < numCut ; i++){ + printf("cut name : %s , VarX: %s, VarY: %s, numPoints: %d \n", + cutList->At(i)->GetName(), + ((TCutG*)cutList->At(i))->GetVarX(), + ((TCutG*)cutList->At(i))->GetVarY(), + ((TCutG*)cutList->At(i))->GetN() + ); + } + } + } + + return cutList; +} + +TCutG * LoadSingleTCut( TString fileName, TString cutName = "cutEZ"){ + + if( fileName == "" ) return nullptr; + TCutG * cut = nullptr; + + TFile * fCut = new TFile(fileName); + bool isCutFileOpen = fCut->IsOpen(); + if( !isCutFileOpen) { + printf( "Failed to open E-Z cutfile : %s\n" , fileName.Data()); + }else{ + cut = (TCutG *) fCut->FindObjectAny(cutName); + if( cut != NULL ) { + printf("Found EZ cut| name : %s, VarX: %s, VarY: %s, numPoints: %d \n", + cut->GetName(), + cut->GetVarX(), + cut->GetVarY(), + cut->GetN() + ); + } + } + + return cut; +} + + +//************************************** Others +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; + +} + + +} + +#endif \ No newline at end of file diff --git a/Armory/AutoFit.C b/Armory/AutoFit.C new file mode 100644 index 0000000..4b94781 --- /dev/null +++ b/Armory/AutoFit.C @@ -0,0 +1,2861 @@ +/*************************************************** + * This is a root macro for Auto fitting + * + * Created by Tsz Leung (Ryan) TANG, around 2019. + * updated 01-04-2022 + * + * contact goluckyryan@gmail.com + ***************************************************/ + +#ifndef AutoFit_C +#define AutoFit_C + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace AutoFit{ + +//Global fit paramaters +std::vector BestFitMean; +std::vector BestFitCount; +std::vector BestFitSigma; + +TString recentFitMethod; + +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("------- 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("\n"); + printf("------- Utility : \n"); + printf(" SaveFitPara() - Save the inital/Best fit parameters.\n"); + printf(" ShowFitMerhod() - Show this menual.\n"); + printf("---------------------------------------------------------\n"); +} + +void AutoFit(){ + ShowFitMethod(); +} + +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 = std::max(0., (1+2*cos(ang))/3.); + double g = std::max(0., (1 - cos(ang) + sqrt(3)* sin(ang))/3.); + double b = std::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"); +} + +std::vector energy, height, sigma, lowE, highE ; +std::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()); + std::ifstream file; + file.open(fitParaFile.Data()); + + if( !file){ + printf("\ncannot read file : %s \n", fitParaFile.Data()); + return 0; + } + + while( file.good()) { + std::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()); + + std::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); + 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"); + + recentFitMethod = "fitGaussPol"; + + 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); + + BestFitCount.clear(); + BestFitMean.clear(); + BestFitSigma.clear(); + + BestFitCount.push_back(paraA[0]); + BestFitMean.push_back(paraA[1]); + BestFitSigma.push_back(paraA[2]); + +} + +//######################################## +//#### fit 2 gauss + pol-1 // not updated +//######################################## +std::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"); + + recentFitMethod = "fit2GaussP1"; + + std::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); + + + BestFitCount.clear(); + BestFitMean.clear(); + BestFitSigma.clear(); + + for( int i = 0; i < 2; i++){ + BestFitCount.push_back(paraA[3*i]/ bw); + BestFitMean.push_back(paraA[3*i+1]); + BestFitSigma.push_back(paraA[3*i+2]); + } + + 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"); + + recentFitMethod = "fitGF3Pol"; + + 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 + std::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 +//############################################## +std::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"); + + recentFitMethod = "fitAuto"; + + 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 ); + std::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); + + std::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")); + + BestFitCount.clear(); + BestFitMean.clear(); + BestFitSigma.clear(); + + 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])); + + BestFitCount.push_back(paraA[3*i]/ bw); + BestFitMean.push_back(paraA[3*i+1]); + BestFitSigma.push_back(paraA[3*i+2]); + } + + return exPos; + +} + + +//######################################## +//###### NOT tested +//######################################## +std::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(); + } + + recentFitMethod = "fitNGF3"; + + 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 ); + std::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); + + std::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"); + + recentFitMethod = "fitNGauss"; + + 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")); + + BestFitCount.clear(); + BestFitMean.clear(); + BestFitSigma.clear(); + + 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])); + + BestFitCount.push_back(paraA[3*i]/ bw); + BestFitMean.push_back(paraA[3*i+1]); + BestFitSigma.push_back(paraA[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"); + + recentFitMethod = "fitNGaussSub"; + + 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")); + + BestFitCount.clear(); + BestFitMean.clear(); + BestFitSigma.clear(); + + 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])); + + BestFitCount.push_back(paraA[3*i]/ bw); + BestFitMean.push_back(paraA[3*i+1]); + BestFitSigma.push_back(paraA[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"); + + recentFitMethod = "fitNGaussPol"; + + 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")); + + BestFitCount.clear(); + BestFitMean.clear(); + BestFitSigma.clear(); + + 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])); + + BestFitCount.push_back(paraA[3*i]/ bw); + BestFitMean.push_back(paraA[3*i+1]); + BestFitSigma.push_back(paraA[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"); + + recentFitMethod = "fitNGaussPolSub"; + + 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")); + + BestFitCount.clear(); + BestFitMean.clear(); + BestFitSigma.clear(); + + 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])); + + BestFitCount.push_back(paraA[3*i]/ bw); + BestFitMean.push_back(paraA[3*i+1]); + BestFitSigma.push_back(paraA[3*i+2]); + } + + +} + +//################################################# +//#### fit N-Gauss with pol-n BG using mouse click +//################################################# + +int nClick = 0; +bool peakFlag = 1; +std::vector xPeakList; +std::vector yPeakList; +std::vector xBGList; +std::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(bool isBestFit = true, TString fileName = "AutoFit_para.txt"){ + + if( xPeakList.size() == 0 && BestFitMean.size() == 0 ){ + printf(" no fit paramaters availible. \n"); + return; + } + + if( recentFitMethod == "fitGF3Pol" || recentFitMethod == "fitGF3" ){ + printf(" Not support for GF3 fitting. \n"); + return; + } + + 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"); + + + if ( xPeakList.size() == 0 || isBestFit ){ + for( int i = 0 ; i < BestFitMean.size() ; i++){ + fprintf(file_out, "%.3f %.3f %.3f 0 %.3f 0 %.0f\n", + BestFitMean[i], + BestFitMean[i] - 5*BestFitSigma[i], + BestFitMean[i] + 5*BestFitSigma[i], + BestFitSigma[i], + BestFitCount[i]); + } + }else{ + 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, double meanRange = 0){ + + printf("=========================================================\n"); + printf("======== fit n-Gauss + Pol-%d BG using mouse click =====\n", degPol ); + printf("==========================================================\n"); + + recentFitMethod = "clickFitNGaussPol"; + + 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); + + if( meanRange <= 0 ) { + 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 ); + }else{ + fit->SetParLimits(3*i+1, xPeakList[i] - meanRange/2. , xPeakList[i] + meanRange/2. ); + } + 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")); + + BestFitCount.clear(); + BestFitMean.clear(); + BestFitSigma.clear(); + + 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])); + + BestFitCount.push_back(paraA[3*i]/ bw); + BestFitMean.push_back(paraA[3*i+1]); + BestFitSigma.push_back(paraA[3*i+2]); + } + +} + + + +void clickFitNGaussPolSub(TH1F * hist, int degPol, double sigmaMax = 0, double meanRange = 0){ + + printf("=========================================================\n"); + printf("= fit n-Gauss + Pol-%d BG using mouse click (method-2) =\n", degPol ); + printf("==========================================================\n"); + + recentFitMethod = "clickFitNGaussPolSub"; + + 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); + + if( meanRange <= 0 ) { + 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 ); + }else{ + fit->SetParLimits(3*i+1, xPeakList[i] - meanRange/2. , xPeakList[i] + meanRange/2. ); + } + 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")); + + BestFitCount.clear(); + BestFitMean.clear(); + BestFitSigma.clear(); + + 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])); + + BestFitCount.push_back(paraA[3*i]/ bw); + BestFitMean.push_back(paraA[3*i+1]); + BestFitSigma.push_back(paraA[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/ClassDetGeo.h b/Armory/ClassDetGeo.h new file mode 100644 index 0000000..1bae2a1 --- /dev/null +++ b/Armory/ClassDetGeo.h @@ -0,0 +1,257 @@ +#ifndef ClassDetGeo_H +#define ClassDetGeo_H + +#include /// for FILE +#include +#include +#include +#include + +#include "TMath.h" +#include "TString.h" +#include "TMacro.h" + +#include "AnalysisLib.h" + +struct Array{ + + double detPerpDist; /// distance from axis + double detWidth; /// width + double detLength; /// length + double blocker; + double firstPos; /// meter + double eSigma; /// intrinsic energy resolution MeV + double zSigma; /// intrinsic position resolution mm + bool detFaceOut; ///detector_facing_Out_or_In + std::vector pos; /// near position in meter + int nDet, mDet; /// nDet = number of different pos, mDet, number of same pos + std::vector detPos; ///absolute position of detector + + double zMin, zMax; + + void DeduceAbsolutePos(){ + nDet = pos.size(); + detPos.clear(); + + for(int id = 0; id < nDet; id++){ + if( firstPos > 0 ) detPos.push_back(firstPos + pos[id]); + if( firstPos < 0 ) detPos.push_back(firstPos - pos[nDet - 1 - id]); + ///printf("%d | %f, %f \n", id, pos[id], detPos[id]); + } + + zMin = TMath::Min(detPos.front(), detPos.back()) - (firstPos < 0 ? detLength : 0); + zMax = TMath::Max(detPos.front(), detPos.back()) + (firstPos > 0 ? detLength : 0); + } + + void PrintArray() const{ + for(int i = 0; i < nDet ; i++){ + if( firstPos > 0 ){ + printf("%d, %8.2f mm - %8.2f mm \n", i, detPos[i], detPos[i] + detLength); + }else{ + printf("%d, %8.2f mm - %8.2f mm \n", i, detPos[i] - detLength , detPos[i]); + } + } + + printf(" Blocker Position: %8.2f mm \n", firstPos > 0 ? firstPos - blocker : firstPos + blocker ); + printf(" First Position: %8.2f mm \n", firstPos); + printf(" number of det : %d x %d \n", mDet, nDet); + printf(" detector facing : %s\n", detFaceOut ? "Out" : "In"); + printf(" energy resol.: %f MeV\n", eSigma); + printf(" pos-Z resol.: %f mm \n", zSigma); + } + +}; + +class DetGeo { + +public: + DetGeo(); + ~DetGeo(); + + double Bfield; /// T + int BfieldSign ; /// sign of B-field + double BfieldTheta; /// rad, 0 = z-axis, pi/2 = y axis, pi = -z axis + double bore; /// bore , mm + + double recoilPos; /// recoil, downstream + double recoilInnerRadius; /// radius recoil inner + double recoilOuterRadius; /// radius recoil outter + + double recoilPos1, recoilPos2; /// imaginary recoils + + double elumPos1, elumPos2; /// imaginary elum, only sensitive to light recoil + + //===================1st array + Array array1; + + //==================2nd array + bool use2ndArray; + Array array2; + + double zMin, zMax; /// range of detectors + bool isCoincidentWithRecoil; + + bool LoadDetectorGeo(TString fileName); + bool LoadDetectorGeo(TMacro * macro); + + void PrintDetGeo( bool printAll = true) const; + +private: + +}; + +inline DetGeo::DetGeo(){ + +} + +inline DetGeo::~DetGeo(){ + +} + +inline bool DetGeo::LoadDetectorGeo(TString fileName){ + + TMacro * haha = new TMacro(); + if( haha->ReadFile(fileName) > 0 ) { + if( LoadDetectorGeo(haha) ){ + return true; + }else{ + return false; + } + }else{ + return false; + } +} + +///Using TMacro to load the detectorGeo frist, +///this indrect method is good for loading detectorGeo from TMacro in root file +inline bool DetGeo::LoadDetectorGeo(TMacro * macro){ + + if( macro == NULL ) return false; + + TList * haha = macro->GetListOfLines(); + int numLine = (haha)->GetSize(); + + array1.pos.clear(); + array2.pos.clear(); + use2ndArray = false; + + int detFlag = 0; + int detLine = 0; + + for( int i = 0 ; i < numLine; i++){ + + std::vector str = AnalysisLib::SplitStr(macro->GetListOfLines()->At(i)->GetName(), " "); + + //printf("%3d | %s\n", i, str[0].c_str()); + + if( str[0].find("####") != std::string::npos ) break; + if( str[0].find("#===") != std::string::npos ) { + detFlag ++; + detLine = 0; + continue;; + } + + if( detFlag == 0 ){ + if ( i == 0 ) { + Bfield = atof(str[0].c_str()); + BfieldSign = Bfield > 0 ? 1: -1; + } + if ( i == 1 ) BfieldTheta = atof(str[0].c_str()); + if ( i == 2 ) bore = atof(str[0].c_str()); + if ( i == 3 ) recoilPos = atof(str[0].c_str()); + if ( i == 4 ) recoilInnerRadius = atof(str[0].c_str()); + if ( i == 5 ) recoilOuterRadius = atof(str[0].c_str()); + if ( i == 6 ) isCoincidentWithRecoil = str[0] == "false" ? false: true; + if ( i == 7 ) recoilPos1 = atof(str[0].c_str()); + if ( i == 8 ) recoilPos2 = atof(str[0].c_str()); + if ( i == 9 ) elumPos1 = atof(str[0].c_str()); + if ( i == 10 ) elumPos2 = atof(str[0].c_str()); + } + + if( detFlag == 1){ + if ( detLine == 0 ) array1.detPerpDist = atof(str[0].c_str()); + if ( detLine == 1 ) array1.detWidth = atof(str[0].c_str()); + if ( detLine == 2 ) array1.detLength = atof(str[0].c_str()); + if ( detLine == 3 ) array1.blocker = atof(str[0].c_str()); + if ( detLine == 4 ) array1.firstPos = atof(str[0].c_str()); + if ( detLine == 5 ) array1.eSigma = atof(str[0].c_str()); + if ( detLine == 6 ) array1.zSigma = atof(str[0].c_str()); + if ( detLine == 7 ) array1.detFaceOut = str[0] == "Out" ? true : false; + if ( detLine == 8 ) array1.mDet = atoi(str[0].c_str()); + if ( detLine >= 9 ) array1.pos.push_back(atof(str[0].c_str())); + detLine ++; + } + + if( detFlag == 2){ + if ( detLine == 0 ) use2ndArray = str[0] == "true" ? true : false; + if ( detLine == 1 ) array2.detPerpDist = atof(str[0].c_str()); + if ( detLine == 2 ) array2.detWidth = atof(str[0].c_str()); + if ( detLine == 3 ) array2.detLength = atof(str[0].c_str()); + if ( detLine == 4 ) array2.blocker = atof(str[0].c_str()); + if ( detLine == 5 ) array2.firstPos = atof(str[0].c_str()); + if ( detLine == 6 ) array2.eSigma = atof(str[0].c_str()); + if ( detLine == 7 ) array2.zSigma = atof(str[0].c_str()); + if ( detLine == 8 ) array2.detFaceOut = str[0] == "Out" ? true : false; + if ( detLine == 9 ) array2.mDet = atoi(str[0].c_str()); + if ( detLine >= 10 ) array2.pos.push_back(atof(str[0].c_str())); + detLine ++; + } + + } + + array1.DeduceAbsolutePos(); + + zMin = array1.zMin; + zMax = array1.zMax; + + if( use2ndArray) { + array2.DeduceAbsolutePos(); + + zMax = TMath::Min(array1.zMax, array2.zMax); + zMin = TMath::Min(array1.zMin, array2.zMin); + } + + PrintDetGeo(false); + + return true; + +} + +inline void DetGeo::PrintDetGeo(bool printAll) const{ + + printf("=====================================================\n"); + printf(" B-field: %8.2f T, Theta : %6.2f deg \n", Bfield, BfieldTheta); + if( BfieldTheta != 0.0 ) { + printf(" +---- field angle != 0 is not supported!!! \n"); + } + printf(" Recoil detector pos: %8.2f mm, radius: %6.2f - %6.2f mm \n", recoilPos, recoilInnerRadius, recoilOuterRadius); + if( printAll ){ + printf("------------------------------------- Detector Position \n"); + array1.PrintArray(); + + if( use2ndArray){ + printf("--------------------------------- 2nd Detector Position \n"); + array2.PrintArray(); + } + }else{ + if( use2ndArray){ + printf("--------------------------------- 2nd Detector Position \n"); + array2.PrintArray(); + }else{ + printf("------------------------------------- Detector Position \n"); + array1.PrintArray(); + } + } + + if( elumPos1 != 0 || elumPos2 != 0 || recoilPos1 != 0 || recoilPos2 != 0){ + printf("=================================== Auxillary/Imaginary Detectors\n"); + } + if( elumPos1 != 0 ) printf(" Elum 1 pos.: %f mm \n", elumPos1); + if( elumPos2 != 0 ) printf(" Elum 2 pos.: %f mm \n", elumPos2); + if( recoilPos1 != 0 ) printf(" Recoil 1 pos.: %f mm \n", recoilPos1); + if( recoilPos2 != 0 ) printf(" Recoil 2 pos.: %f mm \n", recoilPos2); + printf("=====================================================\n"); + +} + +#endif \ No newline at end of file diff --git a/Armory/ClassReactionConfig.h b/Armory/ClassReactionConfig.h new file mode 100644 index 0000000..ebab454 --- /dev/null +++ b/Armory/ClassReactionConfig.h @@ -0,0 +1,190 @@ +#ifndef ClassReactionConfig_H +#define ClassReactionConfig_H + +#include /// for FILE +#include +#include +#include +#include + +#include "TMath.h" +#include "TString.h" +#include "TMacro.h" + +#include "AnalysisLib.h" + +class ReactionConfig { + +public: + ReactionConfig(){} + ~ReactionConfig(){} + + int beamA, beamZ; + int targetA, targetZ; + int recoilLightA, recoilLightZ; + int recoilHeavyA, recoilHeavyZ; + + float beamEnergy; ///MeV/u + float beamEnergySigma; ///beam-energy_sigma_in_MeV/u + float beamAngle; ///beam-angle_in_mrad + float beamAngleSigma; ///beam-emittance_in_mrad + float beamX; ///x_offset_of_Beam_in_mm + float beamY; ///y_offset_of_Beam_in_mm + + int numEvents; ///number_of_Event_being_generated + bool isTargetScattering; ///isTargetScattering + float targetDensity; ///target_density_in_g/cm3 + float targetThickness; ///targetThickness_in_cm + std::string beamStoppingPowerFile; ///stopping_power_for_beam + std::string recoilLightStoppingPowerFile; ///stopping_power_for_light_recoil + std::string recoilHeavyStoppingPowerFile; ///stopping_power_for_heavy_recoil + bool isDecay; ///isDacay + int heavyDecayA; ///decayNucleus_A + int heavyDecayZ; ///decayNucleus_Z + bool isRedo; ///isReDo + std::vector beamEx; ///excitation_energy_of_A[MeV] + + void SetReactionSimple(int beamA, int beamZ, + int targetA, int targetZ, + int recoilA, int recoilZ, float beamEnergy_AMeV); + + bool LoadReactionConfig(TString fileName); + bool LoadReactionConfig(TMacro * macro); + + void PrintReactionConfig() const; + +private: + +}; + +inline void ReactionConfig::SetReactionSimple(int beamA, int beamZ, + int targetA, int targetZ, + int recoilA, int recoilZ, float beamEnergy_AMeV){ + + this->beamA = beamA; + this->beamZ = beamZ; + this->targetA = targetA; + this->targetZ = targetZ; + this->recoilLightA = recoilA; + this->recoilLightZ = recoilZ; + recoilHeavyA = this->beamA + this->targetA - recoilLightA; + recoilHeavyZ = this->beamZ + this->targetZ - recoilLightZ; + + beamEnergy = beamEnergy_AMeV; + beamEnergySigma = 0; + beamAngle = 0; + beamAngleSigma = 0; + beamX = 0; + beamY = 0; + +} + +inline bool ReactionConfig::LoadReactionConfig(TString fileName){ + TMacro * haha = new TMacro(); + if( haha->ReadFile(fileName) > 0 ) { + if( LoadReactionConfig(haha) ){ + return true; + }else{ + return false; + } + }else{ + return false; + } +} + +inline bool ReactionConfig::LoadReactionConfig(TMacro * macro){ + + if( macro == NULL ) return false; + + int numLine = macro->GetListOfLines()->GetSize(); + + for( int i = 0; i < numLine; i ++){ + + std::vector str =AnalysisLib::SplitStr(macro->GetListOfLines()->At(i)->GetName(), " "); + + ///printf("%d | %s\n", i, str[0].c_str()); + + if( str[0].find_first_of("#") == 0 ) break; + + if( i == 0 ) beamA = atoi(str[0].c_str()); + if( i == 1 ) beamZ = atoi(str[0].c_str()); + if( i == 2 ) targetA = atoi(str[0].c_str()); + if( i == 3 ) targetZ = atoi(str[0].c_str()); + if( i == 4 ) recoilLightA = atoi(str[0].c_str()); + if( i == 5 ) recoilLightZ = atoi(str[0].c_str()); + if( i == 6 ) beamEnergy = atof(str[0].c_str()); + if( i == 7 ) beamEnergySigma = atof(str[0].c_str()); + if( i == 8 ) beamAngle = atof(str[0].c_str()); + if( i == 9 ) beamAngleSigma = atof(str[0].c_str()); + if( i == 10 ) beamX = atof(str[0].c_str()); + if( i == 11 ) beamY = atof(str[0].c_str()); + if( i == 12 ) numEvents = atoi(str[0].c_str()); + if( i == 13 ) { + if( str[0].compare("false") == 0 ) isTargetScattering = false; + if( str[0].compare("true") == 0 ) isTargetScattering = true; + } + if( i == 14 ) targetDensity = atof(str[0].c_str()); + if( i == 15 ) targetThickness = atof(str[0].c_str()); + if( i == 16 ) beamStoppingPowerFile = str[0]; + if( i == 17 ) recoilLightStoppingPowerFile = str[0]; + if( i == 18 ) recoilHeavyStoppingPowerFile = str[0]; + if( i == 19 ) { + if( str[0].compare("false") == 0 ) isDecay = false; + if( str[0].compare("true") == 0 ) isDecay = true; + } + if( i == 20 ) heavyDecayA = atoi(str[0].c_str()); + if( i == 21 ) heavyDecayZ = atoi(str[0].c_str()); + if( i == 22 ) { + if( str[0].compare("false") == 0 ) isRedo = false; + if( str[0].compare("true" ) == 0 ) isRedo = true; + } + + if( i >= 23) { + beamEx.push_back( atof(str[0].c_str()) ); + } + } + + recoilHeavyA = beamA + targetA - recoilLightA; + recoilHeavyZ = beamZ + targetZ - recoilLightZ; + + return true; +} + +inline void ReactionConfig::PrintReactionConfig() const{ + + printf("=====================================================\n"); + printf(" beam : A = %3d, Z = %2d \n", beamA, beamZ); + printf(" target : A = %3d, Z = %2d \n", targetA, targetZ); + printf(" light : A = %3d, Z = %2d \n", recoilLightA, recoilLightZ); + + printf(" beam Energy : %.2f +- %.2f MeV/u, dE/E = %5.2f %%\n", beamEnergy, beamEnergySigma, beamEnergySigma/beamEnergy); + printf(" Angle : %.2f +- %.2f mrad\n", beamAngle, beamAngleSigma); + printf(" offset : (x,y) = (%.2f, %.2f) mmm \n", beamX, beamY); + + printf("##### number of Simulation Events : %d \n", numEvents); + + printf(" is target scattering : %s \n", isTargetScattering ? "Yes" : "No"); + + if(isTargetScattering){ + printf(" target density : %.f g/cm3\n", targetDensity); + printf(" thickness : %.f cm\n", targetThickness); + printf(" beam stopping file : %s \n", beamStoppingPowerFile.c_str()); + printf(" recoil light stopping file : %s \n", recoilLightStoppingPowerFile.c_str()); + printf(" recoil heavy stopping file : %s \n", recoilHeavyStoppingPowerFile.c_str()); + } + + printf(" is simulate decay : %s \n", isDecay ? "Yes" : "No"); + if( isDecay ){ + printf(" heavy decay : A = %d, Z = %d \n", heavyDecayA, heavyDecayZ); + } + printf(" is Redo until hit array : %s \n", isRedo ? "Yes" : "No"); + + printf(" beam Ex : %.2f MeV \n", beamEx[0]); + for( int i = 1; i < (int) beamEx.size(); i++){ + printf(" %.2f MeV \n", beamEx[i]); + } + + printf("=====================================================\n"); +} + +#endif \ No newline at end of file diff --git a/Armory/EventBuilder.cpp b/Armory/EventBuilder.cpp new file mode 100644 index 0000000..13a0f0f --- /dev/null +++ b/Armory/EventBuilder.cpp @@ -0,0 +1,351 @@ +#include "SolReader.h" +#include +#include + +#include "TFile.h" +#include "TTree.h" +#include "TMath.h" +#include "TString.h" +#include "TMacro.h" +//#include "TClonesArray.h" // plan to save trace as TVector with TClonesArray +//#include "TVector.h" + +#define MAX_MULTI 64 +#define MAX_TRACE_LEN 2500 + +#define tick2ns 8 // 1 tick = 8 ns + +SolReader ** reader; +Hit ** hit; + +std::vector> idList; + +unsigned long totFileSize = 0; +unsigned long processedFileSize = 0; + +std::vector activeFileID; +std::vector groupIndex; +std::vector> group; // group[i][j], i = group ID, j = group member) + +void findEarliestTime(int &fileID, int &groupID){ + + unsigned long firstTime = 0; + for( int i = 0; i < (int) activeFileID.size(); i++){ + int id = activeFileID[i]; + if( i == 0 ) { + firstTime = hit[id]->timestamp; + fileID = id; + groupID = i; + //printf("%d | %d %lu %d | %d \n", id, reader[id]->GetBlockID(), hit[id]->timestamp, hit[id]->channel, (int) activeFileID.size()); + continue; + } + if( hit[id]->timestamp <= firstTime) { + firstTime = hit[id]->timestamp; + fileID = id; + groupID = i; + //printf("%d | %d %lu %d | %d \n", id, reader[id]->GetBlockID(), hit[id]->timestamp, hit[id]->channel, (int) activeFileID.size()); + } + } + +} + +unsigned long long evID = 0; +unsigned int multi = 0; +unsigned short bd[MAX_MULTI] = {0}; +unsigned short sn[MAX_MULTI] = {0}; +unsigned short ch[MAX_MULTI] = {0}; +unsigned short e[MAX_MULTI] = {0}; +unsigned short e2[MAX_MULTI] = {0}; //for PSD energy short +unsigned long long e_t[MAX_MULTI] = {0}; +unsigned short e_f[MAX_MULTI] = {0}; +unsigned short lowFlag[MAX_MULTI] = {0}; +unsigned short highFlag[MAX_MULTI] = {0}; +int traceLen[MAX_MULTI] = {0}; +int trace[MAX_MULTI][MAX_TRACE_LEN] = {0}; + +void fillData(int &fileID, const bool &saveTrace){ + bd[multi] = idList[fileID][1]; + sn[multi] = idList[fileID][3]; + ch[multi] = hit[fileID]->channel; + e[multi] = hit[fileID]->energy; + e2[multi] = hit[fileID]->energy_short; + e_t[multi] = hit[fileID]->timestamp; + e_f[multi] = hit[fileID]->fine_timestamp; + lowFlag[multi] = hit[fileID]->flags_low_priority; + highFlag[multi] = hit[fileID]->flags_high_priority; + + if( saveTrace ){ + traceLen[multi] = hit[fileID]->traceLenght; + for( int i = 0; i < TMath::Min(traceLen[multi], MAX_TRACE_LEN); i++){ + trace[multi][i] = hit[fileID]->analog_probes[0][i]; + } + } + + multi++; + reader[fileID]->ReadNextBlock(); +} + +void printEvent(){ + printf("==================== evID : %llu\n", evID); + for( int i = 0; i < multi; i++){ + printf(" %2d | %d %d | %llu %d \n", i, bd[i], ch[i], e_t[i], e[i] ); + } + printf("==========================================\n"); +} + +//^################################################################################## +int main(int argc, char ** argv){ + + printf("=======================================================\n"); + printf("=== SOLARIS Event Builder sol --> root ===\n"); + printf("=======================================================\n"); + + if( argc <= 3){ + printf("%s [outfile] [timeWindow] [saveTrace] [sol-1] [sol-2] ... \n", argv[0]); + printf(" outfile : output root file name\n"); + printf(" timeWindow : number of tick, 1 tick = %d ns.\n", tick2ns); + printf(" saveTrace : 1 = save trace, 0 = no trace\n"); + printf(" sol-X : the sol file(s)\n"); + return -1; + } + + // for( int i = 0; i < argc; i++){ + // printf("%d | %s\n", i, argv[i]); + // } + + TString outFileName = argv[1]; + int timeWindow = abs(atoi(argv[2])); + const bool saveTrace = atoi(argv[3]); + + const int nFile = argc - 4; + TString inFileName[nFile]; + for( int i = 0 ; i < nFile ; i++){ + inFileName[i] = argv[i+4]; + } + + //*======================================== setup reader + reader = new SolReader*[nFile]; + hit = new Hit *[nFile]; + + for( int i = 0 ; i < nFile ; i++){ + reader[i] = new SolReader(inFileName[i].Data()); + hit[i] = reader[i]->hit; //TODO check is file open propertly + reader[i]->ReadNextBlock(); // read the first block + } + + //*======================================== group files + idList.clear(); + for( int i = 0; i < nFile; i++){ + TString fn = inFileName[i]; + + int pos = fn.Last('/'); // path + fn.Remove(0, pos+1); + + pos = fn.First('_'); // expName; + fn.Remove(0, pos+1); + + pos = fn.First('_'); // runNum; + fn.Remove(0, pos+1); + + pos = fn.First('_'); // digiID + TString f1 = fn; + int digiID = f1.Remove(pos).Atoi(); + fn.Remove(0, pos+1); + + pos = fn.Last('_'); // digi serial num + f1 = fn; + int digisn = f1.Remove(pos).Atoi(); + fn.Remove(0, pos+1); + + pos = fn.First('.'); // get the file id; + int indexID = fn.Remove(pos).Atoi(); + + int fileID = i; + std::vector haha = {fileID, digiID, indexID, digisn}; + idList.push_back(haha); + } + + // sort by digiID + std::sort(idList.begin(), idList.end(), [](const std::vector& a, const std::vector& b){ + if (a[1] == b[1]) { + return a[2] < b[2]; + } + return a[1] < b[1]; + }); + + group.clear(); // group[i][j], i is the group Index = digiID + int last_id = 0; + std::vector kaka; + for( int i = 0; i < (int) idList.size() ; i++){ + if( i == 0 ) { + kaka.clear(); + last_id = idList[i][1]; + kaka.push_back(idList[i][0]); + continue; + } + + if( idList[i][1] != last_id ) { + last_id = idList[i][1]; + group.push_back(kaka); + kaka.clear(); + kaka.push_back(idList[i][0]); + }else{ + kaka.push_back(idList[i][0]); + } + } + group.push_back(kaka); + + printf(" out file : \033[1;33m%s\033[m\n", outFileName.Data()); + printf(" Event building time window : %d tics = %d nsec \n", timeWindow, timeWindow*tick2ns); + printf(" Save Trace ? %s \n", saveTrace ? "Yes" : "No"); + printf(" Number of input file : %d \n", nFile); + for( int i = 0; i < nFile; i++){ + printf(" %2d| %5.1f MB| %s \n", i, reader[i]->GetFileSize()/1024./1024., inFileName[i].Data()); + totFileSize += reader[i]->GetFileSize(); + } + printf("------------------------------------\n"); + for( int i = 0; i < (int) group.size(); i++){ + printf("Group %d :", i); + for( int j = 0; j < (int) group[i].size(); j ++){ + printf("%d, ", group[i][j]); + } + printf("\n"); + } + printf("------------------------------------\n"); + + //*======================================== setup tree + TFile * outRootFile = new TFile(outFileName, "recreate"); + outRootFile->cd(); + + TTree * tree = new TTree("tree", outFileName); + + tree->Branch("evID", &evID, "event_ID/l"); + tree->Branch("multi", &multi, "multi/i"); + tree->Branch("bd", bd, "board[multi]/s"); + tree->Branch("sn", sn, "sn[multi]/s"); + tree->Branch("ch", ch, "channel[multi]/s"); + tree->Branch("e", e, "energy[multi]/s"); + tree->Branch("e2", e2, "energy_short[multi]/s"); + tree->Branch("e_t", e_t, "timestamp[multi]/l"); + tree->Branch("e_f", e_f, "fine_timestamp[multi]/s"); + tree->Branch("lowFlag", lowFlag, "lowFlag[multi]/s"); + tree->Branch("highFlag", highFlag, "highFlag[multi]/s"); + + if( saveTrace){ + tree->Branch("tl", traceLen, "traceLen[multi]/I"); + tree->Branch("trace", trace, Form("trace[multi][%d]/I", MAX_TRACE_LEN)); + } + + //*=========================================== build event + + //@---- using file from group[i][0] first + + //--- find earlist time among the files + activeFileID.clear(); + groupIndex.clear(); //the index of each group + + for(int i = 0; i < (int) group.size(); i++) { + groupIndex.push_back(0); + activeFileID.push_back(group[i][0]); + } + + int fileID = 0; + int groupID = 0; + findEarliestTime(fileID, groupID); + fillData(fileID, saveTrace); + + unsigned long firstTimeStamp = hit[fileID]->timestamp; + unsigned long lastTimeStamp = 0; + + int last_precentage = 0; + while((activeFileID.size() > 0)){ + + findEarliestTime(fileID, groupID); + if( reader[fileID]->IsEndOfFile() ){ + groupIndex[groupID] ++; + if( groupIndex[groupID] < (int) group[groupID].size() ){ + activeFileID[groupID] = group[groupID][groupIndex[groupID]]; + fileID = activeFileID[groupID]; + }else{ + activeFileID.erase(activeFileID.begin() + groupID); + } + } + + if( hit[fileID]->timestamp - e_t[0] < timeWindow ){ + fillData(fileID, saveTrace); + }else{ + outRootFile->cd(); + tree->Fill(); + evID ++; + + multi = 0; + fillData(fileID, saveTrace); + } + + ///========= calculate progress + processedFileSize = 0; + for( int p = 0; p < (int) group.size(); p ++){ + for( int q = 0; q <= groupIndex[p]; q++){ + if( groupIndex[p] < (int) group[p].size() ){ + int id = group[p][q]; + processedFileSize += reader[id]->GetFilePos(); + } + } + } + double percentage = processedFileSize * 100/ totFileSize; + if( percentage >= last_precentage ) { + printf("Processed : %llu, %.0f%% | %lu/%lu | ", evID, percentage, processedFileSize, totFileSize); + for( int i = 0; i < (int) activeFileID.size(); i++) printf("%d, ", activeFileID[i]); + printf(" \n\033[A\r"); + last_precentage = percentage + 1.0; + } + }; ///====== end of event building loop + + processedFileSize = 0; + for( int p = 0; p < (int) group.size(); p ++){ + for( int q = 0; q < (int) group[p].size(); q++){ + int id = group[p][q]; + processedFileSize += reader[id]->GetFilePos(); + } + } + double percentage = processedFileSize * 100/ totFileSize; + printf("Processed : %llu, %.0f%% | %lu/%lu \n", evID, percentage, processedFileSize, totFileSize); + + lastTimeStamp = hit[fileID]->timestamp; + //*=========================================== save file + outRootFile->cd(); + tree->Fill(); + evID ++; + tree->Write(); + + //*=========================================== Save timestamp as TMacro + TMacro timeStamp; + TString str; + str.Form("%lu", firstTimeStamp); timeStamp.AddLine( str.Data() ); + str.Form("%lu", lastTimeStamp); timeStamp.AddLine( str.Data() ); + timeStamp.Write("timeStamp"); + + unsigned int numBlock = 0; + for( int i = 0; i < nFile; i++){ + //printf("%d | %8ld | %10u/%10u\n", i, reader[i]->GetBlockID() + 1, reader[i]->GetFilePos(), reader[i]->GetFileSize()); + numBlock += reader[i]->GetBlockID() + 1; + } + + printf("===================================== done. \n"); + printf("Number of Block Scanned : %u\n", numBlock); + printf(" Number of Event Built : %lld\n", evID); + printf(" Output Root File Size : %.2f MB\n", outRootFile->GetSize()/1024./1024.); + printf(" first timestamp : %lu \n", firstTimeStamp); + printf(" last timestamp : %lu \n", lastTimeStamp); + unsigned long duration = lastTimeStamp - firstTimeStamp; + printf(" total duration : %lu = %.2f sec \n", duration, duration * tick2ns * 1.0 / 1e9 ); + printf("===================================== end of summary. \n"); + + + //^############## delete new + for( int i = 0; i < nFile; i++) delete reader[i]; + delete [] reader; + outRootFile->Close(); + + return 0; +} \ No newline at end of file diff --git a/Armory/EventBuilder.dSYM/Contents/Info.plist b/Armory/EventBuilder.dSYM/Contents/Info.plist new file mode 100644 index 0000000..079f8bf --- /dev/null +++ b/Armory/EventBuilder.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.EventBuilder + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Armory/GeneralSort.C b/Armory/GeneralSort.C new file mode 100644 index 0000000..b8729a9 --- /dev/null +++ b/Armory/GeneralSort.C @@ -0,0 +1,205 @@ +#define GeneralSort_cxx + +#include +#include +#include + +#include "GeneralSort.h" + +#include +#include +#include +#include +#include + +Long64_t processedEntry = 0; +float lastPercentage = 0; + +//^############################################################## +Bool_t GeneralSort::Process(Long64_t entry){ + + if( entry < 1 ) printf("============================== start processing data\n"); + + ///initialization + for( int i = 0; i < mapping::nDetType; i++){ + for( int j = 0; j < mapping::detNum[i]; j++){ + eE[i][j] = TMath::QuietNaN(); + eT[i][j] = 0; + + if( isTraceExist && traceMethod > 0){ + teE[i][j] = TMath::QuietNaN(); + teT[i][j] = TMath::QuietNaN(); + teR[i][j] = TMath::QuietNaN(); + } + } + } + + multi = 0; + b_event_ID->GetEntry(entry); + b_multi->GetEntry(entry); + b_bd->GetEntry(entry); + b_ch->GetEntry(entry); + b_e->GetEntry(entry); + b_e_t->GetEntry(entry); + + for( int i = 0 ; i < multi; i++){ + int detID = mapping::map[bd[i]][ch[i]]; + int detType = mapping::FindDetTypeIndex(detID); + int low = (i == 0 ? 0 : mapping::detMaxID[detType-1]); + int reducedDetID = detID - low; + + eE[detType][reducedDetID] = e[i] * mapping::detParity[detType]; + eT[detType][reducedDetID] = e_t[i]; + + } + + //@===================================== Trace + if( isTraceExist && traceMethod >= 0 ){ + + b_tl->GetEntry(entry); + b_trace->GetEntry(entry); + + int countTrace = 0; + + arr->Clear("C"); + + for( int i = 0; i < multi; i++){ + int detID = mapping::map[bd[i]][ch[i]]; + + + int traceLength = tl[i]; + gTrace = (TGraph*) arr->ConstructedAt(countTrace, "C"); + gTrace->Clear(); + gTrace->Set(traceLength); + + gTrace->SetTitle(Form("ev:%llu,nHit:%d,id:%d,len:%d", evID, i, detID, traceLength)); + countTrace ++; + + for( int k = 0 ; k < traceLength; k++){ + gTrace->SetPoint(k, k, trace[i][k]); + } + + //***=================== fit + if( traceMethod == 1){ + + int detType = mapping::FindDetTypeIndex(detID); + //TODO use a blackList + //if( mapping::detTypeName[detType] != "rdt") continue; + + //TODO try custom build fiting algorithm. May be faster? + gFit = new TF1("gFit", fitFunc, 0, traceLength, numPara); + gFit->SetLineColor(6); + gFit->SetRange(0, traceLength); + + gFit->SetParameter(0, e[i]); + gFit->SetParameter(1, 100); //triggerTime //TODO how to not hardcode? + gFit->SetParameter(2, 10); //rise time //TODO how to not hardcode? + gFit->SetParameter(3, trace[i][0]); //base line + gFit->SetParameter(4, 100); // decay //TODO how to not hardcode? + gFit->SetParameter(5, -0.01); // pre-rise slope //TODO how to not hardcode? + + gFit->SetParLimits(1, 85, 125); //raneg for the trigger time + gFit->SetParLimits(5, -2, 0); + + gTrace->Fit("gFit", "QR", "", 0, traceLength); + + int low = (i == 0 ? 0 : mapping::detMaxID[detType-1]); + int reducedDetID = detID - low; + + teE[detType][reducedDetID] = gFit->GetParameter(0); + teT[detType][reducedDetID] = gFit->GetParameter(1); + teR[detType][reducedDetID] = gFit->GetParameter(2); + + delete gFit; + gFit = nullptr; + } + + //***=================== Trapezoid filter + if( traceMethod == 2){ + //TODO + } + + } + + } + + if( !isParallel){ + processedEntry ++; + float percentage = processedEntry*100/NumEntries; + if( percentage >= lastPercentage ) { + TString msg; msg.Form("%lu", NumEntries); + int len = msg.Sizeof(); + printf("Processed : %*lld, %3.0f%% | Elapsed %6.1f sec | expect %6.1f sec\n\033[A\r", len, entry, percentage, stpWatch.RealTime(), stpWatch.RealTime()/percentage*100); + stpWatch.Start(kFALSE); + lastPercentage = percentage + 1.0; + if( lastPercentage >= 100) printf("\n"); + + } + } + + newSaveTree->Fill(); + + return kTRUE; +} + +//^############################################################## +void GeneralSort::Terminate(){ + + printf("=============================== %s\n", __func__); + + DecodeOption(); + + if( !isParallel){ + stpWatch.Start(kFALSE); + saveFile->cd(); + newSaveTree->Print("toponly"); + newSaveTree->Write(); + saveFile->Close(); + } + + //get entries + saveFile = TFile::Open(saveFileName); + if( saveFile->IsOpen() ){ + TTree * tree = (TTree*) saveFile->FindObjectAny("gen_tree"); + int validCount = tree->GetEntries(); + + saveFile->Close(); + + printf("=========================================================================\n"); + PrintTraceMethod(); + printf("----- saved as \033[1;33m%s\033[0m. valid event: %d\n", saveFileName.Data() , validCount); + printf("=========================================================================\n"); + } +} + +//^############################################################## +void GeneralSort::Begin(TTree * tree){ + + printf( "=================================================================\n"); + printf( "===================== SOLARIS GeneralSort.C =================\n"); + printf( "=================================================================\n"); + + mapping::PrintMapping(); + + DecodeOption(); + if(!isParallel) { + tree->GetEntriesFast(); + stpWatch.Start(); + } + +} + +void GeneralSort::SlaveBegin(TTree * /*tree*/){ + +} + +void GeneralSort::SlaveTerminate(){ + if( isParallel){ + printf("%s::SaveTree\n", __func__); + saveFile->cd(); + newSaveTree->Write(); + fOutput->Add(proofFile); + saveFile->Close(); + } + +} \ No newline at end of file diff --git a/Armory/GeneralSort.h b/Armory/GeneralSort.h new file mode 100644 index 0000000..632ed7f --- /dev/null +++ b/Armory/GeneralSort.h @@ -0,0 +1,362 @@ +#ifndef GeneralSort_h +#define GeneralSort_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//^######################################### Skip list for trace fitting +//TODO + +/*********************************======= + +the sequence of each method + +1) Begin (master, stdout) + 2) SlaveBegin (slave) + 3) Init + 4) Notify + 5) Process (looping each event) + 6) SlaveTerminate +7) Terminate + +// variable in the Master will not pass to Slave + +******************************************/ + +/// in Process_Sort, copy the Mapping.h to ~/.proof/working/ +#include "../working/Mapping.h" + +//^######################################### FIT FUNCTION +const int numPara = 6; +double fitFunc(double * x, double * par){ + /// par[0] = A + /// par[1] = t0 + /// par[2] = rise time + /// par[3] = baseline + /// par[4] = decay + /// par[5] = pre-rise slope + + if( x[0] < par[1] ) return par[3] + par[5] * (x[0]-par[1]); + + return par[3] + par[0] * (1 - TMath::Exp(- (x[0] - par[1]) / par[2]) ) * TMath::Exp(- (x[0] - par[1]) / par[4]); +} + +//^######################################### TRAPEZOID +TGraph * TrapezoidFilter(TGraph * trace){ + ///Trapezoid filter https://doi.org/10.1016/0168-9002(94)91652-7 + + //TODO how to not hard code? + int baseLineEnd = 80; + int riseTime = 10; //ch + int flatTop = 20; + float decayTime = 2000; + + TGraph * trapezoid = new TGraph(); + trapezoid->Clear(); + + ///find baseline; + double baseline = 0; + for( int i = 0; i < baseLineEnd; i++){ + baseline += trace->Eval(i); + } + baseline = baseline*1./baseLineEnd; + + int length = trace->GetN(); + + double pn = 0.; + double sn = 0.; + for( int i = 0; i < length ; i++){ + + double dlk = trace->Eval(i) - baseline; + if( i - riseTime >= 0 ) dlk -= trace->Eval(i - riseTime) - baseline; + if( i - flatTop - riseTime >= 0 ) dlk -= trace->Eval(i - flatTop - riseTime) - baseline; + if( i - flatTop - 2*riseTime >= 0) dlk += trace->Eval(i - flatTop - 2*riseTime) - baseline; + + if( i == 0 ){ + pn = dlk; + sn = pn + dlk*decayTime; + }else{ + pn = pn + dlk; + sn = sn + pn + dlk*decayTime; + } + trapezoid->SetPoint(i, i, sn / decayTime / riseTime); + } + return trapezoid; +} + +TStopwatch stpWatch; + +//^######################################### Class definition +// Header file for the classes stored in the TTree if any. +class GeneralSort : 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 evID; + Int_t multi; + Int_t bd[100]; //[multi] + Int_t ch[100]; //[multi] + Int_t e[100]; //[multi] + ULong64_t e_t[100]; //[multi] + UShort_t lowFlag[100]; //[multi] + UShort_t highFlag[100]; //[multi] + Int_t tl[100]; //[multi] + Int_t trace[100][2500]; //[multi] + + // List of branches + TBranch *b_event_ID; //! + TBranch *b_multi; //! + TBranch *b_bd; //! + TBranch *b_ch; //! + TBranch *b_e; //! + TBranch *b_e_t; //! + TBranch *b_lowFlag; //! + TBranch *b_highFlag; //! + TBranch *b_tl; //! + TBranch *b_trace; //! + + GeneralSort(TTree * /*tree*/ =0) : fChain(0) { + printf("constructor :: %s\n", __func__); + + isTraceExist = false; + traceMethod = 0; // -1 = ignore trace, 0 = no trace fit, 1 = fit, 2 = trapezoid + + isParallel = false; + + saveFile = nullptr; + newSaveTree = nullptr; + + eE = nullptr; + eT = nullptr; + + arr = nullptr; + gTrace = nullptr; + gFit = nullptr; + arrTrapezoid = nullptr; + gTrapezoid = nullptr; + + teE = nullptr; + teT = nullptr; + teR = nullptr; + + } + virtual ~GeneralSort() { } + 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(GeneralSort,0); + + bool isTraceExist; + int traceMethod; + + void SetTraceMethod(int methodID) {traceMethod = methodID;} + void PrintTraceMethod(); + + void SetUpTree(); + void DecodeOption(); + bool isParallel; + + unsigned long NumEntries; + + TString saveFileName; + TFile * saveFile; //! + TProofOutputFile * proofFile; //! + TTree * newSaveTree; //! + + Float_t ** eE; //! + ULong64_t ** eT; //! + + //trace + TClonesArray * arr ;//! + TGraph * gTrace; //! + TF1 * gFit; //! + TClonesArray * arrTrapezoid ;//! + TGraph * gTrapezoid; //! + + //trace energy, trigger time, rise time + Float_t **teE; //! + Float_t **teT; //! + Float_t **teR; //! + +}; + +#endif + +#ifdef GeneralSort_cxx + +//^############################################################## +void GeneralSort::SetUpTree(){ + + printf("%s\n", __func__); + + if( isParallel){ + proofFile = new TProofOutputFile(saveFileName, "M"); + saveFile = proofFile->OpenFile("RECREATE"); + }else{ + saveFile = new TFile(saveFileName,"RECREATE"); + } + + newSaveTree = new TTree("gen_tree", "Tree After GeneralSort"); + newSaveTree->SetDirectory(saveFile); + newSaveTree->AutoSave(); + + newSaveTree->Branch( "evID", &evID, "EventID/l"); // simply copy + + eE = new Float_t * [mapping::nDetType]; + eT = new ULong64_t * [mapping::nDetType]; + + for( int i = 0 ; i < mapping::nDetType; i++){ + eE[i] = new Float_t[mapping::detNum[i]]; + eT[i] = new ULong64_t[mapping::detNum[i]]; + + for( int j = 0; j < mapping::detNum[i]; j++){ + eE[i][j] = TMath::QuietNaN(); + eT[i][j] = 0; + } + + newSaveTree->Branch( mapping::detTypeName[i].c_str(), eE[i], Form("%s[%d]/F", mapping::detTypeName[i].c_str(), mapping::detNum[i])); + newSaveTree->Branch( (mapping::detTypeName[i]+"_t").c_str(), eT[i], Form("%s_Timestamp[%d]/l", mapping::detTypeName[i].c_str(), mapping::detNum[i])); + } + + + if( isTraceExist && traceMethod >= 0){ + + arr = new TClonesArray("TGraph"); + + newSaveTree->Branch("trace", arr, 256000); + arr->BypassStreamer(); + + if( traceMethod > 0 ){ + + teE = new Float_t * [mapping::nDetType]; + teT = new Float_t * [mapping::nDetType]; + teR = new Float_t * [mapping::nDetType]; + + for( int i = 0 ; i < mapping::nDetType; i++){ + teE[i] = new Float_t[mapping::detNum[i]]; + teT[i] = new Float_t[mapping::detNum[i]]; + teR[i] = new Float_t[mapping::detNum[i]]; + + for( int j = 0; j Branch( ("w" + mapping::detTypeName[i]).c_str(), teE[i], Form("trace_%s[%d]/F", mapping::detTypeName[i].c_str(), mapping::detNum[i])); + newSaveTree->Branch( ("w" + mapping::detTypeName[i]+"T").c_str(), teT[i], Form("trace_%s_time[%d]/l", mapping::detTypeName[i].c_str(), mapping::detNum[i])); + newSaveTree->Branch( ("w" + mapping::detTypeName[i]+"R").c_str(), teR[i], Form("trace_%s_rise[%d]/l", mapping::detTypeName[i].c_str(), mapping::detNum[i])); + } + + } + + } + newSaveTree->Print("toponly"); //very important, otherwise the mac will blow up. +} + +//^############################################################## +void GeneralSort::DecodeOption(){ + TString option = GetOption(); + if( option != ""){ + TObjArray * tokens = option.Tokenize(","); + traceMethod = ((TObjString*) tokens->At(0))->String().Atoi(); + saveFileName = ((TObjString*) tokens->At(1))->String(); + isParallel = ((TObjString*) tokens->At(2))->String().Atoi(); + }else{ + traceMethod = -1; + saveFileName = "temp.root"; + isParallel = false; + } + + printf("|%s| %d %s %d \n", option.Data(), traceMethod, saveFileName.Data(), isParallel); + +} + +//^############################################################## +void GeneralSort::Init(TTree *tree){ + + // Set branch addresses and branch pointers + if (!tree) return; + fChain = tree; + fChain->SetMakeClass(1); + + fChain->SetBranchAddress("evID", &evID, &b_event_ID); + fChain->SetBranchAddress("multi", &multi, &b_multi); + fChain->SetBranchAddress("bd", bd, &b_bd); + fChain->SetBranchAddress("ch", ch, &b_ch); + fChain->SetBranchAddress("e", e, &b_e); + fChain->SetBranchAddress("e_t", e_t, &b_e_t); + fChain->SetBranchAddress("lowFlag", lowFlag, &b_lowFlag); + fChain->SetBranchAddress("highFlag", highFlag, &b_highFlag); + + TBranch * br = (TBranch *) fChain->GetListOfBranches()->FindObject("tl"); + if( br == NULL ){ + printf(" ++++++++ no Trace.\n"); + isTraceExist = false; + }else{ + printf(" ++++++++ Found Trace.\n"); + isTraceExist = true; + fChain->SetBranchAddress("tl", tl, &b_tl); + fChain->SetBranchAddress("trace", trace, &b_trace); + } + + NumEntries = fChain->GetEntries(); + printf( " ========== total Entry : %ld\n", NumEntries); + + //########################### Get Option + DecodeOption(); + + if( isTraceExist ){ + PrintTraceMethod(); + }else{ + printf("++++++++ no Trace found\n"); + } + + SetUpTree(); + + printf("---- end of Init %s\n ", __func__); + +} + +Bool_t GeneralSort::Notify(){ + return kTRUE; +} + +void GeneralSort::PrintTraceMethod(){ + const char* traceMethodStr; + switch(traceMethod) { + case -1 : traceMethodStr = "Ignore Trace"; break; + case 0 : traceMethodStr = "Copy"; break; + case 1 : traceMethodStr = "Fit"; break; + case 2 : traceMethodStr = "Trapezoid"; break; + default: traceMethodStr = "Unknown"; break; + } + printf("\033[1;33m ===== Trace method ? %s \033[m\n", traceMethodStr); +} + +#endif // #ifdef GeneralSort_cxx diff --git a/Armory/GeneralSortAgent.C b/Armory/GeneralSortAgent.C new file mode 100644 index 0000000..63db067 --- /dev/null +++ b/Armory/GeneralSortAgent.C @@ -0,0 +1,56 @@ + +#include "TTree.h" +#include "TProof.h" +#include "TChain.h" +#include "TMacro.h" +#include "TFile.h" + +void GeneralSortAgent(Int_t runNum, int nWorker = 1, int traceMethod = -1){ + + TString name; + name.Form("../root_data/run%03d.root", runNum); + + TChain * chain = new TChain("tree"); + chain->Add(name); + + chain->GetListOfFiles()->Print(); + + printf("\033[1;33m---------------------total number of Events %llu\033[0m\n", chain->GetEntries()); + + if( chain->GetEntries() == 0 ) return; + + //this is the option for TSelector, the first one is traceMethod, 2nd is save fileName; + TString option; + + if( abs(nWorker) == 1){ + + option.Form("%d,../root_data/gen_run%03d.root,%d", traceMethod, runNum, 0); + chain->Process("../armory/GeneralSort.C+", option); + + }else{ + + TProof * p = TProof::Open("", Form("workers=%d", abs(nWorker))); + p->ShowCache(); + printf("----------------------------\n"); + + chain->SetProof(); + option.Form("%d,../root_data/gen_run%03d.root,%d", traceMethod, runNum, 1); + chain->Process("../armory/GeneralSort.C+", option); + } + + //========== open the output root and copy teh timestamp Marco + + TFile * f1 = new TFile(Form("../root_data/run%03d.root", runNum), "READ"); + TMacro * m = (TMacro* ) f1->Get("timeStamp"); + m->AddLine(Form("%d", runNum)); + + TFile * f2 = new TFile(Form("../root_data/gen_run%03d.root", runNum), "UPDATE"); + f2->cd(); + m->Write("timeStamp"); + + f1->Close(); + f2->Close(); + + delete chain; + +} \ No newline at end of file diff --git a/Armory/Hit.h b/Armory/Hit.h new file mode 100644 index 0000000..1a945b1 --- /dev/null +++ b/Armory/Hit.h @@ -0,0 +1,287 @@ +#ifndef HIT_H +#define HIT_H + +#include +#include +#include +#include + +#define MaxTraceLenght 8100 + +enum DataFormat{ + + ALL = 0x00, + OneTrace = 0x01, + NoTrace = 0x02, + Minimum = 0x03, + MiniWithFineTime = 0x04, + Raw = 0x0A, + +}; + +namespace DPPType{ + + const std::string PHA = "DPP_PHA"; + const std::string PSD = "DPP_PSD"; + +}; + +class Hit { + public: + + unsigned short dataType; + std::string DPPType; + + ///============= for dpp-pha + uint8_t channel; // 6 bit + uint16_t energy; // 16 bit + uint16_t energy_short; // 16 bit, only for PSD + uint64_t timestamp; // 48 bit + uint16_t fine_timestamp; // 10 bit + uint16_t flags_low_priority; // 12 bit + uint16_t flags_high_priority; // 8 bit + size_t traceLenght; // 64 bit + uint8_t downSampling; // 8 bit + bool board_fail; + bool flush; + uint8_t analog_probes_type[2]; // 3 bit for PHA, 4 bit for PSD + uint8_t digital_probes_type[4]; // 4 bit for PHA, 5 bit for PSD + int32_t * analog_probes[2]; // 18 bit + uint8_t * digital_probes[4]; // 1 bit + uint16_t trigger_threashold; // 16 bit + size_t event_size; // 64 bit + uint32_t aggCounter; // 32 bit + + ///============= for raw + uint8_t * data; + size_t dataSize; /// number of byte of the data, size/8 = word [64 bits] + uint32_t n_events; + + bool isTraceAllZero; + + Hit(){ + Init(); + } + + ~Hit(){ + ClearMemory(); + } + + void Init(){ + DPPType = DPPType::PHA; + dataType = DataFormat::ALL; + + channel = 0; + energy = 0; + energy_short = 0; + timestamp = 0; + fine_timestamp = 0; + downSampling = 0; + board_fail = false; + flush = false; + flags_low_priority = 0; + flags_high_priority = 0; + trigger_threashold = 0; + event_size = 0; + aggCounter = 0; + analog_probes[0] = NULL; + analog_probes[1] = NULL; + digital_probes[0] = NULL; + digital_probes[1] = NULL; + digital_probes[2] = NULL; + digital_probes[3] = NULL; + + analog_probes_type[0] = 0xFF; + analog_probes_type[1] = 0xFF; + digital_probes_type[0] = 0xFF; + digital_probes_type[1] = 0xFF; + digital_probes_type[2] = 0xFF; + digital_probes_type[3] = 0xFF; + data = NULL; + + isTraceAllZero = true; // indicate trace are all zero + } + + void ClearMemory(){ + if( data != NULL ) delete data; + + if( analog_probes[0] != NULL) delete analog_probes[0]; + if( analog_probes[1] != NULL) delete analog_probes[1]; + + if( digital_probes[0] != NULL) delete digital_probes[0]; + if( digital_probes[1] != NULL) delete digital_probes[1]; + if( digital_probes[2] != NULL) delete digital_probes[2]; + if( digital_probes[3] != NULL) delete digital_probes[3]; + + isTraceAllZero = true; + } + + void SetDataType(unsigned int type, std::string dppType){ + dataType = type; + DPPType = dppType; + ClearMemory(); + + if( dataType == DataFormat::Raw){ + data = new uint8_t[20*1024*1024]; + }else{ + analog_probes[0] = new int32_t[MaxTraceLenght]; + analog_probes[1] = new int32_t[MaxTraceLenght]; + + digital_probes[0] = new uint8_t[MaxTraceLenght]; + digital_probes[1] = new uint8_t[MaxTraceLenght]; + digital_probes[2] = new uint8_t[MaxTraceLenght]; + digital_probes[3] = new uint8_t[MaxTraceLenght]; + + isTraceAllZero = true; + + } + } + + void ClearTrace(){ + if( isTraceAllZero ) return; // no need to clear again + + for( int i = 0; i < MaxTraceLenght; i++){ + analog_probes[0][i] = 0; + analog_probes[1][i] = 0; + + digital_probes[0][i] = 0; + digital_probes[1][i] = 0; + digital_probes[2][i] = 0; + digital_probes[3][i] = 0; + } + isTraceAllZero = true; + } + + void PrintEnergyTimeStamp(){ + printf("ch: %2d, energy: %u, timestamp: %lu ch, traceLenght: %lu\n", channel, energy, timestamp, traceLenght); + } + + std::string AnaProbeType(uint8_t probeType){ + + if( DPPType == DPPType::PHA){ + switch(probeType){ + case 0: return "ADC"; + case 1: return "Time filter"; + case 2: return "Energy filter"; + default : return "none"; + } + }else if (DPPType == DPPType::PSD){ + switch(probeType){ + case 0: return "ADC"; + case 9: return "Baseline"; + case 10: return "CFD"; + default : return "none"; + } + }else{ + return "none"; + } + } + + std::string DigiProbeType(uint8_t probeType){ + + if( DPPType == DPPType::PHA){ + switch(probeType){ + case 0: return "Trigger"; + case 1: return "Time filter armed"; + case 2: return "Re-trigger guard"; + case 3: return "Energy filter baseline freeze"; + case 4: return "Energy filter peaking"; + case 5: return "Energy filter peaking ready"; + case 6: return "Energy filter pile-up guard"; + case 7: return "Event pile-up"; + case 8: return "ADC saturation"; + case 9: return "ADC saturation protection"; + case 10: return "Post-saturation event"; + case 11: return "Energy filter saturation"; + case 12: return "Signal inhibit"; + default : return "none"; + } + }else if (DPPType == DPPType::PSD){ + switch(probeType){ + case 0: return "Trigger"; + case 1: return "CFD Filter Armed"; + case 2: return "Re-trigger guard"; + case 3: return "ADC Input Baseline freeze"; + case 20: return "ADC Input OverThreshold"; + case 21: return "Charge Ready"; + case 22: return "Long Gate"; + case 7: return "Pile-Up Trig."; + case 24: return "Short Gate"; + case 25: return "Energy Saturation"; + case 26: return "Charge over-range"; + case 27: return "ADC Input Neg. OverThreshold"; + default : return "none"; + } + + }else{ + return "none"; + } + } + + std::string HighPriority(uint16_t prio){ + std::string output; + + bool pileup = prio & 0x1; + //bool pileupGuard = (prio >> 1) & 0x1; + //bool eventSaturated = (prio >> 2) & 0x1; + //bool postSatEvent = (prio >> 3) & 0x1; + //bool trapSatEvent = (prio >> 4) & 0x1; + //bool SCA_Event = (prio >> 5) & 0x1; + + output = std::string("Pile-up: ") + (pileup ? "Yes" : "No"); + + return output; + } + + //TODO LowPriority + + void PrintAll(){ + + switch(dataType){ + case DataFormat::ALL : printf("============= Type : ALL\n"); break; + case DataFormat::OneTrace : printf("============= Type : OneTrace\n"); break; + case DataFormat::NoTrace : printf("============= Type : NoTrace\n"); break; + case DataFormat::MiniWithFineTime : printf("============= Type : Min with FineTimestamp\n"); break; + case DataFormat::Minimum : printf("============= Type : Minimum\n"); break; + case DataFormat::Raw : printf("============= Type : Raw\n"); return; break; + default : return; + } + + printf("ch : %2d (0x%02X), fail: %d, flush: %d\n", channel, channel, board_fail, flush); + if( DPPType == DPPType::PHA ) printf("energy: %u, timestamp: %lu, fine_timestamp: %u \n", energy, timestamp, fine_timestamp); + if( DPPType == DPPType::PSD ) printf("energy: %u, energy_S : %u, timestamp: %lu, fine_timestamp: %u \n", energy, energy_short, timestamp, fine_timestamp); + printf("flag (high): 0x%02X, (low): 0x%03X, traceLength: %lu\n", flags_high_priority, flags_low_priority, traceLenght); + printf("Agg counter : %u, trigger Thr.: %u, downSampling: %u \n", aggCounter, trigger_threashold, downSampling); + printf("AnaProbe Type: %s(%u), %s(%u)\n", AnaProbeType(analog_probes_type[0]).c_str(), analog_probes_type[0], + AnaProbeType(analog_probes_type[1]).c_str(), analog_probes_type[1]); + printf("DigProbe Type: %s(%u), %s(%u), %s(%u), %s(%u)\n", DigiProbeType(digital_probes_type[0]).c_str(), digital_probes_type[0], + DigiProbeType(digital_probes_type[1]).c_str(), digital_probes_type[1], + DigiProbeType(digital_probes_type[2]).c_str(), digital_probes_type[2], + DigiProbeType(digital_probes_type[3]).c_str(), digital_probes_type[3]); + } + + void PrintTrace(unsigned short ID){ + for(unsigned short i = 0; i < (unsigned short)traceLenght; i++){ + if( ID == 0 ) printf("%4d| %6d\n", i, analog_probes[0][i]); + if( ID == 1 ) printf("%4d| %6d\n", i, analog_probes[1][i]); + if( ID == 2 ) printf("%4d| %u\n", i, digital_probes[0][i]); + if( ID == 3 ) printf("%4d| %u\n", i, digital_probes[1][i]); + if( ID == 4 ) printf("%4d| %u\n", i, digital_probes[2][i]); + if( ID == 5 ) printf("%4d| %u\n", i, digital_probes[3][i]); + } + } + + void PrintAllTrace(){ + for(unsigned short i = 0; i < (unsigned short)traceLenght; i++){ + printf("%4d| %6d %6d %1d %1d %1d %1d\n", i, analog_probes[0][i], + analog_probes[1][i], + digital_probes[0][i], + digital_probes[1][i], + digital_probes[2][i], + digital_probes[3][i]); + } + } + +}; + +#endif \ No newline at end of file diff --git a/Armory/Makefile b/Armory/Makefile new file mode 100644 index 0000000..4de3a66 --- /dev/null +++ b/Armory/Makefile @@ -0,0 +1,12 @@ +CC=g++ +CFLAG= -g +ROOTFLAG=`root-config --cflags --glibs` + +all: EventBuilder + +EventBuilder: EventBuilder.cpp SolReader.h Hit.h + $(CC) $(CFLAG) EventBuilder.cpp -o EventBuilder ${ROOTFLAG} + + +clean: + -rm EventBuilder \ No newline at end of file diff --git a/Armory/Monitor_Util.C b/Armory/Monitor_Util.C new file mode 100644 index 0000000..fa817a7 --- /dev/null +++ b/Armory/Monitor_Util.C @@ -0,0 +1,359 @@ +#ifndef Utilities +#define Utilities + +#include +#include + +//This file runs after on Monitor.C +//This file is parasite on Monitor.C + +int canvasSize[2] = {2000, 1200}; + +void listDraws(void) { + printf("------------------- List of Plots -------------------\n"); + printf(" newCanvas() - Create a new Canvas\n"); + printf("-----------------------------------------------------\n"); + printf(" rawID() - Raw \033[0;31me\033[0m, \033[0;31mring\033[0m, \033[0;31mxf\033[0m, \033[0;31mxn\033[0m vs detID\n"); + printf(" rawe() - Raw \033[0;31me\033[0m for all %d detectors\n", numDet); + printf(" rawxf() - Raw \033[0;31mxf\033[0m for all %d detectors\n", numDet); + printf(" rawxn() - Raw \033[0;31mxn\033[0m for all %d detectors\n", numDet); + printf(" rawxfVxn() - Raw \033[0;31mxf\033[0m vs. \033[0;31mxn\033[0m for all %d detectors\n", numDet); + printf(" raweVxs() - Raw \033[0;31me\033[0m vs. Raw \033[0;31mxs = xf + xn\033[0m for all %d detectors\n", numDet); + printf(" raweVx() - Raw \033[0;31me\033[0m vs. RAW \033[0;31mx\033[0m for all %d detectors\n", numDet); + printf("-----------------------------------------------------\n"); + printf(" eVxsCal() - Raw \033[0;31me\033[0m vs. Corrected \033[0;31mxs\033[0m for all %d detectors\n", numDet); + printf(" ecal() - Calibrated \033[0;31me\033[0m for all %d detectors\n", numDet); + printf("xfCalVxnCal() - Calibrated \033[0;31mxf\033[0m vs. \033[0;31mxn\033[0m for all %d detectors\n", numDet); + printf(" eCalVxCal() - Cal \033[0;31me\033[0m vs. \033[0;31mx\033[0m for all %d detectors\n", numDet); + printf("-----------------------------------------------------\n"); + printf(" recoils() - Raw DE vs. E Recoil spectra\n"); + //printf(" elum() - Luminosity Energy Spectra\n"); + //printf(" ic() - Ionization Chamber Spectra\n"); + printf("-----------------------------------------------------\n"); + printf(" eCalVz() - Energy vs. Z\n"); + printf(" eCalVzRow() - Energy vs. Z for each row\n"); + printf(" excite() - Excitation Energy\n"); + printf(" ExThetaCM() - Ex vs ThetaCM\n"); + printf(" ExVxCal() - Ex vs X for all %d detectors\n", numDet); + printf("-----------------------------------------------------\n"); + printf(" ShowFitMethod() - Shows various fitting methods \n"); + printf(" RDTCutCreator() - Create RDT Cuts [May need to edit]\n"); + printf(" Check_rdtGate() - Check RDT Cuts. \n"); + printf(" readTrace() - read trace from gen_runXXX.root \n"); + printf(" readRawTrace() - read trace from runXXX.root \n"); + printf(" Check1D() - Count Integral within a range\n"); + printf("-----------------------------------------------------\n"); + printf(" %s\n", canvasTitle.Data()); + printf("-----------------------------------------------------\n"); +} + +int xD, yD; +void FindBesCanvasDivision(int nPad){ + for( int i = TMath::Sqrt(nPad); i >= 2 ; i--){ + if( nPad % i == 0 ) { + yD = i; + xD = nPad/i; + break; + } + } +} + +int nCanvas=0; +void newCanvas(int sizeX = 800, int sizeY = 600, int posX = 0, int posY = 0){ + TString name; name.Form("cNewCanvas%d | %s", nCanvas, canvasTitle.Data()); + TCanvas * cNewCanvas = new TCanvas(name, name, posX, posY, sizeX, sizeY); + nCanvas++; + cNewCanvas->cd(); +} + +void rawID(){ + TCanvas * cRawID = (TCanvas *) gROOT->FindObjectAny("cRawID"); + if( cRawID == NULL ) cRawID = new TCanvas("cRawID", Form("Raw e, Ring, xf, xn vs ID | %s", canvasTitle.Data()), canvasSize[0], canvasSize[1]); + cRawID->Clear();cRawID->Divide(2,2); + cRawID->cd(1); cRawID->cd(1)->SetGrid(); heVID->Draw("colz"); + cRawID->cd(2); cRawID->cd(2)->SetGrid(); hMultiHit->Draw(); + cRawID->cd(3); cRawID->cd(3)->SetGrid(); hxfVID->Draw("colz"); + cRawID->cd(4); cRawID->cd(4)->SetGrid(); hxnVID->Draw("colz"); +} + +void rawe(Bool_t isLogy = false) { + TCanvas *cRawE = (TCanvas *) gROOT->FindObjectAny("cRawE"); + if( cRawE == NULL ) cRawE = new TCanvas("cRawE",Form("E raw | %s", canvasTitle.Data()),canvasSize[0], canvasSize[1]); + cRawE->Clear();cRawE->Divide(numCol,numRow); + for (Int_t i=0; i < numDet; i++) { + cRawE->cd(i+1); + cRawE->cd(i+1)->SetGrid(); + if( isLogy ) cRawE->cd(i+1)->SetLogy(); + he[i]->Draw(""); + } +} + +void rawxf(Bool_t isLogy = false) { + TCanvas *cRawXf = (TCanvas *) gROOT->FindObjectAny("cRawXf"); + if( cRawXf == NULL ) cRawXf = new TCanvas("cRawXf",Form("Xf raw | %s", canvasTitle.Data()),canvasSize[0], canvasSize[1]); + cRawXf->Clear();cRawXf->Divide(numCol,numRow); + for (Int_t i=0; icd(i+1); + cRawXf->cd(i+1)->SetGrid(); + if( isLogy ) cRawXf->cd(i+1)->SetLogy(); + hxf[i]->Draw(""); + } +} + +void rawxn(Bool_t isLogy = false) { + TCanvas *cRawXn = (TCanvas *) gROOT->FindObjectAny("cRawXn"); + if( cRawXn == NULL ) cRawXn = new TCanvas("cRawXn",Form("Xn raw | %s", canvasTitle.Data()),canvasSize[0], canvasSize[1]); + cRawXn->Clear();cRawXn->Divide(numCol,numRow); + for (Int_t i=0; icd(i+1); + cRawXn->cd(i+1)->SetGrid(); + if( isLogy ) cRawXn->cd(i+1)->SetLogy(); + hxn[i]->Draw(""); + } +} + +void rawxfVxn(void) { + TCanvas *cxfxn = (TCanvas *) gROOT->FindObjectAny("cxfxn"); + if( cxfxn == NULL ) cxfxn = new TCanvas("cxfxn",Form("XF vs. XN | %s", canvasTitle.Data()),canvasSize[0], canvasSize[1]); + cxfxn->Clear(); cxfxn->Divide(numCol,numRow); + for (Int_t i=0;icd(i+1); + cxfxn->cd(i+1)->SetGrid(); + hxfVxn[i]->Draw("col"); + } +} + +void raweVxs(void) { + TCanvas *cxfxne = (TCanvas *) gROOT->FindObjectAny("cxfxne"); + if( cxfxne == NULL ) cxfxne = new TCanvas("cxfxne",Form("E - XF+XN | %s", canvasTitle.Data()),canvasSize[0], canvasSize[1]); + cxfxne->Clear(); cxfxne->Divide(numCol,numRow); + TLine line(0,0, 4000, 4000); line.SetLineColor(2); + for (Int_t i=0;icd(i+1); + cxfxne->cd(i+1)->SetGrid(); + heVxs[i]->Draw("col"); + line.Draw("same"); + } +} + +void raweVx(void) { + TCanvas *ceVx = (TCanvas *) gROOT->FindObjectAny("ceVx"); + if(ceVx == NULL) ceVx = new TCanvas("ceVx",Form("E vs. X = (xf-xn)/e | %s", canvasTitle.Data()),canvasSize[0], canvasSize[1]); + ceVx->Clear(); ceVx->Divide(numCol,numRow); + for (Int_t i=0;icd(i+1); heVx[i]->Draw("col"); + } +} + +void eVxsCal(void) { + TCanvas *cxfxneC = (TCanvas *) gROOT->FindObjectAny("cxfxneC"); + if(cxfxneC == NULL)cxfxneC = new TCanvas("cxfxneC",Form("Raw E - Corrected XF+XN | %s", canvasTitle.Data()),canvasSize[0], canvasSize[1]); + cxfxneC->Clear(); cxfxneC->Divide(numCol,numRow); + TLine line(0,0, 4000, 4000); line.SetLineColor(2); + for (Int_t i=0;icd(i+1); + cxfxneC->cd(i+1)->SetGrid(); + heVxsCal[i]->Draw("col"); + line.Draw("same"); + } +} + +void ecal(void) { + TCanvas *cEC = (TCanvas *) gROOT->FindObjectAny("cEC"); + if(cEC == NULL) cEC = new TCanvas("cEC",Form("E corrected | %s", canvasTitle.Data()),canvasSize[0], canvasSize[1]); + cEC->Clear();cEC->Divide(numCol,numRow); + for (Int_t i=0; icd(i+1); + cEC->cd(i+1)->SetGrid(); + heCal[i]->Draw(""); + } + + TCanvas *cEC2 = (TCanvas *) gROOT->FindObjectAny("cEC2"); + if(cEC2 == NULL) cEC2 = new TCanvas("cEC2",Form("E corrected | %s", canvasTitle.Data()),canvasSize[0], canvasSize[1]); + cEC2->Clear(); + heCalID->Draw("colz"); +} + +void xfCalVxnCal(void) { + TCanvas *cxfxnC = (TCanvas *) gROOT->FindObjectAny("cxfxnC"); + if(cxfxnC == NULL) cxfxnC = new TCanvas("cxfxnC",Form("XF vs XN corrected | %s", canvasTitle.Data()),canvasSize[0], canvasSize[1]); + cxfxnC->Clear(); cxfxnC->Divide(numCol,numRow); + for (Int_t i=0;icd(i+1); + cxfxnC->cd(i+1)->SetGrid(); + hxfCalVxnCal[i]->Draw("col"); + } +} + +void eCalVxCal(void) { + TCanvas *cecalVxcal = (TCanvas *) gROOT->FindObjectAny("cecalVxcal"); + if( cecalVxcal == NULL ) cecalVxcal = new TCanvas("cecalVxcal",Form("ECALVXCAL | %s",canvasTitle.Data()),canvasSize[0], canvasSize[1]); + cecalVxcal->Clear(); cecalVxcal->Divide(numCol,numRow); + for (Int_t i=0;icd(i+1); + heCalVxCal[i]->SetMarkerStyle(7); + heCalVxCal[i]->Draw(""); + } +} + +void recoils(bool isLogz = false) { + TCanvas *crdt = (TCanvas *) gROOT->FindObjectAny("crdt"); + if( crdt == NULL ) crdt = new TCanvas("crdt",Form("raw RDT | %s", canvasTitle.Data()),1700, 0, 1000,1000); + crdt->Clear();crdt->Divide(2,2); + + if( isLogz ) crdt->cd(1)->SetLogz(); crdt->cd(1); hrdt2D[0]->Draw("col"); + if( isLogz ) crdt->cd(2)->SetLogz(); crdt->cd(2); hrdt2D[1]->Draw("col"); + if( isLogz ) crdt->cd(3)->SetLogz(); crdt->cd(3); hrdt2D[3]->Draw("col"); + if( isLogz ) crdt->cd(4)->SetLogz(); crdt->cd(4); hrdt2D[2]->Draw("col"); + + TCanvas *crdtID = (TCanvas *) gROOT->FindObjectAny("crdtID"); + if( crdtID == NULL ) crdtID = new TCanvas("crdtID",Form("raw RDT ID | %s", canvasTitle.Data()),0,0, 500, 500); + crdtID->Clear(); + if( isLogz ) crdtID->SetLogz(); + hrdtID->Draw("colz"); + + TCanvas *crdtS = (TCanvas *) gROOT->FindObjectAny("crdtS"); + if( crdtS == NULL ) crdtS = new TCanvas("crdtS",Form("raw RDT | %s", canvasTitle.Data()),600, 0, 1000, 1000); + crdtS->Clear(); crdtS->Divide(2,4); + for( int i = 0; i < 8; i ++){ + crdtS->cd(i+1); + if( isLogz ) crdtS->cd(i+1)->SetLogy(); + hrdt[i]->Draw(""); + } +} + +// void elum(void) { +// TCanvas *celum = (TCanvas *) gROOT->FindObjectAny("celum"); +// if( celum == NULL ) celum = new TCanvas("celum",Form("ELUM | %s", canvasTitle.Data()),1000,1000); +// celum->Clear(); celum->Divide(4,4); +// for( int i = 0 ; i < 16 ; i++){ +// celum->cd(i+1); +// helum[i]->Draw(""); +// } + +// TCanvas *celumID = (TCanvas *) gROOT->FindObjectAny("celumID"); +// if( celumID == NULL ) celumID = new TCanvas("celumID",Form("ELUM-ID | %s", canvasTitle.Data()),1100, 0, 500,500); +// celumID->Clear(); +// helumID->Draw("colz"); + +// } + + +// void ic(){ +// TCanvas *cic = (TCanvas *) gROOT->FindObjectAny("cic"); +// if( cic == NULL ) cic = new TCanvas("cic",Form("Ionization Chamber | %s", canvasTitle.Data() ),1200,800); + +// cic->Clear(); cic->SetGrid(0); cic->Divide(3,2); +// gStyle->SetOptStat("neiou"); + +// cic->cd(1); hic0->Draw(); +// cic->cd(2); hic1->Draw(); +// cic->cd(3); hic2->Draw(); +// cic->cd(4); hic01->Draw("colz"); +// cic->cd(5); hic02->Draw("colz"); +// cic->cd(6); hic12->Draw("colz"); +// } + +void eCalVz(void) { + TCanvas *cecalVz = (TCanvas *) gROOT->FindObjectAny("cecalVz"); + if( cecalVz == NULL ) cecalVz = new TCanvas("cevalVz",Form("ECALVZ : %s", canvasTitle.Data()),1000,650); + cecalVz->Clear(); cecalVz->Divide(2,1); + gStyle->SetOptStat("neiou"); + cecalVz->cd(1);heCalVz->Draw("col"); + cecalVz->cd(2);heCalVzGC->Draw("col"); +} + +void eCalVzRow() { + TCanvas *cecalVzRow = (TCanvas *) gROOT->FindObjectAny("cecalVzRow"); + if( cecalVzRow == NULL ) cecalVzRow = new TCanvas("cevalVzRow",Form("eCal - Z : %s", canvasTitle.Data()),canvasSize[0], canvasSize[1]); + FindBesCanvasDivision(numRow); + cecalVzRow->Clear(); cecalVzRow->Divide(xD,yD); + gStyle->SetOptStat("neiou"); + + for(int row = 0; row < numRow; row ++){ + cecalVzRow->cd(row+1); + cecalVzRow->cd(row+1)->SetGrid(); + hecalVzRow[row]->Draw("colz"); + } +} + +void excite(void) { + TCanvas *cex = (TCanvas *) gROOT->FindObjectAny("cex"); + if( cex == NULL ) cex = new TCanvas("cex",Form("EX : %s", canvasTitle.Data()),0, 0, 1000,650); + cex->Clear(); + gStyle->SetOptStat("neiou"); + hEx->Draw(""); + + + TCanvas *cexI = (TCanvas *) gROOT->FindObjectAny("cexI"); + if( cexI == NULL ) cexI = new TCanvas("cexI",Form("EX : %s", canvasTitle.Data()),500, 0, 1600,1000); + cexI->Clear();cexI->Divide(numCol,numRow); + gStyle->SetOptStat("neiou"); + for( int i = 0; i < numDet; i++){ + cexI->cd(i+1); + hExi[i]->Draw(""); + } +} + +void ExThetaCM(void) { + TCanvas *cExThetaCM = (TCanvas *) gROOT->FindObjectAny("cExThetaCM"); + if( cExThetaCM == NULL ) cExThetaCM = new TCanvas("cExThetaCM",Form("EX - ThetaCM | %s", canvasTitle.Data()),650,650); + cExThetaCM->Clear(); + gStyle->SetOptStat("neiou"); + hExThetaCM->Draw("colz"); +} + +void ExVxCal(TString drawOpt = "") { + TCanvas *cExVxCal = (TCanvas *) gROOT->FindObjectAny("cExVxCal"); + if( cExVxCal == NULL ) cExVxCal = new TCanvas("cExVxCal",Form("EX | %s", canvasTitle.Data()),1600,1000); + cExVxCal->Clear(); + gStyle->SetOptStat("neiou"); + + cExVxCal->Divide(numCol,numRow); + for( int i = 0; i < numDet; i++){ + cExVxCal->cd(i+1); + if( drawOpt == "" )hExVxCal[i]->SetMarkerStyle(7); + hExVxCal[i]->Draw(drawOpt); + } +} + +void Count1DH(TString name, TH1F * hist, TCanvas * canvas, int padID, double x1, double x2, Color_t color){ + + int k1 = hist->FindBin(x1); + int k2 = hist->FindBin(x2); + + int hight = 0 ; + for( int i = k1; i < k2 ; i ++){ + int temp = hist->GetBinContent(i); + if( temp > hight ) hight = temp; + } + hight = hight * 1.2; + int max = hist->GetMaximum(); + + canvas->cd(padID); + + if( color != 0 ){ + TBox box; + box.SetFillColorAlpha(color, 0.1); + box.DrawBox(x1, 0, x2, hight); + } + + int count = hist->Integral(k1, k2); + + TLatex text; + text.SetTextFont(82); + text.SetTextSize(0.06); + if( color != 0 ){ + text.SetTextColor(color); + text.DrawLatex(x1, hight, Form("%d", count)); + }else{ + text.DrawLatex((x1+x2)/2., max, Form("%d", count)); + } + + printf(" %s : %d \n", name.Data(), count); + +} + + + +#endif diff --git a/Armory/Parameters.h b/Armory/Parameters.h new file mode 100644 index 0000000..660d63b --- /dev/null +++ b/Armory/Parameters.h @@ -0,0 +1,306 @@ +#ifndef Parameters_H +#define Parameters_H + +#include "ClassDetGeo.h" +#include "ClassReactionConfig.h" + +struct ReactionParas{ + + double Et; // total energy in CM frame + double beta; // Lorentz beta from Lab to CM + double gamma; // Lorentz gamma from Lab to CM + double alpha; // E-Z slope / beta + double G; //The G-coefficient.... + double massB; // heavy mass + double q; // charge of light particle + double mass; //light mass + bool hasReactionPara; + + double detPrepDist; + +}; + +ReactionParas reactParas1; +ReactionParas reactParas2; + +//~========================================= reaction parameters +void LoadReactionParas(int arrayID, bool verbose = false){ + + //check is the transfer.root is using the latest reactionConfig.txt + //sicne reaction.dat is generated as a by-product of transfer.root + //TFile * transfer = new TFile("transfer.root"); + //TString aaa1 = ""; + //TString aaa2 = ""; + //if( transfer->IsOpen() ){ + // TMacro * reactionConfig = (TMacro *) transfer->FindObjectAny("reactionConfig"); + // TMacro presentReactionConfig ("reactionConfig.txt"); + // aaa1 = ((TMD5*) reactionConfig->Checksum())->AsString(); + // aaa2 = ((TMD5*) presentReactionConfig.Checksum())->AsString(); + //} + //printf("%s\n", aaa1.Data()); + //printf("%s\n", aaa2.Data()); + + //if( aaa1 != aaa2 ) { + // printf("########################## recalculate transfer.root \n"); + // system("../Cleopatra/Transfer"); + // printf("########################## transfer.root updated\n"); + //} + + ReactionParas * reactParas = nullptr; + + std::string fileName; + + if( arrayID == 1){ + reactParas = &AnalysisLib::reactParas1; + fileName = "reaction.dat"; + }else if( arrayID == 2){ + reactParas = &AnalysisLib::reactParas2; + fileName = "reaction2.dat"; + }else{ + printf("arrayID must be either 1 or 2. Abort.\n"); + return; + } + reactParas->detPrepDist = AnalysisLib::detGeo.array1.detPerpDist; + + printf(" loading reaction parameters"); + std::ifstream file; + file.open(fileName.c_str()); + reactParas->hasReactionPara = false; + if( file.is_open() ){ + std::string x; + int i = 0; + while( file >> x ){ + if( x.substr(0,2) == "//" ) continue; + if( i == 0 ) reactParas->mass = atof(x.c_str()); + if( i == 1 ) reactParas->q = atof(x.c_str()); + if( i == 2 ) reactParas->beta = atof(x.c_str()); + if( i == 3 ) reactParas->Et = atof(x.c_str()); + if( i == 4 ) reactParas->massB = atof(x.c_str()); + i = i + 1; + } + printf("........ done.\n"); + + reactParas->hasReactionPara = true; + reactParas->alpha = 299.792458 * abs(detGeo.Bfield) * reactParas->q / TMath::TwoPi()/1000.; //MeV/mm + reactParas->gamma = 1./TMath::Sqrt(1-reactParas->beta * reactParas->beta); + reactParas->G = reactParas->alpha * reactParas->gamma * reactParas->beta * reactParas->detPrepDist ; + + if( verbose ){ + printf("\tmass-b : %f MeV/c2 \n", reactParas->mass); + printf("\tcharge-b : %f \n", reactParas->q); + printf("\tE-total : %f MeV \n", reactParas->Et); + printf("\tmass-B : %f MeV/c2 \n", reactParas->massB); + printf("\tbeta : %f \n", reactParas->beta); + printf("\tB-field : %f T \n", detGeo.Bfield); + printf("\tslope : %f MeV/mm \n", reactParas->alpha * reactParas->beta); + printf("\tdet radius: %f mm \n", reactParas->detPrepDist); + printf("\tG-coeff : %f MeV \n", reactParas->G); + printf("=====================================================\n"); + } + + }else{ + printf("........ fail.\n"); + } + file.close(); + +} + +std::vector CalExTheta(double e, double z){ + + ReactionParas * reactParas = nullptr; + + if( detGeo.array1.zMin <= z && z <= detGeo.array1.zMax ){ + reactParas = &reactParas1; + if( !reactParas->hasReactionPara) return {TMath::QuietNaN(), TMath::QuietNaN()}; + } + + if( detGeo.array2.zMin <= z && z <= detGeo.array2.zMax ){ + reactParas = &reactParas2; + if( !reactParas->hasReactionPara) return {TMath::QuietNaN(), TMath::QuietNaN()}; + } + + double Ex = TMath::QuietNaN(); + double thetaCM = TMath::QuietNaN(); + + double y = e + reactParas->mass; // to give the KE + mass of proton; + double Z = reactParas->alpha * reactParas->gamma * reactParas->beta * z; + double H = TMath::Sqrt(TMath::Power(reactParas->gamma * reactParas->beta,2) * (y*y - reactParas->mass * reactParas->mass) ) ; + + if( TMath::Abs(Z) < H ) { + ///using Newton's method to solve 0 == H * sin(phi) - G * tan(phi) - Z = f(phi) + double tolerrence = 0.001; + double phi = 0; ///initial phi = 0 -> ensure the solution has f'(phi) > 0 + double nPhi = 0; /// new phi + + int iter = 0; + do{ + phi = nPhi; + nPhi = phi - (H * TMath::Sin(phi) - reactParas->G * TMath::Tan(phi) - Z) / (H * TMath::Cos(phi) - reactParas->G /TMath::Power( TMath::Cos(phi), 2)); + iter ++; + if( iter > 10 || TMath::Abs(nPhi) > TMath::PiOver2()) break; + }while( TMath::Abs(phi - nPhi ) > tolerrence); + phi = nPhi; + + /// check f'(phi) > 0 + double Df = H * TMath::Cos(phi) - reactParas->G / TMath::Power( TMath::Cos(phi),2); + if( Df > 0 && TMath::Abs(phi) < TMath::PiOver2() ){ + double K = H * TMath::Sin(phi); + double x = TMath::ACos( reactParas->mass / ( y * reactParas->gamma - K)); + double momt = reactParas->mass * TMath::Tan(x); /// momentum of particel b or B in CM frame + double EB = TMath::Sqrt(reactParas->mass * reactParas->mass + reactParas->Et * reactParas->Et - 2 * reactParas->Et * TMath::Sqrt(momt*momt + reactParas->mass * reactParas->mass)); + Ex = EB - reactParas->massB; + + double hahaha1 = reactParas->gamma * TMath::Sqrt(reactParas->mass * reactParas->mass + momt * momt) - y; + double hahaha2 = reactParas->gamma * reactParas->beta * momt; + thetaCM = TMath::ACos(hahaha1/hahaha2) * TMath::RadToDeg(); + + } + } + return {Ex, thetaCM}; + +} + + +DetGeo detGeo; +ReactionConfig reactionConfig1; +ReactionConfig reactionConfig2; + +void LoadDetGeoAndReactionConfigFile(std::string detGeoFileName = "detectorGeo.txt", + std::string reactionConfigFileName1 = "reactionConfig1.txt", + std::string reactionConfigFileName2 = "reactionConfig2.txt"){ + printf("=====================================================\n"); + printf(" loading detector geometery : %s.", detGeoFileName.c_str()); + TMacro * haha = new TMacro(); + if( haha->ReadFile(detGeoFileName.c_str()) > 0 ) { + detGeo = AnalysisLib::LoadDetectorGeo(haha); + printf("... done.\n"); + AnalysisLib::PrintDetGeo(detGeo); + }else{ + printf("... fail\n"); + } + delete haha; + + printf("=====================================================\n"); + printf(" loading reaction1 config : %s.", reactionConfigFileName1.c_str()); + TMacro * kaka = new TMacro(); + if( kaka->ReadFile(reactionConfigFileName1.c_str()) > 0 ) { + reactionConfig1 = AnalysisLib::LoadReactionConfig(kaka); + printf("..... done.\n"); + AnalysisLib::PrintReactionConfig(reactionConfig1); + }else{ + printf("..... fail\n"); + } + delete kaka; + + if( detGeo.use2ndArray){ + printf("=====================================================\n"); + printf(" loading reaction2 config : %s.", reactionConfigFileName2.c_str()); + TMacro * jaja = new TMacro(); + if( jaja->ReadFile(reactionConfigFileName2.c_str()) > 0 ) { + reactionConfig2 = AnalysisLib::LoadReactionConfig(kaka); + printf("..... done.\n"); + AnalysisLib::PrintReactionConfig(reactionConfig2); + }else{ + printf("..... fail\n"); + } + delete jaja; + } + +} + +//************************************** Correction parameters; + +std::vector xnCorr; //correction of xn to match xf +std::vector xScale; // correction of x to be (0,1) +std::vector> xfxneCorr; //correction of xn and xf to match e +std::vector> eCorr; // correction to e, ch -> MeV +std::vector> rdtCorr; // correction of rdt, ch -> MeV + +//~========================================= xf = xn correction +void LoadXNCorr(bool verbose = false, const char * fileName = "correction_xf_xn.dat"){ + printf(" loading xf-xn correction."); + xnCorr.clear(); + std::ifstream file; + file.open(fileName); + if( file.is_open() ){ + float a; + while( file >> a ) xnCorr.push_back(a); + printf(".......... done.\n"); + }else{ + printf(".......... fail.\n"); + } + file.close(); + if( verbose ) for(int i = 0; i < (int) xnCorr.size(); i++) printf("%2d | %10.3f\n", i, xnCorr[i]); +} + + +//~========================================= X-Scale correction +void LoadXScaleCorr(bool verbose = false, const char * fileName = "correction_scaleX.dat"){ + printf(" loading x-Scale correction."); + xScale.clear(); + std::ifstream file; + file.open(fileName); + if( file.is_open() ){ + float a, b; + while( file >> a ) xScale.push_back(a); + printf("........ done.\n"); + }else{ + printf("........ fail.\n"); + } + file.close(); + if( verbose ) for(int i = 0; i < (int) xScale.size(); i++) printf("%2d | %10.3f\n", i, xnCorr[i]); +} + +//~========================================= e = xf + xn correction +void LoadXFXN2ECorr(bool verbose = false, const char * fileName = "correction_xfxn_e.dat"){ + printf(" loading xf/xn-e correction."); + xfxneCorr.clear(); + std::ifstream file; + file.open(fileName); + if( file.is_open() ){ + float a, b; + while( file >> a >> b) xfxneCorr.push_back({a, b}); + printf("........ done.\n"); + }else{ + printf("........ fail.\n"); + } + file.close(); + if( verbose ) for(int i = 0; i < (int) xfxneCorr.size(); i++) printf("%2d | %10.3f, %10.3f\n", i, xfxneCorr[i][0], xfxneCorr[i][1]); +} + +//~========================================= e correction +void LoadECorr(bool verbose = false, const char * fileName = "correction_e.dat"){ + printf(" loading e correction."); + eCorr.clear(); + std::ifstream file; + file.open(fileName); + if( file.is_open() ){ + float a, b; + while( file >> a >> b) eCorr.push_back( {a, b} ); // 1/a1, a0 , e' = e * a1 + a0 + printf(".............. done.\n"); + }else{ + printf(".............. fail.\n"); + } + file.close(); + if( verbose ) for(int i = 0; i < (int) eCorr.size(); i++) printf("%2d | %10.3f, %10.3f\n", i, eCorr[i][0], eCorr[i][1]); +} + +//~========================================= rdt correction +void LoadRDTCorr(bool verbose = false, const char * fileName = "correction_rdt.dat"){ + printf(" loading rdt correction."); + rdtCorr.clear(); + std::ifstream file; + file.open(fileName); + if( file.is_open() ){ + float a, b; + while( file >> a >> b) rdtCorr.push_back({a, b}); + printf("............ done.\n"); + }else{ + printf("............ fail.\n"); + } + file.close(); + if( verbose ) for(int i = 0; i < (int) rdtCorr.size(); i++) printf("%2d | %10.3f, %10.3f\n", i, rdtCorr[i][0], rdtCorr[i][1]); +} + + +#endif \ No newline at end of file diff --git a/Armory/Process_BasicConfig b/Armory/Process_BasicConfig new file mode 100644 index 0000000..ccc16de --- /dev/null +++ b/Armory/Process_BasicConfig @@ -0,0 +1,73 @@ +#!/bin/bash -l + +############################################## +# +# This script define color, PCID, and dataPath +# +############################################## + +if [ ! -z $RED ]; then + echo "Process_BasicConfig already loaded." + return +fi + +RED='\033[1;31m' +YELLOW='\033[1;33m' +ORANGE='\033[0;33m' +GREEN='\033[1;32m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +NC='\033[0m' #no color +LRED='\033[1;91m' + +############## need to distingish mac and daq +Arch="$(uname -s)" +PCName="$(hostname)" +PCID=-1 #if PCID == 1 (DAQ), 2 (MAC), -1(OTHER) + +#------ Set up data folder, check disk space +echo -e "${YELLOW} ##################### Check computer name and arch. ${NC}" +echo "PC name : ${PCName}" +echo "Archetech: ${Arch}" + +if [ ${Arch} == "Linux" ] && [ ${PCName} == "solaris-daq" ]; then + + PCID=1 + + pathsSetting=${HOME}/SOLARIS_QT6_DAQ/programSettings.txt + if [ -e ${pathsSetting} ]; then + #echo "Found DAQ programSettings.txt for paths settings" + + analysisPath=$(cat ${pathsSetting} | head -n 2 | tail -n 1) + + if [ ! "${analysisPath}" = "$SOLARISANADIR" ]; then + echo "The analysisPath from ${analysisPath} is different from present folder $SOLARISANADIR. Abort." + exit + fi + + rawDataPathParent=$(cat ${pathsSetting} | head -n 3 | tail -n 1) + rootDataPathParent=$(cat ${pathsSetting} | head -n 4 | tail -n 1) + + databaseIP=$(cat ${pathsSetting} | head -n 6 | tail -n 1) + databaseName=$(cat ${pathsSetting} | head -n 7 | tail -n 1) + + #echo ${rawDataPathParent} + #echo ${rootDataPathParent} + #echo ${databaseIP} + #echo ${databaseName} + + else + + echo "${RED} Cannot found DAQ programSettings.txt for path settings ${NC}" + echo "Seek Ryan for help" + exit + + fi + +fi + +if [ ${Arch} == "Darwin" ] && [ ${PCName} == "SOLARISs-Mac-Studio.local" ]; then + PCID=2 + rawDataPathParent=${HOME}/experimentalData/ + rootDataPathParent=${HOME}/experimentalData/ +fi \ No newline at end of file diff --git a/Armory/Process_Download b/Armory/Process_Download new file mode 100755 index 0000000..042be0c --- /dev/null +++ b/Armory/Process_Download @@ -0,0 +1,105 @@ +#!/bin/bash + +if [ $# -eq 0 ] || [ $1 == "-help" ]; then + echo "$./process_Download [RunNum]" + echo " RunNum = run number" + echo " * if RunNum = all, sync all" + exit 1 +fi; +RUN=$1 + +runNum=${RUN#0} #remove zero +RUN=$(printf '%03d' $runNum) ##add back the zero + +source $SOLARISANADIR/armory/Process_BasicConfig +source $SOLARISANADIR/working/expName.sh + +MacRawDataPath=$rawDataPathParent/$expName/ +IP=solarisdaq # defined at ~/.ssh/config +USR=solaris + +if [ ${RUN} == "all" ]; then + + if [ ${PCID} -eq 2 ]; then + + #=========== Ping to check the connectivity + echo "Checking $IP connetivity, max wait for 3 sec...." + ping -c 3 -W 3 $IP #> /dev/null + if [ $? -ne 0 ]; then + echo -e "$RED !!!!!!! $IP is not alive $NC" + else + #============ Get the raw data + rsync -avuht --progress $USR@$IP:$rawDataPath/$expName_* $MacRawDataPath/data/. + + echo -e "$YELLOW======== rsync RunTimeStamp.dat $NC" + rsync -avuht --progress $USR@$IP:$rawDataPath/$RunTimeStamp* $MacRawDataPath/data/. + + echo -e "$YELLOW======== rsync expName.sh $NC" + rsync -avuht --progress $USR@$IP:Analysis/working/expName.sh $SOLARISANADIR/working/. + fi + else + echo -e "$RED############### Only in SOLARIS MAC can donwload data. skip.$NC" + fi + + echo -e "$YELLOW=============================================$NC" + tail -10 $MacRawDataPath/data/RunTimeStamp.dat + echo -e "$YELLOW=============================================$NC" + + exit 1 +fi + +#just in case people put %03d as RUN +if [ "${RUN:0:2}" == "00" ]; then + RUN=${RUN:2:1} +elif [ "${RUN:0:1}" == "0" ]; then + RUN=${RUN:1:2} +else + RUN=$(printf '%d' $RUN) +fi +RUN=$(printf '%03d' ${RUN}) + +####################################### +#################### Download raw data +echo -e "${RED}######################### Download raw data: run ${RUN}${NC}" +if [ ${PCID} -eq 2 ]; then + + #=========== Ping to check the connectivity + echo "Checking $IP connetivity, max wait for 3 sec...." + ping -c 3 $IP -W 3 #> /dev/null + if [ $? -ne 0 ]; then + echo -e "$RED !!!!!!! $IP is not alive $NC" + else + #============ Get the raw data + echo -e "================= RUN $RUN: Get the raw data `date`" + + rsync -avuht --progress $USR@$IP:$rawDataPath/$expName_$RUN* $MacRawDataPath/data/. + + echo -e "$YELLOW======== rsync RunTimeStamp.dat $NC" + rsync -avuht --progress $USR@$IP:$rawDataPath/$RunTimeStamp* $MacRawDataPath/data/. + + echo -e "$YELLOW======== rsync expName.sh $NC" + rsync -avuht --progress $USR@$IP:Analysis/working/expName.sh $SOLARISANADIR/working/. + fi +else + echo -e "$RED############### Only in SOLARIS MAC can donwload data. skip.$NC" +fi + +echo -e "$YELLOW=============================================$NC" +tail -10 $MacRawDataPath/data/RunTimeStamp.dat +echo -e "$YELLOW=============================================$NC" + +count=`ls -1 $SOLARISANADIR/data_raw/${expName}_${RUN}_*.sol 2>/dev/null | wc -l` +echo -e "========== Number of Files : ${count}${NC}" +if [ ${count} -eq 0 ]; then + echo "============================================" + echo "==== RAW Files of RUN-${RUN} not found! " + echo "============================================" + + isRunDataExist=false + exit 1 +else + echo -e "${YELLOW}" + du -hc $SOLARISANADIR/data_raw/${expName}_${RUN}_*.sol + echo -e "$NC=============================================" + isRunDataExist=true +fi diff --git a/Armory/Process_EventBuilder b/Armory/Process_EventBuilder new file mode 100755 index 0000000..942808c --- /dev/null +++ b/Armory/Process_EventBuilder @@ -0,0 +1,108 @@ +#!/bin/bash + +if [ -z $SOLARISANADIR ]; then + echo "###### env variable SOLARISANADIR not defined. Abort. Please run the SOLARIS.sh." + echo "better add \"source \" into .bashrc" + exit +fi + +if [ $# -ne 3 ] || [ $1 == "-help" ]; then + echo "$ Process_EventBuilder [RunNum] [EventBuild] [timeWin]" + echo " RunNum = run number" + echo " EventBld = 2/1/0/-1/-2 || 2 = with Trace" + echo " timeWin = number of tick for an event " + echo "" + exit 1 +fi; + +RUN=$1 +EventBld=$2 +timeWin=$3 + +source ${SOLARISANADIR}/armory/Process_BasicConfig +source ${SOLARISANADIR}/working/expName.sh + +runNum=${RUN#0} #remove zero +RUN=$(printf '%03d' $runNum) ##add back the zero + +rawDataPath=$SOLARISANADIR/data_raw +rootDataPath=$SOLARISANADIR/root_data + +rawDataPattern="$rawDataPath/${expName}_${RUN}_*.sol" +rootDataName="$rootDataPath/run$RUN.root" + +dir=$(pwd) +cd ${SOLARISANADIR}/armory +make +cd ${dir} + +#==== check raw data exist +isRawDataExist=`ls -1 ${rawDataPattern}* 2>/dev/null | wc -l` + +if [ ! $isRawDataExist -gt 0 ]; then + echo -e "${LRED}################# Run Data $rawDataPattern not exist. Abort. ${NC}" + exit +fi + +echo -e "${CYAN} ============== list of files ${NC}" +\du -h ${rawDataPattern}* + +totSize=$(\du -hc ${rawDataPattern}* | tail -n 1 | awk '{print $1}') +echo -e "${CYAN} ============== total file size : ${totSize}${NC}" + + +#==== check raw data timeStamp +if [ ${Arch} == "Linux" ]; then + rawDataTime=`stat -c "%Z" ${rawDataPattern}* | sort -rn | head -1` +else + rawDataTime=`stat -f "%Sm" -t "%Y%m%d%H%M%S" $rawDataPattern | sort -rn | head -1` +fi + +#==== check if root data exist +isRootDataExist=`ls -1 $rootDataName 2>/dev/null | wc -l` + +#==== if root data exist, check timeStamp +if [ ${isRootDataExist} -gt 0 ]; then + if [ ${Arch} == "Linux" ]; then + rootDataTime=`stat -c "%Z" $rootDataName | sort -rn | head -1` + else + rootDataTime=`stat -f "%Sm" -t "%Y%m%d%H%M%S" $rootDataName | sort -rn | head -1` + fi +else + rootDataTime=0 +fi + + +if [ ${EventBld} -eq 0 ]; then + + echo -e "${LRED}>>>>>>>>>>>>>>>>>>>>> Event Building Skipped by user. ${NC}" + +elif [ ${EventBld} -ge 1 ]; then + + if [ ${rawDataTime} -ge ${rootDataTime} ]; then + + echo -e "${LRED}>>>>>>>>>>>>>>>>>>>>> Event Building $(date) ${NC}" + if [ ${EventBld} -eq 1 ]; then + EventBuilder $rootDataName ${timeWin} 0 $rawDataPattern + elif [ ${EventBld} -eq 2 ]; then + EventBuilder $rootDataName ${timeWin} 1 $rawDataPattern + fi + echo -e "${LRED}<<<<<<<<<<<<<<<< Done Event Building $(date) ${NC}" + + else + echo -e "${GREEN} root data are newer than raw data. No need to merged again.${NC}" + echo -e "${GREEN} You can Force merging using option -${EventBld}, ${ORANGE} see ./process_run.sh -help${NC}" + echo -e "${LRED}>>>>>>>>>>>>>>>>>>>>> Event Building Skipped. ${NC}" + fi + +else + + echo -e "${LRED}>>>>>>>>>>>>>>> Force Event Building $(date) ${NC}" + if [ ${EventBld} -eq -1 ]; then + EventBuilder $rootDataName ${timeWin} 0 $rawDataPattern + elif [ ${EventBld} -eq -2 ]; then + EventBuilder $rootDataName ${timeWin} 1 $rawDataPattern + fi + echo -e "${LRED}<<<<<<<<<<<<<<<< Done Event Building $(date) ${NC}" + +fi \ No newline at end of file diff --git a/Armory/Process_MultiRuns b/Armory/Process_MultiRuns new file mode 100755 index 0000000..fd0257f --- /dev/null +++ b/Armory/Process_MultiRuns @@ -0,0 +1,96 @@ +#!/bin/bash -l + +if [ -z $SOLARISANADIR ]; then + echo "###### env variable SOLARISANADIR not defined. Abort. Please run the SOLARIS.sh." + echo "better add \"source \" into .bashrc" + exit +fi + +if [ $# -le 2 ] || [ $1 == "-help" ]; then + echo "$./process_MultiRuns [RunNum1] [RunNum2] [EventBuild] [GeneralSort] [numMacTerminal]" + echo " RunNum1 = start run number" + echo " RunNum2 = stop run number" + echo " EventBld = 2/1/0/-1/-2 || 2 = with Trace" + echo " GeneralSort = n/0/-n || n = number of worker" + echo " TraceMethod = -1/0/1/2 || -1 no trace, 0 save trace, 1 fit, 2 trapezoid" + echo " numMacTerminal = n ^ || in order to speed up in Mac " + echo " * negative option = force " + echo " ^ only for mac, and it will override GeneralSort to be 1 worker. " + exit 1 +fi; + + +runID1=$1 +runID2=$2 +buidEvt=$3 +nWorker=0 +traceMethod=0 +nTerminal=0 + +if [ $# -ge 4 ]; then nWorker=$4; fi +if [ $# -ge 5 ]; then traceMethod=$5; fi +if [ $# -ge 6 ]; then nTerminal=$6; fi + +source ${SOLARISANADIR}/armory/Process_BasicConfig +source ${SOLARISANADIR}/working/expName.sh + + +if [ $PCID -eq 2 ]; then + if [ $nTerminal -ge 2 ]; then + if [[ $nWorker -ge 0 ]]; then + nWorker=1; + else + nWorker=-1; + fi + fi +else + $nTerminal=0; +fi + + +if [ $nTerminal -eq 0 ]; then + + for i in $(seq $runID1 $runID2); do + Process_Run $i $buidEvt $nWorker $traceMethod 0 + done + +else + + if [ $PCID -ne 2 ]; then + exit 1 + fi + + # Calculate the size of each segment + segment_size=$(( ($runID2 - $runID1 + 1) / $nTerminal )) + + # Iterate through the segments + for i in $(seq 0 $(( $nTerminal - 1 ))); do + start=$(( $runID1 + ($i * $segment_size) )) + end=$(( $start + $segment_size - 1 )) + + # Handle the last segment, which may be larger + if [[ $i -eq $(( $nTerminal - 1 )) ]]; then + end=$runID2 + fi + + echo "Segment $(( $i + 1 )): [$start, $end]" + + profile_name="Homebrew" + width=700 + height=500 + x_pos=200 + y_pos=200 + +osascript <\" into .bashrc" + exit +fi + + +if [ $# -eq 0 ] || [ $1 == "-help" ]; then + echo "$ Process_Run [RunNum] [EventBuild] [GeneralSort] [TraceMethod] [Monitor]" + echo " RunNum = run number / \"lastRun\" " + echo " EventBld = 2/1/0/-1/-2 || 2 = with Trace" + echo " GeneralSort = n/0/-n || n = number of worker" + echo " TraceMethod = -1/0/1/2 || -1 no trace, 0 save trace, 1 fit, 2 trapezoid(not implemented)" + echo " Monitor = 2/1/0 || 1 = single run, 2 = using the list in ChainMonitors.C" + echo "" + echo " * negative option = force (except for TraceMethod and Monitor)." + echo " * Defult timeWindow for Event builder is 100 tick = 800 ns." + echo "" + exit 1 +fi; + +RUN=$1 +runNum=$1 +EventBld=2 +nWorker=1 +TraceMethod=-1 +isMonitor=1 + +if [ $# -ge 2 ]; then EventBld=$2; fi +if [ $# -ge 3 ]; then nWorker=$3; fi +if [ $# -ge 4 ]; then TraceMethod=$4; fi +if [ $# -ge 5 ]; then isMonitor=$5; fi + +if [ "$RUN" == "lastRun" ]; then + RUN=$runID +fi + +RUN=${RUN##*(0)} #remove zero +RUN=$(printf '%03d' $RUN) ##add back the zero + +################################### Setting display +echo "#################################################" +echo "### Process_Run #####" +echo "#################################################" +echo "### RunID : ${RUN}" +echo "### Event Builder : $EventBld" +echo "### General Sort : $nWorker worker(s)" +echo "### Trace Method : $TraceMethod" +echo "### Monitor : $isMonitor" +echo "#################################################" + +source ${SOLARISANADIR}/armory/Process_BasicConfig +source ${SOLARISANADIR}/working/expName.sh + +if [ "$PWD" != "${SOLARISANADIR}/working" ]; then + echo "============= go to the Working directory" + cd "${SOLARISANADIR}/working" +fi + + +#################################### CHECK IS RUN DATA EXIST +isRunDataExist=true + +#################################### EVENT BUILDER +source Process_Download $RUN + +if [ $isRunDataExist ]; then + source Process_EventBuilder $RUN $EventBld $timeWin +fi + +#################################### GeneralSort + +if [ $isRunDataExist ]; then + source Process_Sort $RUN $nWorker $TraceMethod +fi +#################################### Monitor + +if [ $isMonitor -eq 0 ]; then + echo -e "${LRED}>>>>>>>>>>>>>>>>>>>>> Monitor Skipped by user. ${NC}" +elif [ $isMonitor -eq 1 ]; then + root -l "ChainMonitors.C($RUN)" +elif [ $isMonitor -eq 2 ]; then + root -l "ChainMonitors.C" +fi + + + + diff --git a/Armory/Process_Sort b/Armory/Process_Sort new file mode 100755 index 0000000..a397393 --- /dev/null +++ b/Armory/Process_Sort @@ -0,0 +1,91 @@ +#!/bin/bash -l + +if [ -z $SOLARISANADIR ]; then + echo "###### env variable SOLARISANADIR not defined. Abort. Please run the SOLARIS.sh." + echo "better add \"source \" into .bashrc" + exit +fi + +if [ $# -eq 0 ] || [ $1 == "-help" ]; then + echo "$ Process_Sort [RunNum] [GeneralSort] [TraceMethod]" + echo " RunNum = run number" + echo " GeneralSort = n/0/-n || n = number of worker" + echo " TraceMethod = -1/0/1/2 || -1 no trace, 0 save trace, 1 fit, 2 trapezoid" + echo "" + exit 1 +fi; + +RUN=$1 +nWorker=$2 +TraceMethod=$3 + +source $SOLARISANADIR/armory/Process_BasicConfig +source $SOLARISANADIR/working/expName.sh + +runNum=${RUN#0} #remove zero +RUN=$(printf '%03d' $runNum) ##add back the zero + +if [ ${nWorker} -eq 0 ]; then + echo -e "${LRED}>>>>>>>>>>>>>>>>>>>>> GeneralSort Skipped by user. ${NC}" +else + source $ROOTSYS/bin/thisroot.sh + + #--------- Check is runXXX.root exist + rootDataPath=$SOLARISANADIR/root_data + rootDataName="$rootDataPath/run$RUN.root" + isRootDataExist=`ls -1 $rootDataName 2>/dev/null | wc -l` + + #==== if root data exist, check timeStamp + if [ $isRootDataExist -gt 0 ]; then + if [ ${Arch} == "Linux" ]; then + rootDataTime=`stat -c "%Z" $rootDataName | sort -rn | head -1` + else + rootDataTime=`stat -f "%Sm" -t "%Y%m%d%H%M%S" $rootDataName | sort -rn | head -1` + fi + else + rootDataTime=0 + echo -e "$LRED ################# run$RUN.root does not exist. Abort. $NC" + exit 1 + fi + + #-------- check gen_root timestamp + genRootDataName="$rootDataPath/gen_run$RUN.root" + isGenRootDataExist=`ls -1 $genRootDataName 2>/dev/null | wc -l` + + #----- if gen_runXXX.data exist, check timeStamp + if [ $isGenRootDataExist -gt 0 ]; then + if [ ${Arch} == "Linux" ]; then + genRootDataTime=`stat -c "%Z" $genRootDataName | sort -rn | head -1` + else + genRootDataTime=`stat -f "%Sm" -t "%Y%m%d%H%M%S" $genRootDataName | sort -rn | head -1` + fi + else + genRootDataTime=0 + fi + + mkdir -p ~/.proof/working + cp ${SOLARISANADIR}/working/Mapping.h ~/.proof/working/. + + if [ $nWorker -le -1 ]; then + echo -e "${LRED}>>>>>>>>>>>>>>> Force GeneralSort $(date) ${NC}" + root -l -q -b "$SOLARISANADIR/armory/GeneralSortAgent.C($runNum, $nWorker, $TraceMethod)" + echo -e "${LRED}<<<<<<<<<<<<<<<< Done GeneralSort $(date) ${NC}" + fi + + if [ $nWorker -ge 1 ]; then + + if [ $rootDataTime -ge $genRootDataTime ]; then + + echo -e "${LRED}>>>>>>>>>>>>>>>>>>>>> GeneralSort $(date) ${NC}" + root -l -q -b "$SOLARISANADIR/armory/GeneralSortAgent.C($runNum, $nWorker, $TraceMethod)" + echo -e "${LRED}<<<<<<<<<<<<<<<< Done GeneralSort $(date) ${NC}" + + else + echo -e "${GREEN} gen_run$RUN.root is newer than run$RUN.root. No need to GeneralSort again.${NC}" + echo -e "${GREEN} You can Force GeneralSort using option -${nWorker}, ${ORANGE} see Process_Run -help${NC}" + echo -e "${LRED}>>>>>>>>>>>>>>>>>>>>> GeneralSort Skipped. ${NC}" + fi + + fi + +fi \ No newline at end of file diff --git a/Armory/SolReader.h b/Armory/SolReader.h new file mode 100644 index 0000000..8761666 --- /dev/null +++ b/Armory/SolReader.h @@ -0,0 +1,258 @@ +#ifndef SOLREADER_H +#define SOLREADER_H + +#include /// for FILE +#include +#include +#include +#include +#include // time in nano-sec + +#include "Hit.h" + +class SolReader { + private: + FILE * inFile; + unsigned int inFileSize; + unsigned int filePos; + unsigned int totNumBlock; + + unsigned short blockStartIdentifier; + unsigned int numBlock; + bool isScanned; + + void init(); + + std::vector blockPos; + + public: + SolReader(); + SolReader(std::string fileName, unsigned short dataType); + ~SolReader(); + + void OpenFile(std::string fileName); + int ReadNextBlock(int isSkip = 0); // opt = 0, noraml, 1, fast + int ReadBlock(unsigned int index, bool verbose = false); + + void ScanNumBlock(); + + bool IsEndOfFile() const {return (filePos >= inFileSize ? true : false);} + unsigned int GetBlockID() const {return numBlock - 1;} + unsigned int GetNumBlock() const {return numBlock;} + unsigned int GetTotalNumBlock() const {return totNumBlock;} + unsigned int GetFilePos() const {return filePos;} + unsigned int GetFileSize() const {return inFileSize;} + + void RewindFile(); + + Hit * hit; + +}; + +void SolReader::init(){ + inFileSize = 0; + numBlock = 0; + filePos = 0; + totNumBlock = 0; + hit = new Hit(); + + isScanned = false; + + blockPos.clear(); + +} + +SolReader::SolReader(){ + init(); +} + +SolReader::SolReader(std::string fileName, unsigned short dataType = 0){ + init(); + OpenFile(fileName); + hit->SetDataType(dataType, DPPType::PHA); +} + +SolReader::~SolReader(){ + if( !inFile ) fclose(inFile); + delete hit; +} + +inline void SolReader::OpenFile(std::string fileName){ + inFile = fopen(fileName.c_str(), "r"); + if( inFile == NULL ){ + printf("Cannot open file : %s \n", fileName.c_str()); + }else{ + fseek(inFile, 0L, SEEK_END); + inFileSize = ftell(inFile); + rewind(inFile); + } +} + +inline int SolReader::ReadBlock(unsigned int index, bool verbose){ + if( isScanned == false) return -1; + if( index >= totNumBlock )return -1; + fseek(inFile, 0L, SEEK_SET); + + if( verbose ) printf("Block index: %u, File Pos: %u byte\n", index, blockPos[index]); + + fseek(inFile, blockPos[index], SEEK_CUR); + + filePos = blockPos[index]; + + numBlock = index; + + return ReadNextBlock(); +} + +inline int SolReader::ReadNextBlock(int isSkip){ + if( inFile == NULL ) return -1; + if( feof(inFile) ) return -1; + if( filePos >= inFileSize) return -1; + + fread(&blockStartIdentifier, 2, 1, inFile); + + if( (blockStartIdentifier & 0xAA00) != 0xAA00 ) { + printf("header fail.\n"); + return -2 ; + } + + if( ( blockStartIdentifier & 0xF ) == DataFormat::Raw ){ + hit->SetDataType(DataFormat::Raw, ((blockStartIdentifier >> 1) & 0xF) == 0 ? DPPType::PHA : DPPType::PSD); + } + hit->dataType = blockStartIdentifier & 0xF; + hit->DPPType = ((blockStartIdentifier >> 4) & 0xF) == 0 ? DPPType::PHA : DPPType::PSD; + + if( hit->dataType == DataFormat::ALL){ + if( isSkip == 0 ){ + fread(&hit->channel, 1, 1, inFile); + fread(&hit->energy, 2, 1, inFile); + if( hit->DPPType == DPPType::PSD ) fread(&hit->energy_short, 2, 1, inFile); + fread(&hit->timestamp, 6, 1, inFile); + fread(&hit->fine_timestamp, 2, 1, inFile); + fread(&hit->flags_high_priority, 1, 1, inFile); + fread(&hit->flags_low_priority, 2, 1, inFile); + fread(&hit->downSampling, 1, 1, inFile); + fread(&hit->board_fail, 1, 1, inFile); + fread(&hit->flush, 1, 1, inFile); + fread(&hit->trigger_threashold, 2, 1, inFile); + fread(&hit->event_size, 8, 1, inFile); + fread(&hit->aggCounter, 4, 1, inFile); + }else{ + fseek(inFile, hit->DPPType == DPPType::PHA ? 31 : 33, SEEK_CUR); + } + fread(&hit->traceLenght, 8, 1, inFile); + if( isSkip == 0){ + fread(hit->analog_probes_type, 2, 1, inFile); + fread(hit->digital_probes_type, 4, 1, inFile); + fread(hit->analog_probes[0], hit->traceLenght*4, 1, inFile); + fread(hit->analog_probes[1], hit->traceLenght*4, 1, inFile); + fread(hit->digital_probes[0], hit->traceLenght, 1, inFile); + fread(hit->digital_probes[1], hit->traceLenght, 1, inFile); + fread(hit->digital_probes[2], hit->traceLenght, 1, inFile); + fread(hit->digital_probes[3], hit->traceLenght, 1, inFile); + }else{ + fseek(inFile, 6 + hit->traceLenght*(12), SEEK_CUR); + } + + }else if( hit->dataType == DataFormat::OneTrace){ + if( isSkip == 0 ){ + fread(&hit->channel, 1, 1, inFile); + fread(&hit->energy, 2, 1, inFile); + if( hit->DPPType == DPPType::PSD ) fread(&hit->energy_short, 2, 1, inFile); + fread(&hit->timestamp, 6, 1, inFile); + fread(&hit->fine_timestamp, 2, 1, inFile); + fread(&hit->flags_high_priority, 1, 1, inFile); + fread(&hit->flags_low_priority, 2, 1, inFile); + }else{ + fseek(inFile, hit->DPPType == DPPType::PHA ? 14 : 16, SEEK_CUR); + } + fread(&hit->traceLenght, 8, 1, inFile); + if( isSkip == 0){ + fread(&hit->analog_probes_type[0], 1, 1, inFile); + fread(hit->analog_probes[0], hit->traceLenght*4, 1, inFile); + }else{ + fseek(inFile, 1 + hit->traceLenght*4, SEEK_CUR); + } + + }else if( hit->dataType == DataFormat::NoTrace){ + if( isSkip == 0 ){ + fread(&hit->channel, 1, 1, inFile); + fread(&hit->energy, 2, 1, inFile); + if( hit->DPPType == DPPType::PSD ) fread(&hit->energy_short, 2, 1, inFile); + fread(&hit->timestamp, 6, 1, inFile); + fread(&hit->fine_timestamp, 2, 1, inFile); + fread(&hit->flags_high_priority, 1, 1, inFile); + fread(&hit->flags_low_priority, 2, 1, inFile); + }else{ + fseek(inFile, hit->DPPType == DPPType::PHA ? 14 : 16, SEEK_CUR); + } + + }else if( hit->dataType == DataFormat::MiniWithFineTime){ + if( isSkip == 0 ){ + fread(&hit->channel, 1, 1, inFile); + fread(&hit->energy, 2, 1, inFile); + if( hit->DPPType == DPPType::PSD ) fread(&hit->energy_short, 2, 1, inFile); + fread(&hit->timestamp, 6, 1, inFile); + fread(&hit->fine_timestamp, 2, 1, inFile); + }else{ + fseek(inFile, hit->DPPType == DPPType::PHA ? 11 : 13, SEEK_CUR); + } + + }else if( hit->dataType == DataFormat::Minimum){ + if( isSkip == 0 ){ + fread(&hit->channel, 1, 1, inFile); + fread(&hit->energy, 2, 1, inFile); + if( hit->DPPType == DPPType::PSD ) fread(&hit->energy_short, 2, 1, inFile); + fread(&hit->timestamp, 6, 1, inFile); + }else{ + fseek(inFile, hit->DPPType == DPPType::PHA ? 9 : 11, SEEK_CUR); + } + + }else if( hit->dataType == DataFormat::Raw){ + fread(&hit->dataSize, 8, 1, inFile); + if( isSkip == 0){ + fread(hit->data, hit->dataSize, 1, inFile); + }else{ + fseek(inFile, hit->dataSize, SEEK_CUR); + } + } + + numBlock ++; + filePos = ftell(inFile); + return 0; +} + +void SolReader::RewindFile(){ + rewind(inFile); + filePos = 0; + numBlock = 0; +} + +void SolReader::ScanNumBlock(){ + if( inFile == NULL ) return; + if( feof(inFile) ) return; + + numBlock = 0; + blockPos.clear(); + + blockPos.push_back(0); + + while( ReadNextBlock(1) == 0){ + blockPos.push_back(filePos); + printf("%u, %.2f%% %u/%u\n\033[A\r", numBlock, filePos*100./inFileSize, filePos, inFileSize); + } + + totNumBlock = numBlock; + numBlock = 0; + isScanned = true; + printf("\nScan complete: number of data Block : %u\n", totNumBlock); + rewind(inFile); + filePos = 0; + + //for( int i = 0; i < totNumBlock; i++){ + // printf("%7d | %u \n", i, blockPos[i]); + //} + +} + +#endif \ No newline at end of file diff --git a/Armory/readRawTrace.C b/Armory/readRawTrace.C new file mode 100644 index 0000000..f2630f9 --- /dev/null +++ b/Armory/readRawTrace.C @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../working/Mapping.h" + +void readRawTrace(TString fileName, int minDetID = 0, int maxDetID = 1000){ + +/**///============================================================== + + TFile * f1 = new TFile (fileName, "read"); + TTree * tree = (TTree *) f1->Get("tree"); + + if( tree == NULL ) { + printf("===== Are you using gen_runXXX.root ? please use runXXX.root\n"); + return; + } + + int totnumEntry = tree->GetEntries(); + printf( "========== total Entry : %d \n", totnumEntry); + + TCanvas * cRead = new TCanvas("cRead", "Read Raw Trace", 0, 1500, 800, 300); + cRead->Divide(1,1); + for( int i = 1; i <= 2 ; i++){ + cRead->cd(i)->SetGrid(); + } + cRead->SetGrid(); + + gStyle->SetOptFit(0); + +/**///============================================================== + Int_t bd[200]; + Int_t ch[200]; + Int_t numHit; + Int_t trace[200][2500]; + Int_t traceLength[200]; + tree->SetBranchAddress("bd", bd); + tree->SetBranchAddress("ch", ch); + tree->SetBranchAddress("multi", &numHit); + tree->SetBranchAddress("trace", trace); + tree->SetBranchAddress("tl", traceLength); + + TLatex text ; + text.SetNDC(); + text.SetTextFont(62); + text.SetTextSize(0.06); + text.SetTextColor(2); + + bool breakFlag = false; + bool lastEvFlag = false; + std::vector oldEv; + int evPointer = 0; + + TGraph * graph = new TGraph(); + + for( int ev = 0; ev < totnumEntry; ev++){ + + if( lastEvFlag ) { + ev = oldEv[evPointer]; + lastEvFlag = false; + } + tree->GetEntry(ev); + + int countJ = 0; + + for( int j = 0; j < numHit ; j++){ + + int detID = mapping[bd[j]][ch[j]]; + + if( !(minDetID <= detID && detID <= maxDetID ) ) continue; + + if( countJ == 0 ) printf("-------------------------------- ev : %d, evPointer : %d| num Trace : %d\n", ev, evPointer, numHit); + + printf("nHit: %d, id : %d, trace Length : %u ( enter = next , q = stop, w = last)\n", j, detID, traceLength[j]); + + graph->Clear(); + graph->Set(traceLength[j]); + for( int k = 0; k < traceLength[j] ; k++){ + graph->SetPoint(k, k, trace[j][k]); + //printf("%4d, %5d |", k, trace[j][k]); + //if( k % 10 ==0 ) printf("\n"); + } + + graph->SetTitle(Form("ev: %d, nHit : %d, id : %d, trace Length : %u\n", ev, j, detID, traceLength[j])); + + cRead->cd(1); + cRead->Clear(); + graph->Draw("Al"); + //g->GetXaxis()->SetRangeUser(0, g->GetN()); + //g->GetYaxis()->SetRangeUser(7500, 35000); + + cRead->Update(); + gSystem->ProcessEvents(); + + + char s[80]; + fgets(s, sizeof s, stdin); + + if( s[0] == 113 ) { // 'q' = 113 + breakFlag = true; + break; + }else if( s[0] == 119 ) { // 'w' = 119 + + if( j > 0 || countJ > 0 ) { + j = j - 2; + } + + if( (j == 0 && (int)oldEv.size() >= 0 && evPointer > 0 ) || countJ == 0 ) { + if( evPointer > 0 ) evPointer --; + if( evPointer == 0 ) printf(" the first event!!! \n"); + lastEvFlag = true; + //printf(" ev : %d, evPt : %d \n", oldEv[evPointer], evPointer); + break; + } + } + + countJ ++; + + } + if( breakFlag ) break; + + if( lastEvFlag == false && countJ > 0 ){ + if( oldEv.size() == evPointer ) oldEv.push_back(ev); + evPointer ++; + } + + + } + + //gROOT->ProcessLine(".q"); + +} diff --git a/Armory/readTrace.C b/Armory/readTrace.C new file mode 100644 index 0000000..980aeb7 --- /dev/null +++ b/Armory/readTrace.C @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void readTrace(TString fileName, int minDetID = 0, int maxDetID = 1000, bool isGoodOnly = false){ + +/**///============================================================== + + TFile * f1 = new TFile (fileName, "read"); + TTree * tree = (TTree *) f1->Get("gen_tree"); + + int totnumEntry = tree->GetEntries(); + printf( "========== total Entry : %d \n", totnumEntry); + + TCanvas * cRead = new TCanvas("cRead", "Read Trace", 0, 1500, 800, 300); + cRead->Divide(1,1); + for( int i = 1; i <= 2 ; i++){ + cRead->cd(i)->SetGrid(); + } + cRead->SetGrid(); + + gStyle->SetOptFit(0); + +/**///============================================================== + TClonesArray * arr = new TClonesArray("TGraph"); + tree->SetBranchAddress("trace", &arr); + + //TODO UP-Down arrow for pervious-next control + TLine timeVLine; + + TLatex text ; + text.SetNDC(); + text.SetTextFont(62); + text.SetTextSize(0.06); + text.SetTextColor(2); + + bool breakFlag = false; + bool lastEvFlag = false; + std::vector oldEv; + int evPointer = 0; + + for( int ev = 0; ev < totnumEntry; ev++){ + + if( lastEvFlag ) { + ev = oldEv[evPointer]; + lastEvFlag = false; + } + tree->GetEntry(ev); + + int nTrace = arr->GetEntriesFast(); + + int countJ = 0; + + for( int j = 0; j < nTrace ; j++){ + + TGraph * g = (TGraph*) arr->At(j); + + TString gTitle; + gTitle = g->GetTitle(); + ///printf("TGraph Title : %s\n", gTitle.Data()); + + int detID = 0; + int pos = gTitle.Index("id:"); + gTitle.Remove(0, pos+3); + gTitle.Remove(3); + detID = gTitle.Atoi(); + + if( !(minDetID <= detID && detID <= maxDetID ) ) continue; + + if( countJ == 0 ) printf("-------------------------------- ev : %d, evPointer : %d| num Trace : %d\n", ev, evPointer, nTrace); + + + TF1 * gFit = (TF1 *) g->FindObject("gFit"); + + TString kTitle; + + if( gFit != NULL ){ + double base, time = 0, riseTime, energy, chiSq; + energy = gFit->GetParameter(0); + time = gFit->GetParameter(1); + riseTime = gFit->GetParameter(2); + base = gFit->GetParameter(3); + chiSq = gFit->GetChisquare()/gFit->GetNDF(); + int kind = gFit->GetLineColor(); + int det = gFit->GetLineStyle(); + + ///if( !(minDetID <= det && det <= maxDetID ) ) continue; + + if( isGoodOnly){ + if( abs(energy) < 1.5* g->GetRMS(2) ) continue; + if( time > gFit->GetXmax() || time < gFit->GetXmin()) continue; + if( time > 200 || time < 20) continue; + if( riseTime > gFit->GetXmax()/7. || riseTime < 0 ) continue; + } + + //if( energy < 400 ) continue; + + kTitle = Form("(%3d,%d), base: %8.1f, rise: %6.2f, time: %6.1f, energy: %8.1f | chi2: %8.1f, RMS: %6.1f", + det, kind, base, riseTime, time, energy, chiSq, g->GetRMS(2)); + + printf("%s |(q = break, w = last one)", kTitle.Data()); + + + timeVLine.SetX1(time); + timeVLine.SetX2(time); + timeVLine.SetY1(-1000); + timeVLine.SetY2(20000); + timeVLine.SetLineColor(4); + } + + cRead->cd(1); + //cRead->Clear(); + g->Draw("AC"); + //g->GetXaxis()->SetRangeUser(0, g->GetN()); + //g->GetYaxis()->SetRangeUser(7500, 35000); + timeVLine.Draw("same"); + if( gFit != NULL ) text.DrawText(0.11, 0.85, kTitle.Data()); + + cRead->Update(); + gSystem->ProcessEvents(); + + + char s[80]; + fgets(s, sizeof s, stdin); + + if( s[0] == 113 ) { // 'q' = 113 + breakFlag = true; + break; + }else if( s[0] == 119 ) { // 'w' = 119 + + if( j > 0 || countJ > 0 ) { + j = j - 2; + } + + if( (j == 0 && (int)oldEv.size() >= 0 && evPointer > 0 ) || countJ == 0 ) { + if( evPointer > 0 ) evPointer --; + if( evPointer == 0 ) printf(" the first event!!! \n"); + lastEvFlag = true; + //printf(" ev : %d, evPt : %d \n", oldEv[evPointer], evPointer); + break; + } + } + + countJ ++; + + } + if( breakFlag ) break; + + if( lastEvFlag == false && countJ > 0 ){ + if( oldEv.size() == evPointer ) oldEv.push_back(ev); + evPointer ++; + } + + + } + + //gROOT->ProcessLine(".q"); + +} diff --git a/Cleopatra/Check_Simulation.C b/Cleopatra/Check_Simulation.C index f36aca4..57eb9cb 100644 --- a/Cleopatra/Check_Simulation.C +++ b/Cleopatra/Check_Simulation.C @@ -18,8 +18,10 @@ #include #include #include -#include "../armory/AnalysisLib.h" -#include "../Cleopatra/Isotope.h" +#include "../Armory/AnalysisLib.h" +#include "../Armory/ClassDetGeo.h" +#include "../Armory/ClassReactionConfig.h" +#include "../Cleopatra/ClassIsotope.h" double * FindRange(TString branch, TString gate, TTree * tree, double output[2]); double ExtractNumber(int index, TMacro * macro); @@ -109,7 +111,8 @@ void Check_Simulation(TString filename = "transfer1.root", TMacro * reactionConfigTxt = (TMacro *) file->FindObjectAny("reactionConfig"); TString Reaction=reactionConfigTxt->GetName(); - AnalysisLib::ReactionConfig reactionConfig = AnalysisLib::LoadReactionConfig(reactionConfigTxt); + ReactionConfig reactionConfig; + reactionConfig.LoadReactionConfig(reactionConfigTxt); int nEvent = reactionConfig.numEvents; printf("number of events generated : %d \n", nEvent); @@ -137,9 +140,10 @@ void Check_Simulation(TString filename = "transfer1.root", printf(" loading detector Geometry.\n"); TMacro * detGeoTxt = (TMacro *) file->FindObjectAny("detGeo"); - AnalysisLib::DetGeo detGeo = AnalysisLib::LoadDetectorGeo(detGeoTxt); + DetGeo detGeo; + detGeo.LoadDetectorGeo(detGeoTxt); - AnalysisLib::Array array; + Array array; if( detGeo.use2ndArray){ array = detGeo.array2; }else{ diff --git a/Cleopatra/ClassDecay.h b/Cleopatra/ClassDecay.h new file mode 100644 index 0000000..b313ae3 --- /dev/null +++ b/Cleopatra/ClassDecay.h @@ -0,0 +1,147 @@ +#ifndef decay_h +#define decay_h + +#include "TVector3.h" + +#include "../Cleopatra/ClassIsotope.h" + +//======================================================= +//####################################################### +// Class for Particle Decay +// B --> d + D +// input : TLorentzVector, emitting particle +// output : scattered TLorentzVector +//======================================================= +class Decay{ +public: + Decay(); + ~Decay(); + + double GetQValue() { return Q;} + + double GetAngleChange(){ + TVector3 vD = PD.Vect(); + TVector3 vB = PB.Vect(); + vD.SetMag(1); + vB.SetMag(1); + double dot = vD.Dot(vB); + return TMath::ACos(dot)*TMath::RadToDeg() ; + } + + double GetThetaCM() { return theta * TMath::RadToDeg();} + + double GetCMMomentum(){ return k;} + TLorentzVector GetDaugther_d() {return Pd;} + TLorentzVector GetDaugther_D() {return PD;} + + void SetMotherDaugther(int AB, int zB, int AD, int zD){ + Isotope Mother(AB, zB); + Isotope Daugther_D(AD, zD); + Isotope Daugther_d(AB-AD, zB-zD); + + mB = Mother.Mass; + mD = Daugther_D.Mass; + md = Daugther_d.Mass; + + double Q = mB - mD - md; + + printf("====== decay mode : %s --> %s + %s, Q = %.3f MeV \n", Mother.Name.c_str(), Daugther_d.Name.c_str(), Daugther_D.Name.c_str(), Q); + + isMotherSet = true; + } + + int CalDecay(TLorentzVector P_mother, double ExB, double ExD, double normOfReactionPlane = 0){ + if( !isMotherSet ) { + return -1; + } + this->PB = P_mother; + + double MB = mB + ExB; ///mother + double MD = mD + ExD; ///Big_Daugther + Q = MB - MD - md; + if( Q < 0 ) { + this->PD = this->PB; + dTheta = TMath::QuietNaN(); + k = TMath::QuietNaN(); + return -2; + } + + //clear + TLorentzVector temp(0,0,0,0); + PD = temp; + Pd = temp; + + k = TMath::Sqrt((MB+MD+md)*(MB+MD-md)*(MB-MD+md)*(MB-MD-md))/2./MB; + + //in mother's frame, assume isotropic decay + theta = TMath::ACos(2 * gRandom->Rndm() - 1) ; + + //for non isotropic decay, edit f1. + //theta = TMath::ACos(f1->GetRandom()); + + double phi = TMath::TwoPi() * gRandom->Rndm(); + PD.SetE(TMath::Sqrt(mD * mD + k * k )); + PD.SetPz(k); + PD.SetTheta(theta); + PD.SetPhi(phi); + + Pd.SetE(TMath::Sqrt(md * md + k * k )); + Pd.SetPz(k); + Pd.SetTheta(theta + TMath::Pi()); + Pd.SetPhi(phi + TMath::Pi()); + + PD.RotateY(TMath::Pi()/2.); + PD.RotateZ(normOfReactionPlane); + + Pd.RotateY(TMath::Pi()/2.); + Pd.RotateZ(normOfReactionPlane); + + //Transform to Lab frame; + TVector3 boost = PB.BoostVector(); + + PD.Boost(boost); + Pd.Boost(boost); + + return 1; + } + +private: + TLorentzVector PB, Pd, PD; + + double mB, mD, md; + double theta; + + TF1 * f1; + + bool isMotherSet; + double Q; + double k; // momentum in B-frame + double dTheta; // change of angle +}; + +Decay::Decay(){ + TLorentzVector temp(0,0,0,0); + PB = temp; + Pd = temp; + PD = temp; + + mB = TMath::QuietNaN(); + mD = TMath::QuietNaN(); + md = TMath::QuietNaN(); + theta = TMath::QuietNaN(); + + k = TMath::QuietNaN(); + + Q = TMath::QuietNaN(); + dTheta = TMath::QuietNaN(); + isMotherSet = false; + + f1 = new TF1("f1", "(1+ROOT::Math::legendre(2,x))/2.", -1, 1); +} + +Decay::~Decay(){ + delete f1; +} + + +#endif \ No newline at end of file diff --git a/Cleopatra/ClassHelios.h b/Cleopatra/ClassHelios.h new file mode 100644 index 0000000..6b19fdf --- /dev/null +++ b/Cleopatra/ClassHelios.h @@ -0,0 +1,479 @@ +#ifndef HELIOS_Library_h +#define HELIOS_Library_h + +#include "TBenchmark.h" +#include "TLorentzVector.h" +#include "TVector3.h" +#include "TMath.h" +#include "TFile.h" +#include "TTree.h" +#include "TRandom.h" +#include "TMacro.h" +#include "TGraph.h" +#include +#include + +#include "../Armory/AnalysisLib.h" +#include "../Armory/ClassDetGeo.h" +#include "../Armory/ClassReactionConfig.h" + +//======================================================= +//####################################################### +//Class for HELIOS +//input Lorentz vector, detector configuration +//output e, z, Ex, thetaCM, etc +//======================================================= + +struct trajectory{ + double theta, phi; + double vt, vp; // tranvser and perpendicular velocity + double rho; // orbit radius + double z0, t0; // position cycle + double x, y, z; // hit position + double t; //actual orbit time; + double R; //hit radius = sqrt(x^2+y^2); + int detID, detRowID; + int loop; + double effLoop; +}; + +void PrintTrajectory(trajectory a){ + printf("=====================\n"); + printf(" theta : %f deg\n", a.theta*TMath::RadToDeg()); + printf(" phi : %f deg\n", a.phi*TMath::RadToDeg()); + printf(" vt : %f mm/ns\n", a.vt); + printf(" vp : %f mm/ns\n", a.vp); + printf(" rho : %f mm\n", a.rho); + printf(" z0 : %f mm\n", a.z0); + printf(" t0 : %f ns\n", a.t0); + printf("(x, y, z) : (%f, %f. %f) mm\n", a.x, a.y, a.z); + printf(" R : %f mm\n", a.R); + printf(" t : %f ns\n", a.t); + printf(" effLoop : %f cycle\n", a.effLoop); + printf(" Loop : %d cycle\n", a.loop); + printf(" detRowID : %d \n", a.detRowID); + printf(" detID : %d \n", a.detID); + +} + +class HELIOS{ +public: + + HELIOS(); + ~HELIOS(); + + void SetCoincidentWithRecoil(bool TorF){ this->isCoincidentWithRecoil = TorF;} + bool GetCoincidentWithRecoil(){return this->isCoincidentWithRecoil;} + bool SetDetectorGeometry(std::string filename); + void SetBeamPosition(double x, double y) { xOff = x; yOff = y;} + + void OverrideMagneticField(double BField){ this->detGeo.Bfield = BField; this->detGeo.BfieldSign = BField > 0 ? 1: -1;} + void OverrideMagneticFieldDirection(double BfieldThetaInDeg){ this->detGeo.BfieldTheta = BfieldThetaInDeg;} + void OverrideFirstPos(double firstPos){ + overrideFirstPos = true; + printf("------ Overriding FirstPosition to : %8.2f mm \n", firstPos); + this->array.firstPos = firstPos; + } + void OverrideDetectorDistance(double perpDist){ + overrideDetDistance = true; + printf("------ Overriding Detector Distance to : %8.2f mm \n", perpDist); + this->array.detPerpDist = perpDist; + } + + void SetDetectorOutside(bool isOutside){ + this->array.detFaceOut = isOutside; + printf(" Detectors are facing %s\n", array.detFaceOut ? "outside": "inside" ); + } + + int DetAcceptance(); + int CalArrayHit(TLorentzVector Pb, int Zb); + int CalRecoilHit(TLorentzVector PB, int ZB); + //int CalHit(TLorentzVector Pb, int Zb, TLorentzVector PB, int ZB, double xOff = 0, double yOff = 0 ); // return 0 for no hit, 1 for hit + + void CalTrajectoryPara(TLorentzVector P, int Z, int id); // id = 0 for Pb, id = 1 for PB. + + int GetNumberOfDetectorsInSamePos(){return array.mDet;} + double GetEnergy(){return e;} + double GetDetX(){return detX;} // position in each detector, range from -1, 1 + + /// clockwise rotation for B-field along the z-axis, sign = 1. + double XPos(double Zpos, double theta, double phi, double rho, int sign){ + return rho * ( TMath::Sin( TMath::Tan(theta) * Zpos / rho - sign * phi ) + sign * TMath::Sin(phi) ) + xOff; + } + double YPos(double Zpos, double theta, double phi, double rho, int sign){ + return rho * sign * (TMath::Cos( TMath::Tan(theta) * Zpos / rho - sign * phi ) - TMath::Cos(phi)) + yOff; + } + double RPos(double Zpos, double theta, double phi, double rho, int sign){ + double x = XPos(Zpos, theta, phi, rho, sign) ; + double y = YPos(Zpos, theta, phi, rho, sign) ; + return sqrt(x*x+y*y); + } + + double GetXPos(double ZPos){ return XPos( ZPos, orbitb.theta, orbitb.phi, orbitb.rho, detGeo.BfieldSign); } + double GetYPos(double ZPos){ return YPos( ZPos, orbitb.theta, orbitb.phi, orbitb.rho, detGeo.BfieldSign); } + double GetR(double ZPos) { return RPos( ZPos, orbitb.theta, orbitb.phi, orbitb.rho, detGeo.BfieldSign); } + + double GetRecoilEnergy(){return eB;} + double GetRecoilXPos(double ZPos){ return XPos( ZPos, orbitB.theta, orbitB.phi, orbitB.rho, detGeo.BfieldSign); } + double GetRecoilYPos(double ZPos){ return YPos( ZPos, orbitB.theta, orbitB.phi, orbitB.rho, detGeo.BfieldSign); } + double GetRecoilR(double ZPos) { return RPos( ZPos, orbitB.theta, orbitB.phi, orbitB.rho, detGeo.BfieldSign); } + + double GetBField() {return detGeo.Bfield;} + double GetDetRadius() {return array.detPerpDist;} + + trajectory GetTrajectory_b() {return orbitb;} + trajectory GetTrajectory_B() {return orbitB;} + + DetGeo GetDetectorGeometry() {return detGeo;} + +private: + + void ClearTrajectory(trajectory t){ + t.theta = TMath::QuietNaN(); + t.phi = TMath::QuietNaN(); + t.vt = TMath::QuietNaN(); + t.vp = TMath::QuietNaN(); + t.rho = TMath::QuietNaN(); + t.z0 = TMath::QuietNaN(); + t.t0 = TMath::QuietNaN(); + t.x = TMath::QuietNaN(); + t.y = TMath::QuietNaN(); + t.z = TMath::QuietNaN(); + t.effLoop = TMath::QuietNaN(); + t.detID = -1; + t.detRowID = -1; + t.loop = -1; + } + + DetGeo detGeo; + Array array; + + trajectory orbitb, orbitB; + + double e,detX ; ///energy of light recoil, position X + double rhoHit; /// radius of particle-b hit on recoil detector + + double eB; ///energy of heavy recoil + + bool isDetReady; + + double xOff, yOff; // beam position + + + bool overrideDetDistance; + bool overrideFirstPos; + bool isCoincidentWithRecoil; + + const double c = 299.792458; //mm/ns +}; + +HELIOS::HELIOS(){ + + ClearTrajectory(orbitb); + ClearTrajectory(orbitB); + + e = TMath::QuietNaN(); + eB = TMath::QuietNaN(); + detX = TMath::QuietNaN(); + rhoHit = TMath::QuietNaN(); + + xOff = 0.0; + yOff = 0.0; + + isDetReady = false; + + overrideDetDistance = false; + overrideFirstPos = false; + isCoincidentWithRecoil = false; + +} + +HELIOS::~HELIOS(){ + +} + +bool HELIOS::SetDetectorGeometry(std::string filename){ + + if( detGeo.LoadDetectorGeo(filename)) { + + if( detGeo.use2ndArray ){ + array = detGeo.array2; + }else{ + array = detGeo.array1; + } + + isCoincidentWithRecoil = detGeo.isCoincidentWithRecoil; + + isDetReady = true; + }else{ + printf("cannot read file %s.\n", filename.c_str()); + isDetReady = false; + } + + return isDetReady; +} + +int HELIOS::DetAcceptance(){ + + //CalArrayHit and CalRecoilHit must be done before. + + if( isDetReady == false ) return 0; + + // -1 ========= when recoil direction is not same side of array + if( array.firstPos < 0 && orbitb.z > 0 ) return -1; + if( array.firstPos > 0 && orbitb.z < 0 ) return -1; + + // -11 ======== rho is too small + if( 2 * orbitb.rho < array.detPerpDist ) return -11; + + // -15 ========= if detRowID == -1, should be (2 * orbitb.rho < perpDist) + if( orbitb.detRowID == -1 ) return -15; + + // -10 =========== when rho is too big . + if( detGeo.bore < 2 * orbitb.rho) return -10; + + // -14 ========== check particle-B hit radius on recoil dectector + if( isCoincidentWithRecoil && orbitB.R > detGeo.recoilOuterRadius ) return -14; + //if( isCoincidentWithRecoil && (orbitB.R > rhoRecoilout || orbitB.R < rhoRecoilin) ) return -14; + + // -12 ========= check is particle-b was blocked by recoil detector + rhoHit = GetR(detGeo.recoilPos); + if( orbitb.z > 0 && detGeo.recoilPos > 0 && orbitb.z > detGeo.recoilPos && rhoHit < detGeo.recoilOuterRadius ) return -12; + if( orbitb.z < 0 && detGeo.recoilPos < 0 && orbitb.z < detGeo.recoilPos && rhoHit < detGeo.recoilOuterRadius ) return -12; + + // -13 ========= not more than 3 loops + if( orbitb.loop > 3 ) return -13; + + // -2 ========= calculate the "y"-distance from detector center + if( sqrt(orbitb.R*orbitb.R - array.detPerpDist * array.detPerpDist)> array.detWidth/2 ) return -2; + + // -3 ==== when zPos further the range of whole array, more loop would not save + if( array.firstPos < 0 && orbitb.z < array.detPos[0] - array.detLength ) return -3; + if( array.firstPos > 0 && orbitb.z > array.detPos[array.nDet-1] + array.detLength ) return -3; + + // -4 ======== Hit on blacker + if( array.blocker != 0 && array.firstPos > 0 && array.detPos[0] - array.blocker < orbitb.z && orbitb.z < array.detPos[0] ) return -4; + if( array.blocker != 0 && array.firstPos < 0 && array.detPos[array.nDet-1] < orbitb.z && orbitb.z < array.detPos[array.nDet-1] + array.blocker ) return -4; + + // 2 ====== when zPos less then the nearest position, more loop may hit + int increaseLoopFlag = 0; + if( array.firstPos < 0 && array.detPos[array.nDet-1] < orbitb.z ) increaseLoopFlag = 2; + if( array.firstPos > 0 && array.detPos[0] > orbitb.z ) increaseLoopFlag = 2; + if (increaseLoopFlag == 2 ) { + orbitb.z += orbitb.z0; + orbitb.effLoop += 1.0; + orbitb.loop += 1; + orbitb.t = orbitb.t0 * orbitb.effLoop; + return 2; + } + + // 1 ======= check hit array z- position + if( array.firstPos < 0 ){ + for( int i = 0; i < array.nDet; i++){ + if( array.detPos[i] - array.detLength <= orbitb.z && orbitb.z <= array.detPos[i]) { + orbitb.detID = i; + detX = ( orbitb.z - (array.detPos[i] + array.detLength/2 ))/ array.detLength * 2 ;// range from -1 , 1 + return 1; + } + } + }else{ + for( int i = 0; i < array.nDet ; i++){ + if( array.detPos[i] <= orbitb.z && orbitb.z <= array.detPos[i] + array.detLength) { + ///printf(" %d | %f < z = %f < %f \n", i, array.detPos[i], orbitb.z, array.detPos[i]+length); + orbitb.detID = i; + detX = ( orbitb.z - (array.detPos[i] - array.detLength/2 ))/ array.detLength*2 ;// range from -1 , 1 + return 1; + } + } + } + + + // -5 ======== check hit array gap + if( array.firstPos < 0 ){ + for( int i = 0; i < array.nDet-1 ; i++){ + if( array.detPos[i] < orbitb.z && orbitb.z < array.detPos[i+1] - array.detLength ) return -5; //increaseLoopFlag = 3; + } + }else{ + for( int i = 0; i < array.nDet-1 ; i++){ + if( array.detPos[i] + array.detLength < orbitb.z && orbitb.z < array.detPos[i+1] ) return -5; //increaseLoopFlag = 3; + } + } + if (increaseLoopFlag == 3 ) { + orbitb.z += orbitb.z0; + orbitb.effLoop += 1.0; + orbitb.loop += 1; + orbitb.t = orbitb.t0 * orbitb.effLoop; + return 3; + } + + + return -20; // for unknown reason +} + +void HELIOS::CalTrajectoryPara(TLorentzVector P, int Z, int id){ + + if( id == 0 ){ + orbitb.theta = P.Theta(); + orbitb.phi = P.Phi(); + orbitb.rho = P.Pt() / abs(detGeo.Bfield) / Z / c * 1000; //mm + orbitb.vt = P.Beta() * TMath::Sin(P.Theta()) * c ; // mm / nano-second + orbitb.vp = P.Beta() * TMath::Cos(P.Theta()) * c ; // mm / nano-second + orbitb.t0 = TMath::TwoPi() * orbitb.rho / orbitb.vt; // nano-second + orbitb.z0 = orbitb.vp * orbitb.t0; + + orbitb.detID = -1; + orbitb.detRowID = -1; + + } + + if( id == 1 ){ + orbitB.theta = P.Theta(); + orbitB.phi = P.Phi(); + orbitB.rho = P.Pt() / abs(detGeo.Bfield) / Z / c * 1000; //mm + orbitB.vt = P.Beta() * TMath::Sin(P.Theta()) * c ; // mm / nano-second + orbitB.vp = P.Beta() * TMath::Cos(P.Theta()) * c ; // mm / nano-second + orbitB.t0 = TMath::TwoPi() * orbitB.rho / orbitB.vt; // nano-second + orbitB.z0 = orbitB.vp * orbitB.t0; + + orbitB.detID = -1; + orbitB.detRowID = -1; + + } +} + +int HELIOS::CalArrayHit(TLorentzVector Pb, int Zb){ + + e = Pb.E() - Pb.M(); + detX = TMath::QuietNaN(); + rhoHit = TMath::QuietNaN(); + + CalTrajectoryPara(Pb, Zb, 0); + + int targetLoop = 1; + int inOut = array.detFaceOut == true ? 1: 0; //1 = from Outside, 0 = from inside + + bool debug = false; + + if( debug ) { + printf("===================================\n"); + printf("theta : %f deg, phi : %f deg \n", orbitb.theta * TMath::RadToDeg(), orbitb.phi * TMath::RadToDeg()); + printf("z0: %f mm, rho : %f mm \n", orbitb.z0, orbitb.rho); + printf(" inOut : %d = %s \n", inOut, inOut == 1 ? "Out" : "in"); + printf(" z range : %.2f - %.2f \n", detGeo.zMin, detGeo.zMax); + printf("-----------------------------------\n"); + } + + std::vector zPossible; + std::vector dID; //detRowID + + int iStart = ( detGeo.BfieldSign == 1 ? 0 : -array.mDet ); + int iEnd = ( detGeo.BfieldSign == 1 ? 2 * array.mDet : array.mDet ); + for( int i = iStart; i < iEnd ; i++){ + + double phiD = TMath::TwoPi()/array.mDet * i ; + double dphi = orbitb.phi - phiD; + double aEff = array.detPerpDist - (xOff * TMath::Cos(phiD) + yOff * TMath::Sin(phiD)); + double hahaha = asin( aEff/ orbitb.rho - detGeo.BfieldTheta * sin(dphi)); + + int n = 2*targetLoop + inOut; + + double zP = orbitb.z0 /TMath::TwoPi() * ( detGeo.BfieldSign * dphi + n * TMath::Pi() + pow(-1, n) * hahaha ); + + if( debug ) { + double xP = GetXPos(zP) ; + double yP = GetYPos(zP) ; + printf("phiD: %4.0f, dphi: %6.1f, mod(pi): %6.1f, Loop : %9.5f, zHit : %8.3f mm, (x,y) = (%7.2f, %7.2f) \n", + phiD * TMath::RadToDeg(), + (orbitb.phi-phiD) * TMath::RadToDeg(), + fmod(orbitb.phi-phiD, TMath::Pi())*TMath::RadToDeg(), + zP/orbitb.z0, zP, xP, yP ); + } + + ///Selection + if( !TMath::IsNaN(zP) && 0< zP/orbitb.z0 && TMath::Max(0, targetLoop-1) < zP/orbitb.z0 && zP/orbitb.z0 < targetLoop ) { + zPossible.push_back(zP); + dID.push_back(i); + } + } + /* + if( zPossible.size() == 0 ){ // will not happen + zHit = TMath::QuietNaN(); + xPos = TMath::QuietNaN(); + yPos = TMath::QuietNaN(); + loop = -1; + detID = -1; + detRowID = -1; + return -1 ; + }*/ + + if( debug ) printf("-----------------------------------\n"); + double dMin = 1; + for( int i = 0; i < (int) zPossible.size(); i++){ + + double dd = abs(zPossible[i]/orbitb.z0 - (targetLoop - (1-inOut))); + + if( debug ) printf(" %d | zP : %8.3f mm; loop : %9.5f ", i, zPossible[i], zPossible[i]/orbitb.z0); + + if( dd < dMin) { + orbitb.z = zPossible[i]; + dMin = dd; + orbitb.effLoop = zPossible[i]/orbitb.z0; + orbitb.loop = TMath::Ceil(orbitb.effLoop); + orbitb.detRowID = (12+dID[i])%4; + orbitb.t = orbitb.t0 * orbitb.effLoop; + + double phiD = TMath::TwoPi()/array.mDet * dID[i] ; + double dphi = orbitb.phi - phiD ; + + if( debug ) { + // Check is in or out + double hitDir = cos( orbitb.z/orbitb.z0 * TMath::TwoPi() - detGeo.BfieldSign * dphi ); + printf(" hitDir : %4.1f ", hitDir); + if( ( inOut == 1 && hitDir > 0 ) || (inOut == 0 && hitDir < 0 ) ) { + printf(" != %f ", array.detPerpDist); + orbitb.z = TMath::QuietNaN(); + orbitb.loop = -1; + orbitb.detRowID = -1; + return - 2; + } + + // this must be false, otherwise, calculation error + double xPos = GetXPos(orbitb.z ) ; + double yPos = GetYPos(orbitb.z ) ; + double a = xPos * cos(phiD) + yPos * sin(phiD); + printf(" a : %f ", a); + if( abs(a - array.detPerpDist) > 0.01) { + printf(" != %f ", array.detPerpDist); + orbitb.z = TMath::QuietNaN(); + orbitb.loop = -1; + orbitb.detRowID = -1; + return -3; + } + } + } + if(debug) printf("\n"); + } + + // calculate x, y, R + orbitb.x = GetXPos(orbitb.z) ; + orbitb.y = GetYPos(orbitb.z) ; + orbitb.R = GetR(orbitb.z); + + return 1; // return 1 when OK +} + +int HELIOS::CalRecoilHit(TLorentzVector PB, int ZB){ + + CalTrajectoryPara(PB, ZB, 1); + + orbitB.z = detGeo.recoilPos; + orbitB.x = GetRecoilXPos(detGeo.recoilPos) ; + orbitB.y = GetRecoilYPos(detGeo.recoilPos) ; + orbitB.R = GetRecoilR(detGeo.recoilPos); + orbitB.effLoop = orbitB.z/orbitB.z0; + orbitB.t = orbitB.t0 * orbitB.effLoop ; + + return 1; +} + +#endif diff --git a/Cleopatra/Isotope.h b/Cleopatra/ClassIsotope.h similarity index 100% rename from Cleopatra/Isotope.h rename to Cleopatra/ClassIsotope.h diff --git a/Cleopatra/ClassKnockout.h b/Cleopatra/ClassKnockout.h new file mode 100644 index 0000000..3edd24d --- /dev/null +++ b/Cleopatra/ClassKnockout.h @@ -0,0 +1,301 @@ +#ifndef knockout_h +#define knockout_h + + +//======================================================= +//####################################################### +// Class for Knockout Reaction +// A(a,12)B, A = B + b, a->1, b->2 +// incident particle is A +// the calculation: 1) go to A's rest frame +// 2) calculate the b = A - B +// 3) go to CM frame +//======================================================= +class Knockout{ +public: + Knockout(); + ~Knockout(); + + void SetA(int A, int Z){ + Isotope temp(A,Z); + mA = temp.Mass; + AA = A; + ZA = Z; + nameA = temp.Name; + } + + void SetExA(double Ex){ + this->ExA = Ex; + } + + void Seta(int A, int Z){ + Isotope temp(A,Z); + ma = temp.Mass; + Aa = A; + Za = Z; + m1 = ma; + A1 = A; + Z1 = Z; + namea = temp.Name; + name1 = temp.Name; + } + + void Set2(int A, int Z){ + Isotope temp(A,Z); + m2 = temp.Mass; + A2 = A; + Z2 = Z; + name2 = temp.Name; + + AB = AA + Aa - A1 - A2; + ZB = ZA + Za - Z1 - Z2; + Isotope temp2(AB,ZB); + mB0 = temp2.Mass; + nameB = temp2.Name; + + } + + void SetBSpk(double S, double kb, double thetab, double phib){ + this->S = S; + AB = AA + Aa - A1 - A2; + ZB = ZA + Za - Z1 - Z2; + Isotope temp(AB,ZB); + mB0 = temp.Mass; + nameB = temp.Name; + this->kb = kb; + this->thetab = thetab; + this->phib = phib; + + mB = mA + ExA - m2 + S; + + ExB = mB - mB0; + + if( ExB < 0 && !isOverRideExNegative ){ + printf(" seperation energy is too small. \n"); + } + } + + void OverRideExNegative(bool YN){ + isOverRideExNegative = YN; + } + + TString GetReactionName(){ + TString rName; + + TString normInv; + if( isNormalKinematics ){ + normInv = "Normal Kinematics"; + }else{ + normInv = "Inverse Kinematics"; + } + + rName.Form("%s(%s,%s%s)%s, %s", nameA.c_str(), namea.c_str(), name1.c_str(), name2.c_str(), nameB.c_str(), normInv.Data()); + + return rName; + } + + void SetIncidentEnergyAngle(double KEA, double theta, double phi){ + this->KEA = KEA; + this->thetaIN = theta; + this->phiIN = phi; + } + + void CalIncidentChannel(bool isNormalKinematics); + void CalReactionConstant(bool isNormalKinematics); + void Event(double thetaCM, double phCM); + + double GetMass_A(){return mA;} + double GetMass_a(){return ma;} + double GetMass_b(){return mb;} + double GetMass_B(){return mB;} + double GetMass_Bgs(){return mB0;} + double GetMass_1(){return m1;} + double GetMass_2(){return m2;} + + TLorentzVector GetPA(){return PA;} + TLorentzVector GetPa(){return Pa;} + TLorentzVector GetPb(){return Pb;} + TLorentzVector GetPB(){return PB;} + TLorentzVector GetP1(){return P1;} + TLorentzVector GetP2(){return P2;} + + double GetMomentumbNN(){return p;} + double GetReactionBeta(){return beta;} + double GetReactionGamma(){return gamma;} + double GetNNTotalEnergy(){return Etot;} + + double GetNNTotalKE() {return Etot - mb - ma;} + double GetQValue() {return mA + ExA - m2 - mB;} + double GetMaxExB() {return Etot - mb - mB0;} + +private: + int AA, Aa, A1, A2, AB; + int ZA, Za, Z1, Z2, ZB; + double mA, ma, m1, m2, mB, mB0, mb; + string nameA, namea, name1, name2, nameB; + + double S; // separation energy + double kb; // momentum of b + double thetab, phib;// direction of b + + TLorentzVector PA, Pa, P1, P2, PB, Pb; // lab + + double KEA, thetaIN, phiIN; + double T; + + double k, beta, gamma, Etot, p; // reaction constant, in NN frame + double ExA, ExB; + + bool isNormalKinematics; + bool isOverRideExNegative; + +}; + +Knockout::Knockout(){ + TLorentzVector temp(0,0,0,0); + + PA = temp; + Pa = temp; + P1 = temp; + P2 = temp; + PB = temp; + Pb = temp; + + SetA(12,6); + Seta(1,1); + Set2(1,1); + + SetBSpk(1000, 0, 0, 0); + SetIncidentEnergyAngle(10, 0, 0); + + ExA = 0; + + isNormalKinematics = false; + isOverRideExNegative = false; +} + +Knockout::~Knockout(){ + +} + +void Knockout::CalIncidentChannel(bool isNormalKinematics){ + if( ExB < 0 && !isOverRideExNegative) return; + + this->isNormalKinematics = isNormalKinematics; + + if(!isNormalKinematics){ + //===== construct Lab frame 4-momentum + this->T = KEA * AA; + double kA = TMath::Sqrt(TMath::Power(mA + ExA + T, 2) - (mA + ExA) * (mA + ExA)); + PA.SetXYZM(0, 0, kA, mA + ExA); + PA.RotateY(thetaIN); + PA.RotateZ(phiIN); + + Pa.SetXYZM(0,0,0,ma); + + }else{ + //===== construct 4-momentum + this->T = KEA * Aa; + double ka = TMath::Sqrt(TMath::Power(ma + T, 2) - (ma) * (ma)); + Pa.SetXYZM(0, 0, ka, ma); + Pa.RotateY(thetaIN); + Pa.RotateZ(phiIN); + + PA.SetXYZM(0, 0, 0, mA + ExA); + } + +} + +void Knockout::CalReactionConstant(bool isNormalKinematics){ + if( ExB < 0 && !isOverRideExNegative) return; + + this->isNormalKinematics = isNormalKinematics; + + CalIncidentChannel(isNormalKinematics); + + if(!isNormalKinematics){ + + //===== change to A's rest frame + TVector3 bA = PA.BoostVector(); + PA.Boost(-bA); + + //===== constructe bounded nucleus b + PB.SetXYZM(0, 0, -kb, mB); + PB.RotateY(thetab); + PB.RotateZ(phib); + + Pb = PA - PB; + mb = Pb.M(); + + //===== change to Lab frame + Pb.Boost(bA); + PA.Boost(bA); + PB.Boost(bA); + + }else{ + + //===== constructe bounded nucleus b + PB.SetXYZM(0, 0, -kb, mB); + PB.RotateY(thetab); + PB.RotateZ(phib); + + Pb = PA - PB; + mb = Pb.M(); + + } + + //====== reaction constant + k = (Pa+Pb).P(); + double E = (Pa+Pb).E(); + beta = (Pa+Pb).Beta(); + gamma = 1 / TMath::Sqrt(1- beta * beta); + Etot = TMath::Sqrt(TMath::Power(E,2) - k * k); + p = TMath::Sqrt( (Etot*Etot - TMath::Power(m1 + m2,2)) * (Etot*Etot - TMath::Power(m1 - m2 ,2)) ) / 2 / Etot; + + //if( TMath::IsNaN(p) ){ + // printf(" Mc: %f, m1+m2: %f, kb:%f, thetab:%f, phib:%f\n", Etot, m1+m2, kb, thetab, phib); + //} + +} + +void Knockout::Event(double thetaCM, double phiCM){ + if( ExB < 0 && !isOverRideExNegative ) return; + + //===== construct Pcm + TLorentzVector Pc = Pb + Pa; + TVector3 bc = Pc.BoostVector(); + + TLorentzVector Pac = Pa; + Pac.Boost(-bc); + TVector3 va = Pac.Vect(); + + TLorentzVector Pbc = Pb; + Pbc.Boost(-bc); + TVector3 vb = Pbc.Vect(); + + //--- from P1 + TVector3 v1 = va; + v1.SetMag(p); + + TVector3 u1 = va.Orthogonal(); + v1.Rotate(thetaCM, u1); + v1.Rotate(phiCM + TMath::PiOver2(), va); // somehow, the calculation turn the vector 90 degree. + + TLorentzVector P1c; + P1c.SetVectM(v1, m1); + + //--- from P2 + TLorentzVector P2c; + P2c.SetVectM(-v1, m2); + + //---- to Lab Frame + P1 = P1c; + P1.Boost(bc); + P2 = P2c; + P2.Boost(bc); + +} + + + +#endif \ No newline at end of file diff --git a/Cleopatra/ClassTargetScattering.h b/Cleopatra/ClassTargetScattering.h new file mode 100644 index 0000000..969608f --- /dev/null +++ b/Cleopatra/ClassTargetScattering.h @@ -0,0 +1,202 @@ +#ifndef targetScattering_h +#define targetScattering_h + +#include +#include +#include + +#include "../Armory/AnalysisLib.h" + +//======================================================= +//####################################################### +// Class for multi-scattering of the beam inside target +// using SRIM to generate stopping power +// input : TLorentzVector, data_files +// output : scattered TLorentzVector +//======================================================= +class TargetScattering{ + +public: + TargetScattering(); + ~TargetScattering(); + + double GetKE0(){return KE0;} + double GetKE() {return KE;} + double GetKELoss() {return KE0-KE;} + double GetDepth() {return depth;} + double GetPathLength() {return length;} + + void LoadStoppingPower(std::string file); + + void SetTarget(double density, double depth){ + this->density = density; + this->depth = depth; + isTargetSet = true; + //printf("===== Target, density: %f g/cm3, depth: %f um \n", density, depth * 1e+4 ); + } + + TLorentzVector Scattering(TLorentzVector P){ + double mass = P.M(); + KE0 = (P.E() - mass); + KE = KE0; + double theta = P.Theta(); + this->length = TMath::Abs(depth/TMath::Cos(theta)); + //printf("------- theta: %f deg, length: %f um, KE: %f MeV \n", theta * TMath::RadToDeg(), this->length * 1e+4, KE); + + //integrate the energy loss within the depth of A + double dx = length/100.; // in cm + double x = 0; + double densityUse = density; + if( unitID == 0 ) densityUse = 1.; + do{ + //assume the particle will not be stopped + //printf(" x: %f, KE: %f, S: %f \n", x, KE, gA->Eval(KE)); + KE = KE - densityUse * gA->Eval(KE) * 10 * dx ; // factor 10, convert MeV/cm -> MeV/cm + + //angular Straggling, assume (Lateral Straggling)/(Projected range) + + + x = x + dx; + }while(x < length && KE > 0 ); + + //printf(" depth: %f cm = %f um, KE : %f -> %f MeV , dE = %f MeV \n", depth, depth * 1e+4, KE0, KE, KE0 - KE); + double newk = 0; + + TLorentzVector Pnew; + TVector3 vb(0,0,0); + + if( KE < 0 ) { + KE = 0.0; // somehow, when KE == 0 , the program has problem to rotate the 4-vector + }else{ + newk = TMath::Sqrt(TMath::Power(mass+KE,2) - mass * mass); + vb = P.Vect(); + vb.SetMag(newk); + } + Pnew.SetVectM(vb,mass); + + return Pnew; + } + +private: + bool isTargetSet; + double density; // density [mg/cm2] + int unitID; // 0 = MeV /mm or keV/um , 1 = MeV / (ug/cm2) + + double depth; // depth in target [cm] + double length; // total path length in target [cm] + double KE0, KE; + + TGraph * gA; // stopping power of A, b, B, in unit of MeV/(mg/cm2) + TGraph * gB; // projection range [nm] + TGraph * gC; // parallel Straggling [nm] + TGraph * gD; // perpendicular Straggling [nm] + +}; + +inline TargetScattering::TargetScattering(){ + isTargetSet = false; + density = 1; // mg/cm2 + unitID = 0; + KE0 = 0; + KE = 0; + depth = 0; + length = 0; + gA = NULL; + gB = NULL; + gC = NULL; + gD = NULL; +} + +inline TargetScattering::~TargetScattering(){ + delete gA; +} + +inline void TargetScattering::LoadStoppingPower(std::string filename){ + + printf("loading Stopping power: %s.", filename.c_str()); + + std::ifstream file; + file.open(filename.c_str()); + + std::vector energy; + std::vector stopping; + std::vector projRange; + std::vector paraStraggling; + std::vector prepStraggling; + + if( file.is_open() ){ + printf("... OK\n"); + char lineChar[16635]; + std::string line; + while( !file.eof() ){ + file.getline(lineChar, 16635, '\n'); + line = lineChar; + + size_t found = line.find("Target Density"); + if( found != std::string::npos ){ + printf(" %s\n", line.c_str()); + } + + found = line.find("Stopping Units ="); + if( found != std::string::npos){ + printf(" %s\n", line.c_str()); + if( line.find("MeV / mm") != std::string::npos ) { + unitID = 0; + }else if( line.find("keV / micron") != std::string::npos ){ + unitID = 0; + }else if( line.find("MeV / (mg/cm2)") != std::string::npos ) { + unitID = 1; + }else{ + printf("please using MeV/mm, keV/um, or MeV/(mg/cm2) \n"); + } + } + + size_t foundkeV = line.find("keV "); + size_t foundMeV = line.find("MeV "); + size_t foundGeV = line.find("GeV "); + if ( foundkeV != std::string::npos || foundMeV != std::string::npos || foundGeV != std::string::npos ){ + std::vector haha = AnalysisLib::SplitStr(line, " "); + //for( int i = 0 ; i < (int) haha.size()-1; i++){ + // printf("%d,%s|", i, haha[i].c_str()); + //} + //printf("\n"); + + found = haha[0].find("keV"); if( found != std::string::npos ) energy.push_back(atof(haha[0].substr(0, found).c_str()) * 0.001); + found = haha[0].find("MeV"); if( found != std::string::npos ) energy.push_back(atof(haha[0].substr(0, found).c_str()) * 1.); + found = haha[0].find("GeV"); if( found != std::string::npos ) energy.push_back(atof(haha[0].substr(0, found).c_str()) * 1000.); + + double a = atof(haha[1].c_str()); + double b = atof(haha[2].c_str()); + stopping.push_back(a+b); + + found = haha[3].find("A") ; if( found != std::string::npos ) projRange.push_back(atof(haha[3].substr(0, found).c_str()) * 0.1); + found = haha[3].find("um"); if( found != std::string::npos ) projRange.push_back(atof(haha[3].substr(0, found).c_str()) * 1000.); + found = haha[3].find("mm"); if( found != std::string::npos ) projRange.push_back(atof(haha[3].substr(0, found).c_str()) * 1e6); + + found = haha[4].find("A") ; if( found != std::string::npos ) paraStraggling.push_back(atof(haha[4].substr(0, found).c_str()) * 0.1); + found = haha[4].find("um"); if( found != std::string::npos ) paraStraggling.push_back(atof(haha[4].substr(0, found).c_str()) * 1e3); + found = haha[4].find("mm"); if( found != std::string::npos ) paraStraggling.push_back(atof(haha[4].substr(0, found).c_str()) * 1e6); + + found = haha[5].find("A") ; if( found != std::string::npos ) prepStraggling.push_back(atof(haha[5].substr(0, found).c_str()) * 0.1); + found = haha[5].find("um"); if( found != std::string::npos ) prepStraggling.push_back(atof(haha[5].substr(0, found).c_str()) * 1e3); + found = haha[5].find("mm"); if( found != std::string::npos ) prepStraggling.push_back(atof(haha[5].substr(0, found).c_str()) * 1e6); + + //printf(" %f, %f, %f, %f, %f \n", energy.back(), stopping.back(), projRange.back(), paraStraggling.back(), prepStraggling.back()); + } + + + } + + }else{ + printf("... fail\n"); + } + + gA = new TGraph(energy.size(), &energy[0], &stopping[0]); + + gB = new TGraph(energy.size(), &energy[0], &projRange[0]); + gC = new TGraph(energy.size(), &energy[0], ¶Straggling[0]); + gD = new TGraph(energy.size(), &energy[0], &prepStraggling[0]); + +} + +#endif \ No newline at end of file diff --git a/Cleopatra/ClassTransfer.h b/Cleopatra/ClassTransfer.h new file mode 100644 index 0000000..6ae8aba --- /dev/null +++ b/Cleopatra/ClassTransfer.h @@ -0,0 +1,384 @@ +#ifndef Transfer_h +#define Transfer_h + +#include "utility" + +#include "ClassIsotope.h" +#include "../Armory/AnalysisLib.h" +#include "../Armory/ClassReactionConfig.h" + +#include "TLorentzVector.h" +#include "TMath.h" + +//======================================================= +//####################################################### +// Class for Transfer Reaction +// reaction notation A(a,b)B +// A = incident particle +// a = target +// b = light scattered particle +// B = heavy scattered particle +//======================================================= +class TransferReaction { +public: + TransferReaction(); + ~TransferReaction(); + + void SetA(int A, int Z, double Ex); + void Seta(int A, int Z); + void Setb(int A, int Z); + void SetB(int A, int Z); + void SetIncidentEnergyAngle(double KEA, double theta, double phi); + + void SetReactionSimple(int beamA, int beamZ, + int targetA, int targetZ, + int recoilA, int recoilZ, float beamEnergy_AMeV); + + void SetExA(double Ex); + void SetExB(double Ex); + void SetReactionFromFile(string settingFile); + + TString GetReactionName(); + TString GetReactionName_Latex(); + + ReactionConfig GetRectionConfig() { return reaction;} + + double GetMass_A() const {return mA + ExA;} + double GetMass_a() const {return ma;} + double GetMass_b() const {return mb;} + double GetMass_B() const {return mB + ExB;} + + int GetCharge_b() const {return reaction.recoilLightZ;} + + double GetCMTotalKE() {return Etot - mA - ma;} + double GetQValue() {return mA + ExA + ma - mb - mB - ExB;} + double GetMaxExB() {return Etot - mb - mB;} + + TLorentzVector GetPA(){return PA;} + TLorentzVector GetPa(){return Pa;} + TLorentzVector GetPb(){return Pb;} + TLorentzVector GetPB(){return PB;} + + void CalReactionConstant(); + + void Event(double thetaCM_rad, double phiCM_rad); + + double GetMomentumbCM() {return p;} + double GetReactionBeta() {return beta;} + double GetReactionGamma() {return gamma;} + double GetCMTotalEnergy() {return Etot;} + + std::pair CalExThetaCM(double e, double z, double Bfield, double a); + +private: + + ReactionConfig reaction; + + string nameA, namea, nameb, nameB; + double thetaIN, phiIN; + double mA, ma, mb, mB; + + double TA, T; // TA = KE of A pre u, T = total energy + double ExA, ExB; + + bool isReady; + bool isBSet; + + double k; // CM Boost momentum + double beta, gamma; //CM boost beta + double Etot; + double p; // CM frame momentum of b, B + + TLorentzVector PA, Pa, Pb, PB; + + TString format(TString name); + +}; + +TransferReaction::TransferReaction(){ + + thetaIN = 0.; + phiIN = 0.; + SetA(12, 6, 0); + Seta(2,1); + Setb(1,1); + SetB(13,6); + TA = 6; + T = TA * reaction.beamA; + + ExA = 0; + ExB = 0; + + CalReactionConstant(); + + TLorentzVector temp (0,0,0,0); + PA = temp; + Pa = temp; + Pb = temp; + PB = temp; + +} + +TransferReaction::~TransferReaction(){ + +} + +void TransferReaction::SetA(int A, int Z, double Ex = 0){ + Isotope temp (A, Z); + mA = temp.Mass; + reaction.beamA = A; + reaction.beamZ = Z; + ExA = Ex; + nameA = temp.Name; + isReady = false; + isBSet = true; +} + +void TransferReaction::Seta(int A, int Z){ + Isotope temp (A, Z); + ma = temp.Mass; + reaction.targetA = A; + reaction.targetZ = Z; + namea = temp.Name; + isReady = false; + isBSet = false; +} +void TransferReaction::Setb(int A, int Z){ + Isotope temp (A, Z); + mb = temp.Mass; + reaction.recoilLightA = A; + reaction.recoilLightZ = Z; + nameb = temp.Name; + isReady = false; + isBSet = false; +} +void TransferReaction::SetB(int A, int Z){ + Isotope temp (A, Z); + mB = temp.Mass; + reaction.recoilHeavyA = A; + reaction.recoilHeavyZ = Z; + nameB = temp.Name; + isReady = false; + isBSet = true; +} + +void TransferReaction::SetIncidentEnergyAngle(double KEA, double theta, double phi){ + this->TA = KEA; + this->T = TA * reaction.beamA; + this->thetaIN = theta; + this->phiIN = phi; + isReady = false; +} + +void TransferReaction::SetReactionSimple(int beamA, int beamZ, + int targetA, int targetZ, + int recoilA, int recoilZ, float beamEnergy_AMeV){ + + reaction.SetReactionSimple(beamA, beamZ, + targetA, targetZ, + recoilA, recoilZ, beamEnergy_AMeV); + + SetA(reaction.beamA, reaction.beamZ); + Seta(reaction.targetA, reaction.targetZ); + Setb(reaction.recoilLightA, reaction.recoilLightZ); + SetB(reaction.recoilHeavyA, reaction.recoilHeavyZ); + SetIncidentEnergyAngle(reaction.beamEnergy, 0, 0); + + CalReactionConstant(); + +} + +void TransferReaction::SetExA(double Ex){ + this->ExA = Ex; + isReady = false; +} + +void TransferReaction::SetExB(double Ex){ + this->ExB = Ex; + isReady = false; +} + +void TransferReaction::SetReactionFromFile(string settingFile){ + + if( reaction.LoadReactionConfig(settingFile) ){ + + SetA(reaction.beamA, reaction.beamZ); + Seta(reaction.targetA, reaction.targetZ); + Setb(reaction.recoilLightA, reaction.recoilLightZ); + SetB(reaction.recoilHeavyA, reaction.recoilHeavyZ); + SetIncidentEnergyAngle(reaction.beamEnergy, 0, 0); + + CalReactionConstant(); + + }else{ + printf("cannot read file %s.\n", settingFile.c_str()); + isReady = false; + } + +} + +TString TransferReaction::GetReactionName(){ + TString rName; + rName.Form("%s(%s,%s)%s", nameA.c_str(), namea.c_str(), nameb.c_str(), nameB.c_str()); + return rName; +} + +TString TransferReaction::format(TString name){ + if( name.IsAlpha() ) return name; + int len = name.Length(); + TString temp = name; + TString temp2 = name; + if( temp.Remove(0, len-2).IsAlpha()){ + temp2.Remove(len-2); + }else{ + temp = name; + temp.Remove(0, len-1); + temp2.Remove(len-1); + } + return "^{"+temp2+"}"+temp; +} +TString TransferReaction::GetReactionName_Latex(){ + TString rName; + rName.Form("%s(%s,%s)%s", format(nameA).Data(), format(namea).Data(), format(nameb).Data(), format(nameB).Data()); + return rName; +} + +void TransferReaction::CalReactionConstant(){ + if( !isBSet){ + reaction.recoilHeavyA = reaction.beamA + reaction.targetA - reaction.recoilLightA; + reaction.recoilHeavyZ = reaction.beamZ + reaction.targetZ - reaction.recoilLightZ; + Isotope temp (reaction.recoilHeavyA, reaction.recoilHeavyZ); + mB = temp.Mass; + isBSet = true; + } + + k = TMath::Sqrt(TMath::Power(mA + ExA + T, 2) - (mA + ExA) * (mA + ExA)); + beta = k / (mA + ExA + ma + T); + gamma = 1 / TMath::Sqrt(1- beta * beta); + Etot = TMath::Sqrt(TMath::Power(mA + ExA + ma + T,2) - k * k); + p = TMath::Sqrt( (Etot*Etot - TMath::Power(mb + mB + ExB,2)) * (Etot*Etot - TMath::Power(mb - mB - ExB,2)) ) / 2 / Etot; + + PA.SetXYZM(0, 0, k, mA + ExA); + PA.RotateY(thetaIN); + PA.RotateZ(phiIN); + + Pa.SetXYZM(0,0,0,ma); + + isReady = true; +} + +void TransferReaction::Event(double thetaCM_rad, double phiCM_rad){ + + if( isReady == false ){ + CalReactionConstant(); + } + + //---- to CM frame + TLorentzVector Pc = PA + Pa; + TVector3 b = Pc.BoostVector(); + + TVector3 vb(0,0,0); + + if( b.Mag() > 0 ){ + TVector3 v0 (0,0,0); + TVector3 nb = v0 - b; + + TLorentzVector PAc = PA; + PAc.Boost(nb); + TVector3 vA = PAc.Vect(); + + TLorentzVector Pac = Pa; + Pac.Boost(nb); + TVector3 va = Pac.Vect(); + + //--- construct vb + vb = va; + vb.SetMag(p); + + TVector3 ub = vb.Orthogonal(); + vb.Rotate(thetaCM_rad, ub); + vb.Rotate(phiCM_rad + TMath::PiOver2(), va); // somehow, the calculation turn the vector 90 degree. + //vb.Rotate(phiCM , va); // somehow, the calculation turn the vector 90 degree. + } + + //--- from Pb + TLorentzVector Pbc; + Pbc.SetVectM(vb, mb); + + //--- from PB + TLorentzVector PBc; + //PBc.SetVectM(vB, mB + ExB); + PBc.SetVectM(-vb, mB + ExB); + + //---- to Lab Frame + Pb = Pbc; Pb.Boost(b); + PB = PBc; PB.Boost(b); + +} + + +std::pair TransferReaction::CalExThetaCM(double e, double z, double Bfield, double perpDist){ + + double Ex = TMath::QuietNaN(); + double thetaCM = TMath::QuietNaN(); + + double mass = mb; + double massB = mB; + double y = e + mass; + double slope = 299.792458 * reaction.recoilLightZ * abs(Bfield) / TMath::TwoPi() * beta / 1000.; // MeV/mm; + double alpha = slope/beta; + double G = alpha * gamma * beta * perpDist ; + double Z = alpha * gamma * beta * z; + double H = TMath::Sqrt(TMath::Power(gamma * beta,2) * (y*y - mass * mass) ) ; + double Et = Etot; + + if( TMath::Abs(Z) < H ) { + //using Newton's method to solve 0 == H * sin(phi) - G * tan(phi) - Z = f(phi) + double tolerrence = 0.001; + double phi = 0; //initial phi = 0 -> ensure the solution has f'(phi) > 0 + double nPhi = 0; // new phi + + int iter = 0; + do{ + phi = nPhi; + nPhi = phi - (H * TMath::Sin(phi) - G * TMath::Tan(phi) - Z) / (H * TMath::Cos(phi) - G /TMath::Power( TMath::Cos(phi), 2)); + iter ++; + if( iter > 10 || TMath::Abs(nPhi) > TMath::PiOver2()) break; + }while( TMath::Abs(phi - nPhi ) > tolerrence); + + phi = nPhi; + + // check f'(phi) > 0 + double Df = H * TMath::Cos(phi) - G / TMath::Power( TMath::Cos(phi),2); + if( Df > 0 && TMath::Abs(phi) < TMath::PiOver2() ){ + double K = H * TMath::Sin(phi); + double x = TMath::ACos( mass / ( y * gamma - K)); + double k = mass * TMath::Tan(x); // momentum of particel b or B in CM frame + double EB = TMath::Sqrt(mass*mass + Et*Et - 2*Et*TMath::Sqrt(k*k + mass * mass)); + Ex = EB - massB; + + double hahaha1 = gamma* TMath::Sqrt(mass * mass + k * k) - y; + double hahaha2 = gamma* beta * k; + thetaCM = TMath::ACos(hahaha1/hahaha2) * TMath::RadToDeg(); + + //double pt = k * TMath::Sin(thetaCM * TMath::DegToRad()); + //double pp = gamma*beta*TMath::Sqrt(mass*mass + k*k) - gamma * k * TMath::Cos(thetaCM * TMath::DegToRad()); + //thetaLab = TMath::ATan(pt/pp) * TMath::RadToDeg(); + + }else{ + Ex = TMath::QuietNaN(); + thetaCM = TMath::QuietNaN(); + //thetaLab = TMath::QuietNaN(); + } + + }else{ + Ex = TMath::QuietNaN(); + thetaCM = TMath::QuietNaN(); + //thetaLab = TMath::QuietNaN(); + } + + return std::make_pair(Ex, thetaCM); +} + + +#endif \ No newline at end of file diff --git a/Cleopatra/Cleopatra.sh b/Cleopatra/Cleopatra.sh deleted file mode 100755 index d6c8ab7..0000000 --- a/Cleopatra/Cleopatra.sh +++ /dev/null @@ -1,205 +0,0 @@ -#!/bin/bash - - -######################################################################## -# -# This is Cleopatra.sh, a scripted version for Cleopatra -# -# Using bash script provide flexibility that user can add difference -# compoenents during the calculation -# -# A full package includes fellowing: -# 1) create a in-file for ptolemy -# 2) run ptolemy from that in-file and output an out-file -# 3) extract cross-section distribution from the out-file -# save as txt or root TGraph format -# 4) call ROOT to draw the TGraph -# 5) load possible experimental Xsec and fit with Ptolemy calulation -# -# User can easily select/comment-out different component -# to suit their needs -#------------------------------------------------------- -# created by Ryan (Tsz Leung) Tang, Nov-18, 2018 -# email: goluckyryan@gmail.com -######################################################################## - -#===== Call thisroot.h -ROOTPATH=$(which root) -len=${#ROOTPATH} -ROOTSOURCE=${ROOTPATH:0:$len-4}"thisroot.sh" -echo $ROOTSOURCE -source $ROOTSOURCE - -#===== go to Cleopatra and make -cd ../Cleopatra -make -cd ../working - -#================================ User Defualt Control -CreateInFile=0 # 0 = false, 1 = true -RunPtolemy=0 -IsExtractXSec=0 -PlotResult=0 -SimTransfer=0 -#============================================ USER don't need to change thing below - -if [ $# -eq 0 ] ; then - echo "$./Cleopatra in-file X X X X X angMin angMax angStep" - echo " | | | | |" - echo " | | | | Simulate Transfer reaction? (1/0)" - echo " | | | |" - echo " | | | PlotResult? (1/0)" - echo " | | Extract cross-section? (2/1/0)" - echo " | | if 1 = extract Ratio to Rutherford for (d,d), (p,p)" - echo " | | if 2 = extract total Xsec for (d,d), (p,p), (n,n)" - echo " | | if 3 = extract Rutherford" - echo " | Run Ptolemy? (1/0)" - echo " Create infile? (1/0)" - echo "default angMin = 0, angMax = 50, angStep = 0.5" - exit 1 -fi; - -loadfile=$1 -infile=$1".in" -outfile=$1".out" -rootfile=$1".root" -exFile=$1".Ex.txt" - -if [ $# -eq 2 ]; then - CreateInFile=$2 -fi; -if [ $# -eq 3 ]; then - CreateInFile=$2 - RunPtolemy=$3 -fi; -if [ $# -eq 4 ]; then - CreateInFile=$2 - RunPtolemy=$3 - IsExtractXSec=$4 -fi; -if [ $# -eq 5 ]; then - CreateInFile=$2 - RunPtolemy=$3 - IsExtractXSec=$4 - PlotResult=$5 -fi; -if [ $# -eq 6 ]; then - CreateInFile=$2 - RunPtolemy=$3 - IsExtractXSec=$4 - PlotResult=$5 - SimTransfer=$6 -fi; -if [ $# -eq 9 ]; then - CreateInFile=$2 - RunPtolemy=$3 - IsExtractXSec=$4 - PlotResult=$5 - SimTransfer=$6 - angMin=$7 - angMax=$8 - angStep=$9 -fi; - -ExtractXsecMsg="" -if [ $IsExtractXSec -eq 1 ]; then - ExtractXsecMsg=", for (d,d)(p,p), extract Ratio to Rutherford" -elif [ $IsExtractXSec -eq 2 ]; then - ExtractXsecMsg=", for (d,d)(p,p), extract Total Xsec" -fi; - -if [ $SimTransfer -eq 1 ]; then - angMin=0 - angMax=180 - angStep=0.5 -fi - -echo "#################################################################" -echo "## @@@@ @@ @@@@ @@@@ @@@@@ @@@@ @@@@@@ @@@@@ @@@@ ##" -echo "## @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ ##" -echo "## @@ @@ @@@@ @@ @@ @@@@@ @@@@@@ @@ @@@@@ @@@@@@ ##" -echo "## @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @ @@ @@ ##" -echo "## @@@@ @@@@@ @@@@ @@@@ @@ @@ @@ @@ @@ @ @@ @@ ##" -echo "#################################################################" -echo "##### Cleopatra, Ptolemy for p,d,t,3He, a #####" -echo "#################################################################" -echo "Supported reactions:" -echo "elastics/inelastics : (p,p), (d,d)" -echo "1-neutron adding : (d,p), (t,d) | (a,3He)?" -echo "1-proton adding : (3He,d)" -echo "2-neutrons adding : (t,p)" -echo "1-neutron removal : (p,d), (d,t) " -echo "1-proton removal : (d,3He), (t,a)" -echo "=================================================================" -echo "USER OPTION:" -echo " --- Is Create Ptolemy infile ? " ${CreateInFile} -echo " --- Is Run Ptolemy ? " ${RunPtolemy} -echo " --- Is Extract Cross-Section ? " ${IsExtractXSec} ${ExtractXsecMsg} -echo " --- Is Plot Results ? " ${PlotResult} -echo " ----Is Simulation Transfer ? " ${SimTransfer} -echo "=================================================================" - -#if [ ${CreateInFile} -eq 1 ] ; then -# echo "infile ----> "${loadfile} -#fi; -# -#if [ ${RunPtolemy} -eq 1 ] ; then -# echo "Ptolemy infile ----> "${infile} -# echo "Ptolemy outfile ----> "${outfile} -#fi; - -if [ ${CreateInFile} -eq 1 ] ; then - if [ $# -eq 9 ]; then - ../Cleopatra/InFileCreator ${loadfile} $angMin $angMax $angStep - else - ../Cleopatra/InFileCreator ${loadfile} 0.0 50.0 0.5 - fi -fi; - -if [ ${RunPtolemy} -eq 1 ] ; then - echo "=================================================================" - echo "===== Ptolemy Calcualtion ===================================" - echo "=================================================================" - - #check is linux or Mac - - arch=$(uname) - - if [ ${arch} == "Darwin" ] ; then - ../Cleopatra/ptolemy_mac <${infile}> ${outfile} - ptolemyOUTPUT=$? - else - ../Cleopatra/ptolemy <${infile}> ${outfile} - ptolemyOUTPUT=$? - fi - - echo "ptolmey exit code : " $ptolemyOUTPUT - if [ ${ptolemyOUTPUT} -eq 0 ] ; then - echo "Ptolmey finished without problem. " - else - echo "Ptolemy has error, check ${infile} or ${outfile}" - exit 1; - fi - -fi; - -#===== Extracting XSec and save into *txt and *root -if [ ${IsExtractXSec} -ge 1 ] ; then - ../Cleopatra/ExtractXSec ${outfile} ${IsExtractXSec} -fi; - -if [ ${PlotResult} -eq 1 ] ; then - #===== Plot the result from the *.root - #./PlotTGraphTObjArray ${rootfile} - #--- other way within ROOT - echo "=================================================================" - echo "===== Plot Result from ${rootfile}" - echo "=================================================================" - com='../Cleopatra/PlotTGraphTObjArray.h("'${rootfile}'")' - echo ${com} - root -l ${com} -fi; - -if [ ${SimTransfer} -eq 1 ] ; then - ../Cleopatra/Transfer reactionConfig.txt detectorGeo.txt ${exFile} ${rootfile} transfer.root reaction.dat -fi; diff --git a/Cleopatra/ExtractXSec.h b/Cleopatra/ExtractXSec.h index 45b03c8..668de9b 100644 --- a/Cleopatra/ExtractXSec.h +++ b/Cleopatra/ExtractXSec.h @@ -25,7 +25,7 @@ #include #include #include -#include "../armory/AnalysisLib.h" +#include "../Armory/AnalysisLib.h" using namespace std; diff --git a/Cleopatra/FindThetaCM.h b/Cleopatra/FindThetaCM.h index ad41d8c..3e124df 100644 --- a/Cleopatra/FindThetaCM.h +++ b/Cleopatra/FindThetaCM.h @@ -16,11 +16,12 @@ #include "TMacro.h" #include "TObjArray.h" #include "TGraph.h" -#include "../Cleopatra/HELIOS_LIB.h" +#include "../Cleopatra/ClassHelios.h" +#include "../Cleopatra/ClassTransfer.h" void FindThetaCM(double Ex, int nDivision=1, double XRATION = 0.95, - string basicConfig="reactionConfig.txt", - string detGeoFileName = "detectorGeo.txt"){ + std::string basicConfig="reactionConfig.txt", + std::string detGeoFileName = "detectorGeo.txt"){ //---- reaction int AA, zA; //beam @@ -34,13 +35,9 @@ void FindThetaCM(double Ex, int nDivision=1, double XRATION = 0.95, double xBeam, yBeam; // mm /**///========================================================= load files - AnalysisLib::ReactionConfig reactionConfig; - AnalysisLib::DetGeo detGeo; - TMacro * haha = new TMacro(); - if( haha->ReadFile(basicConfig.c_str()) > 0 ){ - reactionConfig = AnalysisLib::LoadReactionConfig(haha); - - AnalysisLib::PrintReactionConfig(reactionConfig); + ReactionConfig reactionConfig; + DetGeo detGeo; + if( reactionConfig.LoadReactionConfig(basicConfig) ){ KEAmean = reactionConfig.beamEnergy; KEAsigma = reactionConfig.beamEnergySigma; @@ -62,7 +59,7 @@ void FindThetaCM(double Ex, int nDivision=1, double XRATION = 0.95, return; } - vector pos; + std::vector pos; double a = 11.5; double length = 50.5; double firstPos = 0; @@ -99,10 +96,7 @@ void FindThetaCM(double Ex, int nDivision=1, double XRATION = 0.95, printf("----- loading detector geometery : %s.", detGeoFileName.c_str()); - TMacro * kaka = new TMacro(); - if( kaka->ReadFile(detGeoFileName.c_str()) > 0 ){ - detGeo = AnalysisLib::LoadDetectorGeo(kaka); - + if(detGeo.LoadDetectorGeo(detGeoFileName) ){ pos = detGeo.array1.detPos; a = detGeo.array1.detPerpDist; length = detGeo.array1.detLength; @@ -112,8 +106,6 @@ void FindThetaCM(double Ex, int nDivision=1, double XRATION = 0.95, BField = detGeo.Bfield; printf("... done.\n"); - - AnalysisLib::PrintDetGeo(detGeo); }else{ printf("... fail\n"); diff --git a/Cleopatra/HELIOS_LIB.h b/Cleopatra/HELIOS_LIB.h deleted file mode 100644 index 101e4ec..0000000 --- a/Cleopatra/HELIOS_LIB.h +++ /dev/null @@ -1,1534 +0,0 @@ -#ifndef HELIOS_Library_h -#define HELIOS_Library_h - -#include "TBenchmark.h" -#include "TLorentzVector.h" -#include "TVector3.h" -#include "TMath.h" -#include "TFile.h" -#include "TTree.h" -#include "TRandom.h" -#include "TMacro.h" -#include "TGraph.h" -#include -#include - -#include "Isotope.h" -#include "../armory/AnalysisLib.h" - -//======================================================= -//####################################################### -// Class for Transfer Reaction -// reaction notation A(a,b)B -// A = incident particle -// a = target -// b = light scattered particle -// B = heavy scattered particle -//======================================================= -class TransferReaction { -public: - TransferReaction(); - ~TransferReaction(); - - void SetA(int A, int Z, double Ex); - void Seta(int A, int Z); - void Setb(int A, int Z); - void SetB(int A, int Z); - void SetIncidentEnergyAngle(double KEA, double theta, double phi); - void SetExA(double Ex); - void SetExB(double Ex); - void SetReactionFromFile(string settingFile); - - TString GetReactionName(); - TString GetReactionName_Latex(); - - int GetAtomicNumber_A(){return AA;} - int GetAtomicNumber_a(){return Aa;} - int GetAtomicNumber_b(){return Ab;} - int GetAtomicNumber_B(){return AB;} - - double GetMass_A(){return mA + ExA;} - double GetMass_a(){return ma;} - double GetMass_b(){return mb;} - double GetMass_B(){return mB + ExB;} - - int GetCharge_A(){return zA;} - int GetCharge_a(){return za;} - int GetCharge_b(){return zb;} - int GetCharge_B(){return zB;} - - double GetCMTotalKE() {return Etot - mA - ma;} - double GetQValue() {return mA + ExA + ma - mb - mB - ExB;} - double GetMaxExB() {return Etot - mb - mB;} - - TLorentzVector GetPA(){return PA;} - TLorentzVector GetPa(){return Pa;} - TLorentzVector GetPb(){return Pb;} - TLorentzVector GetPB(){return PB;} - - void CalReactionConstant(); - int CalExThetaCM(double e, double z, double Bfield, double a); // return 0 for no-result, 1 for OK. - - TLorentzVector * Event(double thetaCM, double phiCM); - - double GetEx(){return Ex;} - double GetThetaCM(){return thetaCM;} - - double GetMomentumbCM() {return p;} - double GetReactionBeta() {return beta;} - double GetReactionGamma() {return gamma;} - double GetCMTotalEnergy() {return Etot;} - - AnalysisLib::ReactionConfig GetRectionConfig() { return reaction;} - -private: - - AnalysisLib::ReactionConfig reaction; - - string nameA, namea, nameb, nameB; - double thetaIN, phiIN; - double mA, ma, mb, mB; - int AA, Aa, Ab, AB; - int zA, za, zb, zB; - double TA, T; // TA = KE of A pre u, T = total energy - double ExA, ExB; - double Ex, thetaCM; //calculated Ex using inverse mapping from e and z to thetaCM - - bool isReady; - bool isBSet; - - double k; // CM Boost momentum - double beta, gamma; //CM boost beta - double Etot; - double p; // CM frame momentum of b, B - - TLorentzVector PA, Pa, Pb, PB; - - TString format(TString name); - -}; - -TransferReaction::TransferReaction(){ - - thetaIN = 0.; - phiIN = 0.; - SetA(12, 6, 0); - Seta(2,1); - Setb(1,1); - SetB(13,6); - TA = 6; - T = TA * AA; - - ExA = 0; - ExB = 0; - - Ex = TMath::QuietNaN(); - thetaCM = TMath::QuietNaN(); - - CalReactionConstant(); - - TLorentzVector temp (0,0,0,0); - PA = temp; - Pa = temp; - Pb = temp; - PB = temp; - -} - -TransferReaction::~TransferReaction(){ - -} - -void TransferReaction::SetA(int A, int Z, double Ex = 0){ - Isotope temp (A, Z); - mA = temp.Mass; - AA = A; - zA = Z; - ExA = Ex; - nameA = temp.Name; - isReady = false; - isBSet = true; - -} - -void TransferReaction::Seta(int A, int Z){ - Isotope temp (A, Z); - ma = temp.Mass; - Aa = A; - za = Z; - namea = temp.Name; - isReady = false; - isBSet = false; -} - -void TransferReaction::Setb(int A, int Z){ - Isotope temp (A, Z); - mb = temp.Mass; - Ab = A; - zb = Z; - nameb = temp.Name; - isReady = false; - isBSet = false; -} -void TransferReaction::SetB(int A, int Z){ - Isotope temp (A, Z); - mB = temp.Mass; - AB = A; - zB = Z; - nameB = temp.Name; - isReady = false; - isBSet = true; -} -void TransferReaction::SetIncidentEnergyAngle(double KEA, double theta, double phi){ - this->TA = KEA; - this->T = TA * AA; - this->thetaIN = theta; - this->phiIN = phi; - isReady = false; -} - -void TransferReaction::SetExA(double Ex){ - this->ExA = Ex; - isReady = false; -} - -void TransferReaction::SetExB(double Ex){ - this->ExB = Ex; - isReady = false; -} - -void TransferReaction::SetReactionFromFile(string settingFile){ - - TMacro * haha = new TMacro(); - if( haha->ReadFile(settingFile.c_str()) > 0 ) { - reaction = AnalysisLib::LoadReactionConfig(haha); - - SetA(reaction.beamA, reaction.beamZ); - Seta(reaction.targetA, reaction.targetZ); - Setb(reaction.recoilLightA, reaction.recoilLightZ); - SetB(reaction.recoilHeavyA, reaction.recoilHeavyZ); - - SetIncidentEnergyAngle(reaction.beamEnergy, 0, 0); - CalReactionConstant(); - }else{ - - printf("cannot read file %s.\n", settingFile.c_str()); - isReady = false; - } - -} - -TString TransferReaction::GetReactionName(){ - TString rName; - rName.Form("%s(%s,%s)%s", nameA.c_str(), namea.c_str(), nameb.c_str(), nameB.c_str()); - return rName; -} - -TString TransferReaction::format(TString name){ - if( name.IsAlpha() ) return name; - int len = name.Length(); - TString temp = name; - TString temp2 = name; - if( temp.Remove(0, len-2).IsAlpha()){ - temp2.Remove(len-2); - }else{ - temp = name; - temp.Remove(0, len-1); - temp2.Remove(len-1); - } - return "^{"+temp2+"}"+temp; -} -TString TransferReaction::GetReactionName_Latex(){ - TString rName; - rName.Form("%s(%s,%s)%s", format(nameA).Data(), format(namea).Data(), format(nameb).Data(), format(nameB).Data()); - return rName; -} - -void TransferReaction::CalReactionConstant(){ - if( !isBSet){ - AB = AA + Aa - Ab; - zB = zA + za - zb; - Isotope temp (AB, zB); - mB = temp.Mass; - isBSet = true; - } - - k = TMath::Sqrt(TMath::Power(mA + ExA + T, 2) - (mA + ExA) * (mA + ExA)); - beta = k / (mA + ExA + ma + T); - gamma = 1 / TMath::Sqrt(1- beta * beta); - Etot = TMath::Sqrt(TMath::Power(mA + ExA + ma + T,2) - k * k); - p = TMath::Sqrt( (Etot*Etot - TMath::Power(mb + mB + ExB,2)) * (Etot*Etot - TMath::Power(mb - mB - ExB,2)) ) / 2 / Etot; - - PA.SetXYZM(0, 0, k, mA + ExA); - PA.RotateY(thetaIN); - PA.RotateZ(phiIN); - - Pa.SetXYZM(0,0,0,ma); - - isReady = true; -} - -TLorentzVector * TransferReaction::Event(double thetaCM, double phiCM) -{ - if( isReady == false ){ - CalReactionConstant(); - } - - //TLorentzVector Pa(0, 0, 0, ma); - - //---- to CM frame - TLorentzVector Pc = PA + Pa; - TVector3 b = Pc.BoostVector(); - - TVector3 vb(0,0,0); - - if( b.Mag() > 0 ){ - TVector3 v0 (0,0,0); - TVector3 nb = v0 - b; - - TLorentzVector PAc = PA; - PAc.Boost(nb); - TVector3 vA = PAc.Vect(); - - TLorentzVector Pac = Pa; - Pac.Boost(nb); - TVector3 va = Pac.Vect(); - - //--- construct vb - vb = va; - vb.SetMag(p); - - TVector3 ub = vb.Orthogonal(); - vb.Rotate(thetaCM, ub); - vb.Rotate(phiCM + TMath::PiOver2(), va); // somehow, the calculation turn the vector 90 degree. - //vb.Rotate(phiCM , va); // somehow, the calculation turn the vector 90 degree. - } - - //--- from Pb - TLorentzVector Pbc; - Pbc.SetVectM(vb, mb); - - //--- from PB - TLorentzVector PBc; - //PBc.SetVectM(vB, mB + ExB); - PBc.SetVectM(-vb, mB + ExB); - - //---- to Lab Frame - TLorentzVector Pb = Pbc; - Pb.Boost(b); - TLorentzVector PB = PBc; - PB.Boost(b); - - TLorentzVector * output = new TLorentzVector[4]; - output[0] = PA; - output[1] = Pa; - output[2] = Pb; - output[3] = PB; - - this->Pb = Pb; - this->PB = PB; - - - return output; -} - - -int TransferReaction::CalExThetaCM(double e, double z, double Bfield, double a){ - double mass = mb; - double massB = mB; - double y = e + mass; - double slope = 299.792458 * zb * abs(Bfield) / TMath::TwoPi() * beta / 1000.; // MeV/mm; - double alpha = slope/beta; - double G = alpha * gamma * beta * a ; - double Z = alpha * gamma * beta * z; - double H = TMath::Sqrt(TMath::Power(gamma * beta,2) * (y*y - mass * mass) ) ; - double Et = Etot; - - if( TMath::Abs(Z) < H ) { - //using Newton's method to solve 0 == H * sin(phi) - G * tan(phi) - Z = f(phi) - double tolerrence = 0.001; - double phi = 0; //initial phi = 0 -> ensure the solution has f'(phi) > 0 - double nPhi = 0; // new phi - - int iter = 0; - do{ - phi = nPhi; - nPhi = phi - (H * TMath::Sin(phi) - G * TMath::Tan(phi) - Z) / (H * TMath::Cos(phi) - G /TMath::Power( TMath::Cos(phi), 2)); - iter ++; - if( iter > 10 || TMath::Abs(nPhi) > TMath::PiOver2()) break; - }while( TMath::Abs(phi - nPhi ) > tolerrence); - - phi = nPhi; - - // check f'(phi) > 0 - double Df = H * TMath::Cos(phi) - G / TMath::Power( TMath::Cos(phi),2); - if( Df > 0 && TMath::Abs(phi) < TMath::PiOver2() ){ - double K = H * TMath::Sin(phi); - double x = TMath::ACos( mass / ( y * gamma - K)); - double k = mass * TMath::Tan(x); // momentum of particel b or B in CM frame - double EB = TMath::Sqrt(mass*mass + Et*Et - 2*Et*TMath::Sqrt(k*k + mass * mass)); - Ex = EB - massB; - - double hahaha1 = gamma* TMath::Sqrt(mass * mass + k * k) - y; - double hahaha2 = gamma* beta * k; - thetaCM = TMath::ACos(hahaha1/hahaha2) * TMath::RadToDeg(); - - //double pt = k * TMath::Sin(thetaCM * TMath::DegToRad()); - //double pp = gamma*beta*TMath::Sqrt(mass*mass + k*k) - gamma * k * TMath::Cos(thetaCM * TMath::DegToRad()); - //thetaLab = TMath::ATan(pt/pp) * TMath::RadToDeg(); - - }else{ - Ex = TMath::QuietNaN(); - thetaCM = TMath::QuietNaN(); - //thetaLab = TMath::QuietNaN(); - - return 0; - } - - }else{ - Ex = TMath::QuietNaN(); - thetaCM = TMath::QuietNaN(); - //thetaLab = TMath::QuietNaN(); - return 0; - } - - return 1; -} -//======================================================= -//####################################################### -//Class for HELIOS -//input Lorentz vector, detector configuration -//output e, z, Ex, thetaCM, etc -//======================================================= - -struct trajectory{ - double theta, phi; - double vt, vp; // tranvser and perpendicular velocity - double rho; // orbit radius - double z0, t0; // position cycle - double x, y, z; // hit position - double t; //actual orbit time; - double R; //hit radius = sqrt(x^2+y^2); - int detID, detRowID; - int loop; - double effLoop; -}; - -void PrintTrajectory(trajectory a){ - printf("=====================\n"); - printf(" theta : %f deg\n", a.theta*TMath::RadToDeg()); - printf(" phi : %f deg\n", a.phi*TMath::RadToDeg()); - printf(" vt : %f mm/ns\n", a.vt); - printf(" vp : %f mm/ns\n", a.vp); - printf(" rho : %f mm\n", a.rho); - printf(" z0 : %f mm\n", a.z0); - printf(" t0 : %f ns\n", a.t0); - printf("(x, y, z) : (%f, %f. %f) mm\n", a.x, a.y, a.z); - printf(" R : %f mm\n", a.R); - printf(" t : %f ns\n", a.t); - printf(" effLoop : %f cycle\n", a.effLoop); - printf(" Loop : %d cycle\n", a.loop); - printf(" detRowID : %d \n", a.detRowID); - printf(" detID : %d \n", a.detID); - -} - -class HELIOS{ -public: - - HELIOS(); - ~HELIOS(); - - void SetCoincidentWithRecoil(bool TorF){ this->isCoincidentWithRecoil = TorF;} - bool GetCoincidentWithRecoil(){return this->isCoincidentWithRecoil;} - bool SetDetectorGeometry(string filename); - void SetBeamPosition(double x, double y) { xOff = x; yOff = y;} - - void OverrideMagneticField(double BField){ this->detGeo.Bfield = BField; this->detGeo.BfieldSign = BField > 0 ? 1: -1;} - void OverrideMagneticFieldDirection(double BfieldThetaInDeg){ this->detGeo.BfieldTheta = BfieldThetaInDeg;} - void OverrideFirstPos(double firstPos){ - overrideFirstPos = true; - printf("------ Overriding FirstPosition to : %8.2f mm \n", firstPos); - this->array.firstPos = firstPos; - } - void OverrideDetectorDistance(double perpDist){ - overrideDetDistance = true; - printf("------ Overriding Detector Distance to : %8.2f mm \n", perpDist); - this->array.detPerpDist = perpDist; - } - - void SetDetectorOutside(bool isOutside){ - this->array.detFaceOut = isOutside; - printf(" Detectors are facing %s\n", array.detFaceOut ? "outside": "inside" ); - } - - int DetAcceptance(); - int CalArrayHit(TLorentzVector Pb, int Zb); - int CalRecoilHit(TLorentzVector PB, int ZB); - //int CalHit(TLorentzVector Pb, int Zb, TLorentzVector PB, int ZB, double xOff = 0, double yOff = 0 ); // return 0 for no hit, 1 for hit - - void CalTrajectoryPara(TLorentzVector P, int Z, int id); // id = 0 for Pb, id = 1 for PB. - - int GetNumberOfDetectorsInSamePos(){return array.mDet;} - double GetEnergy(){return e;} - double GetDetX(){return detX;} // position in each detector, range from -1, 1 - - /// clockwise rotation for B-field along the z-axis, sign = 1. - double XPos(double Zpos, double theta, double phi, double rho, int sign){ - return rho * ( TMath::Sin( TMath::Tan(theta) * Zpos / rho - sign * phi ) + sign * TMath::Sin(phi) ) + xOff; - } - double YPos(double Zpos, double theta, double phi, double rho, int sign){ - return rho * sign * (TMath::Cos( TMath::Tan(theta) * Zpos / rho - sign * phi ) - TMath::Cos(phi)) + yOff; - } - double RPos(double Zpos, double theta, double phi, double rho, int sign){ - double x = XPos(Zpos, theta, phi, rho, sign) ; - double y = YPos(Zpos, theta, phi, rho, sign) ; - return sqrt(x*x+y*y); - } - - double GetXPos(double ZPos){ return XPos( ZPos, orbitb.theta, orbitb.phi, orbitb.rho, detGeo.BfieldSign); } - double GetYPos(double ZPos){ return YPos( ZPos, orbitb.theta, orbitb.phi, orbitb.rho, detGeo.BfieldSign); } - double GetR(double ZPos) { return RPos( ZPos, orbitb.theta, orbitb.phi, orbitb.rho, detGeo.BfieldSign); } - - double GetRecoilEnergy(){return eB;} - double GetRecoilXPos(double ZPos){ return XPos( ZPos, orbitB.theta, orbitB.phi, orbitB.rho, detGeo.BfieldSign); } - double GetRecoilYPos(double ZPos){ return YPos( ZPos, orbitB.theta, orbitB.phi, orbitB.rho, detGeo.BfieldSign); } - double GetRecoilR(double ZPos) { return RPos( ZPos, orbitB.theta, orbitB.phi, orbitB.rho, detGeo.BfieldSign); } - - double GetBField() {return detGeo.Bfield;} - double GetDetRadius() {return array.detPerpDist;} - - trajectory GetTrajectory_b() {return orbitb;} - trajectory GetTrajectory_B() {return orbitB;} - - AnalysisLib::DetGeo GetDetectorGeometry() {return detGeo;} - -private: - - void ClearTrajectory(trajectory t){ - t.theta = TMath::QuietNaN(); - t.phi = TMath::QuietNaN(); - t.vt = TMath::QuietNaN(); - t.vp = TMath::QuietNaN(); - t.rho = TMath::QuietNaN(); - t.z0 = TMath::QuietNaN(); - t.t0 = TMath::QuietNaN(); - t.x = TMath::QuietNaN(); - t.y = TMath::QuietNaN(); - t.z = TMath::QuietNaN(); - t.effLoop = TMath::QuietNaN(); - t.detID = -1; - t.detRowID = -1; - t.loop = -1; - } - - AnalysisLib::DetGeo detGeo; - AnalysisLib::Array array; - - trajectory orbitb, orbitB; - - double e,detX ; ///energy of light recoil, position X - double rhoHit; /// radius of particle-b hit on recoil detector - - double eB; ///energy of heavy recoil - - bool isDetReady; - - double xOff, yOff; // beam position - - //detetcor Geometry - //int sign ; // sign of B-field - // double Bfield; // T - // double BfieldTheta; // rad, 0 = z-axis, pi/2 = y axis, pi = -z axis - // double bore; // bore , mm - // double perpDist; // distance from axis - // double width; // width - // double posRecoil; // recoil, downstream - // double rhoRecoilin; // radius recoil inner - // double rhoRecoilout; // radius recoil outter - // double length; // length - // double blocker; - // double firstPos; // m - // vector pos; // near position in m - // int nDet, mDet; // nDet = number of different pos, mDet, number of same pos - // bool isFromOutSide; - - bool overrideDetDistance; - bool overrideFirstPos; - bool isCoincidentWithRecoil; - - const double c = 299.792458; //mm/ns -}; - -HELIOS::HELIOS(){ - - ClearTrajectory(orbitb); - ClearTrajectory(orbitB); - - e = TMath::QuietNaN(); - eB = TMath::QuietNaN(); - detX = TMath::QuietNaN(); - rhoHit = TMath::QuietNaN(); - - xOff = 0.0; - yOff = 0.0; - - isDetReady = false; - - overrideDetDistance = false; - overrideFirstPos = false; - isCoincidentWithRecoil = false; - -} - -HELIOS::~HELIOS(){ - -} - -bool HELIOS::SetDetectorGeometry(string filename){ - - TMacro * haha = new TMacro(); - if( haha->ReadFile(filename.c_str()) > 0 ) { - detGeo = AnalysisLib::LoadDetectorGeo(haha); - - if( detGeo.use2ndArray ){ - array = detGeo.array2; - }else{ - array = detGeo.array1; - } - - PrintDetGeo(detGeo, false); - - isCoincidentWithRecoil = detGeo.isCoincidentWithRecoil; - - isDetReady = true; - }else{ - printf("cannot read file %s.\n", filename.c_str()); - isDetReady = false; - } - - return isDetReady; -} - -int HELIOS::DetAcceptance(){ - - //CalArrayHit and CalRecoilHit must be done before. - - if( isDetReady == false ) return 0; - - // -1 ========= when recoil direction is not same side of array - if( array.firstPos < 0 && orbitb.z > 0 ) return -1; - if( array.firstPos > 0 && orbitb.z < 0 ) return -1; - - // -11 ======== rho is too small - if( 2 * orbitb.rho < array.detPerpDist ) return -11; - - // -15 ========= if detRowID == -1, should be (2 * orbitb.rho < perpDist) - if( orbitb.detRowID == -1 ) return -15; - - // -10 =========== when rho is too big . - if( detGeo.bore < 2 * orbitb.rho) return -10; - - // -14 ========== check particle-B hit radius on recoil dectector - if( isCoincidentWithRecoil && orbitB.R > detGeo.recoilOuterRadius ) return -14; - //if( isCoincidentWithRecoil && (orbitB.R > rhoRecoilout || orbitB.R < rhoRecoilin) ) return -14; - - // -12 ========= check is particle-b was blocked by recoil detector - rhoHit = GetR(detGeo.recoilPos); - if( orbitb.z > 0 && detGeo.recoilPos > 0 && orbitb.z > detGeo.recoilPos && rhoHit < detGeo.recoilOuterRadius ) return -12; - if( orbitb.z < 0 && detGeo.recoilPos < 0 && orbitb.z < detGeo.recoilPos && rhoHit < detGeo.recoilOuterRadius ) return -12; - - // -13 ========= not more than 3 loops - if( orbitb.loop > 3 ) return -13; - - // -2 ========= calculate the "y"-distance from detector center - if( sqrt(orbitb.R*orbitb.R - array.detPerpDist * array.detPerpDist)> array.detWidth/2 ) return -2; - - // -3 ==== when zPos further the range of whole array, more loop would not save - if( array.firstPos < 0 && orbitb.z < array.detPos[0] - array.detLength ) return -3; - if( array.firstPos > 0 && orbitb.z > array.detPos[array.nDet-1] + array.detLength ) return -3; - - // -4 ======== Hit on blacker - if( array.blocker != 0 && array.firstPos > 0 && array.detPos[0] - array.blocker < orbitb.z && orbitb.z < array.detPos[0] ) return -4; - if( array.blocker != 0 && array.firstPos < 0 && array.detPos[array.nDet-1] < orbitb.z && orbitb.z < array.detPos[array.nDet-1] + array.blocker ) return -4; - - // 2 ====== when zPos less then the nearest position, more loop may hit - int increaseLoopFlag = 0; - if( array.firstPos < 0 && array.detPos[array.nDet-1] < orbitb.z ) increaseLoopFlag = 2; - if( array.firstPos > 0 && array.detPos[0] > orbitb.z ) increaseLoopFlag = 2; - if (increaseLoopFlag == 2 ) { - orbitb.z += orbitb.z0; - orbitb.effLoop += 1.0; - orbitb.loop += 1; - orbitb.t = orbitb.t0 * orbitb.effLoop; - return 2; - } - - // 1 ======= check hit array z- position - if( array.firstPos < 0 ){ - for( int i = 0; i < array.nDet; i++){ - if( array.detPos[i] - array.detLength <= orbitb.z && orbitb.z <= array.detPos[i]) { - orbitb.detID = i; - detX = ( orbitb.z - (array.detPos[i] + array.detLength/2 ))/ array.detLength * 2 ;// range from -1 , 1 - return 1; - } - } - }else{ - for( int i = 0; i < array.nDet ; i++){ - if( array.detPos[i] <= orbitb.z && orbitb.z <= array.detPos[i] + array.detLength) { - ///printf(" %d | %f < z = %f < %f \n", i, array.detPos[i], orbitb.z, array.detPos[i]+length); - orbitb.detID = i; - detX = ( orbitb.z - (array.detPos[i] - array.detLength/2 ))/ array.detLength*2 ;// range from -1 , 1 - return 1; - } - } - } - - - // -5 ======== check hit array gap - if( array.firstPos < 0 ){ - for( int i = 0; i < array.nDet-1 ; i++){ - if( array.detPos[i] < orbitb.z && orbitb.z < array.detPos[i+1] - array.detLength ) return -5; //increaseLoopFlag = 3; - } - }else{ - for( int i = 0; i < array.nDet-1 ; i++){ - if( array.detPos[i] + array.detLength < orbitb.z && orbitb.z < array.detPos[i+1] ) return -5; //increaseLoopFlag = 3; - } - } - if (increaseLoopFlag == 3 ) { - orbitb.z += orbitb.z0; - orbitb.effLoop += 1.0; - orbitb.loop += 1; - orbitb.t = orbitb.t0 * orbitb.effLoop; - return 3; - } - - - return -20; // for unknown reason -} - -void HELIOS::CalTrajectoryPara(TLorentzVector P, int Z, int id){ - - if( id == 0 ){ - orbitb.theta = P.Theta(); - orbitb.phi = P.Phi(); - orbitb.rho = P.Pt() / abs(detGeo.Bfield) / Z / c * 1000; //mm - orbitb.vt = P.Beta() * TMath::Sin(P.Theta()) * c ; // mm / nano-second - orbitb.vp = P.Beta() * TMath::Cos(P.Theta()) * c ; // mm / nano-second - orbitb.t0 = TMath::TwoPi() * orbitb.rho / orbitb.vt; // nano-second - orbitb.z0 = orbitb.vp * orbitb.t0; - - orbitb.detID = -1; - orbitb.detRowID = -1; - - } - - if( id == 1 ){ - orbitB.theta = P.Theta(); - orbitB.phi = P.Phi(); - orbitB.rho = P.Pt() / abs(detGeo.Bfield) / Z / c * 1000; //mm - orbitB.vt = P.Beta() * TMath::Sin(P.Theta()) * c ; // mm / nano-second - orbitB.vp = P.Beta() * TMath::Cos(P.Theta()) * c ; // mm / nano-second - orbitB.t0 = TMath::TwoPi() * orbitB.rho / orbitB.vt; // nano-second - orbitB.z0 = orbitB.vp * orbitB.t0; - - orbitB.detID = -1; - orbitB.detRowID = -1; - - } -} - -int HELIOS::CalArrayHit(TLorentzVector Pb, int Zb){ - - e = Pb.E() - Pb.M(); - detX = TMath::QuietNaN(); - rhoHit = TMath::QuietNaN(); - - CalTrajectoryPara(Pb, Zb, 0); - - int targetLoop = 1; - int inOut = array.detFaceOut == true ? 1: 0; //1 = from Outside, 0 = from inside - - bool debug = false; - - if( debug ) { - printf("===================================\n"); - printf("theta : %f deg, phi : %f deg \n", orbitb.theta * TMath::RadToDeg(), orbitb.phi * TMath::RadToDeg()); - printf("z0: %f mm, rho : %f mm \n", orbitb.z0, orbitb.rho); - printf(" inOut : %d = %s \n", inOut, inOut == 1 ? "Out" : "in"); - printf(" z range : %.2f - %.2f \n", detGeo.zMin, detGeo.zMax); - printf("-----------------------------------\n"); - } - - vector zPossible; - vector dID; //detRowID - - int iStart = ( detGeo.BfieldSign == 1 ? 0 : -array.mDet ); - int iEnd = ( detGeo.BfieldSign == 1 ? 2 * array.mDet : array.mDet ); - for( int i = iStart; i < iEnd ; i++){ - - double phiD = TMath::TwoPi()/array.mDet * i ; - double dphi = orbitb.phi - phiD; - double aEff = array.detPerpDist - (xOff * TMath::Cos(phiD) + yOff * TMath::Sin(phiD)); - double hahaha = asin( aEff/ orbitb.rho - detGeo.BfieldTheta * sin(dphi)); - - int n = 2*targetLoop + inOut; - - double zP = orbitb.z0 /TMath::TwoPi() * ( detGeo.BfieldSign * dphi + n * TMath::Pi() + pow(-1, n) * hahaha ); - - if( debug ) { - double xP = GetXPos(zP) ; - double yP = GetYPos(zP) ; - printf("phiD: %4.0f, dphi: %6.1f, mod(pi): %6.1f, Loop : %9.5f, zHit : %8.3f mm, (x,y) = (%7.2f, %7.2f) \n", - phiD * TMath::RadToDeg(), - (orbitb.phi-phiD) * TMath::RadToDeg(), - fmod(orbitb.phi-phiD, TMath::Pi())*TMath::RadToDeg(), - zP/orbitb.z0, zP, xP, yP ); - } - - ///Selection - if( !TMath::IsNaN(zP) && 0< zP/orbitb.z0 && TMath::Max(0, targetLoop-1) < zP/orbitb.z0 && zP/orbitb.z0 < targetLoop ) { - zPossible.push_back(zP); - dID.push_back(i); - } - } - /* - if( zPossible.size() == 0 ){ // will not happen - zHit = TMath::QuietNaN(); - xPos = TMath::QuietNaN(); - yPos = TMath::QuietNaN(); - loop = -1; - detID = -1; - detRowID = -1; - return -1 ; - }*/ - - if( debug ) printf("-----------------------------------\n"); - double dMin = 1; - for( int i = 0; i < (int) zPossible.size(); i++){ - - double dd = abs(zPossible[i]/orbitb.z0 - (targetLoop - (1-inOut))); - - if( debug ) printf(" %d | zP : %8.3f mm; loop : %9.5f ", i, zPossible[i], zPossible[i]/orbitb.z0); - - if( dd < dMin) { - orbitb.z = zPossible[i]; - dMin = dd; - orbitb.effLoop = zPossible[i]/orbitb.z0; - orbitb.loop = TMath::Ceil(orbitb.effLoop); - orbitb.detRowID = (12+dID[i])%4; - orbitb.t = orbitb.t0 * orbitb.effLoop; - - double phiD = TMath::TwoPi()/array.mDet * dID[i] ; - double dphi = orbitb.phi - phiD ; - - if( debug ) { - // Check is in or out - double hitDir = cos( orbitb.z/orbitb.z0 * TMath::TwoPi() - detGeo.BfieldSign * dphi ); - printf(" hitDir : %4.1f ", hitDir); - if( ( inOut == 1 && hitDir > 0 ) || (inOut == 0 && hitDir < 0 ) ) { - printf(" != %f ", array.detPerpDist); - orbitb.z = TMath::QuietNaN(); - orbitb.loop = -1; - orbitb.detRowID = -1; - return - 2; - } - - // this must be false, otherwise, calculation error - double xPos = GetXPos(orbitb.z ) ; - double yPos = GetYPos(orbitb.z ) ; - double a = xPos * cos(phiD) + yPos * sin(phiD); - printf(" a : %f ", a); - if( abs(a - array.detPerpDist) > 0.01) { - printf(" != %f ", array.detPerpDist); - orbitb.z = TMath::QuietNaN(); - orbitb.loop = -1; - orbitb.detRowID = -1; - return -3; - } - } - } - if(debug) printf("\n"); - } - - // calculate x, y, R - orbitb.x = GetXPos(orbitb.z) ; - orbitb.y = GetYPos(orbitb.z) ; - orbitb.R = GetR(orbitb.z); - - return 1; // return 1 when OK -} - -int HELIOS::CalRecoilHit(TLorentzVector PB, int ZB){ - - CalTrajectoryPara(PB, ZB, 1); - - orbitB.z = detGeo.recoilPos; - orbitB.x = GetRecoilXPos(detGeo.recoilPos) ; - orbitB.y = GetRecoilYPos(detGeo.recoilPos) ; - orbitB.R = GetRecoilR(detGeo.recoilPos); - orbitB.effLoop = orbitB.z/orbitB.z0; - orbitB.t = orbitB.t0 * orbitB.effLoop ; - - return 1; -} - -//======================================================= -//####################################################### -// Class for multi-scattering of the beam inside target -// using SRIM to generate stopping power -// input : TLorentzVector, data_files -// output : scattered TLorentzVector -//======================================================= -class TargetScattering{ - -public: - TargetScattering(); - ~TargetScattering(); - - double GetKE0(){return KE0;} - double GetKE() {return KE;} - double GetKELoss() {return KE0-KE;} - double GetDepth() {return depth;} - double GetPathLength() {return length;} - - vector SplitStr(string tempLine, string splitter, int shift = 0); - void LoadStoppingPower(string file); - - void SetTarget(double density, double depth){ - this->density = density; - this->depth = depth; - isTargetSet = true; - //printf("===== Target, density: %f g/cm3, depth: %f um \n", density, depth * 1e+4 ); - } - - TLorentzVector Scattering(TLorentzVector P){ - double mass = P.M(); - KE0 = (P.E() - mass); - KE = KE0; - double theta = P.Theta(); - this->length = TMath::Abs(depth/TMath::Cos(theta)); - //printf("------- theta: %f deg, length: %f um, KE: %f MeV \n", theta * TMath::RadToDeg(), this->length * 1e+4, KE); - - //integrate the energy loss within the depth of A - double dx = length/100.; // in cm - double x = 0; - double densityUse = density; - if( unitID == 0 ) densityUse = 1.; - do{ - //assume the particle will not be stopped - //printf(" x: %f, KE: %f, S: %f \n", x, KE, gA->Eval(KE)); - KE = KE - densityUse * gA->Eval(KE) * 10 * dx ; // factor 10, convert MeV/cm -> MeV/cm - - //angular Straggling, assume (Lateral Straggling)/(Projected range) - - - x = x + dx; - }while(x < length && KE > 0 ); - - //printf(" depth: %f cm = %f um, KE : %f -> %f MeV , dE = %f MeV \n", depth, depth * 1e+4, KE0, KE, KE0 - KE); - double newk = 0; - - TLorentzVector Pnew; - TVector3 vb(0,0,0); - - if( KE < 0 ) { - KE = 0.0; // somehow, when KE == 0 , the program has problem to rotate the 4-vector - }else{ - newk = TMath::Sqrt(TMath::Power(mass+KE,2) - mass * mass); - vb = P.Vect(); - vb.SetMag(newk); - } - Pnew.SetVectM(vb,mass); - - return Pnew; - } - -private: - bool isTargetSet; - double density; // density [mg/cm2] - int unitID; // 0 = MeV /mm or keV/um , 1 = MeV / (ug/cm2) - - double depth; // depth in target [cm] - double length; // total path length in target [cm] - double KE0, KE; - - TGraph * gA; // stopping power of A, b, B, in unit of MeV/(mg/cm2) - TGraph * gB; // projection range [nm] - TGraph * gC; // parallel Straggling [nm] - TGraph * gD; // perpendicular Straggling [nm] - -}; - -TargetScattering::TargetScattering(){ - isTargetSet = false; - density = 1; // mg/cm2 - unitID = 0; - KE0 = 0; - KE = 0; - depth = 0; - length = 0; - gA = NULL; - gB = NULL; - gC = NULL; - gD = NULL; -} - -TargetScattering::~TargetScattering(){ - delete gA; -} - -vector TargetScattering::SplitStr(string tempLine, string splitter, int shift){ - - 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; - } - - string secStr; - if( pos == 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); - } - - if( !secStr.empty() ) output.push_back(secStr); - //printf(" |%s---\n", secStr.c_str()); - - }while(pos != string::npos ); - - return output; -} - -void TargetScattering::LoadStoppingPower(string filename){ - - printf("loading Stopping power: %s.", filename.c_str()); - - ifstream file; - file.open(filename.c_str()); - - vector energy; - vector stopping; - vector projRange; - vector paraStraggling; - vector prepStraggling; - - if( file.is_open() ){ - printf("... OK\n"); - char lineChar[16635]; - string line; - while( !file.eof() ){ - file.getline(lineChar, 16635, '\n'); - line = lineChar; - - size_t found = line.find("Target Density"); - if( found != string::npos ){ - printf(" %s\n", line.c_str()); - } - - found = line.find("Stopping Units ="); - if( found != string::npos){ - printf(" %s\n", line.c_str()); - if( line.find("MeV / mm") != string::npos ) { - unitID = 0; - }else if( line.find("keV / micron") != string::npos ){ - unitID = 0; - }else if( line.find("MeV / (mg/cm2)") != string::npos ) { - unitID = 1; - }else{ - printf("please using MeV/mm, keV/um, or MeV/(mg/cm2) \n"); - } - } - - size_t foundkeV = line.find("keV "); - size_t foundMeV = line.find("MeV "); - size_t foundGeV = line.find("GeV "); - if ( foundkeV != string::npos || foundMeV != string::npos || foundGeV != string::npos ){ - vector haha = SplitStr(line, " "); - //for( int i = 0 ; i < (int) haha.size()-1; i++){ - // printf("%d,%s|", i, haha[i].c_str()); - //} - //printf("\n"); - - found = haha[0].find("keV"); if( found != string::npos ) energy.push_back(atof(haha[0].substr(0, found).c_str()) * 0.001); - found = haha[0].find("MeV"); if( found != string::npos ) energy.push_back(atof(haha[0].substr(0, found).c_str()) * 1.); - found = haha[0].find("GeV"); if( found != string::npos ) energy.push_back(atof(haha[0].substr(0, found).c_str()) * 1000.); - - double a = atof(haha[1].c_str()); - double b = atof(haha[2].c_str()); - stopping.push_back(a+b); - - found = haha[3].find("A") ; if( found != string::npos ) projRange.push_back(atof(haha[3].substr(0, found).c_str()) * 0.1); - found = haha[3].find("um"); if( found != string::npos ) projRange.push_back(atof(haha[3].substr(0, found).c_str()) * 1000.); - found = haha[3].find("mm"); if( found != string::npos ) projRange.push_back(atof(haha[3].substr(0, found).c_str()) * 1e6); - - found = haha[4].find("A") ; if( found != string::npos ) paraStraggling.push_back(atof(haha[4].substr(0, found).c_str()) * 0.1); - found = haha[4].find("um"); if( found != string::npos ) paraStraggling.push_back(atof(haha[4].substr(0, found).c_str()) * 1e3); - found = haha[4].find("mm"); if( found != string::npos ) paraStraggling.push_back(atof(haha[4].substr(0, found).c_str()) * 1e6); - - found = haha[5].find("A") ; if( found != string::npos ) prepStraggling.push_back(atof(haha[5].substr(0, found).c_str()) * 0.1); - found = haha[5].find("um"); if( found != string::npos ) prepStraggling.push_back(atof(haha[5].substr(0, found).c_str()) * 1e3); - found = haha[5].find("mm"); if( found != string::npos ) prepStraggling.push_back(atof(haha[5].substr(0, found).c_str()) * 1e6); - - //printf(" %f, %f, %f, %f, %f \n", energy.back(), stopping.back(), projRange.back(), paraStraggling.back(), prepStraggling.back()); - } - - - } - - }else{ - printf("... fail\n"); - } - - gA = new TGraph(energy.size(), &energy[0], &stopping[0]); - - gB = new TGraph(energy.size(), &energy[0], &projRange[0]); - gC = new TGraph(energy.size(), &energy[0], ¶Straggling[0]); - gD = new TGraph(energy.size(), &energy[0], &prepStraggling[0]); - -} -//======================================================= -//####################################################### -// Class for Particle Decay -// B --> d + D -// input : TLorentzVector, emitting particle -// output : scattered TLorentzVector -//======================================================= -class Decay{ -public: - Decay(); - ~Decay(); - - double GetQValue() { return Q;} - - double GetAngleChange(){ - TVector3 vD = PD.Vect(); - TVector3 vB = PB.Vect(); - vD.SetMag(1); - vB.SetMag(1); - double dot = vD.Dot(vB); - return TMath::ACos(dot)*TMath::RadToDeg() ; - } - - double GetThetaCM() { return theta * TMath::RadToDeg();} - - double GetCMMomentum(){ return k;} - TLorentzVector GetDaugther_d() {return Pd;} - TLorentzVector GetDaugther_D() {return PD;} - - void SetMotherDaugther(int AB, int zB, int AD, int zD){ - Isotope Mother(AB, zB); - Isotope Daugther_D(AD, zD); - Isotope Daugther_d(AB-AD, zB-zD); - - mB = Mother.Mass; - mD = Daugther_D.Mass; - md = Daugther_d.Mass; - - double Q = mB - mD - md; - - printf("====== decay mode : %s --> %s + %s, Q = %.3f MeV \n", Mother.Name.c_str(), Daugther_d.Name.c_str(), Daugther_D.Name.c_str(), Q); - - isMotherSet = true; - } - - int CalDecay(TLorentzVector P_mother, double ExB, double ExD, double normOfReactionPlane = 0){ - if( !isMotherSet ) { - return -1; - } - this->PB = P_mother; - - double MB = mB + ExB; ///mother - double MD = mD + ExD; ///Big_Daugther - Q = MB - MD - md; - if( Q < 0 ) { - this->PD = this->PB; - dTheta = TMath::QuietNaN(); - k = TMath::QuietNaN(); - return -2; - } - - //clear - TLorentzVector temp(0,0,0,0); - PD = temp; - Pd = temp; - - k = TMath::Sqrt((MB+MD+md)*(MB+MD-md)*(MB-MD+md)*(MB-MD-md))/2./MB; - - //in mother's frame, assume isotropic decay - theta = TMath::ACos(2 * gRandom->Rndm() - 1) ; - - //for non isotropic decay, edit f1. - //theta = TMath::ACos(f1->GetRandom()); - - double phi = TMath::TwoPi() * gRandom->Rndm(); - PD.SetE(TMath::Sqrt(mD * mD + k * k )); - PD.SetPz(k); - PD.SetTheta(theta); - PD.SetPhi(phi); - - Pd.SetE(TMath::Sqrt(md * md + k * k )); - Pd.SetPz(k); - Pd.SetTheta(theta + TMath::Pi()); - Pd.SetPhi(phi + TMath::Pi()); - - PD.RotateY(TMath::Pi()/2.); - PD.RotateZ(normOfReactionPlane); - - Pd.RotateY(TMath::Pi()/2.); - Pd.RotateZ(normOfReactionPlane); - - //Transform to Lab frame; - TVector3 boost = PB.BoostVector(); - - PD.Boost(boost); - Pd.Boost(boost); - - return 1; - } - -private: - TLorentzVector PB, Pd, PD; - - double mB, mD, md; - double theta; - - TF1 * f1; - - bool isMotherSet; - double Q; - double k; // momentum in B-frame - double dTheta; // change of angle -}; - -Decay::Decay(){ - TLorentzVector temp(0,0,0,0); - PB = temp; - Pd = temp; - PD = temp; - - mB = TMath::QuietNaN(); - mD = TMath::QuietNaN(); - md = TMath::QuietNaN(); - theta = TMath::QuietNaN(); - - k = TMath::QuietNaN(); - - Q = TMath::QuietNaN(); - dTheta = TMath::QuietNaN(); - isMotherSet = false; - - f1 = new TF1("f1", "(1+ROOT::Math::legendre(2,x))/2.", -1, 1); -} - -Decay::~Decay(){ - delete f1; -} - -//======================================================= -//####################################################### -// Class for Knockout Reaction -// A(a,12)B, A = B + b, a->1, b->2 -// incident particle is A -// the calculation: 1) go to A's rest frame -// 2) calculate the b = A - B -// 3) go to CM frame -//======================================================= -class Knockout{ -public: - Knockout(); - ~Knockout(); - - void SetA(int A, int Z){ - Isotope temp(A,Z); - mA = temp.Mass; - AA = A; - ZA = Z; - nameA = temp.Name; - } - - void SetExA(double Ex){ - this->ExA = Ex; - } - - void Seta(int A, int Z){ - Isotope temp(A,Z); - ma = temp.Mass; - Aa = A; - Za = Z; - m1 = ma; - A1 = A; - Z1 = Z; - namea = temp.Name; - name1 = temp.Name; - } - - void Set2(int A, int Z){ - Isotope temp(A,Z); - m2 = temp.Mass; - A2 = A; - Z2 = Z; - name2 = temp.Name; - - AB = AA + Aa - A1 - A2; - ZB = ZA + Za - Z1 - Z2; - Isotope temp2(AB,ZB); - mB0 = temp2.Mass; - nameB = temp2.Name; - - } - - void SetBSpk(double S, double kb, double thetab, double phib){ - this->S = S; - AB = AA + Aa - A1 - A2; - ZB = ZA + Za - Z1 - Z2; - Isotope temp(AB,ZB); - mB0 = temp.Mass; - nameB = temp.Name; - this->kb = kb; - this->thetab = thetab; - this->phib = phib; - - mB = mA + ExA - m2 + S; - - ExB = mB - mB0; - - if( ExB < 0 && !isOverRideExNegative ){ - printf(" seperation energy is too small. \n"); - } - } - - void OverRideExNegative(bool YN){ - isOverRideExNegative = YN; - } - - TString GetReactionName(){ - TString rName; - - TString normInv; - if( isNormalKinematics ){ - normInv = "Normal Kinematics"; - }else{ - normInv = "Inverse Kinematics"; - } - - rName.Form("%s(%s,%s%s)%s, %s", nameA.c_str(), namea.c_str(), name1.c_str(), name2.c_str(), nameB.c_str(), normInv.Data()); - - return rName; - } - - void SetIncidentEnergyAngle(double KEA, double theta, double phi){ - this->KEA = KEA; - this->thetaIN = theta; - this->phiIN = phi; - } - - void CalIncidentChannel(bool isNormalKinematics); - void CalReactionConstant(bool isNormalKinematics); - void Event(double thetaCM, double phCM); - - double GetMass_A(){return mA;} - double GetMass_a(){return ma;} - double GetMass_b(){return mb;} - double GetMass_B(){return mB;} - double GetMass_Bgs(){return mB0;} - double GetMass_1(){return m1;} - double GetMass_2(){return m2;} - - TLorentzVector GetPA(){return PA;} - TLorentzVector GetPa(){return Pa;} - TLorentzVector GetPb(){return Pb;} - TLorentzVector GetPB(){return PB;} - TLorentzVector GetP1(){return P1;} - TLorentzVector GetP2(){return P2;} - - double GetMomentumbNN(){return p;} - double GetReactionBeta(){return beta;} - double GetReactionGamma(){return gamma;} - double GetNNTotalEnergy(){return Etot;} - - double GetNNTotalKE() {return Etot - mb - ma;} - double GetQValue() {return mA + ExA - m2 - mB;} - double GetMaxExB() {return Etot - mb - mB0;} - -private: - int AA, Aa, A1, A2, AB; - int ZA, Za, Z1, Z2, ZB; - double mA, ma, m1, m2, mB, mB0, mb; - string nameA, namea, name1, name2, nameB; - - double S; // separation energy - double kb; // momentum of b - double thetab, phib;// direction of b - - TLorentzVector PA, Pa, P1, P2, PB, Pb; // lab - - double KEA, thetaIN, phiIN; - double T; - - double k, beta, gamma, Etot, p; // reaction constant, in NN frame - double ExA, ExB; - - bool isNormalKinematics; - bool isOverRideExNegative; - -}; - -Knockout::Knockout(){ - TLorentzVector temp(0,0,0,0); - - PA = temp; - Pa = temp; - P1 = temp; - P2 = temp; - PB = temp; - Pb = temp; - - SetA(12,6); - Seta(1,1); - Set2(1,1); - - SetBSpk(1000, 0, 0, 0); - SetIncidentEnergyAngle(10, 0, 0); - - ExA = 0; - - isNormalKinematics = false; - isOverRideExNegative = false; -} - -Knockout::~Knockout(){ - -} - -void Knockout::CalIncidentChannel(bool isNormalKinematics){ - if( ExB < 0 && !isOverRideExNegative) return; - - this->isNormalKinematics = isNormalKinematics; - - if(!isNormalKinematics){ - //===== construct Lab frame 4-momentum - this->T = KEA * AA; - double kA = TMath::Sqrt(TMath::Power(mA + ExA + T, 2) - (mA + ExA) * (mA + ExA)); - PA.SetXYZM(0, 0, kA, mA + ExA); - PA.RotateY(thetaIN); - PA.RotateZ(phiIN); - - Pa.SetXYZM(0,0,0,ma); - - }else{ - //===== construct 4-momentum - this->T = KEA * Aa; - double ka = TMath::Sqrt(TMath::Power(ma + T, 2) - (ma) * (ma)); - Pa.SetXYZM(0, 0, ka, ma); - Pa.RotateY(thetaIN); - Pa.RotateZ(phiIN); - - PA.SetXYZM(0, 0, 0, mA + ExA); - } - -} - -void Knockout::CalReactionConstant(bool isNormalKinematics){ - if( ExB < 0 && !isOverRideExNegative) return; - - this->isNormalKinematics = isNormalKinematics; - - CalIncidentChannel(isNormalKinematics); - - if(!isNormalKinematics){ - - //===== change to A's rest frame - TVector3 bA = PA.BoostVector(); - PA.Boost(-bA); - - //===== constructe bounded nucleus b - PB.SetXYZM(0, 0, -kb, mB); - PB.RotateY(thetab); - PB.RotateZ(phib); - - Pb = PA - PB; - mb = Pb.M(); - - //===== change to Lab frame - Pb.Boost(bA); - PA.Boost(bA); - PB.Boost(bA); - - }else{ - - //===== constructe bounded nucleus b - PB.SetXYZM(0, 0, -kb, mB); - PB.RotateY(thetab); - PB.RotateZ(phib); - - Pb = PA - PB; - mb = Pb.M(); - - } - - //====== reaction constant - k = (Pa+Pb).P(); - double E = (Pa+Pb).E(); - beta = (Pa+Pb).Beta(); - gamma = 1 / TMath::Sqrt(1- beta * beta); - Etot = TMath::Sqrt(TMath::Power(E,2) - k * k); - p = TMath::Sqrt( (Etot*Etot - TMath::Power(m1 + m2,2)) * (Etot*Etot - TMath::Power(m1 - m2 ,2)) ) / 2 / Etot; - - //if( TMath::IsNaN(p) ){ - // printf(" Mc: %f, m1+m2: %f, kb:%f, thetab:%f, phib:%f\n", Etot, m1+m2, kb, thetab, phib); - //} - -} - -void Knockout::Event(double thetaCM, double phiCM){ - if( ExB < 0 && !isOverRideExNegative ) return; - - //===== construct Pcm - TLorentzVector Pc = Pb + Pa; - TVector3 bc = Pc.BoostVector(); - - TLorentzVector Pac = Pa; - Pac.Boost(-bc); - TVector3 va = Pac.Vect(); - - TLorentzVector Pbc = Pb; - Pbc.Boost(-bc); - TVector3 vb = Pbc.Vect(); - - //--- from P1 - TVector3 v1 = va; - v1.SetMag(p); - - TVector3 u1 = va.Orthogonal(); - v1.Rotate(thetaCM, u1); - v1.Rotate(phiCM + TMath::PiOver2(), va); // somehow, the calculation turn the vector 90 degree. - - TLorentzVector P1c; - P1c.SetVectM(v1, m1); - - //--- from P2 - TLorentzVector P2c; - P2c.SetVectM(-v1, m2); - - //---- to Lab Frame - P1 = P1c; - P1.Boost(bc); - P2 = P2c; - P2.Boost(bc); - -} - - -#endif diff --git a/Cleopatra/InFileCreator.h b/Cleopatra/InFileCreator.h index 3c7473f..68571a7 100644 --- a/Cleopatra/InFileCreator.h +++ b/Cleopatra/InFileCreator.h @@ -26,9 +26,9 @@ #include /* atof */ #include -#include "../Cleopatra/Isotope.h" // for geting Z +#include "../Cleopatra/ClassIsotope.h" // for geting Z #include "potentials.h" -#include "../armory/AnalysisLib.h" +#include "../Armory/AnalysisLib.h" using namespace std; diff --git a/Cleopatra/Isotope.C b/Cleopatra/Isotope.C index 4cdf4e8..d100516 100644 --- a/Cleopatra/Isotope.C +++ b/Cleopatra/Isotope.C @@ -14,7 +14,7 @@ #include #include -#include "Isotope.h" +#include "ClassIsotope.h" using namespace std; diff --git a/Cleopatra/IsotopeShort.C b/Cleopatra/IsotopeShort.C index cccd289..d859fca 100644 --- a/Cleopatra/IsotopeShort.C +++ b/Cleopatra/IsotopeShort.C @@ -15,7 +15,7 @@ #include #include -#include "Isotope.h" +#include "ClassIsotope.h" using namespace std; diff --git a/Cleopatra/Transfer.h b/Cleopatra/Transfer.h index 41fef91..1a41fcd 100644 --- a/Cleopatra/Transfer.h +++ b/Cleopatra/Transfer.h @@ -13,7 +13,11 @@ #include #include -#include "HELIOS_LIB.h" +#include "../Armory/ClassDetGeo.h" +#include "ClassTargetScattering.h" +#include "ClassDecay.h" +#include "ClassTransfer.h" +#include "ClassHelios.h" double exDistFunc(Double_t *x, Double_t * par){ return par[(int) x[0]]; @@ -37,9 +41,9 @@ void Transfer( printf("----- loading reaction setting from %s. \n", basicConfig.c_str()); printf("\e[32m#################################### Beam \e[0m\n"); - const AnalysisLib::ReactionConfig reactionConfig = reaction.GetRectionConfig(); + const ReactionConfig reactionConfig = reaction.GetRectionConfig(); - AnalysisLib::PrintReactionConfig(reactionConfig); + reactionConfig.PrintReactionConfig(); vector ExAList = reactionConfig.beamEx; int nExA = (int) ExAList.size(); @@ -49,7 +53,7 @@ void Transfer( HELIOS helios; helios.SetDetectorGeometry(heliosDetGeoFile); - const AnalysisLib::DetGeo detGeo = helios.GetDetectorGeometry(); + const DetGeo detGeo = helios.GetDetectorGeometry(); printf("==================================== E-Z plot slope\n"); double betaRect = reaction.GetReactionBeta() ; @@ -537,9 +541,9 @@ void Transfer( double phiCM = TMath::TwoPi() * gRandom->Rndm(); //==== Calculate reaction - TLorentzVector * output = reaction.Event(thetaCM, phiCM); - TLorentzVector Pb = output[2]; - TLorentzVector PB = output[3]; + reaction.Event(thetaCM, phiCM); + TLorentzVector Pb = reaction.GetPb(); + TLorentzVector PB = reaction.GetPB(); //==== Calculate energy loss of scattered and recoil in target if( isTargetScattering ){ @@ -646,9 +650,9 @@ void Transfer( rhoRecoil2 = helios.GetRecoilR(detGeo.recoilPos2); } - reaction.CalExThetaCM(e, z, helios.GetBField(), helios.GetDetRadius()); - ExCal = reaction.GetEx(); - thetaCMCal = reaction.GetThetaCM(); + std::pair ExThetaCM = reaction.CalExThetaCM(e, z, helios.GetBField(), helios.GetDetRadius()); + ExCal = ExThetaCM.first; + thetaCMCal = ExThetaCM.second; //change thetaCM into deg thetaCM = thetaCM * TMath::RadToDeg(); diff --git a/Cleopatra/makefile b/Cleopatra/makefile index a840113..0435ddb 100644 --- a/Cleopatra/makefile +++ b/Cleopatra/makefile @@ -4,10 +4,7 @@ ALL = Isotope InFileCreator ExtractXSec ExtractXSecFromText PlotTGraphTObjArray all: $(ALL) -#Cleopatra: Cleopatra.C ../Simulation/Isotope.h ../Simulation/constant.h potentials.h InFileCreator.h ExtractXSec.h PlotTGraphTObjArray.h -# $(CC) Cleopatra.C -o Cleopatra `root-config --cflags --glibs` - -InFileCreator: InFileCreator.C InFileCreator.h ../Cleopatra/Isotope.h ../Cleopatra/constant.h potentials.h +InFileCreator: InFileCreator.C InFileCreator.h ../Cleopatra/ClassIsotope.h ../Cleopatra/constant.h potentials.h $(CC) InFileCreator.C -o InFileCreator `root-config --cflags --glibs` ExtractXSec: ExtractXSec.C ExtractXSec.h @@ -19,19 +16,19 @@ ExtractXSecFromText: ExtractXSecFromText.C ExtractXSec.h PlotTGraphTObjArray: PlotTGraphTObjArray.C PlotTGraphTObjArray.h $(CC) PlotTGraphTObjArray.C -o PlotTGraphTObjArray `root-config --cflags --glibs` -FindThetaCM: FindThetaCM.C FindThetaCM.h ../Cleopatra/HELIOS_LIB.h ../Cleopatra/Isotope.h ../Cleopatra/constant.h +FindThetaCM: FindThetaCM.C FindThetaCM.h ../Cleopatra/ClassHelios.h ../Cleopatra/ClassIsotope.h ../Cleopatra/constant.h $(CC) FindThetaCM.C -o FindThetaCM `root-config --cflags --glibs` -Transfer: Transfer.C Transfer.h ../Cleopatra/HELIOS_LIB.h ../Cleopatra/Isotope.h ../Cleopatra/constant.h +Transfer: Transfer.C Transfer.h ../Cleopatra/ClassHelios.h ../Cleopatra/ClassIsotope.h ../Cleopatra/constant.h $(CC) Transfer.C -o Transfer `root-config --cflags --glibs` PlotSimulation: PlotSimulation.C Check_Simulation.C $(CC) PlotSimulation.C -o PlotSimulation `root-config --cflags --glibs` -Isotope: ../Cleopatra/Isotope.h ../Cleopatra/Isotope.C +Isotope: ../Cleopatra/ClassIsotope.h ../Cleopatra/Isotope.C $(CC) Isotope.C -o Isotope -IsotopeShort: ../Cleopatra/Isotope.h ../Cleopatra/IsotopeShort.C +IsotopeShort: ../Cleopatra/ClassIsotope.h ../Cleopatra/IsotopeShort.C $(CC) IsotopeShort.C -o IsotopeShort clean: diff --git a/Cleopatra/transfer_test.C b/Cleopatra/transfer_test.C deleted file mode 100644 index 50f88a3..0000000 --- a/Cleopatra/transfer_test.C +++ /dev/null @@ -1,77 +0,0 @@ -#include "HELIOS_LIB.h" -#include "TROOT.h" -#include "TBenchmark.h" -#include "TLorentzVector.h" -#include "TMath.h" -#include "TFile.h" -#include "TF1.h" -#include "TTree.h" -#include "TRandom.h" -#include "TGraph.h" -#include "TMacro.h" -#include -#include -#include -#include - -void transfer_test(double t, double p, double bField, bool fromOutSide){ - - TransferReaction reaction; - reaction.SetA(14, 6); - reaction.Seta( 2, 1); - reaction.Setb( 1, 1); - reaction.SetB(15, 6); - - reaction.SetExB(0); - - reaction.SetIncidentEnergyAngle(10, 0, 0); - reaction.CalReactionConstant(); - - HELIOS helios; - helios.SetDetectorGeometry("../working/detectorGeo.txt"); - helios.OverrideMagneticField(bField); - helios.SetDetectorOutside(fromOutSide); - - double beta = reaction.GetReactionBeta() ; - - double slope = 299.792458 * abs(helios.GetBField()) / TMath::TwoPi() * beta / 1000.; // MeV/mm - - double alpha = slope / beta; - - printf("===================================\n"); - printf("Mass A : %8.2f MeV/c2\n", reaction.GetMass_A()); - printf("Mass a : %8.2f MeV/c2\n", reaction.GetMass_a()); - printf("Mass b : %8.2f MeV/c2\n", reaction.GetMass_b()); - printf("Mass B : %8.2f MeV/c2\n", reaction.GetMass_B()); - printf("CM Mass : %8.2f MeV\n", reaction.GetCMTotalEnergy()); - printf("CM beta : %8.6f \n", beta); - printf("slope : %8.6f MeV\n", alpha * beta); - printf("alpha : %8.6f MeV\n", alpha); - - - double thetaCM = t * TMath::DegToRad(); - double phiCM = - p * TMath::DegToRad(); - - TLorentzVector * output = reaction.Event(thetaCM, phiCM); - TLorentzVector Pb = output[2]; - TLorentzVector PB = output[3]; - - Pb.Print(); - PB.Print(); - - helios.CalArrayHit(Pb, 1); - helios.CalRecoilHit(PB, 6); - - printf("+++++++++++++++++++++++++++++++++++++\n"); - - int hitID = 2; - while( hitID > 1 ){ - printf("==================== check accp.\n"); - hitID = helios.DetAcceptance(); - printf("-------------------- hitID %d\n", hitID); - } - - PrintTrajectory(helios.GetTrajectory_b()); - - -} diff --git a/armory/AnalysisLib.h b/armory/AnalysisLib.h index 6fdef81..4ff335c 100644 --- a/armory/AnalysisLib.h +++ b/armory/AnalysisLib.h @@ -49,640 +49,6 @@ std::vector SplitStr(std::string tempLine, std::string splitter, in return output; }; -struct Array{ - - double detPerpDist; /// distance from axis - double detWidth; /// width - double detLength; /// length - double blocker; - double firstPos; /// meter - double eSigma; /// intrinsic energy resolution MeV - double zSigma; /// intrinsic position resolution mm - bool detFaceOut; ///detector_facing_Out_or_In - std::vector pos; /// near position in meter - int nDet, mDet; /// nDet = number of different pos, mDet, number of same pos - std::vector detPos; ///absolute position of detector - - double zMin, zMax; - - void DeduceAbsolutePos(){ - nDet = pos.size(); - detPos.clear(); - - for(int id = 0; id < nDet; id++){ - if( firstPos > 0 ) detPos.push_back(firstPos + pos[id]); - if( firstPos < 0 ) detPos.push_back(firstPos - pos[nDet - 1 - id]); - ///printf("%d | %f, %f \n", id, pos[id], detPos[id]); - } - - zMin = TMath::Min(detPos.front(), detPos.back()) - (firstPos < 0 ? detLength : 0); - zMax = TMath::Max(detPos.front(), detPos.back()) + (firstPos > 0 ? detLength : 0); - } - - void PrintArray(){ - for(int i = 0; i < nDet ; i++){ - if( firstPos > 0 ){ - printf("%d, %8.2f mm - %8.2f mm \n", i, detPos[i], detPos[i] + detLength); - }else{ - printf("%d, %8.2f mm - %8.2f mm \n", i, detPos[i] - detLength , detPos[i]); - } - } - - printf(" Blocker Position: %8.2f mm \n", firstPos > 0 ? firstPos - blocker : firstPos + blocker ); - printf(" First Position: %8.2f mm \n", firstPos); - printf(" number of det : %d x %d \n", mDet, nDet); - printf(" detector facing : %s\n", detFaceOut ? "Out" : "In"); - printf(" energy resol.: %f MeV\n", eSigma); - printf(" pos-Z resol.: %f mm \n", zSigma); - } - -}; - -struct DetGeo{ - - double Bfield; /// T - int BfieldSign ; /// sign of B-field - double BfieldTheta; /// rad, 0 = z-axis, pi/2 = y axis, pi = -z axis - double bore; /// bore , mm - - double recoilPos; /// recoil, downstream - double recoilInnerRadius; /// radius recoil inner - double recoilOuterRadius; /// radius recoil outter - - double recoilPos1, recoilPos2; /// imaginary recoils - - double elumPos1, elumPos2; /// imaginary elum, only sensitive to light recoil - - //===================1st array - Array array1; - - //==================2nd array - bool use2ndArray; - Array array2; - - double zMin, zMax; /// range of detectors - bool isCoincidentWithRecoil; - -}; - -struct ReactionConfig{ - - int beamA; - int beamZ; - int targetA; - int targetZ; - int recoilLightA; - int recoilLightZ; - int recoilHeavyA; - int recoilHeavyZ; - float beamEnergy; ///MeV/u - float beamEnergySigma; ///beam-energy_sigma_in_MeV/u - float beamAngle; ///beam-angle_in_mrad - float beamAngleSigma; ///beam-emittance_in_mrad - float beamX; ///x_offset_of_Beam_in_mm - float beamY; ///y_offset_of_Beam_in_mm - int numEvents; ///number_of_Event_being_generated - bool isTargetScattering; ///isTargetScattering - float targetDensity; ///target_density_in_g/cm3 - float targetThickness; ///targetThickness_in_cm - std::string beamStoppingPowerFile; ///stopping_power_for_beam - std::string recoilLightStoppingPowerFile; ///stopping_power_for_light_recoil - std::string recoilHeavyStoppingPowerFile; ///stopping_power_for_heavy_recoil - bool isDecay; ///isDacay - int heavyDecayA; ///decayNucleus_A - int heavyDecayZ; ///decayNucleus_Z - bool isRedo; ///isReDo - std::vector beamEx; ///excitation_energy_of_A[MeV] - -}; - -///Using TMacro to load the detectorGeo frist, -///this indrect method is good for loading detectorGeo from TMacro in root file -DetGeo LoadDetectorGeo(TMacro * macro){ - - DetGeo detGeo; - - if( macro == NULL ) return detGeo; - - TList * haha = macro->GetListOfLines(); - int numLine = (haha)->GetSize(); - - detGeo.array1.pos.clear(); - detGeo.array2.pos.clear(); - detGeo.use2ndArray = false; - - int detFlag = 0; - int detLine = 0; - - for( int i = 0 ; i < numLine; i++){ - - std::vector str = SplitStr(macro->GetListOfLines()->At(i)->GetName(), " "); - - //printf("%3d | %s\n", i, str[0].c_str()); - - if( str[0].find("####") != std::string::npos ) break; - if( str[0].find("#===") != std::string::npos ) { - detFlag ++; - detLine = 0; - continue;; - } - - if( detFlag == 0 ){ - if ( i == 0 ) { - detGeo.Bfield = atof(str[0].c_str()); - detGeo.BfieldSign = detGeo.Bfield > 0 ? 1: -1; - } - if ( i == 1 ) detGeo.BfieldTheta = atof(str[0].c_str()); - if ( i == 2 ) detGeo.bore = atof(str[0].c_str()); - if ( i == 3 ) detGeo.recoilPos = atof(str[0].c_str()); - if ( i == 4 ) detGeo.recoilInnerRadius = atof(str[0].c_str()); - if ( i == 5 ) detGeo.recoilOuterRadius = atof(str[0].c_str()); - if ( i == 6 ) detGeo.isCoincidentWithRecoil = str[0] == "false" ? false: true; - if ( i == 7 ) detGeo.recoilPos1 = atof(str[0].c_str()); - if ( i == 8 ) detGeo.recoilPos2 = atof(str[0].c_str()); - if ( i == 9 ) detGeo.elumPos1 = atof(str[0].c_str()); - if ( i == 10 ) detGeo.elumPos2 = atof(str[0].c_str()); - } - - if( detFlag == 1){ - if ( detLine == 0 ) detGeo.array1.detPerpDist = atof(str[0].c_str()); - if ( detLine == 1 ) detGeo.array1.detWidth = atof(str[0].c_str()); - if ( detLine == 2 ) detGeo.array1.detLength = atof(str[0].c_str()); - if ( detLine == 3 ) detGeo.array1.blocker = atof(str[0].c_str()); - if ( detLine == 4 ) detGeo.array1.firstPos = atof(str[0].c_str()); - if ( detLine == 5 ) detGeo.array1.eSigma = atof(str[0].c_str()); - if ( detLine == 6 ) detGeo.array1.zSigma = atof(str[0].c_str()); - if ( detLine == 7 ) detGeo.array1.detFaceOut = str[0] == "Out" ? true : false; - if ( detLine == 8 ) detGeo.array1.mDet = atoi(str[0].c_str()); - if ( detLine >= 9 ) (detGeo.array1.pos).push_back(atof(str[0].c_str())); - detLine ++; - } - - if( detFlag == 2){ - if ( detLine == 0 ) detGeo.use2ndArray = str[0] == "true" ? true : false; - if ( detLine == 1 ) detGeo.array2.detPerpDist = atof(str[0].c_str()); - if ( detLine == 2 ) detGeo.array2.detWidth = atof(str[0].c_str()); - if ( detLine == 3 ) detGeo.array2.detLength = atof(str[0].c_str()); - if ( detLine == 4 ) detGeo.array2.blocker = atof(str[0].c_str()); - if ( detLine == 5 ) detGeo.array2.firstPos = atof(str[0].c_str()); - if ( detLine == 6 ) detGeo.array2.eSigma = atof(str[0].c_str()); - if ( detLine == 7 ) detGeo.array2.zSigma = atof(str[0].c_str()); - if ( detLine == 8 ) detGeo.array2.detFaceOut = str[0] == "Out" ? true : false; - if ( detLine == 9 ) detGeo.array2.mDet = atoi(str[0].c_str()); - if ( detLine >= 10 ) (detGeo.array2.pos).push_back(atof(str[0].c_str())); - detLine ++; - } - - } - - detGeo.array1.DeduceAbsolutePos(); - - detGeo.zMin = detGeo.array1.zMin; - detGeo.zMax = detGeo.array1.zMax; - - if( detGeo.use2ndArray) { - detGeo.array2.DeduceAbsolutePos(); - - detGeo.zMin = TMath::Min(detGeo.array1.zMin, detGeo.array2.zMin); - detGeo.zMax = TMath::Min(detGeo.array1.zMax, detGeo.array2.zMax); - } - - return detGeo; -} - -void PrintDetGeo(DetGeo detGeo, bool printAll = true){ - - printf("=====================================================\n"); - printf(" B-field: %8.2f T, Theta : %6.2f deg \n", detGeo.Bfield, detGeo.BfieldTheta); - if( detGeo.BfieldTheta != 0.0 ) { - printf(" +---- field angle != 0 is not supported!!! \n"); - } - printf(" Recoil detector pos: %8.2f mm, radius: %6.2f - %6.2f mm \n", detGeo.recoilPos, detGeo.recoilInnerRadius, detGeo.recoilOuterRadius); - if( printAll ){ - printf("------------------------------------- Detector Position \n"); - detGeo.array1.PrintArray(); - - if( detGeo.use2ndArray){ - printf("--------------------------------- 2nd Detector Position \n"); - detGeo.array2.PrintArray(); - } - }else{ - if( detGeo.use2ndArray){ - printf("--------------------------------- 2nd Detector Position \n"); - detGeo.array2.PrintArray(); - }else{ - printf("------------------------------------- Detector Position \n"); - detGeo.array1.PrintArray(); - } - } - - if( detGeo.elumPos1 != 0 || detGeo.elumPos2 != 0 || detGeo.recoilPos1 != 0 || detGeo.recoilPos2 != 0){ - printf("=================================== Auxillary/Imaginary Detectors\n"); - } - if( detGeo.elumPos1 != 0 ) printf(" Elum 1 pos.: %f mm \n", detGeo.elumPos1); - if( detGeo.elumPos2 != 0 ) printf(" Elum 2 pos.: %f mm \n", detGeo.elumPos2); - if( detGeo.recoilPos1 != 0 ) printf(" Recoil 1 pos.: %f mm \n", detGeo.recoilPos1); - if( detGeo.recoilPos2 != 0 ) printf(" Recoil 2 pos.: %f mm \n", detGeo.recoilPos2); - printf("=====================================================\n"); - -} - -ReactionConfig LoadReactionConfig(TMacro * macro){ - - ReactionConfig reaction; - - if( macro == NULL ) return reaction; - - int numLine = macro->GetListOfLines()->GetSize(); - - for( int i = 0; i < numLine; i ++){ - - std::vector str = SplitStr(macro->GetListOfLines()->At(i)->GetName(), " "); - - ///printf("%d | %s\n", i, str[0].c_str()); - - if( str[0].find_first_of("#") == 0 ) break; - - if( i == 0 ) reaction.beamA = atoi(str[0].c_str()); - if( i == 1 ) reaction.beamZ = atoi(str[0].c_str()); - if( i == 2 ) reaction.targetA = atoi(str[0].c_str()); - if( i == 3 ) reaction.targetZ = atoi(str[0].c_str()); - if( i == 4 ) reaction.recoilLightA = atoi(str[0].c_str()); - if( i == 5 ) reaction.recoilLightZ = atoi(str[0].c_str()); - if( i == 6 ) reaction.beamEnergy = atof(str[0].c_str()); - if( i == 7 ) reaction.beamEnergySigma = atof(str[0].c_str()); - if( i == 8 ) reaction.beamAngle = atof(str[0].c_str()); - if( i == 9 ) reaction.beamAngleSigma = atof(str[0].c_str()); - if( i == 10 ) reaction.beamX = atof(str[0].c_str()); - if( i == 11 ) reaction.beamY = atof(str[0].c_str()); - if( i == 12 ) reaction.numEvents = atoi(str[0].c_str()); - if( i == 13 ) { - if( str[0].compare("false") == 0 ) reaction.isTargetScattering = false; - if( str[0].compare("true") == 0 ) reaction.isTargetScattering = true; - } - if( i == 14 ) reaction.targetDensity = atof(str[0].c_str()); - if( i == 15 ) reaction.targetThickness = atof(str[0].c_str()); - if( i == 16 ) reaction.beamStoppingPowerFile = str[0]; - if( i == 17 ) reaction.recoilLightStoppingPowerFile = str[0]; - if( i == 18 ) reaction.recoilHeavyStoppingPowerFile = str[0]; - if( i == 19 ) { - if( str[0].compare("false") == 0 ) reaction.isDecay = false; - if( str[0].compare("true") == 0 ) reaction.isDecay = true; - } - if( i == 20 ) reaction.heavyDecayA = atoi(str[0].c_str()); - if( i == 21 ) reaction.heavyDecayZ = atoi(str[0].c_str()); - if( i == 22 ) { - if( str[0].compare("false") == 0 ) reaction.isRedo = false; - if( str[0].compare("true" ) == 0 ) reaction.isRedo = true; - } - - if( i >= 23) { - reaction.beamEx.push_back( atof(str[0].c_str()) ); - } - } - - reaction.recoilHeavyA = reaction.beamA + reaction.targetA - reaction.recoilLightA; - reaction.recoilHeavyZ = reaction.beamZ + reaction.targetZ - reaction.recoilLightZ; - - return reaction; - -} - -void PrintReactionConfig(ReactionConfig reaction){ - - printf("=====================================================\n"); - printf(" beam : A = %3d, Z = %2d \n", reaction.beamA, reaction.beamZ); - printf(" target : A = %3d, Z = %2d \n", reaction.targetA, reaction.targetZ); - printf(" light : A = %3d, Z = %2d \n", reaction.recoilLightA, reaction.recoilLightZ); - - printf(" beam Energy : %.2f +- %.2f MeV/u, dE/E = %5.2f %%\n", reaction.beamEnergy, reaction.beamEnergySigma, reaction.beamEnergySigma/reaction.beamEnergy); - printf(" Angle : %.2f +- %.2f mrad\n", reaction.beamAngle, reaction.beamAngleSigma); - printf(" offset : (x,y) = (%.2f, %.2f) mmm \n", reaction.beamX, reaction.beamY); - - printf("##### number of Simulation Events : %d \n", reaction.numEvents); - - printf(" is target scattering : %s \n", reaction.isTargetScattering ? "Yes" : "No"); - - if(reaction.isTargetScattering){ - printf(" target density : %.f g/cm3\n", reaction.targetDensity); - printf(" thickness : %.f cm\n", reaction.targetThickness); - printf(" beam stopping file : %s \n", reaction.beamStoppingPowerFile.c_str()); - printf(" recoil light stopping file : %s \n", reaction.recoilLightStoppingPowerFile.c_str()); - printf(" recoil heavy stopping file : %s \n", reaction.recoilHeavyStoppingPowerFile.c_str()); - } - - printf(" is simulate decay : %s \n", reaction.isDecay ? "Yes" : "No"); - if( reaction.isDecay ){ - printf(" heavy decay : A = %d, Z = %d \n", reaction.heavyDecayA, reaction.heavyDecayZ); - } - printf(" is Redo until hit array : %s \n", reaction.isRedo ? "Yes" : "No"); - - printf(" beam Ex : %.2f MeV \n", reaction.beamEx[0]); - for( int i = 1; i < (int) reaction.beamEx.size(); i++){ - printf(" %.2f MeV \n", reaction.beamEx[i]); - } - - printf("=====================================================\n"); - -} - -DetGeo detGeo; -ReactionConfig reactionConfig1; -ReactionConfig reactionConfig2; - -void LoadDetGeoAndReactionConfigFile(std::string detGeoFileName = "detectorGeo.txt", - std::string reactionConfigFileName1 = "reactionConfig1.txt", - std::string reactionConfigFileName2 = "reactionConfig2.txt"){ - printf("=====================================================\n"); - printf(" loading detector geometery : %s.", detGeoFileName.c_str()); - TMacro * haha = new TMacro(); - if( haha->ReadFile(detGeoFileName.c_str()) > 0 ) { - detGeo = AnalysisLib::LoadDetectorGeo(haha); - printf("... done.\n"); - AnalysisLib::PrintDetGeo(detGeo); - }else{ - printf("... fail\n"); - } - delete haha; - - printf("=====================================================\n"); - printf(" loading reaction1 config : %s.", reactionConfigFileName1.c_str()); - TMacro * kaka = new TMacro(); - if( kaka->ReadFile(reactionConfigFileName1.c_str()) > 0 ) { - reactionConfig1 = AnalysisLib::LoadReactionConfig(kaka); - printf("..... done.\n"); - AnalysisLib::PrintReactionConfig(reactionConfig1); - }else{ - printf("..... fail\n"); - } - delete kaka; - - if( detGeo.use2ndArray){ - printf("=====================================================\n"); - printf(" loading reaction2 config : %s.", reactionConfigFileName2.c_str()); - TMacro * jaja = new TMacro(); - if( jaja->ReadFile(reactionConfigFileName2.c_str()) > 0 ) { - reactionConfig2 = AnalysisLib::LoadReactionConfig(kaka); - printf("..... done.\n"); - AnalysisLib::PrintReactionConfig(reactionConfig2); - }else{ - printf("..... fail\n"); - } - delete jaja; - } - -} - -//************************************** Correction parameters; - -std::vector xnCorr; //correction of xn to match xf -std::vector xScale; // correction of x to be (0,1) -std::vector> xfxneCorr; //correction of xn and xf to match e -std::vector> eCorr; // correction to e, ch -> MeV -std::vector> rdtCorr; // correction of rdt, ch -> MeV - -//~========================================= xf = xn correction -void LoadXNCorr(bool verbose = false, const char * fileName = "correction_xf_xn.dat"){ - printf(" loading xf-xn correction."); - xnCorr.clear(); - std::ifstream file; - file.open(fileName); - if( file.is_open() ){ - float a; - while( file >> a ) xnCorr.push_back(a); - printf(".......... done.\n"); - }else{ - printf(".......... fail.\n"); - } - file.close(); - if( verbose ) for(int i = 0; i < (int) xnCorr.size(); i++) printf("%2d | %10.3f\n", i, xnCorr[i]); -} - - -//~========================================= X-Scale correction -void LoadXScaleCorr(bool verbose = false, const char * fileName = "correction_scaleX.dat"){ - printf(" loading x-Scale correction."); - xScale.clear(); - std::ifstream file; - file.open(fileName); - if( file.is_open() ){ - float a, b; - while( file >> a ) xScale.push_back(a); - printf("........ done.\n"); - }else{ - printf("........ fail.\n"); - } - file.close(); - if( verbose ) for(int i = 0; i < (int) xScale.size(); i++) printf("%2d | %10.3f\n", i, xnCorr[i]); -} - -//~========================================= e = xf + xn correction -void LoadXFXN2ECorr(bool verbose = false, const char * fileName = "correction_xfxn_e.dat"){ - printf(" loading xf/xn-e correction."); - xfxneCorr.clear(); - std::ifstream file; - file.open(fileName); - if( file.is_open() ){ - float a, b; - while( file >> a >> b) xfxneCorr.push_back({a, b}); - printf("........ done.\n"); - }else{ - printf("........ fail.\n"); - } - file.close(); - if( verbose ) for(int i = 0; i < (int) xfxneCorr.size(); i++) printf("%2d | %10.3f, %10.3f\n", i, xfxneCorr[i][0], xfxneCorr[i][1]); -} - -//~========================================= e correction -void LoadECorr(bool verbose = false, const char * fileName = "correction_e.dat"){ - printf(" loading e correction."); - eCorr.clear(); - std::ifstream file; - file.open(fileName); - if( file.is_open() ){ - float a, b; - while( file >> a >> b) eCorr.push_back( {a, b} ); // 1/a1, a0 , e' = e * a1 + a0 - printf(".............. done.\n"); - }else{ - printf(".............. fail.\n"); - } - file.close(); - if( verbose ) for(int i = 0; i < (int) eCorr.size(); i++) printf("%2d | %10.3f, %10.3f\n", i, eCorr[i][0], eCorr[i][1]); -} - -//~========================================= rdt correction -void LoadRDTCorr(bool verbose = false, const char * fileName = "correction_rdt.dat"){ - printf(" loading rdt correction."); - rdtCorr.clear(); - std::ifstream file; - file.open(fileName); - if( file.is_open() ){ - float a, b; - while( file >> a >> b) rdtCorr.push_back({a, b}); - printf("............ done.\n"); - }else{ - printf("............ fail.\n"); - } - file.close(); - if( verbose ) for(int i = 0; i < (int) rdtCorr.size(); i++) printf("%2d | %10.3f, %10.3f\n", i, rdtCorr[i][0], rdtCorr[i][1]); -} - - -struct ReactionParas{ - - double Et; // total energy in CM frame - double beta; // Lorentz beta from Lab to CM - double gamma; // Lorentz gamma from Lab to CM - double alpha; // E-Z slope / beta - double G; //The G-coefficient.... - double massB; // heavy mass - double q; // charge of light particle - double mass; //light mass - bool hasReactionPara; - - double detPrepDist; - -}; - -ReactionParas reactParas1; -ReactionParas reactParas2; - -//~========================================= reaction parameters -void LoadReactionParas(int arrayID, bool verbose = false){ - - //check is the transfer.root is using the latest reactionConfig.txt - //sicne reaction.dat is generated as a by-product of transfer.root - //TFile * transfer = new TFile("transfer.root"); - //TString aaa1 = ""; - //TString aaa2 = ""; - //if( transfer->IsOpen() ){ - // TMacro * reactionConfig = (TMacro *) transfer->FindObjectAny("reactionConfig"); - // TMacro presentReactionConfig ("reactionConfig.txt"); - // aaa1 = ((TMD5*) reactionConfig->Checksum())->AsString(); - // aaa2 = ((TMD5*) presentReactionConfig.Checksum())->AsString(); - //} - //printf("%s\n", aaa1.Data()); - //printf("%s\n", aaa2.Data()); - - //if( aaa1 != aaa2 ) { - // printf("########################## recalculate transfer.root \n"); - // system("../Cleopatra/Transfer"); - // printf("########################## transfer.root updated\n"); - //} - - ReactionParas * reactParas = nullptr; - - std::string fileName; - - if( arrayID == 1){ - reactParas = &AnalysisLib::reactParas1; - fileName = "reaction.dat"; - }else if( arrayID == 2){ - reactParas = &AnalysisLib::reactParas2; - fileName = "reaction2.dat"; - }else{ - printf("arrayID must be either 1 or 2. Abort.\n"); - return; - } - reactParas->detPrepDist = AnalysisLib::detGeo.array1.detPerpDist; - - printf(" loading reaction parameters"); - std::ifstream file; - file.open(fileName.c_str()); - reactParas->hasReactionPara = false; - if( file.is_open() ){ - std::string x; - int i = 0; - while( file >> x ){ - if( x.substr(0,2) == "//" ) continue; - if( i == 0 ) reactParas->mass = atof(x.c_str()); - if( i == 1 ) reactParas->q = atof(x.c_str()); - if( i == 2 ) reactParas->beta = atof(x.c_str()); - if( i == 3 ) reactParas->Et = atof(x.c_str()); - if( i == 4 ) reactParas->massB = atof(x.c_str()); - i = i + 1; - } - printf("........ done.\n"); - - reactParas->hasReactionPara = true; - reactParas->alpha = 299.792458 * abs(detGeo.Bfield) * reactParas->q / TMath::TwoPi()/1000.; //MeV/mm - reactParas->gamma = 1./TMath::Sqrt(1-reactParas->beta * reactParas->beta); - reactParas->G = reactParas->alpha * reactParas->gamma * reactParas->beta * reactParas->detPrepDist ; - - if( verbose ){ - printf("\tmass-b : %f MeV/c2 \n", reactParas->mass); - printf("\tcharge-b : %f \n", reactParas->q); - printf("\tE-total : %f MeV \n", reactParas->Et); - printf("\tmass-B : %f MeV/c2 \n", reactParas->massB); - printf("\tbeta : %f \n", reactParas->beta); - printf("\tB-field : %f T \n", detGeo.Bfield); - printf("\tslope : %f MeV/mm \n", reactParas->alpha * reactParas->beta); - printf("\tdet radius: %f mm \n", reactParas->detPrepDist); - printf("\tG-coeff : %f MeV \n", reactParas->G); - printf("=====================================================\n"); - } - - }else{ - printf("........ fail.\n"); - } - file.close(); - -} - -std::vector CalExTheta(double e, double z){ - - ReactionParas * reactParas = nullptr; - - if( detGeo.array1.zMin <= z && z <= detGeo.array1.zMax ){ - reactParas = &reactParas1; - if( !reactParas->hasReactionPara) return {TMath::QuietNaN(), TMath::QuietNaN()}; - } - - if( detGeo.array2.zMin <= z && z <= detGeo.array2.zMax ){ - reactParas = &reactParas2; - if( !reactParas->hasReactionPara) return {TMath::QuietNaN(), TMath::QuietNaN()}; - } - - double Ex = TMath::QuietNaN(); - double thetaCM = TMath::QuietNaN(); - - double y = e + reactParas->mass; // to give the KE + mass of proton; - double Z = reactParas->alpha * reactParas->gamma * reactParas->beta * z; - double H = TMath::Sqrt(TMath::Power(reactParas->gamma * reactParas->beta,2) * (y*y - reactParas->mass * reactParas->mass) ) ; - - if( TMath::Abs(Z) < H ) { - ///using Newton's method to solve 0 == H * sin(phi) - G * tan(phi) - Z = f(phi) - double tolerrence = 0.001; - double phi = 0; ///initial phi = 0 -> ensure the solution has f'(phi) > 0 - double nPhi = 0; /// new phi - - int iter = 0; - do{ - phi = nPhi; - nPhi = phi - (H * TMath::Sin(phi) - reactParas->G * TMath::Tan(phi) - Z) / (H * TMath::Cos(phi) - reactParas->G /TMath::Power( TMath::Cos(phi), 2)); - iter ++; - if( iter > 10 || TMath::Abs(nPhi) > TMath::PiOver2()) break; - }while( TMath::Abs(phi - nPhi ) > tolerrence); - phi = nPhi; - - /// check f'(phi) > 0 - double Df = H * TMath::Cos(phi) - reactParas->G / TMath::Power( TMath::Cos(phi),2); - if( Df > 0 && TMath::Abs(phi) < TMath::PiOver2() ){ - double K = H * TMath::Sin(phi); - double x = TMath::ACos( reactParas->mass / ( y * reactParas->gamma - K)); - double momt = reactParas->mass * TMath::Tan(x); /// momentum of particel b or B in CM frame - double EB = TMath::Sqrt(reactParas->mass * reactParas->mass + reactParas->Et * reactParas->Et - 2 * reactParas->Et * TMath::Sqrt(momt*momt + reactParas->mass * reactParas->mass)); - Ex = EB - reactParas->massB; - - double hahaha1 = reactParas->gamma * TMath::Sqrt(reactParas->mass * reactParas->mass + momt * momt) - y; - double hahaha2 = reactParas->gamma * reactParas->beta * momt; - thetaCM = TMath::ACos(hahaha1/hahaha2) * TMath::RadToDeg(); - - } - } - return {Ex, thetaCM}; - -} //************************************** TCutG