// $Id: BottomUpSoftDrop.cc 1064 2017-09-08 09:19:57Z gsoyez $
//
// Copyright (c) 2017-, Gavin P. Salam, Gregory Soyez, Jesse Thaler,
// Kevin Zhou, Frederic Dreyer
//
//----------------------------------------------------------------------
// 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 "BottomUpSoftDrop.hh"
#include
#include
#include
#include
#include "fastjet/ClusterSequenceActiveAreaExplicitGhosts.hh"
#include "fastjet/Selector.hh"
#include "fastjet/config.h"
using namespace std;
FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
namespace contrib{
//----------------------------------------------------------------------
// BottomUpSoftDrop class
//----------------------------------------------------------------------
// action on a single jet
PseudoJet BottomUpSoftDrop::result(const PseudoJet &jet) const{
// soft drop can only be applied to jets that have constituents
if (!jet.has_constituents()){
throw Error("BottomUpSoftDrop: trying to apply the Soft Drop transformer to a jet that has no constituents");
}
// if the jet has area support and there are explicit ghosts, we can
// transfer that support to the internal re-clustering
//
// Note that this is just meant to maintain the information since
// all the jes will have a 0 area
bool do_areas = jet.has_area() && _check_explicit_ghosts(jet);
// build the soft drop plugin
BottomUpSoftDropPlugin * softdrop_plugin;
// for some constructors, we get the recombiner from the
// input jet -- some acrobatics are needed
if (_get_recombiner_from_jet) {
JetDefinition jet_def = _jet_def;
// if all the pieces have a shared recombiner, we'll use that
// one. Otherwise, use the one from _jet_def as a fallback.
JetDefinition jet_def_for_recombiner;
if (_check_common_recombiner(jet, jet_def_for_recombiner)){
#if FASTJET_VERSION_NUMBER >= 30100
// Note that this is better than the option directly passing the
// recombiner (for cases where th ejet def own its recombiner)
// but it's only available in FJ>=3.1
jet_def.set_recombiner(jet_def_for_recombiner);
#else
jet_def.set_recombiner(jet_def_for_recombiner.recombiner());
#endif
}
softdrop_plugin = new BottomUpSoftDropPlugin(jet_def, _beta, _symmetry_cut, _R0);
} else {
softdrop_plugin = new BottomUpSoftDropPlugin(_jet_def, _beta, _symmetry_cut, _R0);
}
// now recluster the constituents of the jet with that plugin
JetDefinition internal_jet_def(softdrop_plugin);
// flag the plugin for automatic deletion _before_ we make
// copies (so that as long as the copies are also present
// it doesn't get deleted).
internal_jet_def.delete_plugin_when_unused();
ClusterSequence * cs;
if (do_areas){
vector particles, ghosts;
SelectorIsPureGhost().sift(jet.constituents(), ghosts, particles);
// determine the ghost area from the 1st ghost (if none, any value
// will do, as the area will be 0 and subtraction will have
// no effect!)
double ghost_area = (ghosts.size()) ? ghosts[0].area() : 0.01;
cs = new ClusterSequenceActiveAreaExplicitGhosts(particles, internal_jet_def,
ghosts, ghost_area);
} else {
cs = new ClusterSequence(jet.constituents(), internal_jet_def);
}
PseudoJet result_local = SelectorNHardest(1)(cs->inclusive_jets())[0];
BottomUpSoftDropStructure * s = new BottomUpSoftDropStructure(result_local);
s->_beta = _beta;
s->_symmetry_cut = _symmetry_cut;
s->_R0 = _R0;
result_local.set_structure_shared_ptr(SharedPtr(s));
// make sure things remain persistent -- i.e. tell the jet definition
// and the cluster sequence that it is their responsibility to clean
// up memory once the "result" reaches the end of its life in the user's
// code. (The CS deletes itself when the result goes out of scope and
// that also triggers deletion of the plugin)
cs->delete_self_when_unused();
return result_local;
}
// global grooming on a full event
// note: does not support jet areas
vector BottomUpSoftDrop::global_grooming(const vector & event) const {
// start by reclustering the event into one very large jet
ClusterSequence cs(event, _jet_def);
std::vector global_jet = SelectorNHardest(1)(cs.inclusive_jets());
// if the event is empty, do nothing
if (global_jet.size() == 0) return vector();
// apply the groomer to the large jet
PseudoJet result = this->result(global_jet[0]);
return result.constituents();
}
// check if the jet has explicit_ghosts (knowing that there is an
// area support)
bool BottomUpSoftDrop::_check_explicit_ghosts(const PseudoJet &jet) const {
// if the jet comes from a Clustering check explicit ghosts in that
// clustering
if (jet.has_associated_cluster_sequence())
return jet.validated_csab()->has_explicit_ghosts();
// if the jet has pieces, recurse in the pieces
if (jet.has_pieces()){
vector pieces = jet.pieces();
for (unsigned int i=0;ijet_def().has_same_recombiner(jet_def_for_recombiner);
// otherwise, assign it.
jet_def_for_recombiner = jet.validated_cs()->jet_def();
assigned = true;
return true;
}
// if the jet has pieces, recurse in the pieces
if (jet.has_pieces()){
vector pieces = jet.pieces();
if (pieces.size() == 0) return false;
for (unsigned int i=0;i kept(internal_hist.size(), true);
const vector &sd_rej = softdrop_recombiner.rejected();
for (unsigned int i=0;i internal2input(internal_hist.size());
for (unsigned int i=0; i