// $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