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