D0_2001_S4674421.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 #include "Rivet/Analysis.hh"
00003 #include "Rivet/RivetAIDA.hh"
00004 #include "Rivet/Tools/Logging.hh"
00005 #include "Rivet/Tools/ParticleIdUtils.hh"
00006 #include "Rivet/Projections/LeadingParticlesFinalState.hh"
00007 #include "Rivet/Projections/VetoedFinalState.hh"
00008 
00009 namespace Rivet {
00010 
00011 
00012   /// @brief D0 Run I differential W/Z boson cross-section analysis
00013   /// @author Lars Sonnenschein
00014   class D0_2001_S4674421 : public Analysis {
00015   public:
00016 
00017     /// @name Constructors etc.
00018     //@{
00019 
00020     /// Constructor.
00021     D0_2001_S4674421() : Analysis("D0_2001_S4674421") {
00022       setBeams(PROTON, ANTIPROTON);
00023       setNeedsCrossSection(true);
00024     }
00025  
00026  
00027     /// @name Analysis methods
00028     //@{
00029  
00030     void init() {
00031       // Final state projection
00032       FinalState fs(-5.0, 5.0); // corrected for detector acceptance
00033       addProjection(fs, "FS");
00034 
00035       // Z -> e- e+
00036       LeadingParticlesFinalState eeFS(FinalState(-2.5, 2.5, 0.)); //20.);
00037       eeFS.addParticleIdPair(ELECTRON);
00038       addProjection(eeFS, "eeFS");
00039    
00040       // W- -> e- nu_e~
00041       LeadingParticlesFinalState enuFS(FinalState(-2.5, 2.5, 0.)); //25.);
00042       enuFS.addParticleId(ELECTRON).addParticleId(NU_EBAR);
00043       addProjection(enuFS, "enuFS");
00044    
00045       // W+ -> e+ nu_e
00046       LeadingParticlesFinalState enubFS(FinalState(-2.5, 2.5, 0.)); //25.);
00047       enubFS.addParticleId(POSITRON).addParticleId(NU_E);
00048       addProjection(enubFS, "enubFS");
00049 
00050       // Remove neutrinos for isolation of final state particles
00051       VetoedFinalState vfs(fs);
00052       vfs.vetoNeutrinos();
00053       addProjection(vfs, "VFS");
00054 
00055       // Counters
00056       _eventsFilledW = 0.0;
00057       _eventsFilledZ = 0.0;
00058 
00059       // Histograms
00060       _h_dsigdpt_w = bookHistogram1D(1, 1, 1);
00061       _h_dsigdpt_z = bookHistogram1D(1, 1, 2);
00062       _h_dsigdpt_scaled_z = bookDataPointSet(2, 1, 1);
00063     }
00064 
00065 
00066 
00067     void analyze(const Event& event) {
00068       const double weight = event.weight();
00069 
00070       const LeadingParticlesFinalState& eeFS = applyProjection<LeadingParticlesFinalState>(event, "eeFS");
00071       if (eeFS.particles().size() == 2) {
00072         // If there is a Z candidate:
00073         static size_t Zcount = 0;
00074         // Fill Z pT distributions
00075         const ParticleVector& Zdaughters = eeFS.particles();
00076         const FourMomentum pmom = Zdaughters[0].momentum() + Zdaughters[1].momentum();
00077         double mass = sqrt(pmom.invariant());
00078         if (inRange(mass/GeV, 75.0, 105.0)) {
00079           ++Zcount;
00080           _eventsFilledZ += weight;
00081           //getLog() << Log::DEBUG << "Z #" << Zcount << " pmom.pT() = " << pmom.pT()/GeV << " GeV" << endl;
00082           _h_dsigdpt_z->fill(pmom.pT()/GeV, weight);
00083         }
00084       } else {
00085         // There is no Z -> ee candidate... so this must be a W event, right?
00086         const LeadingParticlesFinalState& enuFS = applyProjection<LeadingParticlesFinalState>(event, "enuFS");
00087         const LeadingParticlesFinalState& enubFS = applyProjection<LeadingParticlesFinalState>(event, "enubFS");
00088         static size_t Wcount = 0;
00089 
00090         // Fill W pT distributions
00091         ParticleVector Wdaughters;
00092         if (enuFS.particles().size() == 2 && enubFS.empty()) {
00093           Wdaughters = enuFS.particles();
00094         } else if (enuFS.empty() && enubFS.particles().size() == 2) {
00095           Wdaughters = enubFS.particles();
00096         }
00097         if (! Wdaughters.empty()) {
00098           assert(Wdaughters.size() == 2);
00099           const FourMomentum pmom = Wdaughters[0].momentum() + Wdaughters[1].momentum();
00100           ++Wcount;
00101           _eventsFilledW += weight;
00102           _h_dsigdpt_w->fill(pmom.pT()/GeV, weight);
00103         }
00104       }
00105     }
00106 
00107 
00108 
00109     void finalize() {
00110       // Get cross-section per event (i.e. per unit weight) from generator
00111       const double xSecPerEvent = crossSectionPerEvent()/picobarn;
00112 
00113       // Correct W pT distribution to W cross-section
00114       const double xSecW = xSecPerEvent * _eventsFilledW;
00115 
00116       // Correct Z pT distribution to Z cross-section
00117       const double xSecZ = xSecPerEvent * _eventsFilledZ;
00118 
00119       // Get W and Z pT integrals
00120       const double wpt_integral = integral(_h_dsigdpt_w);
00121       const double zpt_integral = integral(_h_dsigdpt_z);
00122 
00123       // Divide and scale ratio histos
00124       if (xSecW == 0 || wpt_integral == 0 || xSecZ == 0 || zpt_integral == 0) {
00125         getLog() << Log::WARN << "Not filling ratio plot because input histos are empty" << endl;
00126       } else {
00127         std::vector<double> xval;
00128         std::vector<double> xerr;
00129         std::vector<double> yval;
00130         std::vector<double> yerr;
00131 
00132         // Scale factor converts event counts to cross-sections, and inverts the
00133         // branching ratios since only one decay channel has been analysed for each boson.
00134         // Oh, and we put MW/MZ in, like they do in the paper.
00135         const double MW_MZ = 0.8820; // Ratio M_W/M_Z
00136         const double BRZEE_BRWENU = 0.033632 / 0.1073; // Ratio of branching fractions
00137         const double scalefactor = (xSecW / wpt_integral) / (xSecZ / zpt_integral) * MW_MZ * BRZEE_BRWENU;
00138         for (int ibin=0; ibin<_h_dsigdpt_scaled_z->size(); ibin++) {
00139           /// @todo I would love to use axis().binMidPoint(ibin) here, but this #*&$*^%$ LWH IAxis doesn't have it!!!!
00140           ///       It's only in Axis and VariAxis, but doesn't get passed through to the user. I WANT YODA!!! *SIGH*
00141           xval.push_back(0.5*(_h_dsigdpt_w->axis().binUpperEdge(ibin)+_h_dsigdpt_w->axis().binLowerEdge(ibin)));
00142           xerr.push_back(0.5*_h_dsigdpt_w->axis().binWidth(ibin));
00143           if (_h_dsigdpt_w->binHeight(ibin) == 0 || _h_dsigdpt_z->binHeight(ibin) == 0) {
00144             yval.push_back(0.);
00145             yerr.push_back(0.);
00146           } else {
00147             yval.push_back(scalefactor * _h_dsigdpt_w->binHeight(ibin) / _h_dsigdpt_z->binHeight(ibin));
00148             double dy2 = 0.;
00149             // binWidth(ibin) is needed because binHeight is actually sumofweights. It's AIDA. Don't ask.  :-((((
00150             dy2 += pow(_h_dsigdpt_w->binError(ibin)/_h_dsigdpt_w->binHeight(ibin)*_h_dsigdpt_w->axis().binWidth(ibin),2);
00151             dy2 += pow(_h_dsigdpt_z->binError(ibin)/_h_dsigdpt_z->binHeight(ibin)*_h_dsigdpt_z->axis().binWidth(ibin),2);
00152             double dy = scalefactor * _h_dsigdpt_w->binHeight(ibin)/_h_dsigdpt_z->binHeight(ibin) * sqrt(dy2);
00153             yerr.push_back(dy);
00154           }
00155         }
00156         _h_dsigdpt_scaled_z->setCoordinate(0, xval, xerr);
00157         _h_dsigdpt_scaled_z->setCoordinate(1, yval, yerr);
00158       }
00159 
00160       // Normalize non-ratio histos
00161       normalize(_h_dsigdpt_w, xSecW);
00162       normalize(_h_dsigdpt_z, xSecZ);
00163 
00164     }
00165 
00166 
00167     //@}
00168  
00169   private:
00170 
00171     /// @name Event counters for cross section normalizations
00172     //@{
00173     double _eventsFilledW;
00174     double _eventsFilledZ;
00175     //@}
00176 
00177     //@{
00178     /// Histograms
00179     AIDA::IHistogram1D*  _h_dsigdpt_w;
00180     AIDA::IHistogram1D*  _h_dsigdpt_z;
00181     AIDA::IDataPointSet* _h_dsigdpt_scaled_z;
00182     //@}
00183 
00184   };
00185 
00186 
00187 
00188   // This global object acts as a hook for the plugin system
00189   AnalysisBuilder<D0_2001_S4674421> plugin_D0_2001_S4674421;
00190 
00191 }