rivet is hosted by Hepforge, IPPP Durham
ATLAS_2011_I944826.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 #include "Rivet/Analysis.hh"
00003 #include "Rivet/Projections/ChargedFinalState.hh"
00004 #include "Rivet/Projections/IdentifiedFinalState.hh"
00005 #include "Rivet/Projections/UnstableFinalState.hh"
00006 
00007 namespace Rivet {
00008 
00009 
00010   class ATLAS_2011_I944826 : public Analysis {
00011   public:
00012 
00013     /// Constructor
00014     ATLAS_2011_I944826()
00015       : Analysis("ATLAS_2011_I944826")
00016     {
00017       _sum_w_ks     = 0.0;
00018       _sum_w_lambda = 0.0;
00019       _sum_w_passed = 0.0;
00020     }
00021 
00022 
00023     /// Book histograms and initialise projections before the run
00024     void init() {
00025 
00026       UnstableFinalState ufs(-MAXRAPIDITY, MAXRAPIDITY, 100*MeV);
00027       addProjection(ufs, "UFS");
00028 
00029       vector<pair<double, double> > etaRanges;
00030       etaRanges.push_back(make_pair(-3.84, -2.09));
00031       etaRanges.push_back(make_pair(2.09, 3.84));
00032       ChargedFinalState  mbts(etaRanges);
00033       addProjection(mbts, "MBTS");
00034 
00035       IdentifiedFinalState nstable(-2.5, 2.5, 100*MeV);
00036       nstable.acceptIdPair(PID::ELECTRON)
00037         .acceptIdPair(PID::MUON)
00038         .acceptIdPair(PID::PIPLUS)
00039         .acceptIdPair(PID::KPLUS)
00040         .acceptIdPair(PID::PROTON);
00041       addProjection(nstable, "nstable");
00042 
00043       if (fuzzyEquals(sqrtS()*GeV, 7000, 1e-3)) {
00044         _hist_Ks_pT      = bookHisto1D(1, 1, 1);
00045         _hist_Ks_y       = bookHisto1D(2, 1, 1);
00046         _hist_Ks_mult    = bookHisto1D(3, 1, 1);
00047         _hist_L_pT       = bookHisto1D(7, 1, 1);
00048         _hist_L_y        = bookHisto1D(8, 1, 1);
00049         _hist_L_mult     = bookHisto1D(9, 1, 1);
00050         _hist_Ratio_v_y  = bookScatter2D(13, 1, 1);
00051         _hist_Ratio_v_pT = bookScatter2D(14, 1, 1);
00052         //
00053         _temp_lambda_v_y = Histo1D(10, 0.0, 2.5);
00054         _temp_lambdabar_v_y = Histo1D(10, 0.0, 2.5);
00055         _temp_lambda_v_pT = Histo1D(18, 0.5, 4.1);
00056         _temp_lambdabar_v_pT = Histo1D(18, 0.5, 4.1);
00057       }
00058       else if (fuzzyEquals(sqrtS()*GeV, 900, 1E-3)) {
00059         _hist_Ks_pT   = bookHisto1D(4, 1, 1);
00060         _hist_Ks_y    = bookHisto1D(5, 1, 1);
00061         _hist_Ks_mult = bookHisto1D(6, 1, 1);
00062         _hist_L_pT    = bookHisto1D(10, 1, 1);
00063         _hist_L_y     = bookHisto1D(11, 1, 1);
00064         _hist_L_mult  = bookHisto1D(12, 1, 1);
00065         _hist_Ratio_v_y      = bookScatter2D(15, 1, 1);
00066         _hist_Ratio_v_pT     = bookScatter2D(16, 1, 1);
00067         //
00068         _temp_lambda_v_y = Histo1D(5, 0.0, 2.5);
00069         _temp_lambdabar_v_y = Histo1D(5, 0.0, 2.5);
00070         _temp_lambda_v_pT = Histo1D(8, 0.5, 3.7);
00071         _temp_lambdabar_v_pT = Histo1D(8, 0.5, 3.7);
00072       }
00073     }
00074 
00075 
00076     // This function is required to impose the flight time cuts on Kaons and Lambdas
00077     double getPerpFlightDistance(const Rivet::Particle& p) {
00078       const HepMC::GenParticle* genp = p.genParticle();
00079       HepMC::GenVertex* prodV = genp->production_vertex();
00080       HepMC::GenVertex* decV  = genp->end_vertex();
00081       const HepMC::ThreeVector prodPos = prodV->point3d();
00082       if (decV) {
00083         const HepMC::ThreeVector decPos = decV->point3d();
00084         double dy = prodPos.y() - decPos.y();
00085         double dx = prodPos.x() - decPos.x();
00086         return add_quad(dx, dy);
00087       }
00088       return numeric_limits<double>::max();
00089     }
00090 
00091 
00092     bool daughtersSurviveCuts(const Rivet::Particle& p) {
00093       // We require the Kshort or Lambda to decay into two charged
00094       // particles with at least pT = 100 MeV inside acceptance region
00095       const HepMC::GenParticle* genp = p.genParticle();
00096       HepMC::GenVertex* decV  = genp->end_vertex();
00097       bool decision = true;
00098 
00099       if (!decV) return false;
00100       if (decV->particles_out_size() == 2) {
00101         std::vector<double> pTs;
00102         std::vector<int> charges;
00103         std::vector<double> etas;
00104         foreach (HepMC::GenParticle* gp, particles(decV, HepMC::children)) {
00105           pTs.push_back(gp->momentum().perp());
00106           etas.push_back(fabs(gp->momentum().eta()));
00107           charges.push_back( Rivet::PID::threeCharge(gp->pdg_id()) );
00108           // gp->print();
00109         }
00110         if ( (pTs[0]/Rivet::GeV < 0.1) || (pTs[1]/Rivet::GeV < 0.1) ) {
00111           decision = false;
00112           MSG_DEBUG("Failed pT cut: " << pTs[0]/Rivet::GeV << " " << pTs[1]/Rivet::GeV);
00113         }
00114         if ( etas[0] > 2.5 || etas[1] > 2.5 ) {
00115           decision = false;
00116           MSG_DEBUG("Failed eta cut: " << etas[0] << " " << etas[1]);
00117         }
00118         if ( charges[0] * charges[1] >= 0 ) {
00119           decision = false;
00120           MSG_DEBUG("Failed opposite charge cut: " << charges[0] << " " << charges[1]);
00121         }
00122       }
00123       else {
00124         decision = false;
00125         MSG_DEBUG("Failed nDaughters cut: " << decV->particles_out_size());
00126       }
00127 
00128       return decision;
00129     }
00130 
00131     /// Perform the per-event analysis
00132     void analyze(const Event& event) {
00133       const double weight = event.weight();
00134 
00135       // ATLAS MBTS trigger requirement of at least one hit in either hemisphere
00136       if (applyProjection<FinalState>(event, "MBTS").size() < 1) {
00137         MSG_DEBUG("Failed trigger cut");
00138         vetoEvent;
00139       }
00140 
00141       // Veto event also when we find less than 2 particles in the acceptance region of type 211,2212,11,13,321
00142       if (applyProjection<FinalState>(event, "nstable").size() < 2) {
00143         MSG_DEBUG("Failed stable particle cut");
00144         vetoEvent;
00145       }
00146       _sum_w_passed += weight;
00147 
00148       // This ufs holds all the Kaons and Lambdas
00149       const UnstableFinalState& ufs = applyProjection<UnstableFinalState>(event, "UFS");
00150 
00151       // Some conters
00152       int n_KS0 = 0;
00153       int n_LAMBDA = 0;
00154 
00155       // Particle loop
00156       foreach (const Particle& p, ufs.particles()) {
00157 
00158         // General particle quantities
00159         const double pT = p.pT();
00160         const double y = p.rapidity();
00161         const PdgId apid = abs(p.pdgId());
00162 
00163         double flightd = 0.0;
00164 
00165         // Look for Kaons, Lambdas
00166         switch (apid) {
00167 
00168         case PID::K0S:
00169           flightd = getPerpFlightDistance(p);
00170           if (!inRange(flightd/mm, 4., 450.) ) {
00171             MSG_DEBUG("Kaon failed flight distance cut:" << flightd);
00172             break;
00173           }
00174           if (daughtersSurviveCuts(p) ) {
00175             _hist_Ks_y ->fill(y, weight);
00176             _hist_Ks_pT->fill(pT/GeV, weight);
00177             _sum_w_ks += weight;
00178             n_KS0++;
00179           }
00180           break;
00181 
00182         case PID::LAMBDA:
00183           if (pT < 0.5*GeV) { // Lambdas have an additional pT cut of 500 MeV
00184             MSG_DEBUG("Lambda failed pT cut:" << pT/GeV << " GeV");
00185             break;
00186           }
00187           flightd = getPerpFlightDistance(p);
00188           if (!inRange(flightd/mm, 17., 450.)) {
00189             MSG_DEBUG("Lambda failed flight distance cut:" << flightd/mm << " mm");
00190             break;
00191           }
00192           if ( daughtersSurviveCuts(p) ) {
00193             if (p.pdgId() == PID::LAMBDA) {
00194               _temp_lambda_v_y.fill(fabs(y), weight);
00195               _temp_lambda_v_pT.fill(pT/GeV, weight);
00196               _hist_L_y->fill(y, weight);
00197               _hist_L_pT->fill(pT/GeV, weight);
00198               _sum_w_lambda += weight;
00199               n_LAMBDA++;
00200             } else if (p.pdgId() == -PID::LAMBDA) {
00201              _temp_lambdabar_v_y.fill(fabs(y), weight);
00202               _temp_lambdabar_v_pT.fill(pT/GeV, weight);
00203             }
00204           }
00205           break;
00206 
00207         }
00208       }
00209 
00210       // Fill multiplicity histos
00211       _hist_Ks_mult->fill(n_KS0, weight);
00212       _hist_L_mult->fill(n_LAMBDA, weight);
00213     }
00214 
00215 
00216 
00217     /// Normalise histograms etc., after the run
00218     void finalize() {
00219       MSG_DEBUG("# Events that pass the trigger: " << _sum_w_passed);
00220       MSG_DEBUG("# Kshort events: " << _sum_w_ks);
00221       MSG_DEBUG("# Lambda events: " << _sum_w_lambda);
00222 
00223       /// @todo Replace with normalize()?
00224       scale(_hist_Ks_pT,   1.0/_sum_w_ks);
00225       scale(_hist_Ks_y,    1.0/_sum_w_ks);
00226       scale(_hist_Ks_mult, 1.0/_sum_w_passed);
00227 
00228       /// @todo Replace with normalize()?
00229       scale(_hist_L_pT,   1.0/_sum_w_lambda);
00230       scale(_hist_L_y,    1.0/_sum_w_lambda);
00231       scale(_hist_L_mult, 1.0/_sum_w_passed);
00232 
00233       // Division of histograms to obtain lambda_bar/lambda ratios
00234       divide(_temp_lambdabar_v_y, _temp_lambda_v_y, _hist_Ratio_v_y);
00235       divide(_temp_lambdabar_v_pT, _temp_lambda_v_pT, _hist_Ratio_v_pT);
00236     }
00237 
00238 
00239   private:
00240 
00241     /// Counters
00242     double _sum_w_ks, _sum_w_lambda, _sum_w_passed;
00243 
00244     /// @name Persistent histograms
00245     //@{
00246     Histo1DPtr _hist_Ks_pT, _hist_Ks_y, _hist_Ks_mult;
00247     Histo1DPtr _hist_L_pT, _hist_L_y, _hist_L_mult;
00248     Scatter2DPtr _hist_Ratio_v_pT, _hist_Ratio_v_y;
00249     //@}
00250 
00251     /// @name Temporary histograms
00252     //@{
00253     Histo1D _temp_lambda_v_y, _temp_lambdabar_v_y;
00254     Histo1D _temp_lambda_v_pT, _temp_lambdabar_v_pT;
00255     //@}
00256 
00257   };
00258 
00259 
00260   // The hook for the plugin system
00261   DECLARE_RIVET_PLUGIN(ATLAS_2011_I944826);
00262 
00263 }