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-2023 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 Move constructor */
121 /** @brief = */
123 /** @brief = */
125
126
127 /// @brief internal copy of func for evaluation
128 /// on the heap so will persist in resulting Filters even if
129 /// parent Feature object was destroyed
131};
132
133//////////////////////////////////////////////////////////////////////
134
135/** @brief Expose GenericFeature interface to derived Feature class
136 *
137 * This will get used for generic class types that aren't integral or
138 * floating point types.
139 *
140 * A Feature wraps a function object that can extract a
141 * generic Feature_type from a ConstGenParticlePtr. Usually the
142 * Feature_type would be something like int (e.g. status) or
143 * double (e.g. pT), but it could in principle be any attribute of a
144 * particle so long as there are well defined <, <=, >, >=, == and
145 * != operators for that attribute, as well as an abs function.
146 *
147 * Once a Feature is defined, you can obtain Filters that select
148 * Particles according to that Feature by e.g.
149 * Feature<int> status([](ConstGenParticlePtr p)->int{return p->status();});
150 * bool is_stable = (status == 1)(p);
151 * Filter is_beam = (status == 4);
152 * bool beam = is_beam(p);
153 *
154 * An abs function is also defined, so abs(Feature) works as you'd
155 * expect, e.g.
156 * Feature<double> rapidity([](ConstGenParticlePtr p)->double{return p->momentum().rap();});
157 * Filter rapCut = abs(rapidity) < 2.5;
158 *
159 * Please also see the Selector interface, which defines an
160 * abstract interface to Feature that is free of the template params
161 * and also includes some standard Features such as
162 *
163 * Selector::STATUS;
164 * Selector::PDG_ID;
165 * Selector::PT;
166 * Selector::RAPIDITY;
167
168 */
169template<typename Feature_type, typename Dummy = void>
170class Feature : public GenericFeature<Feature_type> {
171public:
174 using GenericFeature<Feature_type>::m_internal;
175
176 using GenericFeature<Feature_type>::operator ();
177 using GenericFeature<Feature_type>::operator >;
178 using GenericFeature<Feature_type>::operator >=;
179 using GenericFeature<Feature_type>::operator <;
180 using GenericFeature<Feature_type>::operator <=;
181 using GenericFeature<Feature_type>::operator ==;
182 using GenericFeature<Feature_type>::operator !=;
183
184 /// @brief Feature
185 Feature(Evaluator_type functor) : GenericFeature<Feature_type>(functor) {}
186 /// @brief Copy
187 Feature(const Feature &copy) : GenericFeature<Feature_type>(copy) {}
188
189 /// @brief Abs function
191 EvaluatorPtr functor = m_internal;
192 Evaluator_type absfunctor = [functor](ConstGenParticlePtr p)->Feature_type{return ::abs((*functor)(p));};
193 return Feature<Feature_type>(absfunctor);
194 }
195};
196
197//////////////////////////////////////////////////////////////////////
198
199/** @brief Specialisation of Feature for integral types
200 *
201 * It is a valid operator to compare an int to a float, but the
202 * generic version of these operators in the base class will
203 * first cast input float to an int, then compare that. In some cases
204 * the comparison will be incorrect because of rounding the float.
205 * e.g. int x=5; float y=5.5; bool result = x<y; would be wrong
206 * because y first gets converted to int 5.
207 *
208 * To solve this, we provide specialised comparison operators for
209 * integral type and double. Note that the opposite specialisation
210 * in which the Feature_type is floating_point is not necessary
211 */
212template<typename Feature_type>
213class Feature<Feature_type, typename std::enable_if<std::is_integral<Feature_type>::value, void>::type> : public GenericFeature<Feature_type> {
214public:
215 using GenericFeature<Feature_type>::operator ();
216 using GenericFeature<Feature_type>::operator >;
217 using GenericFeature<Feature_type>::operator >=;
218 using GenericFeature<Feature_type>::operator <;
219 using GenericFeature<Feature_type>::operator <=;
220 using GenericFeature<Feature_type>::operator ==;
221 using GenericFeature<Feature_type>::operator !=;
222
225
226 using GenericFeature<Feature_type>::m_internal;
227
228 /// @brief Feature
229 Feature(Evaluator_type functor) : GenericFeature<Feature_type>(functor) {}
230 /// @brief Feature
231 Feature(const Feature &copy) : GenericFeature<Feature_type>(copy) {}
232
233 /// @brief abs function
235 EvaluatorPtr functor = m_internal;
236 Evaluator_type absfunctor = [functor](ConstGenParticlePtr p)->Feature_type{return ::abs((*functor)(p));};
237 return Feature<Feature_type>(absfunctor);
238 }
239
240 /// @brief greater operator
241 Filter operator > (double value) const {
242 EvaluatorPtr functor = m_internal;
243 return [value, functor](ConstGenParticlePtr input)->bool{return (*functor)(input) > value;};
244 }
245
246 /// @brief less operator
247 Filter operator < (double value) const {
248 EvaluatorPtr functor = m_internal;
249 return [value, functor](ConstGenParticlePtr input)->bool{return (*functor)(input) < value;};
250 }
251
252 /// @brief equal operator
253 Filter operator == (double value) const {
254 EvaluatorPtr functor = m_internal;
255 return [value, functor](ConstGenParticlePtr input)->bool{
256 Feature_type local = (*functor)(input);
257 return std::abs(local - value) < std::numeric_limits<double>::epsilon();
258 };
259 }
260
261 /// @brief greater or equal operator
262 Filter operator >= (double value) const { return !( (*this) < value );}
263
264 /// @brief less or equal operator
265 Filter operator <= (double value) const { return !( (*this) > value );}
266
267 /// @brief not equal operator
268 Filter operator != (double value) const {
269 return !( (*this) == value );
270 }
271};
272
273//////////////////////////////////////////////////////////////////////
274
275/** @brief specialisation of Feature for floating point type
276 *
277 * Test of equality of floating point types is not safe. Here we
278 * provide a "reasonable" definition of equality based on the
279 * floating point precision.
280 */
281
282template<typename Feature_type>
283class Feature<Feature_type, typename std::enable_if<std::is_floating_point<Feature_type>::value, void>::type> : public GenericFeature<Feature_type> {
284public:
287
288 using GenericFeature<Feature_type>::operator ();
289 using GenericFeature<Feature_type>::operator >;
290 using GenericFeature<Feature_type>::operator >=;
291 using GenericFeature<Feature_type>::operator <;
292 using GenericFeature<Feature_type>::operator <=;
293
294 using GenericFeature<Feature_type>::m_internal;
295
296 /// @brief Feature
297 Feature(Evaluator_type functor) : GenericFeature<Feature_type>(functor) {}
298 /// @brief Copy
299 Feature(const Feature &copy) : GenericFeature<Feature_type>(copy) {}
300
301 /// @brief abs function
303 EvaluatorPtr functor = m_internal;
304 Evaluator_type absfunctor = [functor](ConstGenParticlePtr p)->Feature_type{return std::abs((*functor)(p));};
305 return Feature<Feature_type>(absfunctor);
306 }
307
308 Filter operator == (Feature_type value) const override {
309 EvaluatorPtr functor = m_internal;
310 return [value, functor](ConstGenParticlePtr input)->bool{
311 Feature_type local = (*functor)(input);
312 return std::less_equal<Feature_type>{}(fabs(local - value) , std::numeric_limits<Feature_type>::epsilon());
313 };
314 }
315
316 Filter operator != (Feature_type value) const override {
317 return !( (*this) == value );
318 }
319};
320
321//////////////////////////////////////////////////////////////////////
322
323/**
324 * @brief Obtain the absolute value of a Feature.
325 * This works as you'd expect. If foo is a valid Feature, then
326 * abs(foo) returns a new Feature that corresponds to the absolute
327 * value of the foo feature. You can construct a Filter from that in
328 * the usual way with e.g. Filter f = abs(foo) > 10.;
329 */
330template<typename Feature_type>
332 return input.abs();
333}
334
335}
336
337#endif
Defines Filter operations for combingin Filters.
Definition of class GenParticle.
Expose GenericFeature interface to derived Feature class.
Definition Feature.h:170
Feature< Feature_type > abs() const
Abs function.
Definition Feature.h:190
Feature(Evaluator_type functor)
Feature.
Definition Feature.h:185
Feature(const Feature &copy)
Copy.
Definition Feature.h:187
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:130
Filter operator>=(Feature_type value) const
greater than or equals operator
Definition Feature.h:86
GenericFeature & operator=(const GenericFeature &)=default
=
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(GenericFeature &&)=default
Move constructor.
GenericFeature(const GenericFeature &copy)
Hide the copy constructor.
Definition Feature.h:117
GenericFeature & operator=(GenericFeature &&)=default
=
std::shared_ptr< Evaluator_type > EvaluatorPtr
shared pointer for evaluator type
Definition Feature.h:64
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:331