HepMC3 event record library
Feature.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // This file is part of HepMC
4 // Copyright (C) 2014-2021 The HepMC collaboration (see AUTHORS for details)
5 //
6 ///
7 /// @file Feature.h
8 /// @brief Defines Feature interface for selecting Particles according to extracted Features.
9 ///
10 
11 #ifndef HEPMC3_FEATURE_H
12 #define HEPMC3_FEATURE_H
13 
14 #include <functional>
15 #include <memory>
16 #include <limits>
17 #include "HepMC3/GenParticle.h"
18 #include "HepMC3/Filter.h"
19 
20 
21 namespace HepMC3 {
22 
23 //////////////////////////////////////////////////////////////////////
24 
25 /**
26  * @brief GenericFeature defines the Feature interface
27  * GenericFeature is not intended to be used directly. The
28  * derived Feature class and its specialisations should be used.
29  *
30  * A Feature wraps a function object that can extract a
31  * generic Feature_type from a ConstGenParticlePtr. Usually the
32  * Feature_type would be something like int (e.g. status) or
33  * double (e.g. pT), but it could in principle be any attribute of a
34  * particle so long as there are well defined <, <=, >, >=, == and
35  * != operators for that attribute, as well as an abs function.
36  *
37  * Once a Feature is defined, you can obtain Filters that select
38  * Particles according to that Feature by e.g.
39  * Feature<int> status([](ConstGenParticlePtr p)->int{return p->status();});
40  * bool is_stable = (status == 1)(p);
41  * Filter is_beam = (status == 4);
42  * bool beam = is_beam(p);
43  *
44  * An abs function is also defined, so abs(Feature) works as you'd
45  * expect, e.g.
46  * Feature<double> rapidity([](ConstGenParticlePtr p)->double{return p->momentum().rap();});
47  * Filter rapCut = abs(rapidity) < 2.5;
48  *
49  * Please also see the Selector interface, which defines an
50  * abstract interface to Feature that is free of the template params
51  * and also includes some standard Features such as
52  *
53  * Selector::STATUS;
54  * Selector::PDG_ID;
55  * Selector::PT;
56  * Selector::RAPIDITY;
57  */
58 template<typename Feature_type>
60 public:
61  /// @brief evaluator type
62  using Evaluator_type = std::function<Feature_type(ConstGenParticlePtr)>;
63  /// @brief shared pointer for evaluator type
64  using EvaluatorPtr = std::shared_ptr<Evaluator_type>;
65 
66  /// @brief access the underlying feature value
67  Feature_type operator()(ConstGenParticlePtr input)const {
68  return (*m_internal)(input);
69  }
70 
71  /// @brief greater than operator
72  /// @return Filter function
73  Filter operator > (Feature_type value) const {
74  EvaluatorPtr functor = m_internal;
75  return [value, functor](ConstGenParticlePtr input)->bool{return (*functor)(input) > value;};
76  }
77  /// @brief less than operator
78  /// @return Filter function
79  Filter operator < (Feature_type value) const {
80  EvaluatorPtr functor = m_internal;
81  return [value, functor](ConstGenParticlePtr input)->bool{return (*functor)(input) < value;};
82  }
83 
84  /// @brief greater than or equals operator
85  /// @return Filter function
86  Filter operator >= (Feature_type value) const {
87  EvaluatorPtr functor = m_internal;
88  return [value, functor](ConstGenParticlePtr input)->bool{return (*functor)(input) >= value;};
89  }
90 
91  /// @brief less than or equals operator
92  /// @return Filter function
93  Filter operator <= (Feature_type value) const {
94  EvaluatorPtr functor = m_internal;
95  return [value, functor](ConstGenParticlePtr input)->bool{return (*functor)(input) <= value;};
96  }
97 
98  /// @brief equality operator
99  /// @return Filter function
100  virtual Filter operator == (Feature_type value) const {
101  EvaluatorPtr functor = m_internal;
102  return [value, functor](ConstGenParticlePtr input)->bool{return (*functor)(input) == value;};
103  }
104 
105  /// @brief inequality operator
106  /// @return Filter function
107  virtual Filter operator != (Feature_type value) const {
108  EvaluatorPtr functor = m_internal;
109  return [value, functor](ConstGenParticlePtr input)->bool{return (*functor)(input) != value;};
110  }
111 
112 protected:
113  /// Hide the constructor so no one can use GenericFeature directly
114  GenericFeature(Evaluator_type functor):m_internal(std::make_shared<Evaluator_type>(functor)) {}
115 
116  /// Hide the copy constructor
118 
119  /// @brief internal copy of func for evaluation
120  /// on the heap so will persist in resulting Filters even if
121  /// parent Feature object was destroyed
123 };
124 
125 //////////////////////////////////////////////////////////////////////
126 
127 /** @brief Expose GenericFeature interface to derived Feature class
128  *
129  * This will get used for generic class types that aren't integral or
130  * floating point types.
131  *
132  * A Feature wraps a function object that can extract a
133  * generic Feature_type from a ConstGenParticlePtr. Usually the
134  * Feature_type would be something like int (e.g. status) or
135  * double (e.g. pT), but it could in principle be any attribute of a
136  * particle so long as there are well defined <, <=, >, >=, == and
137  * != operators for that attribute, as well as an abs function.
138  *
139  * Once a Feature is defined, you can obtain Filters that select
140  * Particles according to that Feature by e.g.
141  * Feature<int> status([](ConstGenParticlePtr p)->int{return p->status();});
142  * bool is_stable = (status == 1)(p);
143  * Filter is_beam = (status == 4);
144  * bool beam = is_beam(p);
145  *
146  * An abs function is also defined, so abs(Feature) works as you'd
147  * expect, e.g.
148  * Feature<double> rapidity([](ConstGenParticlePtr p)->double{return p->momentum().rap();});
149  * Filter rapCut = abs(rapidity) < 2.5;
150  *
151  * Please also see the Selector interface, which defines an
152  * abstract interface to Feature that is free of the template params
153  * and also includes some standard Features such as
154  *
155  * Selector::STATUS;
156  * Selector::PDG_ID;
157  * Selector::PT;
158  * Selector::RAPIDITY;
159 
160  */
161 template<typename Feature_type, typename Dummy = void>
162 class Feature : public GenericFeature<Feature_type> {
163 public:
167 
175 
176  /// @brief Feature
177  Feature(Evaluator_type functor) : GenericFeature<Feature_type>(functor) {}
178  /// @brief Copy
179  Feature(const Feature &copy) : GenericFeature<Feature_type>(copy) {}
180 
181  /// @brief Abs function
183  EvaluatorPtr functor = m_internal;
184  Evaluator_type absfunctor = [functor](ConstGenParticlePtr p)->Feature_type{return ::abs((*functor)(p));};
185  return Feature<Feature_type>(absfunctor);
186  }
187 };
188 
189 //////////////////////////////////////////////////////////////////////
190 
191 /** @brief Specialisation of Feature for integral types
192  *
193  * It is a valid operator to compare an int to a float, but the
194  * generic version of these operators in the base class will
195  * first cast input float to an int, then compare that. In some cases
196  * the comparison will be incorrect because of rounding the float.
197  * e.g. int x=5; float y=5.5; bool result = x<y; would be wrong
198  * because y first gets converted to int 5.
199  *
200  * To solve this, we provide specialised comparison operators for
201  * integral type and double. Note that the opposite specialisation
202  * in which the Feature_type is floating_point is not necessary
203  */
204 template<typename Feature_type>
205 class Feature<Feature_type, typename std::enable_if<std::is_integral<Feature_type>::value, void>::type> : public GenericFeature<Feature_type> {
206 public:
214 
217 
219 
220  /// @brief Feature
221  Feature(Evaluator_type functor) : GenericFeature<Feature_type>(functor) {}
222  /// @brief Feature
223  Feature(const Feature &copy) : GenericFeature<Feature_type>(copy) {}
224 
225  /// @brief abs function
227  EvaluatorPtr functor = m_internal;
228  Evaluator_type absfunctor = [functor](ConstGenParticlePtr p)->Feature_type{return ::abs((*functor)(p));};
229  return Feature<Feature_type>(absfunctor);
230  }
231 
232  /// @brief greater operator
233  Filter operator > (double value) const {
234  EvaluatorPtr functor = m_internal;
235  return [value, functor](ConstGenParticlePtr input)->bool{return (*functor)(input) > value;};
236  }
237 
238  /// @brief less operator
239  Filter operator < (double value) const {
240  EvaluatorPtr functor = m_internal;
241  return [value, functor](ConstGenParticlePtr input)->bool{return (*functor)(input) < value;};
242  }
243 
244  /// @brief equal operator
245  Filter operator == (double value) const {
246  EvaluatorPtr functor = m_internal;
247  return [value, functor](ConstGenParticlePtr input)->bool{
248  Feature_type local = (*functor)(input);
249  return std::abs(local - value) < std::numeric_limits<double>::epsilon();
250  };
251  }
252 
253  /// @brief greater or equal operator
254  Filter operator >= (double value) const { return !( (*this) < value );}
255 
256  /// @brief less or equal operator
257  Filter operator <= (double value) const { return !( (*this) > value );}
258 
259  /// @brief not equal operator
260  Filter operator != (double value) const {
261  return !( (*this) == value );
262  }
263 };
264 
265 //////////////////////////////////////////////////////////////////////
266 
267 /** @brief specialisation of Feature for floating point type
268  *
269  * Test of equality of floating point types is not safe. Here we
270  * provide a "reasonable" definition of equality based on the
271  * floating point precision.
272  */
273 
274 template<typename Feature_type>
275 class Feature<Feature_type, typename std::enable_if<std::is_floating_point<Feature_type>::value, void>::type> : public GenericFeature<Feature_type> {
276 public:
279 
285 
287 
288  /// @brief Feature
289  Feature(Evaluator_type functor) : GenericFeature<Feature_type>(functor) {}
290  /// @brief Copy
291  Feature(const Feature &copy) : GenericFeature<Feature_type>(copy) {}
292 
293  /// @brief abs function
295  EvaluatorPtr functor = m_internal;
296  Evaluator_type absfunctor = [functor](ConstGenParticlePtr p)->Feature_type{return std::abs((*functor)(p));};
297  return Feature<Feature_type>(absfunctor);
298  }
299 
300  Filter operator == (Feature_type value) const override {
301  EvaluatorPtr functor = m_internal;
302  return [value, functor](ConstGenParticlePtr input)->bool{
303  Feature_type local = (*functor)(input);
304  return std::less_equal<Feature_type>{}(fabs(local - value) , std::numeric_limits<Feature_type>::epsilon());
305  };
306  }
307 
308  Filter operator != (Feature_type value) const override {
309  return !( (*this) == value );
310  }
311 };
312 
313 //////////////////////////////////////////////////////////////////////
314 
315 /**
316  * @brief Obtain the absolute value of a Feature.
317  * This works as you'd expect. If foo is a valid Feature, then
318  * abs(foo) returns a new Feature that corresponds to the absolute
319  * value of the foo feature. You can construct a Filter from that in
320  * the usual way with e.g. Filter f = abs(foo) > 10.;
321  */
322 template<typename Feature_type>
324  return input.abs();
325 }
326 
327 }
328 
329 #endif
GenericFeature(Evaluator_type functor)
Hide the constructor so no one can use GenericFeature directly.
Definition: Feature.h:114
virtual Filter operator==(Feature_type value) const
equality operator
Definition: Feature.h:100
virtual Filter operator!=(Feature_type value) const
inequality operator
Definition: Feature.h:107
Definition of class GenParticle.
Filter operator>=(Feature_type value) const
greater than or equals operator
Definition: Feature.h:86
GenericFeature defines the Feature interface GenericFeature is not intended to be used directly...
Definition: Feature.h:59
Defines Filter operations for combingin Filters.
Feature(Evaluator_type functor)
Feature.
Definition: Feature.h:177
Filter operator>(Feature_type value) const
greater than operator
Definition: Feature.h:73
Feature< Feature_type > abs() const
Abs function.
Definition: Feature.h:182
Filter operator<(Feature_type value) const
less than operator
Definition: Feature.h:79
std::function< bool(ConstGenParticlePtr)> Filter
type of Filter
Definition: Filter.h:19
Expose GenericFeature interface to derived Feature class.
Definition: Feature.h:162
EvaluatorPtr m_internal
internal copy of func for evaluation on the heap so will persist in resulting Filters even if parent ...
Definition: Feature.h:122
std::shared_ptr< Evaluator_type > EvaluatorPtr
shared pointer for evaluator type
Definition: Feature.h:64
Filter operator<=(Feature_type value) const
less than or equals operator
Definition: Feature.h:93
std::function< Feature_type(ConstGenParticlePtr)> Evaluator_type
evaluator type
Definition: Feature.h:62
GenericFeature(const GenericFeature &copy)
Hide the copy constructor.
Definition: Feature.h:117
Feature_type operator()(ConstGenParticlePtr input) const
access the underlying feature value
Definition: Feature.h:67
Feature< Feature_type > abs(const Feature< Feature_type > &input)
Obtain the absolute value of a Feature. This works as you&#39;d expect. If foo is a valid Feature...
Definition: Feature.h:323
Feature(const Feature &copy)
Copy.
Definition: Feature.h:179