1 //FJSTARTHEADER
2 // $Id: ClusterSequenceStructure.cc 4442 2020-05-05 07:50:11Z soyez $
3 //
4 // Copyright (c) 2005-2020, 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. They are described in the original FastJet paper,
16 //  hep-ph/0512210 and in the manual, arXiv:1111.6097. If you use
17 //  FastJet as part of work towards a scientific publication, please
18 //  quote the version you use and include a citation to the manual and
19 //  optionally also to hep-ph/0512210.
20 //
21 //  FastJet is distributed in the hope that it will be useful,
22 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
23 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 //  GNU General Public License for more details.
25 //
26 //  You should have received a copy of the GNU General Public License
27 //  along with FastJet. If not, see <http://www.gnu.org/licenses/>.
28 //----------------------------------------------------------------------
29 //FJENDHEADER
30 
31 #include "fastjet/ClusterSequenceStructure.hh"
32 #include "fastjet/Error.hh"
33 #include "fastjet/PseudoJet.hh"
34 #include "fastjet/ClusterSequence.hh"
35 #ifndef __FJCORE__
36 #include "fastjet/ClusterSequenceAreaBase.hh"
37 #endif  // __FJCORE__
38 #include <iostream>
39 
40 FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
41 
42 using namespace std;
43 
~ClusterSequenceStructure()44 ClusterSequenceStructure::~ClusterSequenceStructure(){
45   if (_associated_cs != NULL
46       && _associated_cs->will_delete_self_when_unused()) {
47     // automatically handle deletion of the cluster sequence;
48     // execution should only ever reach this point if the user had
49     // called CS::delete_self_when_unused, which resets the count of
50     // the shared pointer to CSS (otherwise the CS's own destructor
51     // will have zeroed the _associated_cs pointer before the shared
52     // pointer count goes to zero [on destruction of the last of the
53     // jets in the CS and the destruction of the CS's copy of the
54     // shared pointer)
55     _associated_cs->signal_imminent_self_deletion();
56     delete _associated_cs;
57   }
58 }
59 
60 
61 //----------------------------------------------------------------------
62 // Direct access to the associated ClusterSequence object.
63 //----------------------------------------------------------------------
64 
65 // check whether this PseudoJet has an associated parent
66 // ClusterSequence
has_valid_cluster_sequence() const67 bool ClusterSequenceStructure::has_valid_cluster_sequence() const{
68   return (_associated_cs != NULL);
69 }
70 
71 // get a (const) pointer to the associated ClusterSequence (NULL if
72 // inexistent)
associated_cluster_sequence() const73 const ClusterSequence* ClusterSequenceStructure::associated_cluster_sequence() const{
74   return _associated_cs;
75 }
76 
77 
78 // If there is a valid cluster sequence associated with this jet,
79 // returns a pointer to it; otherwise throws an Error.
80 //
81 // Open question: should these errors be upgraded to classes of their
82 // own so that they can be caught? [Maybe, but later]
validated_cs() const83 const ClusterSequence * ClusterSequenceStructure::validated_cs() const {
84   if (!_associated_cs)
85     throw Error("you requested information about the internal structure of a jet, but its associated ClusterSequence has gone out of scope.");
86   return _associated_cs;
87 }
88 
89 
90 //----------------------------------------------------------------------
91 // Methods for access to information about jet structure
92 //----------------------------------------------------------------------
93 
94 // check if it has been recombined with another PseudoJet in which
95 // case, return its partner through the argument. Otherwise,
96 // 'partner' is set to 0.
97 //
98 // false is also returned if this PseudoJet has no associated
99 // ClusterSequence
has_partner(const PseudoJet & reference,PseudoJet & partner) const100 bool ClusterSequenceStructure::has_partner(const PseudoJet &reference, PseudoJet &partner) const{
101   return validated_cs()->has_partner(reference, partner);
102 }
103 
104 // check if it has been recombined with another PseudoJet in which
105 // case, return its child through the argument. Otherwise, 'child'
106 // is set to 0.
107 //
108 // false is also returned if this PseudoJet has no associated
109 // ClusterSequence, with the child set to 0
has_child(const PseudoJet & reference,PseudoJet & child) const110 bool ClusterSequenceStructure::has_child(const PseudoJet &reference, PseudoJet &child) const{
111   return validated_cs()->has_child(reference, child);
112 }
113 
114 // check if it is the product of a recombination, in which case
115 // return the 2 parents through the 'parent1' and 'parent2'
116 // arguments. Otherwise, set these to 0.
117 //
118 // false is also returned if this PseudoJet has no parent
119 // ClusterSequence
has_parents(const PseudoJet & reference,PseudoJet & parent1,PseudoJet & parent2) const120 bool ClusterSequenceStructure::has_parents(const PseudoJet &reference, PseudoJet &parent1, PseudoJet &parent2) const{
121   return validated_cs()->has_parents(reference, parent1, parent2);
122 }
123 
124 
125 // check if the reference PseudoJet is inside the "jet" passed as an argument
126 //
127 // an error is thrown if there is no CS associated with one of the 2 jets.
128 // fasle is returned if teh 2 jets do not belong to the same CS
object_in_jet(const PseudoJet & reference,const PseudoJet & jet) const129 bool ClusterSequenceStructure::object_in_jet(const PseudoJet &reference, const PseudoJet &jet) const{
130   if ((!has_associated_cluster_sequence()) || (!jet.has_associated_cluster_sequence()))
131     throw Error("you requested information about the internal structure of a jet, but it is not associated with a ClusterSequence or its associated ClusterSequence has gone out of scope.");
132 
133   if (reference.associated_cluster_sequence() != jet.associated_cluster_sequence()) return false;
134 
135   return validated_cs()->object_in_jet(reference, jet);
136 }
137 
138 
139 // return true if the structure supports constituents.
140 //
141 // an Error is thrown if this PseudoJet has no currently valid
142 // associated ClusterSequence
has_constituents() const143 bool ClusterSequenceStructure::has_constituents() const{
144   if (!has_associated_cluster_sequence())
145     throw Error("you requested information about the internal structure of a jet, but it is not associated with a ClusterSequence or its associated ClusterSequence has gone out of scope.");
146 
147   return true;
148 }
149 
150 
151 // retrieve the constituents. An empty vector is returned if there is
152 // no associated ClusterSequence
constituents(const PseudoJet & reference) const153 vector<PseudoJet> ClusterSequenceStructure::constituents(const PseudoJet &reference) const{
154   return validated_cs()->constituents(reference);
155 }
156 
157 // return true if the structure supports exclusive_subjets.
158 //
159 // an Error is thrown if this PseudoJet has no currently valid
160 // associated ClusterSequence
has_exclusive_subjets() const161 bool ClusterSequenceStructure::has_exclusive_subjets() const{
162   if (!has_associated_cluster_sequence())
163     throw Error("you requested information about the internal structure of a jet, but it is not associated with a ClusterSequence or its associated ClusterSequence has gone out of scope.");
164 
165   return true;
166 }
167 
168 // return a vector of all subjets of the current jet (in the sense
169 // of the exclusive algorithm) that would be obtained when running
170 // the algorithm with the given dcut.
171 //
172 // Time taken is O(m ln m), where m is the number of subjets that
173 // are found. If m gets to be of order of the total number of
174 // constituents in the jet, this could be substantially slower than
175 // just getting that list of constituents.
176 //
177 // an Error is thrown if this PseudoJet has no currently valid
178 // associated ClusterSequence
exclusive_subjets(const PseudoJet & reference,const double & dcut) const179 std::vector<PseudoJet> ClusterSequenceStructure::exclusive_subjets (const PseudoJet &reference, const double & dcut) const {
180   return validated_cs()->exclusive_subjets(reference, dcut);
181 }
182 
183 // return the size of exclusive_subjets(...); still n ln n with same
184 // coefficient, but marginally more efficient than manually taking
185 // exclusive_subjets.size()
186 //
187 // an Error is thrown if this PseudoJet has no currently valid
188 // associated ClusterSequence
n_exclusive_subjets(const PseudoJet & reference,const double & dcut) const189 int ClusterSequenceStructure::n_exclusive_subjets(const PseudoJet &reference, const double & dcut) const {
190   return validated_cs()->n_exclusive_subjets(reference, dcut);
191 }
192 
193 // return the list of subjets obtained by unclustering the supplied
194 // jet down to n subjets (or all constituents if there are fewer
195 // than n).
196 //
197 // requires n ln n time
198 //
199 // an Error is thrown if this PseudoJet has no currently valid
200 // associated ClusterSequence
exclusive_subjets_up_to(const PseudoJet & reference,int nsub) const201 std::vector<PseudoJet> ClusterSequenceStructure::exclusive_subjets_up_to (const PseudoJet &reference, int nsub) const {
202   return validated_cs()->exclusive_subjets_up_to(reference, nsub);
203 }
204 
205 // return the dij that was present in the merging nsub+1 -> nsub
206 // subjets inside this jet.
207 //
208 // an Error is thrown if this PseudoJet has no currently valid
209 // associated ClusterSequence
exclusive_subdmerge(const PseudoJet & reference,int nsub) const210 double ClusterSequenceStructure::exclusive_subdmerge(const PseudoJet &reference, int nsub) const {
211   return validated_cs()->exclusive_subdmerge(reference, nsub);
212 }
213 
214 // return the maximum dij that occurred in the whole event at the
215 // stage that the nsub+1 -> nsub merge of subjets occurred inside
216 // this jet.
217 //
218 // an Error is thrown if this PseudoJet has no currently valid
219 // associated ClusterSequence
exclusive_subdmerge_max(const PseudoJet & reference,int nsub) const220 double ClusterSequenceStructure::exclusive_subdmerge_max(const PseudoJet &reference, int nsub) const {
221   return validated_cs()->exclusive_subdmerge_max(reference, nsub);
222 }
223 
224 
225 //----------------------------------------------------------------------
226 // information related to the pieces of the jet
227 //----------------------------------------------------------------------
228 
229 // by convention, a jet associated with a ClusterSequence will have
230 // pieces if it has parents in the cluster sequence.
231 //
232 // an error is thrown if the ClusterSequence is out of scope (since
233 // the answer depends on information in the Cluster Sequence)
has_pieces(const PseudoJet & reference) const234 bool ClusterSequenceStructure::has_pieces(const PseudoJet &reference) const{
235   PseudoJet dummy1, dummy2;
236   return has_parents(reference, dummy1, dummy2);
237 }
238 
239 // by convention, the pieces of a jet associated with a
240 // ClusterSequence are its parents in the Cluster Sequence. If it has
241 // no parents, an empty jet is returned.
242 //
243 // an error is thrown if the ClusterSequence is out of scope
pieces(const PseudoJet & reference) const244 vector<PseudoJet> ClusterSequenceStructure::pieces(const PseudoJet &reference) const{
245   PseudoJet j1, j2;
246   vector<PseudoJet> res;
247   if (has_parents(reference, j1, j2)){
248     res.push_back(j1);
249     res.push_back(j2);
250   }
251 
252   return res;
253 }
254 
255 
256 //----------------------------------------------------------------------
257 // the following ones require a computation of the area in the
258 // associated ClusterSequence (See ClusterSequenceAreaBase for details)
259 //----------------------------------------------------------------------
260 
261 #ifndef __FJCORE__
262 // if possible, return a valid ClusterSequenceAreaBase pointer; otherwise
263 // throw an error
validated_csab() const264 const ClusterSequenceAreaBase * ClusterSequenceStructure::validated_csab() const {
265   const ClusterSequenceAreaBase *csab = dynamic_cast<const ClusterSequenceAreaBase*>(validated_cs());
266   if (csab == NULL) throw Error("you requested jet-area related information, but the PseudoJet does not have associated area information.");
267   return csab;
268 }
269 
270 // check if it has a defined area
has_area() const271 bool ClusterSequenceStructure::has_area() const{
272   if (! has_associated_cluster_sequence()) return false;
273   return (dynamic_cast<const ClusterSequenceAreaBase*>(_associated_cs) != NULL);
274 }
275 
276 // return the jet (scalar) area.
277 // throw an Error if there is no support for area in the associated CS
area(const PseudoJet & reference) const278 double ClusterSequenceStructure::area(const PseudoJet &reference) const{
279   return validated_csab()->area(reference);
280 }
281 
282 // return the error (uncertainty) associated with the determination
283 // of the area of this jet.
284 // throws an Error if there is no support for area in the associated CS
area_error(const PseudoJet & reference) const285 double ClusterSequenceStructure::area_error(const PseudoJet &reference) const{
286   return validated_csab()->area_error(reference);
287 }
288 
289 // return the jet 4-vector area
290 // throws an Error if there is no support for area in the associated CS
area_4vector(const PseudoJet & reference) const291 PseudoJet ClusterSequenceStructure::area_4vector(const PseudoJet &reference) const{
292   return validated_csab()->area_4vector(reference);
293 }
294 
295 // true if this jet is made exclusively of ghosts
296 // throws an Error if there is no support for area in the associated CS
is_pure_ghost(const PseudoJet & reference) const297 bool ClusterSequenceStructure::is_pure_ghost(const PseudoJet &reference) const{
298   return validated_csab()->is_pure_ghost(reference);
299 }
300 
301 #endif  // __FJCORE__
302 
303 
304 
305 FASTJET_END_NAMESPACE
306