// $Id$
//
// Copyright (c) -,
//
//----------------------------------------------------------------------
// This file is part of FastJet contrib.
//
// It is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at
// your option) any later version.
//
// It is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this code. If not, see .
//----------------------------------------------------------------------
#include
#include "SubjetCounting.hh"
FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
namespace contrib{
//------------------------------------------------------------------------
//
// Implementation of the two subjet counting algorithms used in
// "Learning How to Count: A High Multiplicity Search for the LHC"
// Sonia El Hedri, Anson Hook, Martin Jankowiak, Jay G. Wacker
// JHEP 1308:136,2013
// http://arxiv.org/abs/1302.1870
//
//------------------------------------------------------------------------
// **************************************************************************************
//
// subjet counting with the exclusive Kt algorithm
//
// **************************************************************************************
// the actual n_Kt function; called internally
unsigned int SubjetCountingKt::_n_Kt(const fastjet::PseudoJet &jet) const
{
return (unsigned int)SubjetCountingKt::getSubjets(jet).size();
}
// get the subjets identified by the Kt subjet counting algorithm
std::vector SubjetCountingKt::getSubjets(const fastjet::PseudoJet &jet) const
{
JetAlgorithm algorithm = kt_algorithm;
// this choice of jet_rad ensures that no beam jets are identified
double jet_rad = fastjet::JetDefinition::max_allowable_R;
JetDefinition jetDef = JetDefinition(algorithm, jet_rad, E_scheme, Best);
ClusterSequence clust_seq(jet.constituents(), jetDef);
double total_jet_pt=jet.perp();
double Kt_scale = total_jet_pt*total_jet_pt*_f_Kt*_f_Kt;
// Kt_scale has to be scaled down to compensate for the choice of jet_rad
Kt_scale /= fastjet::JetDefinition::max_allowable_R*fastjet::JetDefinition::max_allowable_R;
std::vector Kt_jets = sorted_by_pt(clust_seq.exclusive_jets(Kt_scale));
std::vector return_subjets;
for (int k=0; k<(int)Kt_jets.size(); k++)
if (Kt_jets[k].perp()>_pt_cut)
return_subjets.push_back(Kt_jets[k]);
return return_subjets;
}
// *************************************************************************************
//
// subjet counting with the CA algorithm
//
// *************************************************************************************
// internal function called recursively by the CA variant of getSubjets (see below)
void SubjetCountingCA::_FindHardSubst(const fastjet::PseudoJet & this_jet,
std::vector & t_parts) const
{
fastjet::PseudoJet parent1(0.0,0.0,0.0,0.0), parent2(0.0,0.0,0.0,0.0);
bool had_parents=this_jet.validated_cs()->has_parents(this_jet,parent1,parent2);
if ( (this_jet.m() < _mass_cut_off) || (!had_parents) )
{
t_parts.push_back(this_jet); return;
} // stop recursion on this branch
if (had_parents && parent1.plain_distance(parent2) < (_R_min*_R_min) )
{
t_parts.push_back(this_jet); return;
} // stop recursion on this branch
if (parent1.perp() < parent2.perp()) std::swap(parent1,parent2);
double pt1=parent1.perp();
double pt2=parent2.perp();
double totalpt=pt1+pt2;
if (pt2>_ycut*totalpt)
{
_FindHardSubst(parent1, t_parts);
_FindHardSubst(parent2, t_parts);
} // continue recursion on both branches
else
_FindHardSubst(parent1, t_parts);
// continue recursion on harder branch, discarding softer branch
return;
}
// the actual n_CA function, which is used internally;
// most of the hard work done by _FindHardSubst which is called by getSubjets
unsigned int SubjetCountingCA::_n_CA(const fastjet::PseudoJet &jet) const
{
return (unsigned int)SubjetCountingCA::getSubjets(jet).size();
}
// get the subjets identified by the CA subjet counting algorithm
std::vector SubjetCountingCA::getSubjets(const PseudoJet& jet) const
{
JetAlgorithm algorithm = cambridge_algorithm;
double jet_rad = fastjet::JetDefinition::max_allowable_R;
// want to make sure we capture all the constituents in a single jet
JetDefinition jetDef = JetDefinition(algorithm, jet_rad, E_scheme, Best);
ClusterSequence clust_seq(jet.constituents(), jetDef);
std::vector ca_jets = sorted_by_pt(clust_seq.inclusive_jets());
std::vector empty_parts, return_subjets;
_FindHardSubst(ca_jets[0], empty_parts);
for (int k=0; k<(int)empty_parts.size(); k++)
if (empty_parts[k].perp() > _pt_cut)
return_subjets.push_back(empty_parts[k]);
return return_subjets;
}
//---------------------------------
unsigned int SubjetCountingKt::result(const PseudoJet& jet) const {
// if jet does not have constituents, throw error
if (!jet.has_constituents()) throw Error("SubjetCountingKt called on jet with no constituents.");
return _n_Kt(jet);
}
unsigned int SubjetCountingCA::result(const PseudoJet& jet) const {
// if jet does not have constituents, throw error
if (!jet.has_constituents()) throw Error("SubjetCountingCA called on jet with no constituents.");
return _n_CA(jet);
}
//---------------------------------
std::string SubjetCountingCA::description() const {
std::ostringstream oss;
oss << "SubjetCountingCA using ";
oss << "parameters mass_cutoff = " << _mass_cut_off <<
", ycut = " << _ycut << ", Rmin = " << _R_min << " and pt_cut = " << _pt_cut;
return oss.str();
}
std::string SubjetCountingKt::description() const {
std::ostringstream oss;
oss << "SubjetCountingKt using ";
oss << "parameters f_Kt = " << _f_Kt << " and pt_cut = " << _pt_cut;
return oss.str();
}
} // namespace contrib
FASTJET_END_NAMESPACE