Fork me on GitHub

source: git/external/fastjet/tools/Filter.cc@ a1f42b2

ImprovedOutputFile Timing dual_readout llp
Last change on this file since a1f42b2 was d7d2da3, checked in by pavel <pavel@…>, 11 years ago

move branches/ModularDelphes to trunk

  • Property mode set to 100644
File size: 16.0 KB
Line 
1//STARTHEADER
2// $Id$
3//
4// Copyright (c) 2005-2011, Matteo Cacciari, Gavin P. Salam and Gregory Soyez
5//
6//----------------------------------------------------------------------
7// This file is part of FastJet.
8//
9// FastJet is free software; you can redistribute it and/or modify
10// it under the terms of the GNU General Public License as published by
11// the Free Software Foundation; either version 2 of the License, or
12// (at your option) any later version.
13//
14// The algorithms that underlie FastJet have required considerable
15// development and are described in hep-ph/0512210. If you use
16// FastJet as part of work towards a scientific publication, please
17// include a citation to the FastJet paper.
18//
19// FastJet is distributed in the hope that it will be useful,
20// but WITHOUT ANY WARRANTY; without even the implied warranty of
21// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22// GNU General Public License for more details.
23//
24// You should have received a copy of the GNU General Public License
25// along with FastJet. If not, see <http://www.gnu.org/licenses/>.
26//----------------------------------------------------------------------
27//ENDHEADER
28
29#include "fastjet/tools/Filter.hh"
30#include <fastjet/ClusterSequenceActiveAreaExplicitGhosts.hh>
31#include <cassert>
32#include <algorithm>
33#include <sstream>
34#include <typeinfo>
35
36using namespace std;
37
38
39FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
40
41//----------------------------------------------------------------------
42// Filter class implementation
43//----------------------------------------------------------------------
44
45// class description
46string Filter::description() const {
47 ostringstream ostr;
48 ostr << "Filter with subjet_def = ";
49 if (_Rfiltfunc) {
50 ostr << "Cambridge/Aachen algorithm with dynamic Rfilt"
51 << " (recomb. scheme deduced from jet, or E-scheme if not unique)";
52 } else if (_Rfilt > 0) {
53 ostr << "Cambridge/Aachen algorithm with Rfilt = "
54 << _Rfilt
55 << " (recomb. scheme deduced from jet, or E-scheme if not unique)";
56 } else {
57 ostr << _subjet_def.description();
58 }
59 ostr<< ", selection " << _selector.description();
60 if (_subtractor) {
61 ostr << ", subtractor: " << _subtractor->description();
62 } else if (_rho != 0) {
63 ostr << ", subtracting with rho = " << _rho;
64 }
65 return ostr.str();
66}
67
68
69// core functions
70//----------------------------------------------------------------------
71
72// return a vector of subjets, which are the ones that would be kept
73// by the filtering
74PseudoJet Filter::result(const PseudoJet &jet) const {
75 // start by getting the list of subjets (including a list of sanity
76 // checks)
77 // NB: subjets is empty to begin with (see the comment for
78 // _set_filtered_elements_cafilt)
79 vector<PseudoJet> subjets;
80 JetDefinition subjet_def;
81 bool discard_area;
82 // NB: on return, subjet_def is set to the jet definition actually
83 // used (so that we can make use of its recombination scheme
84 // when joining the jets to be kept).
85 _set_filtered_elements(jet, subjets, subjet_def, discard_area);
86
87 // now build the vector of kept and rejected subjets
88 vector<PseudoJet> kept, rejected;
89 // Note that in the following line we make a copy of the _selector
90 // to avoid issues with needing a mutable _selector
91 Selector selector_copy = _selector;
92 if (selector_copy.takes_reference()) selector_copy.set_reference(jet);
93 selector_copy.sift(subjets, kept, rejected);
94
95 // gather the info under the form of a PseudoJet
96 return _finalise(jet, kept, rejected, subjet_def, discard_area);
97}
98
99
100// sets filtered_elements to be all the subjets on which filtering will work
101void Filter::_set_filtered_elements(const PseudoJet & jet,
102 vector<PseudoJet> & filtered_elements,
103 JetDefinition & subjet_def,
104 bool & discard_area) const {
105 // sanity checks
106 //-------------------------------------------------------------------
107 // make sure that the jet has constituents
108 if (! jet.has_constituents())
109 throw Error("Filter can only be applied on jets having constituents");
110
111 // for a whole variety of checks, we shall need the "recursive"
112 // pieces of the jet (the jet itself or recursing down to its most
113 // fundamental pieces).
114 // So we do compute these once and for all
115 vector<PseudoJet> all_pieces; //.clear();
116 if ((!_get_all_pieces(jet, all_pieces)) || (all_pieces.size()==0))
117 throw Error("Attempt to filter a jet that has no associated ClusterSequence or is not a superposition of jets associated with a ClusterSequence");
118
119 // if the filter uses subtraction, make sure we have a CS that supports area and has
120 // explicit ghosts
121 if (_uses_subtraction()) {
122 if (!jet.has_area())
123 throw Error("Attempt to filter and subtract (non-zero rho or subtractor) without area info for the original jet");
124
125 if (!_check_explicit_ghosts(all_pieces))
126 throw Error("Attempt to filter and subtract (non-zero rho or subtractor) without explicit ghosts");
127 }
128
129 // if we're dealing with a dynamic determination of the filtering
130 // radius, do it now
131 if ((_Rfilt>=0) || (_Rfiltfunc)){
132 double Rfilt = (_Rfiltfunc) ? (*_Rfiltfunc)(jet) : _Rfilt;
133 const JetDefinition::Recombiner * common_recombiner = _get_common_recombiner(all_pieces);
134 if (common_recombiner) {
135 if (typeid(*common_recombiner) == typeid(JetDefinition::DefaultRecombiner)) {
136 RecombinationScheme scheme =
137 static_cast<const JetDefinition::DefaultRecombiner *>(common_recombiner)->scheme();
138 subjet_def = JetDefinition(cambridge_algorithm, Rfilt, scheme);
139 } else {
140 subjet_def = JetDefinition(cambridge_algorithm, Rfilt, common_recombiner);
141 }
142 } else {
143 subjet_def = JetDefinition(cambridge_algorithm, Rfilt);
144 }
145 } else {
146 subjet_def = _subjet_def;
147 }
148
149 // get the jet definition to be use and whether we can apply our
150 // simplified C/A+C/A filter
151 //
152 // we apply C/A clustering iff
153 // - the request subjet_def is C/A
154 // - the jet is either directly coming from C/A or if it is a
155 // superposition of C/A jets
156 // - the pieces agree with the recombination scheme of subjet_def
157 //------------------------------------------------------------------
158 bool simple_cafilt = _check_ca(all_pieces);
159
160 // extract the subjets
161 //-------------------------------------------------------------------
162 discard_area = false;
163 if (simple_cafilt){
164 // first make sure that 'filtered_elements' is empty
165 filtered_elements.clear();
166 _set_filtered_elements_cafilt(jet, filtered_elements, subjet_def.R());
167 // in the following case, areas can be erroneous and will be discarded
168 discard_area = (!_uses_subtraction()) && (jet.has_area()) && (!_check_explicit_ghosts(all_pieces));
169 } else {
170 // here we'll simply recluster the jets.
171 //
172 // To include an area support we need
173 // - the jet to have an area
174 // - subtraction requested or explicit ghosts
175 bool do_areas = (jet.has_area()) && ((_uses_subtraction()) || (_check_explicit_ghosts(all_pieces)));
176 _set_filtered_elements_generic(jet, filtered_elements, subjet_def, do_areas);
177 }
178
179 // order the filtered elements in pt
180 filtered_elements = sorted_by_pt(filtered_elements);
181}
182
183// set the filtered elements in the simple case of C/A+C/A
184//
185// WATCH OUT: this could be recursively called, so filtered elements
186// of 'jet' are APPENDED to 'filtered_elements'
187void Filter::_set_filtered_elements_cafilt(const PseudoJet & jet,
188 vector<PseudoJet> & filtered_elements,
189 double Rfilt) const{
190 // we know that the jet is either a C/A jet or a superposition of
191 // such pieces
192 if (jet.has_associated_cluster_sequence()){
193 // just extract the exclusive subjets of 'jet'
194 const ClusterSequence *cs = jet.associated_cluster_sequence();
195 vector<PseudoJet> local_fe;
196
197 double dcut = Rfilt / cs->jet_def().R();
198 if (dcut>=1.0){
199 local_fe.push_back(jet);
200 } else {
201 dcut *= dcut;
202 local_fe = jet.exclusive_subjets(dcut);
203 }
204
205 // subtract the jets if needed
206 // Note that this one would work on pieces!!
207 //-----------------------------------------------------------------
208 if (_uses_subtraction()){
209 const ClusterSequenceAreaBase * csab = jet.validated_csab();
210 for (unsigned int i=0;i<local_fe.size();i++) {
211 if (_subtractor) {
212 local_fe[i] = (*_subtractor)(local_fe[i]);
213 } else {
214 local_fe[i] = csab->subtracted_jet(local_fe[i], _rho);
215 }
216 }
217 }
218
219 copy(local_fe.begin(), local_fe.end(), back_inserter(filtered_elements));
220 return;
221 }
222
223 // just recurse into the pieces
224 const vector<PseudoJet> & pieces = jet.pieces();
225 for (vector<PseudoJet>::const_iterator it = pieces.begin();
226 it!=pieces.end(); it++)
227 _set_filtered_elements_cafilt(*it, filtered_elements, Rfilt);
228}
229
230
231// set the filtered elements in the generic re-clustering case (wo
232// subtraction)
233void Filter::_set_filtered_elements_generic(const PseudoJet & jet,
234 vector<PseudoJet> & filtered_elements,
235 const JetDefinition & subjet_def,
236 bool do_areas) const{
237 // create a new, internal, ClusterSequence from the jet constituents
238 // get the subjets directly from there
239 //
240 // If the jet has area support then we separate the ghosts from the
241 // "regular" particles so the subjets will also have area
242 // support. Note that we do this regardless of whether rho is zero
243 // or not.
244 //
245 // Note that to be able to separate the ghosts, one needs explicit
246 // ghosts!!
247 // ---------------------------------------------------------------
248 if (do_areas){
249 vector<PseudoJet> all_constituents = jet.constituents();
250 vector<PseudoJet> regular_constituents, ghosts;
251
252 for (vector<PseudoJet>::iterator it = all_constituents.begin();
253 it != all_constituents.end(); it++){
254 if (it->is_pure_ghost())
255 ghosts.push_back(*it);
256 else
257 regular_constituents.push_back(*it);
258 }
259
260 // figure out the ghost area from the 1st ghost (if none, any value
261 // would probably do as the area will be 0 and subtraction will have
262 // no effect!)
263 double ghost_area = (ghosts.size()) ? ghosts[0].area() : 0.01;
264 ClusterSequenceActiveAreaExplicitGhosts * csa
265 = new ClusterSequenceActiveAreaExplicitGhosts(regular_constituents,
266 subjet_def,
267 ghosts, ghost_area);
268
269 // get the subjets: we use the subtracted or unsubtracted ones
270 // depending on rho or _subtractor being non-zero
271 if (_uses_subtraction()) {
272 if (_subtractor) {
273 filtered_elements = (*_subtractor)(csa->inclusive_jets());
274 } else {
275 filtered_elements = csa->subtracted_jets(_rho);
276 }
277 } else {
278 filtered_elements = csa->inclusive_jets();
279 }
280
281 // allow the cs to be deleted when it's no longer used
282 csa->delete_self_when_unused();
283 } else {
284 ClusterSequence * cs = new ClusterSequence(jet.constituents(), subjet_def);
285 filtered_elements = cs->inclusive_jets();
286 // allow the cs to be deleted when it's no longer used
287 cs->delete_self_when_unused();
288 }
289}
290
291
292// gather the information about what is kept and rejected under the
293// form of a PseudoJet with a special ClusterSequenceInfo
294PseudoJet Filter::_finalise(const PseudoJet & /*jet*/,
295 vector<PseudoJet> & kept,
296 vector<PseudoJet> & rejected,
297 const JetDefinition & subjet_def,
298 const bool discard_area) const {
299 // figure out which recombiner to use
300 const JetDefinition::Recombiner &rec = *(subjet_def.recombiner());
301
302 // create an appropriate structure and transfer the info to it
303 PseudoJet filtered_jet = join<StructureType>(kept, rec);
304 StructureType *fs = (StructureType*) filtered_jet.structure_non_const_ptr();
305// fs->_original_jet = jet;
306 fs->_rejected = rejected;
307
308 if (discard_area){
309 // safety check: make sure there is an area to discard!!!
310 assert(fs->_area_4vector_ptr);
311 delete fs->_area_4vector_ptr;
312 fs->_area_4vector_ptr=0;
313 }
314
315 return filtered_jet;
316}
317
318// various checks
319//----------------------------------------------------------------------
320
321// get the pieces down to the fundamental pieces
322//
323// Note that this just checks that there is an associated CS to the
324// fundamental pieces, not that it is still valid
325bool Filter::_get_all_pieces(const PseudoJet &jet, vector<PseudoJet> &all_pieces) const{
326 if (jet.has_associated_cluster_sequence()){
327 all_pieces.push_back(jet);
328 return true;
329 }
330
331 if (jet.has_pieces()){
332 const vector<PseudoJet> pieces = jet.pieces();
333 for (vector<PseudoJet>::const_iterator it=pieces.begin(); it!=pieces.end(); it++)
334 if (!_get_all_pieces(*it, all_pieces)) return false;
335 return true;
336 }
337
338 return false;
339}
340
341// get the common recombiner to all pieces (NULL if none)
342//
343// Note that if the jet has an associated cluster sequence that is no
344// longer valid, an error will be thrown (needed since it could be the
345// 1st check called after the enumeration of the pieces)
346const JetDefinition::Recombiner* Filter::_get_common_recombiner(const vector<PseudoJet> &all_pieces) const{
347 const JetDefinition & jd_ref = all_pieces[0].validated_cs()->jet_def();
348 for (unsigned int i=1; i<all_pieces.size(); i++)
349 if (!all_pieces[i].validated_cs()->jet_def().has_same_recombiner(jd_ref)) return NULL;
350
351 return jd_ref.recombiner();
352}
353
354// check if the jet (or all its pieces) have explicit ghosts
355// (assuming the jet has area support
356//
357// Note that if the jet has an associated cluster sequence that is no
358// longer valid, an error will be thrown (needed since it could be the
359// 1st check called after the enumeration of the pieces)
360bool Filter::_check_explicit_ghosts(const vector<PseudoJet> &all_pieces) const{
361 for (vector<PseudoJet>::const_iterator it=all_pieces.begin(); it!=all_pieces.end(); it++)
362 if (! it->validated_csab()->has_explicit_ghosts()) return false;
363 return true;
364}
365
366// check if one can apply the simplification for C/A subjets
367//
368// This includes:
369// - the subjet definition asks for C/A subjets
370// - all the pieces share the same CS
371// - that CS is C/A with the same recombiner as the subjet def
372// - the filtering radius is not larger than any of the pairwise
373// distance between the pieces
374//
375// Note that if the jet has an associated cluster sequence that is no
376// longer valid, an error will be thrown (needed since it could be the
377// 1st check called after the enumeration of the pieces)
378bool Filter::_check_ca(const vector<PseudoJet> &all_pieces) const{
379 if (_subjet_def.jet_algorithm() != cambridge_algorithm) return false;
380
381 // check that the 1st of all the pieces (we're sure there is at
382 // least one) is coming from a C/A clustering. Then check that all
383 // the following pieces share the same ClusterSequence
384 const ClusterSequence * cs_ref = all_pieces[0].validated_cs();
385 if (cs_ref->jet_def().jet_algorithm() != cambridge_algorithm) return false;
386 for (unsigned int i=1; i<all_pieces.size(); i++)
387 if (all_pieces[i].validated_cs() != cs_ref) return false;
388
389 // check that the 1st peice has the same recombiner as the one used
390 // for the subjet clustering
391 // Note that since they share the same CS, checking the 2st one is enough
392 if (!cs_ref->jet_def().has_same_recombiner(_subjet_def)) return false;
393
394 // we also have to make sure that the filtering radius is not larger
395 // than any of the inter-pieces distance
396 double Rfilt2 = _subjet_def.R();
397 Rfilt2 *= Rfilt2;
398 for (unsigned int i=0; i<all_pieces.size()-1; i++){
399 for (unsigned int j=i+1; j<all_pieces.size(); j++){
400 if (all_pieces[i].squared_distance(all_pieces[j]) < Rfilt2) return false;
401 }
402 }
403
404 return true;
405}
406
407//----------------------------------------------------------------------
408// FilterInterface implementation
409//----------------------------------------------------------------------
410
411
412FASTJET_END_NAMESPACE // defined in fastjet/internal/base.hh
Note: See TracBrowser for help on using the repository browser.