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
21namespace 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 */
58template<typename Feature_type>
60public:
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
112protected:
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 */
161template<typename Feature_type, typename Dummy = void>
162class Feature : public GenericFeature<Feature_type> {
163public:
166 using GenericFeature<Feature_type>::m_internal;
167
168 using GenericFeature<Feature_type>::operator ();
169 using GenericFeature<Feature_type>::operator >;
170 using GenericFeature<Feature_type>::operator >=;
171 using GenericFeature<Feature_type>::operator <;
172 using GenericFeature<Feature_type>::operator <=;
173 using GenericFeature<Feature_type>::operator ==;
174 using GenericFeature<Feature_type>::operator !=;
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 */
204template<typename Feature_type>
205class Feature<Feature_type, typename std::enable_if<std::is_integral<Feature_type>::value, void>::type> : public GenericFeature<Feature_type> {
206public:
207 using GenericFeature<Feature_type>::operator ();
208 using GenericFeature<Feature_type>::operator >;
209 using GenericFeature<Feature_type>::operator >=;
210 using GenericFeature<Feature_type>::operator <;
211 using GenericFeature<Feature_type>::operator <=;
212 using GenericFeature<Feature_type>::operator ==;
213 using GenericFeature<Feature_type>::operator !=;
214
217
218 using GenericFeature<Feature_type>::m_internal;
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
274template<typename Feature_type>
275class Feature<Feature_type, typename std::enable_if<std::is_floating_point<Feature_type>::value, void>::type> : public GenericFeature<Feature_type> {
276public:
279
280 using GenericFeature<Feature_type>::operator ();
281 using GenericFeature<Feature_type>::operator >;
282 using GenericFeature<Feature_type>::operator >=;
283 using GenericFeature<Feature_type>::operator <;
284 using GenericFeature<Feature_type>::operator <=;
285
286 using GenericFeature<Feature_type>::m_internal;
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 */
322template<typename Feature_type>
324 return input.abs();
325}
326
327}
328
329#endif
Defines Filter operations for combingin Filters.
Definition of class GenParticle.
Expose GenericFeature interface to derived Feature class.
Definition: Feature.h:162
Feature< Feature_type > abs() const
Abs function.
Definition: Feature.h:182
Feature(Evaluator_type functor)
Feature.
Definition: Feature.h:177
Feature(const Feature &copy)
Copy.
Definition: Feature.h:179
GenericFeature defines the Feature interface GenericFeature is not intended to be used directly....
Definition: Feature.h:59
Filter operator>(Feature_type value) const
greater than operator
Definition: Feature.h:73
Filter operator<(Feature_type value) const
less than operator
Definition: Feature.h:79
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
greater than or equals operator
Definition: Feature.h:86
std::function< Feature_type(ConstGenParticlePtr)> Evaluator_type
evaluator type
Definition: Feature.h:62
virtual Filter operator!=(Feature_type value) const
inequality operator
Definition: Feature.h:107
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
virtual Filter operator==(Feature_type value) const
equality operator
Definition: Feature.h:100
Filter operator<=(Feature_type value) const
less than or equals operator
Definition: Feature.h:93
GenericFeature(Evaluator_type functor)
Hide the constructor so no one can use GenericFeature directly.
Definition: Feature.h:114
HepMC3 main namespace.
std::function< bool(ConstGenParticlePtr)> Filter
type of Filter
Definition: Filter.h:19
Feature< Feature_type > abs(const Feature< Feature_type > &input)
Obtain the absolute value of a Feature. This works as you'd expect. If foo is a valid Feature,...
Definition: Feature.h:323