rivet is hosted by Hepforge, IPPP Durham
ATLAS_2012_I1084540.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /**
00003  * @name ATLAS Diffractive Gaps Rivet Analysis
00004  * @author Tim Martin, tim.martin@cern.ch
00005  * @version 1.0
00006  * @date 16/01/2012
00007  * @see http://arxiv.org/abs/1201.2808
00008  * @note pp, sqrt(s) = 7 TeV
00009  * @note Rapidity gap finding algorithm designed to compliment
00010  * the ATLAS detector acceptance. Forward rapidity gap sizes
00011  * are calculated for each event, considering all stable
00012  * particles above pT cut values 200, 400, 600 and 800 MeV in
00013  * turn. A forward rapidity gap is defined to be the largest
00014  * continuous region stretching inward from either edge of the
00015  * detector at eta = |4.9| which contains zero particles above
00016  * pT Cut. Soft diffractive topologies are isolated at large
00017  * gap sizes.
00018  *
00019  */
00020 #include "Rivet/Analysis.hh"
00021 #include "Rivet/RivetYODA.hh"
00022 #include "Rivet/Tools/Logging.hh"
00023 #include "Rivet/Projections/FinalState.hh"
00024 
00025 namespace Rivet {
00026 
00027 
00028   class ATLAS_2012_I1084540 : public Analysis {
00029   public:
00030 
00031     ATLAS_2012_I1084540() : Analysis("ATLAS_2012_I1084540"), _etaBins(49), _etaMax(4.9) {
00032     }
00033 
00034 
00035     /// @name Analysis methods
00036     //@{
00037     /// Book histograms and initialise projections before the run
00038     void init() {
00039       //All final states. Rapidity range = ATLAS calorimetry. Lowest pT cut = 200 MeV.
00040       const FinalState cnfs2(-_etaMax, _etaMax, 0.2 * GeV);
00041       const FinalState cnfs4(-_etaMax, _etaMax, 0.4 * GeV);
00042       const FinalState cnfs6(-_etaMax, _etaMax, 0.6 * GeV);
00043       const FinalState cnfs8(-_etaMax, _etaMax, 0.8 * GeV);
00044       addProjection(cnfs2, "CNFS2");
00045       addProjection(cnfs4, "CNFS4");
00046       addProjection(cnfs6, "CNFS6");
00047       addProjection(cnfs8, "CNFS8");
00048 
00049       _etaBinSize = (2. * _etaMax)/(double)_etaBins;
00050 
00051       //Book histogram
00052       _h_DeltaEtaF_200 = bookHisto1D(1, 1, 1);
00053       _h_DeltaEtaF_400 = bookHisto1D(2, 1, 1);
00054       _h_DeltaEtaF_600 = bookHisto1D(3, 1, 1);
00055       _h_DeltaEtaF_800 = bookHisto1D(4, 1, 1);
00056     }
00057 
00058   private:
00059     void fillMap(const FinalState& fs, bool* energyMap, double pTcut) {
00060       // Fill true/false array by iterating over particles and compare their
00061       // pT with pTcut
00062       foreach (const Particle& p, fs.particlesByEta()) {
00063         int checkBin = -1;
00064         double checkEta = -_etaMax;
00065         while (1) {
00066           checkEta += _etaBinSize;
00067           ++checkBin;
00068           if (p.momentum().eta() < checkEta) {
00069             energyMap[checkBin] = (p.momentum().pT() > pTcut * GeV);
00070             break;
00071           }
00072         }
00073       }
00074     }
00075 
00076   public:
00077     /// Perform the per-event analysis
00078     void analyze(const Event& event) {
00079       static unsigned int event_count = 0;
00080       ++event_count;
00081       const double weight = event.weight();
00082       const FinalState& fs2 = applyProjection<FinalState>(event, "CNFS2");
00083       const FinalState& fs4 = applyProjection<FinalState>(event, "CNFS4");
00084       const FinalState& fs6 = applyProjection<FinalState>(event, "CNFS6");
00085       const FinalState& fs8 = applyProjection<FinalState>(event, "CNFS8");
00086 
00087       // Set up Yes/No arrays for energy in each eta bin at each pT cut
00088       bool* energyMap_200 = new bool[_etaBins];
00089       bool* energyMap_400 = new bool[_etaBins];
00090       bool* energyMap_600 = new bool[_etaBins];
00091       bool* energyMap_800 = new bool[_etaBins];
00092       for (int i = 0; i < _etaBins; ++i) {
00093         energyMap_200[i] = false;
00094         energyMap_400[i] = false;
00095         energyMap_600[i] = false;
00096         energyMap_800[i] = false;
00097       }
00098 
00099       // Veto bins based on final state particles > Cut (Where Cut = 200 - 800 MeV pT)
00100       fillMap(fs2, energyMap_200, 0.2);
00101       fillMap(fs4, energyMap_400, 0.4);
00102       fillMap(fs6, energyMap_600, 0.6);
00103       fillMap(fs8, energyMap_800, 0.8);
00104 
00105       // Apply gap finding algorithm
00106       // Detector layout follows...
00107       // -Eta [Proton  ---  DetectorCSide  ---  DetectorBarrel  ---  DetectorASide  ---  Proton] +Eta
00108       bool gapDirectionAt200 = false; //False is gap on C size, True is gap on A side.
00109       double largestEdgeGap_200 = 0.;
00110       double largestEdgeGap_400 = 0.;
00111       double largestEdgeGap_600 = 0.;
00112       double largestEdgeGap_800 = 0.;
00113 
00114       for (int E = 200; E <= 800; E += 200) {
00115         double EdgeGapSizeA = -1, EdgeGapSizeC = -1;
00116         bool* energyMap = 0;
00117         switch (E) {
00118           case 200: energyMap = energyMap_200; break;
00119           case 400: energyMap = energyMap_400; break;
00120           case 600: energyMap = energyMap_600; break;
00121           case 800: energyMap = energyMap_800; break;
00122         }
00123 
00124         // Look left to right
00125         for (int a = 0; a < _etaBins; ++a) {
00126           if (energyMap[a] == true) {
00127             EdgeGapSizeA = (_etaBinSize * a);
00128             break;
00129           }
00130         }
00131 
00132         // And look right to left
00133         for (int c = _etaBins-1; c >= 0; --c) {
00134           if (energyMap[c] == true) {
00135             EdgeGapSizeC = (2 * _etaMax) - (_etaBinSize * (c+1));
00136             if (fuzzyEquals(EdgeGapSizeC, 4.47035e-08)) EdgeGapSizeC = 0.0;
00137             break;
00138           }
00139         }
00140         // Put your hands on your hips
00141 
00142         // Find the largest gap
00143         double largestEdgeGap = 0.;
00144         if (E == 200) {
00145           // If the 200 MeV pass, take the biggest of the two gaps. Make note of which side for higher pT cuts.
00146           largestEdgeGap = std::max(EdgeGapSizeA,EdgeGapSizeC);
00147           gapDirectionAt200 = (EdgeGapSizeA > EdgeGapSizeC);
00148         } else {
00149           // Use the direction from 200 MeV pass, most accurate measure of which side gap is on.
00150           if (gapDirectionAt200) {
00151             largestEdgeGap = EdgeGapSizeA;
00152           }
00153           else largestEdgeGap = EdgeGapSizeC;
00154         }
00155 
00156         // Check case of empty detector
00157         if (largestEdgeGap < 0.0) largestEdgeGap = 2.0 * _etaMax;
00158 
00159         // Fill bin centre
00160         switch (E) {
00161           case 200: _h_DeltaEtaF_200->fill(largestEdgeGap + _etaBinSize/2., weight); break;
00162           case 400: _h_DeltaEtaF_400->fill(largestEdgeGap + _etaBinSize/2., weight); break;
00163           case 600: _h_DeltaEtaF_600->fill(largestEdgeGap + _etaBinSize/2., weight); break;
00164           case 800: _h_DeltaEtaF_800->fill(largestEdgeGap + _etaBinSize/2., weight); break;
00165         }
00166 
00167         if (E == 200) largestEdgeGap_200 = largestEdgeGap;
00168         if (E == 400) largestEdgeGap_400 = largestEdgeGap;
00169         if (E == 600) largestEdgeGap_600 = largestEdgeGap;
00170         if (E == 800) largestEdgeGap_800 = largestEdgeGap;
00171       }
00172 
00173       // Algorithm result every 1000 events
00174       if (event_count % 1000 == 0) {
00175         for (int E = 200; E <= 800; E += 200) {
00176           bool* energyMap = 0;
00177           double largestEdgeGap = 0;
00178           switch (E) {
00179             case 200: energyMap = energyMap_200; largestEdgeGap = largestEdgeGap_200; break;
00180             case 400: energyMap = energyMap_400; largestEdgeGap = largestEdgeGap_400; break;
00181             case 600: energyMap = energyMap_600; largestEdgeGap = largestEdgeGap_600; break;
00182             case 800: energyMap = energyMap_800; largestEdgeGap = largestEdgeGap_800; break;
00183           }
00184           MSG_DEBUG("Largest Forward Gap at pT Cut " << E << " MeV=" << largestEdgeGap
00185             << " eta, NFinalState pT > 200 in ATLAS acceptance:" << fs2.particles().size());
00186           std::string hitPattern = "Detector HitPattern=-4.9[";
00187           for (int a = 0; a < _etaBins; ++a) {
00188             if (energyMap[a] == true) hitPattern += "X";
00189             else hitPattern += "_";
00190           }
00191           hitPattern += "]4.9";
00192           MSG_DEBUG(hitPattern);
00193           std::string gapArrow = "                         ";
00194             if (!gapDirectionAt200) {
00195             int drawSpaces = (int)(_etaBins - (largestEdgeGap/_etaBinSize) + 0.5);
00196             for (int i = 0; i < drawSpaces; ++i) gapArrow += " ";
00197           }
00198           int drawArrows = (int)((largestEdgeGap/_etaBinSize) + 0.5);
00199           for (int i = 0; i < drawArrows; ++i) gapArrow += "^";
00200           MSG_DEBUG(gapArrow);
00201         }
00202       }
00203 
00204       delete[] energyMap_200;
00205       delete[] energyMap_400;
00206       delete[] energyMap_600;
00207       delete[] energyMap_800;
00208     }
00209 
00210     /// Normalise histograms after the run, Scale to cross section
00211     void finalize() {
00212       MSG_DEBUG("Cross Section=" << crossSection() / millibarn << "mb, SumOfWeights=" << sumOfWeights());
00213       scale(_h_DeltaEtaF_200, (crossSection() / millibarn)/sumOfWeights());
00214       scale(_h_DeltaEtaF_400, (crossSection() / millibarn)/sumOfWeights());
00215       scale(_h_DeltaEtaF_600, (crossSection() / millibarn)/sumOfWeights());
00216       scale(_h_DeltaEtaF_800, (crossSection() / millibarn)/sumOfWeights());
00217     }
00218     //@}
00219 
00220   private:
00221     /// @name Histograms
00222     //@{
00223     Histo1DPtr _h_DeltaEtaF_200;
00224     Histo1DPtr _h_DeltaEtaF_400;
00225     Histo1DPtr _h_DeltaEtaF_600;
00226     Histo1DPtr _h_DeltaEtaF_800;
00227     //@}
00228     /// @name Private variables
00229     //@{
00230     int _etaBins;
00231     double _etaMax;
00232     double _etaBinSize;
00233     //@}
00234   };
00235 
00236   // The hook for the plugin system
00237   DECLARE_RIVET_PLUGIN(ATLAS_2012_I1084540);
00238 
00239 }