rivet is hosted by Hepforge, IPPP Durham
ATLAS_2012_I1094564.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 #include "Rivet/Analysis.hh"
00003 #include "Rivet/Projections/FinalState.hh"
00004 #include "Rivet/Projections/FastJets.hh"
00005 #include "Rivet/Tools/BinnedHistogram.hh"
00006 
00007 namespace Rivet {
00008 
00009 
00010   /// ATLAS jet substructure measurement
00011   class ATLAS_2012_I1094564 : public Analysis {
00012   public:
00013 
00014     ATLAS_2012_I1094564()
00015       : Analysis("ATLAS_2012_I1094564")
00016     {}
00017 
00018 
00019     // Returns constituents to make it easier to do the filtering
00020     PseudoJets splitjet(fastjet::PseudoJet jet, double& last_R, const FastJets& fj, bool& unclustered) const {
00021 
00022       // Build a new cluster sequence just using the constituents of this jet.
00023       fastjet::ClusterSequence cs(fj.clusterSeq()->constituents(jet), fastjet::JetDefinition(fastjet::cambridge_algorithm, M_PI/2.));
00024 
00025       // Get the jet back again
00026       vector<fastjet::PseudoJet> remadeJets = cs.inclusive_jets(0.);
00027 
00028       if ( remadeJets.size() != 1 ) return remadeJets;
00029 
00030       fastjet::PseudoJet remadeJet = remadeJets[0];
00031       fastjet::PseudoJet parent1, parent2;
00032       unclustered = false;
00033 
00034       while ( cs.has_parents(remadeJet, parent1, parent2) ) {
00035         if (parent1.squared_distance(parent2) < 0.09) break;
00036         if (parent1.m2() < parent2.m2()) {
00037           fastjet::PseudoJet tmp;
00038           tmp = parent1; parent1 = parent2; parent2 = tmp;
00039         }
00040 
00041         double ktdist = parent1.kt_distance(parent2);
00042         double rtycut2 = 0.3*0.3;
00043         if (parent1.m() < 0.67*remadeJet.m() && ktdist > rtycut2*remadeJet.m2()) {
00044           unclustered = true;
00045           break;
00046         } else {
00047           remadeJet = parent1;
00048         }
00049       }
00050 
00051       last_R = 0.5 * sqrt(parent1.squared_distance(parent2));
00052       return cs.constituents(remadeJet);
00053     }
00054 
00055 
00056     fastjet::PseudoJet filterjet(PseudoJets jets, double& stingy_R, const double def_R) const {
00057       if (stingy_R == 0.0) stingy_R = def_R;
00058       stingy_R = def_R < stingy_R ? def_R : stingy_R;
00059       fastjet::JetDefinition stingy_jet_def(fastjet::cambridge_algorithm, stingy_R);
00060       fastjet::ClusterSequence scs(jets, stingy_jet_def);
00061       vector<fastjet::PseudoJet> stingy_jets = sorted_by_pt(scs.inclusive_jets(0));
00062       fastjet::PseudoJet reconst_jet(0, 0, 0, 0);
00063       for (size_t isj = 0; isj < std::min((size_t) 3, stingy_jets.size()); ++isj) {
00064         reconst_jet += stingy_jets[isj];
00065       }
00066       return reconst_jet;
00067     }
00068 
00069 
00070     // These are custom functions for n-subjettiness.
00071     PseudoJets jetGetAxes(int n_jets, const PseudoJets& inputJets, double subR) const {
00072       // Sanity check
00073       if (inputJets.size() < (size_t) n_jets) {
00074         MSG_ERROR("Not enough input particles.");
00075         return inputJets;
00076       }
00077 
00078       // Get subjets, return
00079       fastjet::ClusterSequence sub_clust_seq(inputJets, fastjet::JetDefinition(fastjet::kt_algorithm, subR, fastjet::E_scheme, fastjet::Best));
00080       return sub_clust_seq.exclusive_jets(n_jets);
00081     }
00082 
00083 
00084     double jetTauValue(double beta, double jet_rad, const PseudoJets& particles, const PseudoJets& axes, double Rcut) const {
00085       double tauNum = 0.0;
00086       double tauDen = 0.0;
00087 
00088       if (particles.size() == 0) return 0.0;
00089 
00090       for (size_t i = 0; i < particles.size(); i++) {
00091         // find minimum distance (set R large to begin)
00092         double minR = 10000.0;
00093         for (size_t j = 0; j < axes.size(); j++) {
00094           double tempR = sqrt(particles[i].squared_distance(axes[j]));
00095           if (tempR < minR) minR = tempR;
00096         }
00097         if (minR > Rcut) minR = Rcut;
00098         // calculate nominator and denominator
00099         tauNum += particles[i].perp() * pow(minR,beta);
00100         tauDen += particles[i].perp() * pow(jet_rad,beta);
00101       }
00102 
00103       // return N-subjettiness (or 0 if denominator is 0)
00104       return safediv(tauNum, tauDen, 0);
00105     }
00106 
00107 
00108     void jetUpdateAxes(double beta, const PseudoJets& particles, PseudoJets& axes) const {
00109       vector<int> belongsto;
00110       for (size_t i = 0; i < particles.size(); i++) {
00111         // find minimum distance axis
00112         int assign = 0;
00113         double minR = 10000.0;
00114         for (size_t j = 0; j < axes.size(); j++) {
00115           double tempR = sqrt(particles[i].squared_distance(axes[j]));
00116           if (tempR < minR) {
00117             minR = tempR;
00118             assign = j;
00119           }
00120         }
00121         belongsto.push_back(assign);
00122       }
00123 
00124       // iterative step
00125       double deltaR2, distphi;
00126       vector<double> ynom, phinom, den;
00127 
00128       ynom.resize(axes.size());
00129       phinom.resize(axes.size());
00130       den.resize(axes.size());
00131 
00132       for (size_t i = 0; i < particles.size(); i++) {
00133         distphi = particles[i].phi() - axes[belongsto[i]].phi();
00134         deltaR2 = particles[i].squared_distance(axes[belongsto[i]]);
00135         if (deltaR2 == 0.) continue;
00136         if (abs(distphi) <= M_PI) phinom.at(belongsto[i]) += particles[i].perp() * particles[i].phi() * pow(deltaR2, (beta-2)/2);
00137         else if ( distphi > M_PI) phinom.at(belongsto[i]) += particles[i].perp() * (-2 * M_PI + particles[i].phi()) * pow(deltaR2, (beta-2)/2);
00138         else if ( distphi < M_PI) phinom.at(belongsto[i]) += particles[i].perp() * (+2 * M_PI + particles[i].phi()) * pow(deltaR2, (beta-2)/2);
00139         ynom.at(belongsto[i]) += particles[i].perp() * particles[i].rap() * pow(deltaR2, (beta-2)/2);
00140         den.at(belongsto[i])  += particles[i].perp() * pow(deltaR2, (beta-2)/2);
00141       }
00142 
00143       // reset to new axes
00144       for (size_t j = 0; j < axes.size(); j++) {
00145         if (den[j] == 0.) axes.at(j) = axes[j];
00146         else {
00147           double phi_new = fmod( 2*M_PI + (phinom[j] / den[j]), 2*M_PI );
00148           double pt_new  = axes[j].perp();
00149           double y_new   = ynom[j] / den[j];
00150           double px = pt_new * cos(phi_new);
00151           double py = pt_new * sin(phi_new);
00152           double pz = pt_new * sinh(y_new);
00153           axes.at(j).reset(px, py, pz, axes[j].perp()/2);
00154         }
00155       }
00156     }
00157 
00158 
00159     void init() {
00160 
00161       /// Projections:
00162       FinalState fs(-4.5, 4.5, 0.*GeV);
00163       addProjection(fs, "FS");
00164       addProjection(FastJets(fs, FastJets::ANTIKT, 1.0), "AKT");
00165       addProjection(FastJets(fs, FastJets::CAM, 1.2)   , "CA" );
00166 
00167       /// Histograms:
00168       _h_camass.addHistogram(200, 300, bookHisto1D(1, 1, 1));
00169       _h_camass.addHistogram(300, 400, bookHisto1D(2, 1, 1));
00170       _h_camass.addHistogram(400, 500, bookHisto1D(3, 1, 1));
00171       _h_camass.addHistogram(500, 600, bookHisto1D(4, 1, 1));
00172 
00173       _h_filtmass.addHistogram(200, 300, bookHisto1D(5, 1, 1));
00174       _h_filtmass.addHistogram(300, 400, bookHisto1D(6, 1, 1));
00175       _h_filtmass.addHistogram(400, 500, bookHisto1D(7, 1, 1));
00176       _h_filtmass.addHistogram(500, 600, bookHisto1D(8, 1, 1));
00177 
00178       _h_ktmass.addHistogram(200, 300, bookHisto1D( 9, 1, 1));
00179       _h_ktmass.addHistogram(300, 400, bookHisto1D(10, 1, 1));
00180       _h_ktmass.addHistogram(400, 500, bookHisto1D(11, 1, 1));
00181       _h_ktmass.addHistogram(500, 600, bookHisto1D(12, 1, 1));
00182 
00183       _h_ktd12.addHistogram(200, 300, bookHisto1D(13, 1, 1));
00184       _h_ktd12.addHistogram(300, 400, bookHisto1D(14, 1, 1));
00185       _h_ktd12.addHistogram(400, 500, bookHisto1D(15, 1, 1));
00186       _h_ktd12.addHistogram(500, 600, bookHisto1D(16, 1, 1));
00187 
00188       _h_ktd23.addHistogram(200, 300, bookHisto1D(17, 1 ,1));
00189       _h_ktd23.addHistogram(300, 400, bookHisto1D(18, 1 ,1));
00190       _h_ktd23.addHistogram(400, 500, bookHisto1D(19, 1 ,1));
00191       _h_ktd23.addHistogram(500, 600, bookHisto1D(20, 1 ,1));
00192 
00193       _h_cat21.addHistogram(200, 300, bookHisto1D(21, 1, 1));
00194       _h_cat21.addHistogram(300, 400, bookHisto1D(22, 1, 1));
00195       _h_cat21.addHistogram(400, 500, bookHisto1D(23, 1, 1));
00196       _h_cat21.addHistogram(500, 600, bookHisto1D(24, 1, 1));
00197 
00198       _h_cat32.addHistogram(200, 300, bookHisto1D(25, 1, 1));
00199       _h_cat32.addHistogram(300, 400, bookHisto1D(26, 1, 1));
00200       _h_cat32.addHistogram(400, 500, bookHisto1D(27, 1, 1));
00201       _h_cat32.addHistogram(500, 600, bookHisto1D(28, 1, 1));
00202 
00203       _h_ktt21.addHistogram(200, 300, bookHisto1D(29, 1, 1));
00204       _h_ktt21.addHistogram(300, 400, bookHisto1D(30, 1, 1));
00205       _h_ktt21.addHistogram(400, 500, bookHisto1D(31, 1, 1));
00206       _h_ktt21.addHistogram(500, 600, bookHisto1D(32, 1, 1));
00207 
00208       _h_ktt32.addHistogram(200, 300, bookHisto1D(33, 1, 1));
00209       _h_ktt32.addHistogram(300, 400, bookHisto1D(34, 1, 1));
00210       _h_ktt32.addHistogram(400, 500, bookHisto1D(35, 1, 1));
00211       _h_ktt32.addHistogram(500, 600, bookHisto1D(36, 1, 1));
00212     }
00213 
00214 
00215     /// Perform the per-event analysis
00216     void analyze(const Event& event) {
00217       const double weight = event.weight();
00218 
00219       using namespace fastjet;
00220 
00221       // Get anti-kt jets with p_T > 200 GeV, check abs(y) < 2, and fill mass histograms
00222       const FastJets& ktfj = applyProjection<FastJets>(event, "AKT");
00223       PseudoJets ktjets = ktfj.pseudoJetsByPt(200*GeV);
00224       foreach (const PseudoJet ajet, ktjets) {
00225         if (abs(ajet.rap()) < 2) {
00226           _h_ktmass.fill(ajet.perp(), ajet.m(), weight);
00227         }
00228       }
00229 
00230       // Same as above but C/A jets
00231       const FastJets& cafj = applyProjection<FastJets>(event, "CA");
00232       PseudoJets cajets = cafj.pseudoJetsByPt(200*GeV);
00233       foreach (const PseudoJet ajet, cajets) {
00234         if (abs(ajet.rap()) < 2) {
00235           _h_camass.fill(ajet.perp(), ajet.m(), weight);
00236         }
00237       }
00238 
00239       // Split and filter.
00240       // Only do this to C/A jets in this analysis.
00241       foreach (const PseudoJet pjet, cajets) {
00242         if ( pjet.perp() > 600 || abs(pjet.rap()) > 2) continue;
00243         double dR = 0;
00244         bool unclustered = false;
00245         PseudoJets split_jets = splitjet(pjet, dR, cafj, unclustered);
00246         if ( (dR < 0.15) || (unclustered == false) ) continue;
00247         PseudoJet filt_jet = filterjet(split_jets, dR, 0.3);
00248         _h_filtmass.fill(filt_jet.perp(), filt_jet.m(), weight);
00249       }
00250 
00251       // Use the two last stages of clustering to get sqrt(d_12) and sqrt(d_23).
00252       // Only use anti-kt jets in this analysis.
00253       foreach (const PseudoJet pjet, ktjets) {
00254         if (pjet.perp() > 600 || abs(pjet.rap()) > 2) continue;
00255         ClusterSequence subjet_cseq(ktfj.clusterSeq()->constituents(pjet), JetDefinition(kt_algorithm, M_PI/2.));
00256         double d_12 = subjet_cseq.exclusive_dmerge(1) * M_PI*M_PI/4.;
00257         double d_23 = subjet_cseq.exclusive_dmerge(2) * M_PI*M_PI/4.;
00258         _h_ktd12.fill(pjet.perp(), sqrt(d_12), weight);
00259         _h_ktd23.fill(pjet.perp(), sqrt(d_23), weight);
00260       }
00261 
00262       // N-subjettiness, use beta = 1 (no rationale given).
00263       // Uses the functions defined above.
00264       // C/A jets first, anti-kt after.
00265       double beta = 1.;
00266       //Rcut is used for particles that are very far from the closest axis. At 10
00267       //is has no impact on the outcome of the calculation
00268       double Rcut = 10.;
00269       foreach (const PseudoJet pjet, cajets) {
00270         if (pjet.perp() > 600*GeV || fabs(pjet.rap()) > 2) continue;
00271 
00272         const PseudoJets constituents = cafj.clusterSeq()->constituents(pjet);
00273         if (constituents.size() < 3) continue;
00274 
00275         const PseudoJets axis1 = jetGetAxes(1, constituents, M_PI/2.0);
00276         const PseudoJets axis2 = jetGetAxes(2, constituents, M_PI/2.0);
00277         const PseudoJets axis3 = jetGetAxes(3, constituents, M_PI/2.0);
00278 
00279         const double radius = 1.2;
00280         const double tau1 = jetTauValue(beta, radius, constituents, axis1, Rcut);
00281         const double tau2 = jetTauValue(beta, radius, constituents, axis2, Rcut);
00282         const double tau3 = jetTauValue(beta, radius, constituents, axis3, Rcut);
00283 
00284         if (tau1 == 0 || tau2 == 0) continue;
00285         _h_cat21.fill(pjet.perp(), tau2/tau1, weight);
00286         _h_cat32.fill(pjet.perp(), tau3/tau2, weight);
00287       }
00288 
00289       foreach (const PseudoJet pjet, ktjets) {
00290         if (pjet.perp() > 600*GeV || fabs(pjet.rap()) > 2) continue;
00291 
00292         const PseudoJets constituents = ktfj.clusterSeq()->constituents(pjet);
00293         if (constituents.size() < 3) continue;
00294 
00295         const PseudoJets axis1 = jetGetAxes(1, constituents, M_PI/2.0);
00296         const PseudoJets axis2 = jetGetAxes(2, constituents, M_PI/2.0);
00297         const PseudoJets axis3 = jetGetAxes(3, constituents, M_PI/2.0);
00298 
00299         const double radius = 1.0;
00300         const double tau1 = jetTauValue(beta, radius, constituents, axis1, Rcut);
00301         const double tau2 = jetTauValue(beta, radius, constituents, axis2, Rcut);
00302         const double tau3 = jetTauValue(beta, radius, constituents, axis3, Rcut);
00303         if (tau1 == 0 || tau2 == 0) continue;
00304 
00305         _h_ktt21.fill(pjet.perp(), tau2/tau1, weight);
00306         _h_ktt32.fill(pjet.perp(), tau3/tau2, weight);
00307       }
00308     }
00309 
00310 
00311     /// Normalise histograms etc., after the run
00312     void finalize() {
00313       foreach (Histo1DPtr h, _h_camass.getHistograms()) normalize(h);
00314       foreach (Histo1DPtr h, _h_filtmass.getHistograms()) normalize(h);
00315       foreach (Histo1DPtr h, _h_ktmass.getHistograms()) normalize(h);
00316       foreach (Histo1DPtr h, _h_ktd12.getHistograms()) normalize(h);
00317       foreach (Histo1DPtr h, _h_ktd23.getHistograms()) normalize(h);
00318       foreach (Histo1DPtr h, _h_cat21.getHistograms()) normalize(h);
00319       foreach (Histo1DPtr h, _h_cat32.getHistograms()) normalize(h);
00320       foreach (Histo1DPtr h, _h_ktt21.getHistograms()) normalize(h);
00321       foreach (Histo1DPtr h, _h_ktt32.getHistograms()) normalize(h);
00322     }
00323 
00324   private:
00325 
00326     BinnedHistogram<double> _h_camass;
00327     BinnedHistogram<double> _h_filtmass;
00328     BinnedHistogram<double> _h_ktmass;
00329     BinnedHistogram<double> _h_ktd12;
00330     BinnedHistogram<double> _h_ktd23;
00331     BinnedHistogram<double> _h_cat21;
00332     BinnedHistogram<double> _h_cat32;
00333     BinnedHistogram<double> _h_ktt21;
00334     BinnedHistogram<double> _h_ktt32;
00335 
00336   };
00337 
00338 
00339   // The hook for the plugin system
00340   DECLARE_RIVET_PLUGIN(ATLAS_2012_I1094564);
00341 
00342 }