Created
February 17, 2026 20:50
-
-
Save jdbrice/b186e06dd1847dbc75d74f40ae4415d4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <TMinuit.h> | |
| #include <TVirtualFitter.h> | |
| #include <TGraph.h> | |
| #include <TCanvas.h> | |
| #include <TFile.h> | |
| #include <TStyle.h> | |
| #include <TF1.h> | |
| #include <TF1Convolution.h> | |
| #include <TLegend.h> | |
| #include <iostream> | |
| #include <cmath> | |
| #include <TROOT.h> | |
| #include <TMath.h> | |
| #include <TColor.h> | |
| #include <TH1F.h> | |
| TString pName = "fit_nophase"; | |
| double Gamma( double Mkk, double Mphi, double Gamma0 ){ | |
| double Mkk2 = Mkk*Mkk; | |
| double Mphi2 = Mphi*Mphi; | |
| double mk = 495.2; | |
| double mk2 = mk*mk; | |
| double t0 = Gamma0 * ( Mphi / Mkk ); | |
| double t1 = pow( (Mkk2 - 4*mk2)/(Mphi2-4*mk2), (3.0/2.0) ); | |
| return t0 * t1; | |
| } | |
| // Relativistic Breit-Wigner (amplitude level) for the phi | |
| // Real or Imaginary part of the amplitude | |
| double Amplitude_BW( double A, double Mkk, double Mphi, double Gamma0, bool real = true ){ | |
| double Mkk2 = Mkk*Mkk; | |
| double Mphi2 = Mphi*Mphi; | |
| double G = Gamma( Mkk, Mphi, Gamma0 ); | |
| double G2 = G*G; | |
| double pre = A * sqrt(Mkk * Mphi * G); | |
| double t0 = Mkk2 - Mphi2; | |
| double t1 = pow( Mkk2 - Mphi2, 2 ) + Mphi2*G2; | |
| if (real){ | |
| return pre * t0 / t1; | |
| } else { | |
| return pre * (-Mphi*G) / t1; | |
| } | |
| } | |
| double Amplitude_BW( double *x, double *p ){ | |
| double Mkk = x[0]; // x-variable | |
| double Mphi = p[0]; // mass of the phi | |
| double Gamma0 = p[1]; // width of the phi | |
| double A = p[2]; // alpha | |
| double Br = p[3]; // beta (Real) | |
| double Bi = p[4]; // beta (Imaginary) | |
| double RI = p[5]; // real or imaginary | |
| return Amplitude_BW( A, Mkk, Mphi, Gamma0, (int)(RI) ); | |
| } | |
| double ResidualBackground( double *x, double *p ){ | |
| double Mkk = x[0]; // x-variable | |
| double Bg0 = p[0]; // background | |
| double Bg1 = p[1]; // background | |
| double Bg2 = p[2]; // background | |
| // double Bg3 = p[3]; // background | |
| // double Bg4 = p[4]; // background | |
| return Bg0 / ( 1 + exp( -Bg1 * (Mkk - Bg2) ) ); | |
| // return fabs(Bg0) + fabs(Bg1 * Mkk) + fabs(Bg2 * Mkk * Mkk); | |
| // return fabs(Bg0 + (Bg1 * Mkk) + Bg2 * Mkk * Mkk); | |
| } | |
| double xs( double *x, double *p ){ | |
| double Mkk = x[0]; // x-variable | |
| // fit parameters | |
| double Mphi = p[0]; // mass of the phi | |
| double Gamma0 = p[1]; // width of the phi | |
| double alpha = p[2]; // alpha | |
| double betaR = p[3]; // beta (Real) | |
| double betaI = p[4]; // beta (Imaginary) | |
| double ReA = Amplitude_BW( alpha, Mkk, Mphi, Gamma0, true ); | |
| double ImA = Amplitude_BW( alpha, Mkk, Mphi, Gamma0, false ); | |
| // Let the continuum be complex B = betaR + i*betaI | |
| double ReB = betaR; | |
| double ImB = betaI; | |
| // compute each (real) term in the matrix element squared | |
| // (ReA + ImA) * (ReA + ImA) = ReA*ReA + ImA*ImA + 2*ReA*ImA | |
| // (ReB + ImB) * (ReB + ImB) = ReB*ReB + ImB*ImB + 2*ReB*ImB | |
| // (ReA + ImA) * (ReB + ImB) = ReA*ReB + ImA*ImB + ReA*ImB + ReB*ImA | |
| double t0 = ReA*ReA + ImA*ImA; | |
| double t1 = ReA*ReB + ImA*ImB; | |
| double t2 = 2*(ReB*ReB + ImB*ImB); | |
| return t0 + t1 + t2 + ResidualBackground( x, &(p[5]) ); | |
| } | |
| double xs_( double *x, double *p ){ | |
| double Mkk = x[0]; // x-variable | |
| // fit parameters | |
| double Mphi = p[0]; // mass of the phi | |
| double Gamma0 = p[1]; // width of the phi | |
| double alpha = p[2]; // alpha | |
| double betaR = p[3]; // beta (Real) | |
| double betaI = p[4]; // beta (Imaginary) | |
| double term0 = p[5]; // background | |
| double ReA = Amplitude_BW( alpha, Mkk, Mphi, Gamma0, true ); | |
| double ImA = Amplitude_BW( alpha, Mkk, Mphi, Gamma0, false ); | |
| // Let the continuum be complex B = betaR + i*betaI | |
| double ReB = betaR; | |
| double ImB = betaI; | |
| // compute each (real) term in the matrix element squared | |
| // (ReA + ImA) * (ReA + ImA) = ReA*ReA + ImA*ImA + 2*ReA*ImA | |
| // (ReB + ImB) * (ReB + ImB) = ReB*ReB + ImB*ImB + 2*ReB*ImB | |
| // (ReA + ImA) * (ReB + ImB) = ReA*ReB + ImA*ImB + ReA*ImB + ReB*ImA | |
| double t0 = ReA*ReA + ImA*ImA; | |
| double t1 = ReA*ReB + ImA*ImB; | |
| double t2 = 2*(ReB*ReB + ImB*ImB); | |
| if (term0< -1) | |
| return t0 ; | |
| else if ( fabs(term0) < 1 ) | |
| return t1; | |
| else | |
| return t2; | |
| } | |
| TGraph* contour_for(int nSigma = 1, int color = kBlue) { | |
| gMinuit->SetErrorDef(nSigma * nSigma); // Set the error definition for the contour | |
| TGraph *contour_BrBi = (TGraph*)gMinuit->Contour(100, 3, 4); | |
| TGraph *contour_ABr = (TGraph*)gMinuit->Contour(100, 2, 3); | |
| if (!contour_BrBi || !contour_ABr) { | |
| printf("Error: Contour could not be generated.\n"); | |
| return nullptr; | |
| } | |
| int nPoints = contour_BrBi->GetN(); | |
| double *Br_vals = contour_BrBi->GetX(); | |
| double *Bi_vals = contour_BrBi->GetY(); | |
| double *A_vals = contour_ABr->GetX(); | |
| double BoA_vals[10000]; // Array for B over A values | |
| double delta_vals[10000]; // Array for delta values | |
| for ( int i = 0; i < nPoints; i++ ){ | |
| double Br = Br_vals[i]; | |
| double Bi = Bi_vals[i]; | |
| double A = A_vals[i]; | |
| // Calculate B over A and delta | |
| BoA_vals[i] = sqrt( pow( Br, 2 ) + pow( Bi, 2 ) ) / A; | |
| delta_vals[i] = atan2( Bi, Br ); | |
| // cout << "Br = " << Br << ", Bi = " << Bi << ", A = " << A << endl; | |
| } | |
| TGraph *contour_ALICE = new TGraph(nPoints, BoA_vals, delta_vals); | |
| contour_ALICE->SetTitle(TString::Format("%d-sigma Contour;|B/A|;#delta", nSigma)); | |
| contour_ALICE->SetLineColor(color); | |
| contour_ALICE->SetLineColor(color); | |
| contour_ALICE->SetLineWidth(2); | |
| contour_ALICE->SetMarkerStyle(20); | |
| contour_ALICE->SetMarkerSize(0.001); | |
| return contour_ALICE; | |
| } | |
| void fit_histo( TH1 * hm){ | |
| TCanvas *c1 = new TCanvas("c1", "c1", 1600, 900); | |
| c1->SetTopMargin(0.05); | |
| c1->SetRightMargin(0.05); | |
| c1->SetLeftMargin(0.15); | |
| c1->SetBottomMargin(0.15); | |
| c1->cd(); | |
| hm->GetXaxis()->SetRangeUser( 990, 1450 ); | |
| hm->SetFillColorAlpha( kBlue, 0.35 ); | |
| hm->SetLineColor( kBlue ); | |
| hm->GetYaxis()->SetTitle("Events / 10 MeV"); | |
| hm->GetXaxis()->SetTitle("M_{KK} [MeV]"); | |
| hm->SetTitle("M_{KK} Spectrum"); | |
| hm->GetYaxis()->SetRangeUser( 10, hm->GetMaximum()*1.5 ); | |
| hm->Draw( "pe" ) ; | |
| hm->Draw( "same h" ) ; | |
| // draw the candidates and background as well | |
| // hc->SetFillColorAlpha( kRed, 0.35 ); | |
| // hc->SetLineColor( kRed ); | |
| // hc->Draw( "same pe" ) ; | |
| // hbg->SetFillColorAlpha( kGreen, 0.35 ); | |
| // hbg->SetLineColor( kGreen ); | |
| // hbg->Draw( "same pe" ) ; | |
| gStyle->SetFitFormat( "5.3g" ); | |
| gStyle->SetOptFit( 1111 ); | |
| // hm->Draw(); | |
| int colors[6] = {kRed, kBlue, kGreen+2, kMagenta, kOrange+7, kCyan+2}; | |
| TF1 * tf1kkKernel = new TF1("xs", xs, 1000, 1400, 8); | |
| tf1kkKernel->SetNpx(1000); | |
| tf1kkKernel->SetLineColor( colors[0] ); | |
| tf1kkKernel->SetLineWidth( 5 ); | |
| tf1kkKernel->SetParNames( "Mphi", "Gamma", "A", "Br", "Bi", "Bg0", "Bg1", "Bg2" ); | |
| tf1kkKernel->SetParameters( 1020, 5.09, 63, 1, 0, 100, 1.0, 1000 ); // setting initial guess for each parameter | |
| hm->Fit(tf1kkKernel, "MER", "", 1005, 1100); | |
| TF1 *gaus = new TF1("gaus", "exp(-0.5*(x/[0])*(x/[0]))", -100, 100); | |
| gaus->SetParameter(0, 1.0); // Initial sigma, e.g., 1 GeV, adjust as needed | |
| TF1Convolution *conv = new TF1Convolution(tf1kkKernel, gaus, true); | |
| conv->SetNofPointsFFT(10); | |
| // TF1 *tf1kk = new TF1("cxs", conv, 1000, 1200, tf1kkKernel->GetNpar() + gaus->GetNpar()); | |
| TF1 * tf1kk = new TF1("xs", xs, 1000, 1400, 8); | |
| tf1kk->SetParameters( tf1kkKernel->GetParameters() ); | |
| tf1kk->SetParNames( "Mphi", "Gamma", "A", "Br", "Bi", "Bg0", "Bg1", "Bg2", "RES" ); | |
| // tf1kk->FixParameter( 8, 1.0 ); // Fix the resolution parameter | |
| // tf1kk->FixParameter( 6, 0 ); | |
| // tf1kk->FixParameter( 7, 0 ); | |
| // hm->Fit(tf1kk, "R", "", 1000, 1040); | |
| // hm->Fit(tf1kk, "R", "", 1000, 1200); | |
| // tf1kk->Draw(""); | |
| // c1->Print(TString::Format("%s.png", pName.Data()).Data()); | |
| // return; | |
| // Draw the residual background separately | |
| TF1 * tf1bg = new TF1("bg", ResidualBackground, 1000, 1400, 3); | |
| tf1bg->SetNpx(1000); | |
| tf1bg->SetLineWidth( 5 ); | |
| tf1bg->SetParameters( tf1kk->GetParameter(5), tf1kk->GetParameter(6), tf1kk->GetParameter(7) ); | |
| tf1bg->SetLineColor( colors[1] ); | |
| tf1bg->Draw("same"); | |
| gPad->SetLogy(); | |
| double Mphi = tf1kk->GetParameter(0); | |
| double Gamma = tf1kk->GetParameter(1); | |
| double A = tf1kk->GetParameter(2); | |
| double Br = tf1kk->GetParameter(3); | |
| double Bi = tf1kk->GetParameter(4); | |
| double Bg0 = tf1kk->GetParameter(5); | |
| double Bg1 = tf1kk->GetParameter(6); | |
| double Bg2 = tf1kk->GetParameter(7); | |
| // lets plot each part of the amplitude separately | |
| TF1 * tf1xs0 = new TF1("xs0", xs_, 1000, 1400, 6); | |
| tf1xs0->SetNpx(1000); | |
| tf1xs0->SetLineWidth( 5 ); | |
| tf1xs0->SetParameters( Mphi, Gamma, A, Br, Bi, -10 ); // first term | |
| tf1xs0->SetLineColor( colors[2] ); | |
| tf1xs0->Draw("same"); | |
| TF1 * tf1xs1 = new TF1("xs1", xs_, 1000, 1400, 6); | |
| tf1xs1->SetNpx(1000); | |
| tf1xs1->SetLineWidth( 5 ); | |
| tf1xs1->SetParameters( Mphi, Gamma, A, Br, Bi, 0 ); // second term | |
| tf1xs1->SetLineColor( colors[3] ); | |
| tf1xs1->Draw("same"); | |
| TF1 * tf1xs2 = new TF1("xs2", xs_, 1000, 1400, 6); | |
| tf1xs2->SetNpx(1000); | |
| tf1xs2->SetLineWidth( 5 ); | |
| tf1xs2->SetParameters( Mphi, Gamma, A, Br, Bi, 10 ); // third term | |
| tf1xs2->SetLineColor( colors[4] ); | |
| tf1xs2->Draw("same"); | |
| TLegend *leg = new TLegend(0.45, 0.75, 0.6, 0.95); | |
| leg->AddEntry( tf1kk, "Total Amplitude", "l" ); | |
| leg->AddEntry( tf1xs0, "First Term", "l" ); | |
| leg->AddEntry( tf1xs1, "Second Term", "l" ); | |
| leg->AddEntry( tf1xs2, "Third Term", "l" ); | |
| leg->AddEntry( tf1bg, "Residual Background", "l" ); | |
| leg->Draw("same"); | |
| c1->Print(TString::Format("%s.png", pName.Data()).Data()); | |
| // make a new canvas | |
| TCanvas *c2 = new TCanvas("c2", "c2", 1600, 900); | |
| c2->SetTopMargin(0.05); | |
| c2->SetRightMargin(0.05); | |
| c2->SetLeftMargin(0.15); | |
| c2->SetBottomMargin(0.15); | |
| c2->cd(); | |
| // lets make a pull plot between the tf1kk and the data | |
| TH1F *hpull = (TH1F*)hm->Clone("hpull"); | |
| hpull->SetTitle("Pull Plot"); | |
| for (int i = 1; i <= hm->GetNbinsX(); i++){ | |
| double x = hm->GetBinCenter(i); | |
| double y = hm->GetBinContent(i); | |
| double yerr = hm->GetBinError(i); | |
| double yfit = tf1kk->Eval(x); | |
| double pull = (y - yfit) / yerr; | |
| if (pull!=pull || y < 10) continue; | |
| cout << "pull[" << i << "]: " << pull << endl; | |
| hpull->SetBinContent(i, pull); | |
| hpull->SetBinError(i, 1.0); | |
| } | |
| hpull->SetMarkerStyle(20); | |
| hpull->SetMarkerSize(1.5); | |
| hpull->SetLineWidth(5); | |
| hpull->SetLineColor( kBlue ); | |
| hpull->GetYaxis()->SetRangeUser( -5, 5 ); | |
| hpull->Draw( "pe"); | |
| c1->Print(TString::Format("%s_pull.png", pName.Data()).Data()); | |
| return; | |
| // new canvas | |
| TCanvas *c3 = new TCanvas("c3", "c3", 1600, 900); | |
| c3->SetTopMargin(0.05); | |
| c3->SetRightMargin(0.05); | |
| c3->SetLeftMargin(0.15); | |
| c3->SetBottomMargin(0.15); | |
| c3->cd(); | |
| // TGraph *contour = (TGraph*)fitResult->GetConfidenceEllipse(0, 1, 50, 1); // Parameters 0, 1, 50 points, 1-sigma | |
| // contour->SetTitle("1-sigma Contour;Parameter 0;Parameter 1"); | |
| // contour->Draw("AL"); | |
| // TGraph *gr12 = (TGraph*)gMinuit->Contour(40,3,4); | |
| // gr12->Draw("alp"); | |
| // c3->Draw(); | |
| // c3->Print("fit_nophase_contour.png"); | |
| double BoA = sqrt( | |
| pow( tf1kk->GetParameter(3), 2 ) + pow( tf1kk->GetParameter(4), 2 ) | |
| ) / tf1kk->GetParameter(2); | |
| double BoAerr = BoA * sqrt( | |
| pow( tf1kk->GetParError(3) / tf1kk->GetParameter(3), 2 ) + | |
| pow( tf1kk->GetParError(4) / tf1kk->GetParameter(4), 2 ) + | |
| pow( tf1kk->GetParError(2) / tf1kk->GetParameter(2), 2 ) | |
| ); | |
| cout << "BoA = " << BoA << " +/- " << BoAerr << endl; | |
| double delta = atan2( tf1kk->GetParameter(4), tf1kk->GetParameter(3) ); | |
| double deltaerr = sqrt( | |
| pow( tf1kk->GetParError(4) / tf1kk->GetParameter(4), 2 ) + | |
| pow( tf1kk->GetParError(3) / tf1kk->GetParameter(3), 2 ) | |
| ); | |
| cout << "delta = " << delta << " +/- " << deltaerr << endl; | |
| return; | |
| // now we compute the contours | |
| TGraph * contour_ALICE3 = contour_for( /*nSigma=*/3, kRed ); | |
| contour_ALICE3->SetTitle("Phase-free fit;|B/A|;#delta"); | |
| contour_ALICE3->Draw("ALP"); | |
| TGraph * contour_ALICE1 = contour_for( /*nSigma=*/1, kBlue ); | |
| contour_ALICE1->Draw("same LP"); | |
| TGraph * best_fit = new TGraph(1); | |
| best_fit->SetPoint(0, BoA, delta); | |
| best_fit->SetMarkerStyle(20); | |
| best_fit->SetMarkerSize(2); | |
| best_fit->SetMarkerColor(kBlack); | |
| best_fit->Draw("same P"); | |
| TLegend *leg2 = new TLegend(0.15, 0.15, 0.35, 0.35); | |
| leg2->AddEntry( contour_ALICE1, "1-sigma Contour", "l" ); | |
| leg2->AddEntry( contour_ALICE3, "3-sigma Contour", "l" ); | |
| leg2->AddEntry( best_fit, "Best Fit", "p" ); | |
| leg2->Draw("same"); | |
| c1->Print(TString::Format("%s_contour.png", pName.Data()).Data()); | |
| TFile *fout = new TFile("fit_nophase.root", "RECREATE"); | |
| contour_ALICE1->SetName("contour_nophase1"); | |
| contour_ALICE1->Write(); | |
| contour_ALICE3->SetName("contour_nophase3"); | |
| contour_ALICE3->Write(); | |
| best_fit->SetName("central_nophase"); | |
| best_fit->Write(); | |
| } | |
| void fit_nophase( TString n = "FILTERED.root" ){ | |
| //be sure default is Minuit since we will use gMinuit | |
| TVirtualFitter::SetDefaultFitter("Minuit"); | |
| // open a root TFile for reading | |
| TFile *f = new TFile(TString::Format("%s", n.Data()).Data()); | |
| auto hm0 = (TH1*)f->Get("hY"); // candidates | |
| fit_histo(hm0); | |
| for (int i = 0; i < 10; i++){ | |
| cout << "i = " << i << endl; | |
| auto hm = (TH1*)f->Get(TString::Format("hY_%d", i)); // candidates | |
| pName = TString::Format("fit_nophase_%d", i); | |
| fit_histo(hm); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment