Back to home page

sPhenix code displayed by LXR

 
 

    


Warning, file /analysis/LightFlavorRatios/yield_and_ratios/kinematicThreshold.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 #ifndef KINEMATIC_THRESHOLD_H
0002 #define KINEMATIC_THRESHOLD_H
0003 
0004 #include "../util/binning.h"
0005 
0006 // For near-threshold decays in bins of mother pT, both signal and background are modified by the daughter pT cutoff in reconstruction.
0007 // Some fraction of decays at a given mass produce one or both daughter tracks with pT too small to be reconstructed.
0008 // This fraction goes up with decreasing mother pT and mother mass.
0009 // The functions below semi-analytically calculate this threshold turn-on as a function of mass, mother pT, and daughter pT cutoff.
0010 // This also assumes reconstruction is being done at mid-rapidity.
0011 
0012 // Lab-frame daughter pT as a function of CM-frame daughter theta, for a given CM-frame daughter (E,p)
0013 Double_t lab_pt_vs_cm_decay_axis(Double_t* v, Double_t* par)
0014 {
0015   double theta = v[0];
0016   double phi = v[1];
0017   double mother_mass = par[0];
0018   double mother_pt = par[1];
0019   double pcm = par[2];
0020   double Ecm = par[3];
0021 
0022   double mother_E = sqrt(pow(mother_pt,2)+pow(mother_mass,2));
0023   double mother_gamma = mother_E/mother_mass;
0024   double mother_beta = mother_pt/(mother_gamma*mother_mass);
0025 
0026   double pt_lab = sqrt(pow(mother_gamma*(pcm*cos(theta)*cos(phi)+mother_beta*Ecm),2)+pow(pcm*cos(theta)*sin(phi),2));
0027   return pt_lab;
0028 }
0029 
0030 // Comparator that tests if the lab-frame daughter pT is above the cutoff
0031 Double_t pt_above_cutoff(Double_t* v, Double_t* par)
0032 {
0033   double theta = v[0];
0034   double pt_cutoff = par[4];
0035   if(lab_pt_vs_cm_decay_axis(v,par)<pt_cutoff) return 0.;
0036   // integration weight for spherical surface element is cos(theta)
0037   else return cos(theta);
0038 }
0039 
0040 // threshold turnon function
0041 Double_t kinematic_threshold_turnon(Double_t* v, Double_t* par)
0042 {
0043   double mass = v[0];
0044   double mother_pt = par[0];
0045   double daughter_pt_cutoff = par[1];
0046   double daughter1_mass = par[2];
0047   double daughter2_mass = par[3];
0048 
0049   // energy must be conserved
0050   if(mass<daughter1_mass+daughter2_mass) return 0.;
0051 
0052   double daughter1_Ecm = (pow(mass,2)+pow(daughter1_mass,2)-pow(daughter2_mass,2))/2*mass;
0053   double daughter2_Ecm = (pow(mass,2)+pow(daughter2_mass,2)-pow(daughter1_mass,2))/2*mass;
0054 
0055   double daughter1_pcm = sqrt(pow(daughter1_Ecm,2)-pow(daughter1_mass,2));
0056   double daughter2_pcm = sqrt(pow(daughter2_Ecm,2)-pow(daughter2_mass,2));
0057 
0058   // average value of (pt above threshold? 1 : 0) function gives you fraction of reconstructible daughters
0059   // this function is not that well behaved with the standard adaptive singular integrator (sharp transitions from 1 to 0)
0060   // but is pretty ideal for a MC integrator [TODO]
0061 
0062   ROOT::Math::IntegratorMultiDimOptions::SetDefaultIntegrator("VEGAS");
0063 
0064   TF2* daughter1_comp = new TF2("daughter1_comp",&pt_above_cutoff,-M_PI/2.,M_PI/2.,0.,2*M_PI,5);
0065   daughter1_comp->SetParameters(mass,mother_pt,daughter1_pcm,daughter1_Ecm,daughter_pt_cutoff);
0066   double daughter1_frac = daughter1_comp->Integral(-M_PI/2.,M_PI/2.,0.,2*M_PI,1e-4) / (4.*M_PI);
0067   delete daughter1_comp;
0068 
0069   TF2* daughter2_comp = new TF2("daughter2_comp",&pt_above_cutoff,-M_PI/2.,M_PI/2.,0.,2*M_PI,5);
0070   daughter2_comp->SetParameters(mass,mother_pt,daughter2_pcm,daughter2_Ecm,daughter_pt_cutoff);
0071   double daughter2_frac = daughter2_comp->Integral(-M_PI/2.,M_PI/2.,0.,2*M_PI,1e-4) / (4.*M_PI);
0072   delete daughter2_comp;
0073 
0074   // both daughters must be reconstructible
0075   return daughter1_frac*daughter2_frac;
0076 }
0077 
0078 TF1* threshold_turnon_TF1(std::pair<double,double> mass_range, double mother_pt, double daughter_pt_cutoff, int daughter1_pdgid, int daughter2_pdgid)
0079 {
0080   double daughter1_mass = TDatabasePDG::Instance()->GetParticle(daughter1_pdgid)->Mass();
0081   double daughter2_mass = TDatabasePDG::Instance()->GetParticle(daughter2_pdgid)->Mass();
0082 
0083   TF1* threshold_TF1 = new TF1("threshold_turnon",&kinematic_threshold_turnon,mass_range.first,mass_range.second,4);
0084   threshold_TF1->SetParameters(mother_pt,daughter_pt_cutoff,daughter1_mass,daughter2_mass);
0085   return threshold_TF1;
0086 }
0087 
0088 // These functions turned out to be quite slow, so here are lookup tables from which we can draw the relevant info
0089 
0090 void build_turnon_lookup_tables(std::string mother_name, int daughter1_pdgid, int daughter2_pdgid)
0091 {
0092   const double ptcut_min = 0.;
0093   const double ptcut_max = 0.5;
0094   const int nbins_ptcut = 100;
0095 
0096   HistogramInfo massbins = BinInfo::mass_bins.at(mother_name);
0097   const int nbins_mass = 100;
0098   const double mass_min = 0.9*massbins.bins[0];
0099   const double mass_max = 1.1*massbins.bins.back();
0100 
0101   const double daughter1_mass = TDatabasePDG::Instance()->GetParticle(daughter1_pdgid)->Mass();
0102   const double daughter2_mass = TDatabasePDG::Instance()->GetParticle(daughter2_pdgid)->Mass();
0103 
0104   std::string filename = "threshold_turnon_tables_"+mother_name+".root";
0105   TFile* f = new TFile(filename.c_str(),"RECREATE");
0106   // dummy, to get bin centers
0107   TH1F* h_pt = makeHistogram("","",BinInfo::final_pt_bins);
0108   for(int i=1;i<=h_pt->GetNbinsX();i++)
0109   {
0110     std::cout << "building threshold turnon lookup table for " << mother_name << " bin " << i << std::endl;
0111     double mother_pT = h_pt->GetBinLowEdge(i);
0112     std::string name = "threshold_bin"+std::to_string(i);
0113     std::string title = "Threshold turnon modification for mother pT = "+std::to_string(mother_pT);
0114 
0115     TH2F* threshold = new TH2F(name.c_str(),title.c_str(),nbins_mass,mass_min,mass_max,nbins_ptcut,ptcut_min,ptcut_max);
0116 
0117     for(int j=1;j<=threshold->GetNbinsX();j++)
0118     {
0119       double mass = threshold->GetXaxis()->GetBinCenter(j);
0120       for(int k=1;k<=threshold->GetNbinsY();k++)
0121       {
0122         std::cout << "sub-bin (" << j << ", " << k << ")" << std::endl;
0123         double ptcut = threshold->GetYaxis()->GetBinCenter(k);
0124         Double_t v[1] = {mass};
0125         Double_t par[4] = {mother_pT,ptcut,daughter1_mass,daughter2_mass};
0126         threshold->SetBinContent(j,k,kinematic_threshold_turnon(v,par));
0127       }
0128     }
0129     threshold->Write();
0130   }
0131   f->Close();
0132 }
0133 
0134 class LinearSidebandThresholdFast
0135 {
0136   public:
0137   LinearSidebandThresholdFast(std::string mother_name, float daughter_pt_cut, int mother_pt_bin, std::pair<float,float> lsb, std::pair<float,float> rsb)
0138   {
0139     std::string filename = "threshold_turnon_tables_"+mother_name+"_daughterpT_"+std::to_string(daughter_pt_cut)+".root";
0140     tablefile = TFile::Open(filename.c_str());
0141     h_threshold = (TH1F*)tablefile->Get(("threshold_bin"+std::to_string(mother_pt_bin)).c_str());
0142     h_threshold->SetDirectory(nullptr);
0143     tablefile->Close();
0144     left_sideband = lsb;
0145     right_sideband = rsb;
0146   }
0147   double operator()(double* v, double* par)
0148   {
0149     double x = v[0];
0150     double slope = par[0];
0151     double c = par[1];
0152     double spectrum_cutoff = par[2];
0153     if(restrict_to_sidebands && (x<left_sideband.first || x>left_sideband.second) && (x<right_sideband.first || x>right_sideband.second))
0154     {
0155       TF1::RejectPoint();
0156     }
0157     return (slope*x+c) * h_threshold->Interpolate(x,spectrum_cutoff);
0158   }
0159   bool restrict_to_sidebands = true;
0160   private:
0161   TFile* tablefile;
0162   TH1F* h_threshold;
0163   std::pair<float,float> left_sideband;
0164   std::pair<float,float> right_sideband;
0165 };
0166 #endif