// $Id$
//
// Copyright (c) 2014-, Matteo Cacciari, Gavin P. Salam and Gregory Soyez
//
//----------------------------------------------------------------------
// 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 "SafeSubtractor.hh"
#include "fastjet/config.h"
using namespace std;
FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
namespace contrib{
//----------------------------------------------------------------------
// SubtractorBase implementation
//----------------------------------------------------------------------
// the result of the subtraction
// - jet the jet to be subtracted
PseudoJet SafeSubtractorBase::result(const PseudoJet &jet) const{
// \todo Notes:
//
// - the whole procedure is overkilling for "regular" areasub: no
// need for constituents, no need for all the sifting,...
// pre-requirement: the jet should have constituents
if (! jet.has_constituents()){
throw Error("SubtractionBase: subtraction can only be applied for jets with constituents");
return PseudoJet();
}
// separate the jet constituents in 3 groups:
// unknown vertex
// known vertex, leading vertex
// known vertex, non-leading vertex (PU)
vector constits_unknown, constits_known;
_selector_known_vertex.sift(jet.constituents(),
constits_known,
constits_unknown);
vector constits_known_lv, constits_known_pu;
_selector_leading_vertex.sift(constits_known,
constits_known_lv,
constits_known_pu);
// compute the momentum of these 3 sets of constiutuents
//
// For the parts related to the known vertices (LV or PU), we just
// sum the 4-momenta. For the unknown part, we assign it the full
// jet area.
//
//Selector sel_id = SelectorIdentity();
//PseudoJet known_lv = (constits_known_lv.size() != 0)
// ? sel_id.sum(constits_known_lv) : 0.0*jet;
//PseudoJet known_pu = (constits_known_pu.size() != 0)
// ? sel_id.sum(constits_known_pu) : 0.0*jet;
//PseudoJet unknown = jet; // that keeps all info including area
//unknown.reset_momentum((constits_unknown.size() != 0)
// ? sel_id.sum(constits_unknown) : 0.0*jet);
//
PseudoJet known_lv = _sum(constits_known_lv, jet);
PseudoJet known_pu = _sum(constits_known_pu, jet);
PseudoJet unknown = jet; // that keeps all info including area
unknown.reset_momentum(_sum(constits_unknown, jet));
// compute the 4-momentum that needs to be subtracted given these 3
// components of the jet
PseudoJet to_subtract = _amount_to_subtract(known_lv, known_pu, unknown);
// now apply the subtraction itself (optionally performing safety
// tests)
PseudoJet subtracted_jet = jet;
// for the moment only check that subtraction does not give a -ve
// pt.
//
// Note that the lines below preserve the structural information
// associated with the original jet
if (to_subtract.pt2() <= subtracted_jet.pt2()){
subtracted_jet -= to_subtract;
} else {
// we have subtracted more than what we know for sure comes from
// the leading vertex, so we just return the part we know for sure
// comes from the leading vertex
subtracted_jet.reset_momentum(known_lv);
// skip the safety tests below
return subtracted_jet;
}
// now perform safety tests compared to the part we know comes from
// the leading vertex
//
// Note that at this stage 'subtracted_jet' has already its momentum
// subtracted (and has +ve pt)
//
// first check that the pt is at least the pt of the known particles
if (subtracted_jet.pt2() < known_lv.pt2()){
// we have subtracted more than what we know for sure comes
// from the leading vertex [GS: not totally happy with this comment]
// Note that in this case we can skip the mass test below!
subtracted_jet.reset_momentum(known_lv);
} else { // the pt safety test passed...
// ... now perform the mass test
if ((_safe_mass) && (subtracted_jet.m2() < known_lv.m2())){
// in this case, we keep pt and phi as obtained from the
// subtraction above and take rap and m from 'known_lv'
subtracted_jet.reset_momentum(PtYPhiM(subtracted_jet.pt(),
known_lv.rap(),
subtracted_jet.phi(),
known_lv.m()));
}
}
return subtracted_jet;
}
// given a vector of PseudoJet, this returns the 4-vector sum of the
// jets passing the selection creteria. If the vector is empty, return
// a 0-momentum PSeudoJet with structural info inherited from 'jet'
PseudoJet SafeSubtractorBase::_sum(const vector &particles,
const PseudoJet &jet) const{
// note that in FJ3.1 we could use
// return (particles.size() != 0) ? SelectoIdentity().sum(particles) : 0.0*jet;
PseudoJet this_sum = 0.0*jet;
for (unsigned i = 0; i < particles.size(); i++)
this_sum += particles[i];
return this_sum;
}
//----------------------------------------------------------------------
// AreaSubtractor implementation
//----------------------------------------------------------------------
// class description
string SafeAreaSubtractor::description() const{
ostringstream oss;
oss << "Area-median subtraction using background estimation: " << _bge->description();
if (_bge_m)
oss << ", background estimation for particle masses: " << _bge_m->description();
oss << ", known vertex selection: " << _selector_known_vertex.description()
<< ", leading vertex selection: " << _selector_leading_vertex.description();
oss << " and safety checks for pt";
if (_safe_mass) oss << " and mass";
oss << ".";
return oss.str();
}
// compute the amount to be subtracted from the various bits in the jet:
// - known_lv momentum known as coming from the leading vertex
// - known_pu momentum known as coming from the pu vertices
// - unknown momentum of unknown vertex origin
PseudoJet SafeAreaSubtractor::_amount_to_subtract(const PseudoJet &known_lv,
const PseudoJet &known_pu,
const PseudoJet &unknown) const{
// make sure the background estimator is present
if (!_bge){
throw Error("AreaSubtractor requires a non-zero background estimator");
return PseudoJet();
}
// the amount to subtract receives 3 contributions:
// 1. the known pu
PseudoJet to_subtract = known_pu;
// 2. the "pt" background from the unknown (obtained from the area)
PseudoJet area = unknown.area_4vector();
to_subtract += _bge->rho(unknown) * area;
// 3. an optional contribution from the unknown particles masses
if (_bge_m)
to_subtract += _bge_m->rho(unknown) * PseudoJet(0.0, 0.0, area.pz(), area.E());
return to_subtract;
}
//----------------------------------------------------------------------
// NpCSubtractor implementation
//----------------------------------------------------------------------
// class description
string SafeNpCSubtractor::description() const{
ostringstream oss;
oss << "Neutral-proportional-to-Charged subtraction using known fraction: ";
// the fraction of known pt
if (_gamma_fct)
oss << _gamma_fct->description();
else
oss << _gamma;
oss << ", known vertex selection: " << _selector_known_vertex.description()
<< ", leading vertex selection: " << _selector_leading_vertex.description();
oss << " and safety checks for pt";
if (_safe_mass) oss << " and mass";
oss << ".";
return oss.str();
}
// compute the amount to be subtracted from the various bits in the jet:
// - known_lv momentum known as coming from the leading vertex
// - known_pu momentum known as coming from the pu vertices
// - unknown momentum of unknown vertex origin
PseudoJet SafeNpCSubtractor::_amount_to_subtract(const PseudoJet &known_lv,
const PseudoJet &known_pu,
const PseudoJet &unknown) const{
// the amount to subtract receives 2 contributions:
// 1. the known pu
// 2. the unknown PU obtained by scaling the known PU
//
// This is known_pu + (1-g)/g known_pu = 1/g known_pu
double g = (_gamma_fct) ? (*_gamma_fct)(known_pu) : _gamma;
return 1.0/g * known_pu;
}
} // namespace contrib
FASTJET_END_NAMESPACE