GCC Code Coverage Report


Directory: ./
File: include/na64dp/abstractHitHandler.hh
Date: 2025-09-01 06:19:01
Exec Total Coverage
Lines: 0 9 0.0%
Functions: 0 5 0.0%
Branches: 0 0 -%

Line Branch Exec Source
1 /* This file is a part of NA64SW software.
2 * Copyright (C) 2015-2022 NA64 Collaboration, CERN
3 *
4 * NA64SW is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17 #pragma once
18
19 #include "na64dp/abstractHandler.hh"
20 #include "na64calib/manager.hh"
21 #include "na64dp/fallback.hh"
22 #include "na64util/selector.hh"
23 #include "na64detID/TBName.hh"
24 #include "na64event/data/event.hh"
25 #include "na64util/str-fmt.hh"
26
27 #include <algorithm>
28
29 namespace na64dp {
30
31 ///\defgroup sadc-handlers Data processing handlers related to (M)SADC hits
32 ///\defgroup apv-handlers Data processing handlers related to APV hits
33 ///\defgroup f1-handlers Data processing handlers related to F1-based detector hits
34 ///\defgroup apv-cluster-handlers Data processing handlers related to APV clusters
35 ///\defgroup calo-handlers Data processing handlers related to reconstructed calorimeter hits
36 ///\defgroup track-score-handlers Data processing handlers related to reconstructed track score
37 ///\defgroup tracking-handlers Data processing handlers related to reconstructed track
38 ///\defgroup mc-handlers Data manipulation/processing handlers facilitating simulation routines
39
40 /// Small non-template shim providing hit handler statistics for monitoring
41 class HitHandlerStats : public AbstractHandler {
42 protected:
43 /// Number of considered hits
44 size_t _nHitsConsidered;
45 /// Number of discriminated hits
46 size_t _nHitsDiscriminated;
47 public:
48 HitHandlerStats(log4cpp::Category & logCat)
49 : AbstractHandler(logCat)
50 , _nHitsConsidered(0)
51 , _nHitsDiscriminated(0)
52 {}
53 /// Returns number of hits being considered by this handler
54 size_t n_hits_considered() const { return _nHitsConsidered; }
55 /// Returns number of hits being discriminated by this handler
56 size_t n_hits_discriminated() const { return _nHitsDiscriminated; }
57
58 void inc_num_of_considered_hits() { ++_nHitsConsidered; }
59 void inc_num_of_discriminated_hits() { ++_nHitsDiscriminated; }
60 };
61
62 /**\brief Generic mixing (stub) for hits that do not support selections.
63 *
64 * Methods here are just stubs for generic code that usually re-implemented
65 * by SFINAE-based specializations. The stubs are used by `HitHandler` template
66 * in its generic code.
67 * */
68 template<typename HitT, typename=void>
69 class SelectiveHitHandler {
70 public:
71 SelectiveHitHandler( calib::Dispatcher & cdsp
72 , const std::string & sel
73 , log4cpp::Category & logCat
74 ) {}
75 typedef typename event::Association<event::Event, HitT>::Collection::key_type HitKey;
76 /// Default stub for hit handler which index doesn't support selection,
77 /// returns `false` (handler is NOT selective).
78 constexpr bool is_selective() const { return false; }
79 /// Default stub for hit handler which index doesn't support selection
80 /// always returns `true` (all IDs match).
81 constexpr bool matches( const HitKey ) const { return true; }
82 };
83
84 class SelectiveHandlerMixin
85 : protected calib::Handle<nameutils::DetectorNaming> {
86 public:
87 typedef std::pair<std::string, DetSelect *> Selector;
88 private:
89 /// Selection limits detector IDs this handler is applicable to.
90 Selector _selector;
91 public:
92 SelectiveHandlerMixin( calib::Dispatcher & dspt
93 , const std::string & selExpr
94 , log4cpp::Category & logCat
95 , const std::string & detNamingSubclass="default"
96 )
97 : calib::Handle<nameutils::DetectorNaming>(detNamingSubclass, dspt)
98 , _selector( selExpr, nullptr ) {}
99 ~SelectiveHandlerMixin() {
100 if( _selector.second ) {
101 delete _selector.second;
102 }
103 }
104
105 ///\brief Performs basic conversion of the names set to detector IDs set.
106 ///
107 /// At the level of AbstractHandler<> template, performs conversion of
108 /// string set _selector to set _onlyDetectors of numerical IDs.
109 /// Subclasses may call this parent function to avoid duplication.
110 virtual void handle_update( const nameutils::DetectorNaming & nm ) override {
111 calib::Handle<nameutils::DetectorNaming>::handle_update(nm);
112 if( _selector.first.empty() ) return;
113 if( ! _selector.second ) {
114 _selector.second = new DetSelect( _selector.first.c_str()
115 , util::gDetIDGetters
116 , nm );
117 } else {
118 _selector.second->reset_context( nm );
119 }
120 }
121 /// Returns current naming instance
122 const nameutils::DetectorNaming & naming() const {
123 return static_cast<const calib::Handle<nameutils::DetectorNaming>*>(this)->operator*();
124 }
125 /// Returns true if detector ID matches selection expression
126 bool matches( DetID did ) const {
127 if( _selector.first.empty() ) return true;
128 if( !_selector.second ) { // handle_update() wasn't called yet
129 NA64DP_RUNTIME_ERROR("Detector selector was not compiled (is there"
130 " forgotten Parent::handle_update() call?)");
131 }
132 return _selector.second->matches(did);
133 }
134 /// Returns true if selection expression is set.
135 bool is_selective() const { return !_selector.first.empty(); }
136 /// Returns selector expression that this handler is set to process. Empty
137 /// for all hits of certain type.
138 ///\todo rename to detector_selection_str()
139 const Selector & detector_selection() const { return _selector; }
140 }; // class SelectiveHandlerMixin
141
142 /**\brief Helper class implementing frequent functions on name slections
143 *
144 * This class is designed for handlers that depends on "current" instance of
145 * `util::TBNameMappings` calibration information entry, thus reducing
146 * genericity of handler to single dispatcher instance.
147 *
148 * This specialization is enabled for `DetID` and all its superclasses.
149 * */
150 template<typename HitT>
151 class SelectiveHitHandler<HitT, typename std::enable_if<
152 std::is_constructible< typename event::Association<event::Event, HitT>::Collection::key_type
153 , DetID >::value
154 ||
155 std::is_convertible< typename event::Association<event::Event, HitT>::Collection::key_type
156 , DetID
157 >::value
158 >::type>
159 : protected SelectiveHandlerMixin {
160 public:
161 typedef typename event::Association<event::Event, HitT>::Collection::key_type HitKey;
162 using SelectiveHandlerMixin::is_selective;
163 using SelectiveHandlerMixin::matches;
164 public:
165 /// Initializes hit selection mixing
166 SelectiveHitHandler( calib::Dispatcher & dspt
167 , const std::string & selExpr
168 , log4cpp::Category & logCat
169 , const std::string & detNamingSubclass="default"
170 )
171 : SelectiveHandlerMixin(dspt, selExpr, logCat, detNamingSubclass) {}
172 };
173
174 template<typename HitT>
175 class HitHandlerState {
176 typedef event::Association<event::Event, HitT> Association;
177 protected:
178 /// process_hit() may set this to the resulting code of process_event()
179 AbstractHandler::ProcRes _pr;
180 /// process_hit() may set this to remove current entry from map
181 bool _removeFieldEntry;
182 /// process_hit() may retrieve current event reference
183 event::Event * _cEvPtr;
184 /// A reference to hit currently being processed.
185 typename event::Association<event::Event, HitT>::Collection::iterator _cHitIt;
186
187 std::vector< typename Association::Collection::iterator > _hitsToRemove;
188 public:
189 /// Local failflag wrapper (per-hit)
190 aux::FallbackableMixin localFailflag;
191
192 void set_state_new_event(event::Event & ev) {
193 _pr = AbstractHandler::ProcRes::kOk;
194 _cEvPtr = &ev;
195 _hitsToRemove.clear();
196 }
197
198 void set_state_new_hit(typename event::Association<event::Event, HitT>::Collection::iterator cHitIt) {
199 _cHitIt = cHitIt;
200 _removeFieldEntry = false;
201 }
202
203 HitHandlerState() : _cEvPtr(nullptr) {}
204 /// `process_hit()` may call this to retrieve reference to the current event
205 event::Event & _current_event() { assert( _cEvPtr ); return *_cEvPtr; }
206 /// Const version of `_current_event()`
207 const event::Event & _current_event() const { assert( _cEvPtr ); return *_cEvPtr; }
208 /// process_hit() may call this to retrieve reference to the current hit
209 auto _current_hit_iterator() { return _cHitIt; }
210 /// process_hit() should call this to set the return value of the
211 /// process_event()
212 virtual void _set_event_processing_result( AbstractHandler::ProcRes r ) { _pr = r; }
213 /// process_hit() should call this to erase current hit entry from
214 /// processing
215 virtual void _set_hit_erase_flag() { _removeFieldEntry = true; }
216 };
217
218 template<typename HitT>
219 class AbstractHitHandler : public HitHandlerStats
220 , public SelectiveHitHandler<HitT>
221 , protected HitHandlerState<HitT> {
222 public:
223 using typename SelectiveHitHandler<HitT>::HitKey;
224 public:
225 AbstractHitHandler( calib::Dispatcher & dsp
226 , log4cpp::Category & logCat
227 ) : HitHandlerStats(logCat)
228 , SelectiveHitHandler<HitT>(dsp, logCat, "")
229 {}
230 /// Initializes discriminative hit handler (handles only certain detector
231 /// IDs).
232 AbstractHitHandler( calib::Dispatcher & dsp
233 , const std::string & sel
234 , log4cpp::Category & logCat
235 , const std::string & namingSubclass="default"
236 ) : HitHandlerStats(logCat)
237 , SelectiveHitHandler<HitT>(dsp, sel, logCat, namingSubclass)
238 {}
239
240 ///\brief Shortcut constructor
241 ///
242 /// This constructor sets logging category for handler to be "handlers" and
243 /// detector naming assumed to be "default". Although it most often usecase,
244 /// wide usage of this shortcut has to be generally discouraged.
245 AbstractHitHandler( calib::Dispatcher & dsp
246 , const std::string & selExpr
247 )
248 : HitHandlerStats(log4cpp::Category::getInstance("handlers"))
249 , SelectiveHitHandler<HitT>(dsp, selExpr, log4cpp::Category::getInstance("handlers"), "default")
250 {}
251
252 /// Performs iteration over hits of certain type within an event and
253 /// delegates particular treatment to process_hit(). Will return true
254 /// if all the process_hit() invocations returned true AND there were at
255 /// least one process_hit() invocation.
256 AbstractHandler::ProcRes process_event( event::Event & e ) override;
257
258 /// Shall perform treatment of particular hit and return `false' to abrupt
259 /// an iteration over event hits.
260 virtual bool process_hit( EventID eventID
261 , HitKey
262 , HitT & hit ) = 0;
263
264 /// Returns handler state for external modifications (use with caution,
265 /// advanced level)
266 HitHandlerState<HitT> & hit_handler_state() { return *this; }
267
268 friend class EventSteeringObject;
269 };
270
271 template<typename HitT> AbstractHandler::ProcRes
272 AbstractHitHandler<HitT>::process_event( event::Event & e ) {
273 typedef event::Association<event::Event, HitT> Association;
274 HitHandlerState<HitT>::set_state_new_event(e);
275 bool doEFProc = false;
276 auto & hm = Association::map(e);
277 if( !SelectiveHitHandler<HitT>::is_selective() ) { // selection is not enabled, just iterate over entries
278 for( auto it = hm.begin(); hm.end() != it; ++it ) {
279 inc_num_of_considered_hits();
280 auto hitEntry = *it;
281 auto ref = it->second;
282 HitHandlerState<HitT>::set_state_new_hit(it);
283 assert(ref); // otherwise ref set to nullptr, check creating routines
284 doEFProc = process_hit( e.id, hitEntry.first, *ref );
285 if( HitHandlerState<HitT>::_removeFieldEntry ) {
286 HitHandlerState<HitT>::_hitsToRemove.push_back( it );
287 }
288 if( ! doEFProc ) break;
289 }
290 } else { // selection is enabled, apply selection
291 for( auto it = hm.begin(); hm.end() != it; ++it ) {
292 if( ! SelectiveHitHandler<HitT>::matches(DetID(it->first)) ) continue; // selection doesn't match
293 inc_num_of_considered_hits();
294 auto ref = it->second;
295 HitHandlerState<HitT>::set_state_new_hit(it);
296 assert(ref); // otherwise ref set to nullptr, check creating routines
297 doEFProc = process_hit( e.id, it->first, *ref );
298 if( HitHandlerState<HitT>::_removeFieldEntry ) {
299 HitHandlerState<HitT>::_hitsToRemove.push_back( it );
300 }
301 if( ! doEFProc ) break;
302 }
303 }
304 HitHandlerState<HitT>::_cHitIt = hm.end();
305 for( auto it : HitHandlerState<HitT>::_hitsToRemove ) {
306 Association::remove( Association::map(e), it );
307 }
308 _nHitsDiscriminated += HitHandlerState<HitT>::_hitsToRemove.size();
309 HitHandlerState<HitT>::_cEvPtr = nullptr; // unset current event ptr
310 return HitHandlerState<HitT>::_pr;
311 }
312
313 //
314 // Specialization for track iterating handlers
315 template<>
316 class AbstractHitHandler<event::Track> : public HitHandlerStats {
317 private:
318 /// Track is accounted if any of this patterns matches this set
319 std::unordered_set<int> _permittedZonePatterns;
320 /// Track is accounted if bitwise-AND of this value and track zone pattern
321 /// is non-zero
322 int _permittedZones;
323 /// If true, alterate result of track zone pattern matching
324 bool _invertZonePatternMatching;
325
326 /// process_hit() may set this to the resulting code of process_event()
327 ProcRes _pr;
328 /// process_hit() may set this to remove current entry from map
329 bool _removeFieldEntry;
330 /// process_hit() may retrieve current event reference
331 event::Event * _cEvPtr;
332 /// A reference to hit currently being processed.
333 mem::Ref<event::Track> _cTrack;
334 protected:
335 /// Pointer to track entry currently being processed
336 typename event::Association<event::Event, event::Track>::Collection::iterator _cTrackIt;
337 /// process_hit() may call this to retrieve reference to the current event
338 event::Event & _current_event() { assert( _cEvPtr ); return *_cEvPtr; }
339 /// Const version of `_current_event()`
340 const event::Event & _current_event() const { assert( _cEvPtr ); return *_cEvPtr; }
341 /// process_hit() may call this to retrieve reference to the current hit
342 mem::Ref<event::Track> _current_hit_ref() { return _cTrack; }
343 /// process_hit() should call this to set the return value of the
344 /// process_event()
345 virtual void _set_event_processing_result( ProcRes r ) { _pr = r; }
346 /// process_hit() should call this to erase current hit entry from
347 /// processing
348 virtual void _set_hit_erase_flag() { _removeFieldEntry = true; }
349 public:
350 AbstractHitHandler( const std::unordered_set<int> permittedPatterns
351 , int permittedZones
352 , bool invert
353 , log4cpp::Category & logCat
354 ) : HitHandlerStats(logCat)
355 , _permittedZonePatterns(permittedPatterns)
356 , _permittedZones(permittedZones)
357 , _invertZonePatternMatching(invert)
358 {}
359 AbstractHitHandler( calib::Dispatcher &
360 , const std::string &
361 , log4cpp::Category & logCat
362 , const std::string & namingClass="default"
363 );
364 /// Virtual method to be implemented by subclasses
365 virtual bool process_hit(EventID, TrackID, event::Track &) = 0;
366
367 /// Returns true if given zone pattern matches current selection
368 virtual bool zone_pattern_matches(int) const;
369 /// Invokes `process_hit()` for tracks matching zone pattern
370 ProcRes process_event(event::Event &) override;
371 }; // class AbstractHitHandler<event::Track>
372
373 namespace aux { // TODO: util
374
375 /// Parses the "applyTo" list of strings if given within the node
376 std::string retrieve_det_selection( const YAML::Node & );
377
378 ///\brief Looks for "detectorNamingClass" parameter, returns "default" if not
379 /// found
380 std::string get_naming_class(const YAML::Node &);
381
382 ///\brief Looks for "placementsNamingClass" parameter, returns "default" if not
383 /// found
384 std::string get_placements_class(const YAML::Node &);
385
386 ///\brief Gets the hit type part from getter strings
387 ///
388 /// This function is frequently used to determine the C++ type of the classes
389 /// to be returned in VCtr. It is pretty simple, though.
390 ///
391 /// \todo Correctly infer "event" when ((todo: hits x-macro)) implemented
392 std::string get_val_entry_type(const std::string &);
393
394 } // namespace ::na64dp::aux
395
396 } // namespace na64dp
397
398