rivet is hosted by Hepforge, IPPP Durham
CDF_2004_S5839831.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 // "Acosta" underlying event analysis at CDF, inc. "Swiss Cheese"
00003 
00004 #include "Rivet/Analysis.hh"
00005 #include "Rivet/Jet.hh"
00006 #include "Rivet/Projections/Beam.hh"
00007 #include "Rivet/Projections/ChargedFinalState.hh"
00008 #include "Rivet/Projections/FastJets.hh"
00009 #include "Rivet/Projections/TriggerCDFRun0Run1.hh"
00010 
00011 namespace Rivet {
00012 
00013 
00014   /// @brief CDF calo jet underlying event analysis at 630 and 1800 GeV
00015   ///
00016   /// CDF measurement of underlying event using calorimeter jet scales and
00017   /// alignment, particle flow activity in transverse cones, and the Swiss
00018   /// Cheese analysis method, where cones are excluded around the 2 and 3
00019   /// hardest jets.
00020   ///
00021   /// @author Andy Buckley
00022   class CDF_2004_S5839831 : public Analysis {
00023   public:
00024 
00025     /// Constructor: cuts on charged final state are \f$ -1 < \eta < 1 \f$
00026     /// and \f$ p_T > 0.4 \f$ GeV.
00027     CDF_2004_S5839831()
00028       : Analysis("CDF_2004_S5839831")
00029     {
00030     }
00031 
00032 
00033   private:
00034 
00035 
00036     /// @cond CONEUE_DETAIL
00037 
00038     struct ConesInfo {
00039       ConesInfo() : numMax(0), numMin(0), ptMax(0), ptMin(0), ptDiff(0) {}
00040       unsigned int numMax, numMin;
00041       double ptMax, ptMin, ptDiff;
00042     };
00043 
00044     /// @endcond
00045 
00046     ConesInfo _calcTransCones(const double etaLead, const double phiLead,
00047                               const Particles& tracks) {
00048       const double phiTransPlus = mapAngle0To2Pi(phiLead + PI/2.0);
00049       const double phiTransMinus = mapAngle0To2Pi(phiLead - PI/2.0);
00050       MSG_DEBUG("phi_lead = " << phiLead
00051                << " -> trans = (" << phiTransPlus
00052                << ", " << phiTransMinus << ")");
00053 
00054       unsigned int numPlus(0), numMinus(0);
00055       double ptPlus(0), ptMinus(0);
00056       // Run over all charged tracks
00057       foreach (const Particle& t, tracks) {
00058         FourMomentum trackMom = t.momentum();
00059         const double pt = trackMom.pT();
00060 
00061         // Find if track mom is in either transverse cone
00062         if (deltaR(trackMom, etaLead, phiTransPlus) < 0.7) {
00063           ptPlus += pt;
00064           numPlus += 1;
00065         } else if (deltaR(trackMom, etaLead, phiTransMinus) < 0.7) {
00066           ptMinus += pt;
00067           numMinus += 1;
00068         }
00069       }
00070 
00071       ConesInfo rtn;
00072       // Assign N_{min,max} from N_{plus,minus}
00073       rtn.numMax = (ptPlus >= ptMinus) ? numPlus : numMinus;
00074       rtn.numMin = (ptPlus >= ptMinus) ? numMinus : numPlus;
00075       // Assign pT_{min,max} from pT_{plus,minus}
00076       rtn.ptMax = (ptPlus >= ptMinus) ? ptPlus : ptMinus;
00077       rtn.ptMin = (ptPlus >= ptMinus) ? ptMinus : ptPlus;
00078       rtn.ptDiff = fabs(rtn.ptMax - rtn.ptMin);
00079 
00080       MSG_DEBUG("Min cone has " << rtn.numMin << " tracks -> "
00081                << "pT_min = " << rtn.ptMin/GeV << " GeV");
00082       MSG_DEBUG("Max cone has " << rtn.numMax << " tracks -> "
00083                << "pT_max = " << rtn.ptMax/GeV << " GeV");
00084 
00085       return rtn;
00086     }
00087 
00088 
00089     ConesInfo _calcTransCones(const FourMomentum& leadvec,
00090                               const Particles& tracks) {
00091       const double etaLead = leadvec.pseudorapidity();
00092       const double phiLead = leadvec.azimuthalAngle();
00093       return _calcTransCones(etaLead, phiLead, tracks);
00094     }
00095 
00096 
00097     /// @name Analysis methods
00098     //@{
00099 
00100     void init() {
00101       // Set up projections
00102       addProjection(TriggerCDFRun0Run1(), "Trigger");
00103       addProjection(Beam(), "Beam");
00104       const FinalState calofs(-1.2, 1.2);
00105       addProjection(calofs, "CaloFS");
00106       addProjection(FastJets(calofs, FastJets::CDFJETCLU, 0.7), "Jets");
00107       const ChargedFinalState trackfs(-1.2, 1.2, 0.4*GeV);
00108       addProjection(trackfs, "TrackFS");
00109       // Restrict tracks to |eta| < 0.7 for the min bias part.
00110       const ChargedFinalState mbfs(-0.7, 0.7, 0.4*GeV);
00111       addProjection(mbfs, "MBFS");
00112       // Restrict tracks to |eta| < 1 for the Swiss-Cheese part.
00113       const ChargedFinalState cheesefs(-1.0, 1.0, 0.4*GeV);
00114       addProjection(cheesefs, "CheeseFS");
00115       addProjection(FastJets(cheesefs, FastJets::CDFJETCLU, 0.7), "CheeseJets");
00116 
00117       // Book histograms
00118       if (fuzzyEquals(sqrtS()/GeV, 1800, 1E-3)) {
00119         _pt90MaxAvg1800 = bookProfile1D(1, 1, 1);
00120         _pt90MinAvg1800 = bookProfile1D(1, 1, 2);
00121         _pt90Max1800 = bookProfile1D(2, 1, 1);
00122         _pt90Min1800 = bookProfile1D(2, 1, 2);
00123         _pt90Diff1800 = bookProfile1D(2, 1, 3);
00124         _num90Max1800 = bookProfile1D(4, 1, 1);
00125         _num90Min1800 = bookProfile1D(4, 1, 2);
00126         _pTSum1800_2Jet = bookProfile1D(7, 1, 1);
00127         _pTSum1800_3Jet = bookProfile1D(7, 1, 2);
00128 
00129         _pt90Dbn1800Et40 = bookHisto1D(3, 1, 1);
00130         _pt90Dbn1800Et80 = bookHisto1D(3, 1, 2);
00131         _pt90Dbn1800Et120 = bookHisto1D(3, 1, 3);
00132         _pt90Dbn1800Et160 = bookHisto1D(3, 1, 4);
00133         _pt90Dbn1800Et200 = bookHisto1D(3, 1, 5);
00134         _numTracksDbn1800MB = bookHisto1D(5, 1, 1);
00135         _ptDbn1800MB = bookHisto1D(6, 1, 1);
00136       } else if (fuzzyEquals(sqrtS()/GeV, 630, 1E-3)) {
00137         _pt90Max630 = bookProfile1D(8, 1, 1);
00138         _pt90Min630 = bookProfile1D(8, 1, 2);
00139         _pt90Diff630 = bookProfile1D(8, 1, 3);
00140         _pTSum630_2Jet = bookProfile1D(9, 1, 1);
00141         _pTSum630_3Jet = bookProfile1D(9, 1, 2);
00142 
00143         _numTracksDbn630MB = bookHisto1D(10, 1, 1);
00144         _ptDbn630MB = bookHisto1D(11, 1, 1);
00145       }
00146     }
00147 
00148 
00149     /// Do the analysis
00150     void analyze(const Event& event) {
00151       // Trigger
00152       const bool trigger = applyProjection<TriggerCDFRun0Run1>(event, "Trigger").minBiasDecision();
00153       if (!trigger) vetoEvent;
00154 
00155       // Get sqrt(s) and event weight
00156       const double sqrtS = applyProjection<Beam>(event, "Beam").sqrtS();
00157       const double weight = event.weight();
00158 
00159       {
00160         MSG_DEBUG("Running max/min analysis");
00161         vector<Jet> jets = applyProjection<JetAlg>(event, "Jets").jetsByE();
00162         if (!jets.empty()) {
00163           // Leading jet must be in central |eta| < 0.5 region
00164           const Jet leadingjet = jets.front();
00165           const double etaLead = leadingjet.eta();
00166           // Get Et of the leading jet: used to bin histograms
00167           const double ETlead = leadingjet.Et();
00168           MSG_DEBUG("Leading Et = " << ETlead/GeV << " GeV");
00169           if (fabs(etaLead) > 0.5 && ETlead < 15*GeV) {
00170             MSG_DEBUG("Leading jet eta = " << etaLead
00171                      << " not in |eta| < 0.5 & pT > 15 GeV");
00172           } else {
00173             // Multiplicity & pT distributions for sqrt(s) = 630 GeV, 1800 GeV
00174             const Particles tracks = applyProjection<FinalState>(event, "TrackFS").particles();
00175             const ConesInfo cones = _calcTransCones(leadingjet.momentum(), tracks);
00176             if (fuzzyEquals(sqrtS/GeV, 630)) {
00177               _pt90Max630->fill(ETlead/GeV, cones.ptMax/GeV, weight);
00178               _pt90Min630->fill(ETlead/GeV, cones.ptMin/GeV, weight);
00179               _pt90Diff630->fill(ETlead/GeV, cones.ptDiff/GeV, weight);
00180             } else if (fuzzyEquals(sqrtS/GeV, 1800)) {
00181               _num90Max1800->fill(ETlead/GeV, cones.numMax, weight);
00182               _num90Min1800->fill(ETlead/GeV, cones.numMin, weight);
00183               _pt90Max1800->fill(ETlead/GeV, cones.ptMax/GeV, weight);
00184               _pt90Min1800->fill(ETlead/GeV, cones.ptMin/GeV, weight);
00185               _pt90Diff1800->fill(ETlead/GeV, cones.ptDiff/GeV, weight);
00186               _pt90MaxAvg1800->fill(ETlead/GeV, cones.ptMax/GeV, weight); // /numMax
00187               _pt90MinAvg1800->fill(ETlead/GeV, cones.ptMin/GeV, weight); // /numMin
00188               //
00189               const double ptTransTotal = cones.ptMax + cones.ptMin;
00190               if (inRange(ETlead/GeV, 40., 80.)) {
00191                 _pt90Dbn1800Et40->fill(ptTransTotal/GeV, weight);
00192               } else if (inRange(ETlead/GeV, 80., 120.)) {
00193                 _pt90Dbn1800Et80->fill(ptTransTotal/GeV, weight);
00194               } else if (inRange(ETlead/GeV, 120., 160.)) {
00195                 _pt90Dbn1800Et120->fill(ptTransTotal/GeV, weight);
00196               } else if (inRange(ETlead/GeV, 160., 200.)) {
00197                 _pt90Dbn1800Et160->fill(ptTransTotal/GeV, weight);
00198               } else if (inRange(ETlead/GeV, 200., 270.)) {
00199                 _pt90Dbn1800Et200->fill(ptTransTotal/GeV, weight);
00200               }
00201             }
00202 
00203           }
00204         }
00205       }
00206 
00207 
00208       // Fill min bias total track multiplicity histos
00209       {
00210         MSG_DEBUG("Running min bias multiplicity analysis");
00211         const Particles mbtracks = applyProjection<FinalState>(event, "MBFS").particles();
00212         if (fuzzyEquals(sqrtS/GeV, 1800)) {
00213           _numTracksDbn1800MB->fill(mbtracks.size(), weight);
00214         } else if (fuzzyEquals(sqrtS/GeV, 630)) {
00215           _numTracksDbn630MB->fill(mbtracks.size(), weight);
00216         }
00217         // Run over all charged tracks
00218         foreach (const Particle& t, mbtracks) {
00219           FourMomentum trackMom = t.momentum();
00220           const double pt = trackMom.pT();
00221           // Plot total pT distribution for min bias
00222           if (fuzzyEquals(sqrtS/GeV, 1800)) {
00223             _ptDbn1800MB->fill(pt/GeV, weight);
00224           } else if (fuzzyEquals(sqrtS/GeV, 630)) {
00225             _ptDbn630MB->fill(pt/GeV, weight);
00226           }
00227         }
00228       }
00229 
00230 
00231 
00232       // Construct "Swiss Cheese" pT distributions, with pT contributions from
00233       // tracks within R = 0.7 of the 1st, 2nd (and 3rd) jets being ignored. A
00234       // different set of charged tracks, with |eta| < 1.0, is used here, and all
00235       // the removed jets must have Et > 5 GeV.
00236       {
00237         MSG_DEBUG("Running Swiss Cheese analysis");
00238         const Particles cheesetracks = applyProjection<FinalState>(event, "CheeseFS").particles();
00239         vector<Jet> cheesejets = applyProjection<JetAlg>(event, "Jets").jetsByE();
00240         if (cheesejets.empty()) {
00241           MSG_DEBUG("No 'cheese' jets found in event");
00242           return;
00243         }
00244         if (cheesejets.size() > 1 &&
00245             fabs(cheesejets[0].momentum().pseudorapidity()) <= 0.5 &&
00246             cheesejets[0].momentum().Et()/GeV > 5.0 &&
00247             cheesejets[1].momentum().Et()/GeV > 5.0) {
00248 
00249           const double cheeseETlead = cheesejets[0].momentum().Et();
00250 
00251           const double eta1 = cheesejets[0].momentum().pseudorapidity();
00252           const double phi1 = cheesejets[0].momentum().azimuthalAngle();
00253           const double eta2 = cheesejets[1].momentum().pseudorapidity();
00254           const double phi2 = cheesejets[1].momentum().azimuthalAngle();
00255 
00256           double ptSumSub2(0), ptSumSub3(0);
00257           foreach (const Particle& t, cheesetracks) {
00258             FourMomentum trackMom = t.momentum();
00259             const double pt = trackMom.pT();
00260 
00261             // Subtracting 2 leading jets
00262             const double deltaR1 = deltaR(trackMom, eta1, phi1);
00263             const double deltaR2 = deltaR(trackMom, eta2, phi2);
00264             MSG_TRACE("Track vs jet(1): "
00265                      << "|(" << trackMom.pseudorapidity() << ", " << trackMom.azimuthalAngle() << ") - "
00266                      << "|(" << eta1 << ", " << phi1 << ")| = " << deltaR1);
00267             MSG_TRACE("Track vs jet(2): "
00268                      << "|(" << trackMom.pseudorapidity() << ", " << trackMom.azimuthalAngle() << ") - "
00269                      << "|(" << eta2 << ", " << phi2 << ")| = " << deltaR2);
00270             if (deltaR1 > 0.7 && deltaR2 > 0.7) {
00271               ptSumSub2 += pt;
00272 
00273               // Subtracting 3rd leading jet
00274               if (cheesejets.size() > 2 &&
00275                   cheesejets[2].momentum().Et()/GeV > 5.0) {
00276                 const double eta3 = cheesejets[2].momentum().pseudorapidity();
00277                 const double phi3 = cheesejets[2].momentum().azimuthalAngle();
00278                 const double deltaR3 = deltaR(trackMom, eta3, phi3);
00279                 MSG_TRACE("Track vs jet(3): "
00280                          << "|(" << trackMom.pseudorapidity() << ", " << trackMom.azimuthalAngle() << ") - "
00281                          << "|(" << eta3 << ", " << phi3 << ")| = " << deltaR3);
00282                 if (deltaR3 > 0.7) {
00283                   ptSumSub3 += pt;
00284                 }
00285               }
00286             }
00287           }
00288 
00289           // Swiss Cheese sub 2,3 jets distributions for sqrt(s) = 630 GeV, 1800 GeV
00290           if (fuzzyEquals(sqrtS/GeV, 630)) {
00291             if (!isZero(ptSumSub2)) _pTSum630_2Jet->fill(cheeseETlead/GeV, ptSumSub2/GeV, weight);
00292             if (!isZero(ptSumSub3))_pTSum630_3Jet->fill(cheeseETlead/GeV, ptSumSub3/GeV, weight);
00293           } else if (fuzzyEquals(sqrtS/GeV, 1800)) {
00294             if (!isZero(ptSumSub2))_pTSum1800_2Jet->fill(cheeseETlead/GeV, ptSumSub2/GeV, weight);
00295             if (!isZero(ptSumSub3))_pTSum1800_3Jet->fill(cheeseETlead/GeV, ptSumSub3/GeV, weight);
00296           }
00297 
00298         }
00299       }
00300 
00301     }
00302 
00303 
00304     void finalize() {
00305       /// @todo Take these normalisations from the data histo (it can't come from just the MC)
00306 
00307       if (fuzzyEquals(sqrtS()/GeV, 1800, 1E-3)) {
00308         // Normalize to actual number of entries in pT dbn histos...
00309         normalize(_pt90Dbn1800Et40,  1656.75); // norm OK
00310         normalize(_pt90Dbn1800Et80,  4657.5); // norm OK
00311         normalize(_pt90Dbn1800Et120, 5395.5); // norm OK
00312         normalize(_pt90Dbn1800Et160, 7248.75); // norm OK
00313         normalize(_pt90Dbn1800Et200, 2442.0); // norm OK
00314       }
00315 
00316       // ...and for min bias distributions:
00317       if (fuzzyEquals(sqrtS()/GeV, 1800, 1E-3)) {
00318         normalize(_numTracksDbn1800MB, 309718.25); // norm OK
00319         normalize(_ptDbn1800MB, 33600.0); // norm OK
00320       } else if (fuzzyEquals(sqrtS()/GeV, 630, 1E-3)) {
00321         normalize(_numTracksDbn630MB, 1101024.0); // norm OK
00322         normalize(_ptDbn630MB, 105088.0); // norm OK
00323       }
00324     }
00325 
00326     //@}
00327 
00328 
00329   private:
00330 
00331     /// @name Histogram collections
00332     //@{
00333     /// Profile histograms, binned in the \f$ E_T \f$ of the leading jet, for
00334     /// the average \f$ p_T \f$ in the toward, transverse and away regions at
00335     /// \f$ \sqrt{s} = 1800 \text{GeV} \f$.
00336     /// Corresponds to Table 1, and HepData table 1.
00337     Profile1DPtr _pt90MaxAvg1800, _pt90MinAvg1800;
00338 
00339     /// Profile histograms, binned in the \f$ E_T \f$ of the leading jet, for
00340     /// the \f$ p_T \f$ sum in the toward, transverse and away regions at
00341     /// \f$ \sqrt{s} = 1800 \text{GeV} \f$.
00342     /// Corresponds to figure 2/3, and HepData table 2.
00343     Profile1DPtr _pt90Max1800, _pt90Min1800, _pt90Diff1800;
00344 
00345     /// Profile histograms, binned in the \f$ E_T \f$ of the leading jet, for
00346     /// the \f$ p_T \f$ sum in the toward, transverse and away regions at
00347     /// at \f$ \sqrt{s} = 630 \text{GeV} \f$.
00348     /// Corresponds to figure 8, and HepData table 8.
00349     Profile1DPtr _pt90Max630, _pt90Min630, _pt90Diff630;
00350 
00351     /// Profile histograms, binned in the \f$ E_T \f$ of the leading jet, for
00352     /// the cone track multiplicity at \f$ \sqrt{s} = 1800 \text{GeV} \f$.
00353     /// Corresponds to figure 5, and HepData table 4.
00354     Profile1DPtr _num90Max1800, _num90Min1800;
00355 
00356     /// Profile histograms, binned in the \f$ E_T \f$ of the leading jet, for
00357     /// the \f$ p_T \f$ sum at \f$ \sqrt{s} = 1800 \text{GeV} \f$.
00358     /// Corresponds to figure 7, and HepData table 7.
00359     Profile1DPtr _pTSum1800_2Jet, _pTSum1800_3Jet;
00360 
00361     /// Profile histograms, binned in the \f$ E_T \f$ of the leading jet, for
00362     /// the \f$ p_T \f$ sum at \f$ \sqrt{s} = 630 \text{GeV} \f$.
00363     /// Corresponds to figure 9, and HepData table 9.
00364     Profile1DPtr _pTSum630_2Jet, _pTSum630_3Jet;
00365 
00366     /// Histogram of \f$ p_{T\text{sum}} \f$ distribution for 5 different
00367     /// \f$ E_{T1} \f$ bins.
00368     /// Corresponds to figure 4, and HepData table 3.
00369     Histo1DPtr _pt90Dbn1800Et40, _pt90Dbn1800Et80, _pt90Dbn1800Et120,
00370       _pt90Dbn1800Et160, _pt90Dbn1800Et200;
00371 
00372     /// Histograms of track multiplicity and \f$ p_T \f$ distributions for
00373     /// minimum bias events.
00374     /// Figure 6, and HepData tables 5 & 6.
00375     /// Figure 10, and HepData tables 10 & 11.
00376     Histo1DPtr _numTracksDbn1800MB, _ptDbn1800MB;
00377     Histo1DPtr _numTracksDbn630MB, _ptDbn630MB;
00378     //@}
00379 
00380   };
00381 
00382 
00383 
00384   // The hook for the plugin system
00385   DECLARE_RIVET_PLUGIN(CDF_2004_S5839831);
00386 
00387 }