| 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 |