R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BDigitizingEngine.h
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH *
3 * Copyright (C) 2019-2025 Members of R3B Collaboration *
4 * *
5 * This software is distributed under the terms of the *
6 * GNU General Public Licence (GPL) version 3, *
7 * copied verbatim in the file "LICENSE". *
8 * *
9 * In applying this license GSI does not waive the privileges and immunities *
10 * granted to it by virtue of its status as an Intergovernmental Organization *
11 * or submit itself to any jurisdiction. *
12 ******************************************************************************/
13
14#ifndef NEULAND_DIGITIZING_ENGINE_H
15#define NEULAND_DIGITIZING_ENGINE_H
16
18#include "R3BDigitizingPaddle.h"
19#include "R3BShared.h"
20#include <algorithm>
21#include <atomic>
22#include <cmath>
23#include <functional>
24#include <memory>
25#include <range/v3/algorithm/find_if.hpp>
26#include <range/v3/view/take.hpp>
27#include <range/v3/view/transform.hpp>
28#include <type_traits>
29#include <utility>
30#include <vector>
31
32namespace R3B::Digitizing
33{
35 {
36 public:
38 EngineInterface() = default;
39
41 virtual ~EngineInterface() = default;
42
44 EngineInterface(const EngineInterface& other) = delete;
46 auto operator=(const EngineInterface& other) -> EngineInterface& = delete;
50 auto operator=(EngineInterface&& other) -> EngineInterface& = delete;
51
63 void DepositLight(int paddle_id, double time, double energy_dep, double dist)
64 {
65 auto& paddle = add_paddle(paddle_id);
66 paddle.DepositLight({ time, energy_dep, dist });
67 }
68
74 [[nodiscard]] auto GetTriggerTime() const -> double
75 {
76 auto paddles_view = ranges::views::take(paddles_, size_);
77 auto min_element = std::min_element(paddles_view.begin(),
78 paddles_view.end(),
79 [](const auto& left, const auto& right)
80 { return left->GetTrigTime() < right->GetTrigTime(); });
81 return (min_element == paddles_view.end()) ? NAN : min_element->get()->GetTrigTime();
82 }
83
91 void Init(int initial_capacity = 1)
92 {
93 ExtraInit(initial_capacity);
94 reserve_additional_paddles(initial_capacity);
95 }
96
102 void Reset()
103 {
104 ExtraReset();
105 size_ = 0;
106 }
107
116 {
117 for (auto& paddle : ranges::views::take(paddles_, size_))
118 {
119 paddle->Construct();
120 }
121 }
122
129 [[nodiscard]] auto get_capacity() const { return paddles_.size(); };
130
150 template <typename Unary>
151 void DoEachPaddle(Unary fnt) const
152 {
153 for (const auto& paddle : ranges::views::take(paddles_, size_))
154 {
155 fnt(*paddle);
156 }
157 }
158
182 template <typename Unary>
183 auto DoAllPaddles(Unary fnt) const
184 {
185 return fnt(ranges::views::take(paddles_, size_) |
186 ranges::views::transform([](auto& paddle) -> const AbstractPaddle& { return *paddle; }));
187 }
188
189 private:
190 std::atomic<int> size_ = 0;
191 std::vector<std::unique_ptr<AbstractPaddle>>
193
194 [[nodiscard]] virtual auto make_new_paddle() const -> std::unique_ptr<AbstractPaddle> = 0;
195 virtual void ExtraInit(int initial_capacity) {}
196 virtual void ExtraReset() {}
197
204 {
205 {
206 paddles_.reserve(num + get_capacity());
207 for (int idx{}; idx < num; ++idx)
208 {
209 paddles_.emplace_back(make_new_paddle());
210 }
211 }
212 }
213
214 auto add_paddle(int paddle_id) -> AbstractPaddle&
215 {
216 // find if a paddle with the paddle_id is already added
217 auto valid_view = ranges::views::take(paddles_, size_);
218 auto iter =
219 ranges::find_if(valid_view, [paddle_id](auto& paddle) { return paddle->GetPaddleID() == paddle_id; });
220 if (iter != valid_view.end())
221 {
222 return *(*iter);
223 }
224 // check if size is still smaller than capacity
225 if (size_ >= get_capacity())
226 {
227 // underlying data storage need to grow
229 }
230 auto* new_paddle = paddles_.at(size_++).get();
231 new_paddle->Reset();
232 new_paddle->SetPaddleID(paddle_id);
233 return *new_paddle;
234 }
235 };
236
237 // factory classes for paddle and channel:
238 template <typename ChannelClass, typename = std::enable_if_t<std::is_base_of_v<AbstractChannel, ChannelClass>>>
240 {
241 template <typename... Args>
242 explicit UseChannel(const Args&... args)
243 : BuildChannel([=](Side side) { return std::make_unique<ChannelClass>(side, args...); })
244 {
245 }
246 std::function<std::unique_ptr<ChannelClass>(Side)> BuildChannel;
247 };
248
249 template <typename PaddleClass, typename = std::enable_if_t<std::is_base_of_v<AbstractPaddle, PaddleClass>>>
251 {
252 template <typename... Args>
253 explicit UsePaddle(const Args&... args)
254 : BuildPaddle([=](int paddleID) { return std::make_unique<PaddleClass>(paddleID, args...); })
255 {
256 }
257 std::function<std::unique_ptr<PaddleClass>(int)> BuildPaddle;
258 };
259
260 template <typename PaddleClass, typename ChannelClass, typename InitFunc = std::function<void()>>
261 class Engine : public EngineInterface
262 {
263 public:
265 const UsePaddle<PaddleClass>& p_paddleClass,
266 const UseChannel<ChannelClass>& p_channelClass,
267 InitFunc initFunc = []() {})
268 : paddleClass_{ p_paddleClass }
269 , channelClass_{ p_channelClass }
271 , initFunc_{ initFunc }
272 {
273 }
274
282 void SetInit(const InitFunc& initFunc) { initFunc_ = initFunc; }
283 void ExtraReset() override {}
284
285 private:
288 InitFunc initFunc_;
289
290 void ExtraInit(int /*initial_capacity*/) override { initFunc_(); }
291 [[nodiscard]] auto make_new_paddle() const -> std::unique_ptr<AbstractPaddle> override
292 {
293 auto new_paddle = paddleClass_.BuildPaddle(-1);
294 new_paddle->SetChannel(channelClass_.BuildChannel(R3B::Side::left));
295 new_paddle->SetChannel(channelClass_.BuildChannel(R3B::Side::right));
296 return new_paddle;
297 }
298 };
299
300 // helper to create owning digitizingEngine:
301 template <typename... Args>
302 [[nodiscard]] auto CreateEngine(Args&&... args) -> std::unique_ptr<decltype(Engine{ std::forward<Args>(args)... })>
303 {
304 return std::make_unique<decltype(Engine{ std::forward<Args>(args)... })>(std::forward<Args>(args)...);
305 }
306
307} // namespace R3B::Digitizing
308
309#endif // NEULAND_DIGITIZING_ENGINE_H
UseChannel< ChannelClass > channelClass_
Channel class factory.
Engine(const UsePaddle< PaddleClass > &p_paddleClass, const UseChannel< ChannelClass > &p_channelClass, InitFunc initFunc=[]() {})
auto make_new_paddle() const -> std::unique_ptr< AbstractPaddle > override
void SetInit(const InitFunc &initFunc)
Initialize the underlying data.
UsePaddle< PaddleClass > paddleClass_
Paddle class factory.
void reserve_additional_paddles(int num)
Reserve memories for additional number of paddles.
EngineInterface()=default
Default constructor.
auto operator=(const EngineInterface &other) -> EngineInterface &=delete
Copy assignment operator.
auto DoAllPaddles(Unary fnt) const
Accessor operator for all paddles stored in the current event.
auto operator=(EngineInterface &&other) -> EngineInterface &=delete
Move assignment operator.
virtual void ExtraInit(int initial_capacity)
EngineInterface(EngineInterface &&other)=delete
Move constructor.
void Init(int initial_capacity=1)
Initialization of the engine class.
EngineInterface(const EngineInterface &other)=delete
Copy constructor.
void Reset()
Reset the engine for a new event.
void Construct()
Construct singals from the paddles and channels.
virtual auto make_new_paddle() const -> std::unique_ptr< AbstractPaddle >=0
auto GetTriggerTime() const -> double
Get the trigger time of the current event.
auto add_paddle(int paddle_id) -> AbstractPaddle &
void DoEachPaddle(Unary fnt) const
Accessor operator for each paddle stored in the current event.
void DepositLight(int paddle_id, double time, double energy_dep, double dist)
Takes in a light deposition and pass it to the paddle.
std::vector< std::unique_ptr< AbstractPaddle > > paddles_
main data. This vector should rarely grow in the event loop!
virtual ~EngineInterface()=default
virtual destructor
std::atomic< int > size_
size of bars with valid signals in the current event
auto get_capacity() const
The number of preallocated bar objects in the engine.
auto CreateEngine(Args &&... args) -> std::unique_ptr< decltype(Engine{ std::forward< Args >(args)... })>
UseChannel(const Args &... args)
std::function< std::unique_ptr< Type >(Side)> BuildChannel
std::function< std::unique_ptr< Type >(int)> BuildPaddle
UsePaddle(const Args &... args)