R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BNeulandTamexReader2.cxx
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH *
3 * Copyright (C) 2019-2023 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#include "FairLogger.h"
15#include "FairRootManager.h"
16
17#include "R3BLogger.h"
19#include "TClonesArray.h"
20#include "ext_data_client.h"
21#include "ext_data_struct_info.hh"
23#include <R3BShared.h>
24#include <boost/regex.hpp>
25
26// TODO: C++20 std::span
27#include <gsl/span>
28// TODO: C++20 std::range
29#include <range/v3/view.hpp>
30
35
36using gsl::span;
37namespace views = ranges::views;
38using R3B::Side;
40
41namespace
42{
43 constexpr size_t INITIAL_SIGNAL_SIZE = 20;
44 constexpr size_t PRINT_ERROR_MAX = 100000;
45 constexpr auto BarsPerPlane = 50;
46 const auto errorStrings = std::map<Errors, std::string>{
47 { Errors::module_size, "Incompatible module size" },
48 { Errors::data_size, "Incompatible signal size" },
49 { Errors::divider, "Incompatible signal dividers" },
50 { Errors::indices, "Incompatible module IDs" },
51 };
52
53 const auto SIDES = std::array<Side, 2>{ Side::left, Side::right };
54 template <typename BinaryOperation, typename Item0, typename Item1>
55 inline constexpr auto CheckAmong(BinaryOperation optn, const Item0& item0, const Item1& item1) -> bool
56 {
57 return optn(item0, item1);
58 }
59
60 template <typename BinaryOperation, typename Item0, typename Item1, typename... Items>
61 inline constexpr auto CheckAmong(BinaryOperation optn,
62 const Item0& item0,
63 const Item1& item1,
64 const Items&... items) -> bool
65 {
66 return CheckAmong(optn, item0, item1) && CheckAmong(optn, item1, items...);
67 }
68
69 template <typename UnaryOperation, typename... Items>
70 inline auto CheckAny(UnaryOperation optn, const Items&... items)
71 {
72 return (optn(items) || ...);
73 }
74
75 template <typename UnaryFunction, typename... Items>
76 inline auto Zip_from(UnaryFunction optn, const Items&... items)
77 {
78 return ranges::zip_view(optn(items)...);
79 }
80
81 template <typename Signals, typename ModuleNum_divider, typename UnaryFunction>
82 inline void FillData(const Signals& signals_view,
83 const ModuleNum_divider& moduleNum_divider_view,
84 UnaryFunction optn)
85 {
86 auto range_begin = signals_view.begin();
87 auto range_iter = signals_view.begin();
88 for (const auto& [module_num, divider] : moduleNum_divider_view)
89 {
90 for (; !(range_iter == signals_view.end() || range_iter == (range_begin + divider)); ++range_iter)
91 {
92 optn(*range_iter, module_num);
93 }
94 }
95 }
96} // namespace
97
99 : R3BReader("R3BNeulandTamexReader2")
100 , max_limit_(PRINT_ERROR_MAX)
101 , fOffset(offset)
102 , numPlanes_(R3B::GetSize(inputData_->NN_P))
103 , inputData_{ data }
104 , mappedDataPtr_{ &mappedData_ }
105 , mappedTrigDataPtr_{ &mappedTrigData_ }
106{
107 mappedData_.reserve(INITIAL_SIGNAL_SIZE);
108 error_log_.insert_or_assign(Errors::module_size, 0);
109 error_log_.insert_or_assign(Errors::data_size, 0);
110 error_log_.insert_or_assign(Errors::indices, 0);
111 error_log_.insert_or_assign(Errors::divider, 0);
112}
113
114Bool_t R3BNeulandTamexReader2::Init(ext_data_struct_info* a_struct_info) // NOLINT
115{
116 auto status_ok = 1;
117 R3BLOG(info, "");
118 EXT_STR_h101_raw_nnp_tamex_ITEMS_INFO(status_ok, *a_struct_info, fOffset, EXT_STR_h101_raw_nnp_tamex, 0); // NOLINT
119
120 if (status_ok == 0)
121 {
122 R3BLOG(error, "Failed to setup structure information.");
123 return false;
124 }
125
126 R3BLOG(info, "Number of planes " << numPlanes_);
127
128 // Register output arrays in tree
129 auto* rootMan = FairRootManager::Instance();
130 rootMan->RegisterAny("NeulandMappedData", mappedDataPtr_, !is_online_);
131 if (is_triggered_)
132 {
133 rootMan->RegisterAny("NeulandTrigMappedData", mappedTrigDataPtr_, !is_online_);
134 }
135 Reset();
136 if (not is_online_)
137 {
138 histogram_init();
139 }
140 return kTRUE;
141}
142
143void R3BNeulandTamexReader2::histogram_init()
144{
145 const auto BarBinSize = numPlanes_ * 50;
146 histograms_.add_hist<TH1I>(
147 "bar_FT_l", "number of hits on left PMTS for each bar", BarBinSize, 0.5, 0.5 + BarBinSize);
148 histograms_.add_hist<TH1I>(
149 "bar_FT_r", "number of hits on right PMTS for each bar", BarBinSize, 0.5, 0.5 + BarBinSize);
150}
151
152template <typename ErrorLog, typename... Items>
153auto CheckCondition(ErrorLog& log, const Items&... items) -> bool
154{
155 auto ApplyCriterium = [&log, &items...](Errors error, auto criterium) -> bool
156 {
157 if (!CheckAmong(criterium, items...))
158 {
159 ++log.at(error);
160 return false;
161 }
162 return true;
163 };
164 return ApplyCriterium(Errors::module_size,
165 [](const auto& left, const auto& right) { return left.BM == right.BM; }) &&
166 ApplyCriterium(Errors::data_size, [](const auto& left, const auto& right) { return left.B == right.B; }) &&
167 ApplyCriterium(Errors::indices,
168 [](const auto& left, const auto& right) {
169 return ranges::equal(views::take(left.BMI, left.BM), views::take(right.BMI, right.BM));
170 }) &&
171 ApplyCriterium(Errors::divider,
172 [](const auto& left, const auto& right)
173 { return ranges::equal(views::take(left.BME, left.BM), views::take(right.BME, right.BM)); });
174}
175
176template <typename ViewType>
177auto R3BNeulandTamexReader2::extract_plane_signals(const ViewType& signalsPlane, int planeNum)
178{
179 auto planeSignals = R3BPaddleTamexMappedData2{ static_cast<unsigned int>(planeNum) };
180 const auto signals_sides_view =
181 ranges::zip_view(signalsPlane.tcl_T, signalsPlane.tfl_T, signalsPlane.tct_T, signalsPlane.tft_T, SIDES);
182 for (const auto& [coarse_leading, fine_leading, coarse_trailing, fine_trailing, side] : signals_sides_view)
183 {
184 // pass if no data
185 if (CheckAny([](const auto& item) { return item.BM == 0; },
186 coarse_leading,
187 fine_leading,
188 coarse_trailing,
189 fine_trailing))
190 {
191 R3BLOG(debug3, fmt::format("No signals at the current event from plane {}.", planeNum));
192 continue;
193 }
194
195 if (!CheckCondition(error_log_, coarse_leading, fine_leading, coarse_trailing, fine_trailing))
196 {
198 }
199
200 const auto module_size = coarse_leading.BM;
201 const auto signal_size = coarse_leading.B;
202 R3BLOG(debug, fmt::format("Signals at the current event from plane {}: {}", planeNum, signal_size));
203 mappedData_.reserve(signal_size);
204 const auto barNum_divider_view = ranges::zip_view(span(coarse_leading.BMI), span(coarse_leading.BME));
205
206 const auto signals_view = Zip_from([](const auto& item) { return span(item.Bv); },
207 coarse_leading,
208 fine_leading,
209 coarse_trailing,
210 fine_trailing);
211 // TODO C++20: planeID and side can be directly captured by the lambda. Before C++20, capturing struture
212 // bindings is undefined behaviour
213 auto side_temp = side;
214 FillData(
215 signals_view | ranges::views::take(signal_size),
216 barNum_divider_view | ranges::views::take(module_size),
217 [&](const auto& signals, const auto& barNum)
218 {
219 const auto& [cl_time, fl_time, ct_time, ft_time] = signals;
220 auto doubleEdgeSignal = R3B::DoubleEdgeSignal{};
221 doubleEdgeSignal.leading.fine = fl_time;
222 doubleEdgeSignal.leading.coarse = cl_time;
223 doubleEdgeSignal.trailing.fine = ft_time;
224 doubleEdgeSignal.trailing.coarse = ct_time;
225
226 planeSignals.push_back(side_temp, barNum, doubleEdgeSignal);
227 R3BLOG(
228 debug3,
229 fmt::format(
230 "Writing a doube edge signal: barNum: {}, fl_time: {}, cl_time: {}, ft_time: {}, ct_time: {}",
231 barNum,
232 fl_time,
233 cl_time,
234 ft_time,
235 ct_time));
236
237 if (is_online_)
238 {
239 return;
240 }
241
242 if (side_temp == R3B::Side::left)
243 {
244 histograms_.get("bar_FT_l")->Fill(barNum + (planeNum - 1) * BarsPerPlane);
245 }
246 else
247 {
248 histograms_.get("bar_FT_r")->Fill(barNum + (planeNum - 1) * BarsPerPlane);
249 }
250 });
251 }
252 return planeSignals;
253}
254
256{
257 const auto signalsAllPlanes = span(inputData->NN_P);
258
259 mappedData_.clear();
260 for (const auto& [signalsPlane, planeID] : ranges::zip_view(signalsAllPlanes, ranges::iota_view(1)))
261 {
262 auto planeSignals = extract_plane_signals(signalsPlane, planeID);
263 if (!planeSignals.empty())
264 {
265 if (not is_online_)
266 {
267 histogram_action(planeSignals);
268 }
269 mappedData_.emplace_back(std::move(planeSignals));
270 }
271 }
272
273 return true;
274}
275
276void R3BNeulandTamexReader2::histogram_action(const R3B::PaddleTamexMappedData& mappedData)
277{
278 for (const auto& [hist_name, action] : hist_actions_)
279 {
280 action(mappedData, histograms_.get(hist_name));
281 }
282}
283
284template <typename ErrorLog, typename... Items>
285auto Checkondition(ErrorLog& log, EXT_STR_h101_raw_nnp_tamex_onion* inputData)
286{
287 auto ApplyCriterium = [&log](Errors error, bool criterium) -> bool
288 {
289 if (!criterium)
290 {
291 ++log.at(error);
292 return false;
293 }
294 return true;
295 };
296 return ApplyCriterium(Errors::module_size, inputData->NN_TRIGCM == inputData->NN_TRIGFM) &&
297 ApplyCriterium(Errors::data_size, inputData->NN_TRIGC == inputData->NN_TRIGF) &&
298 ApplyCriterium(Errors::indices,
299 ranges::equal(views::take(inputData->NN_TRIGCMI, inputData->NN_TRIGCM),
300 views::take(inputData->NN_TRIGFMI, inputData->NN_TRIGFM))) &&
301 ApplyCriterium(Errors::divider,
302 ranges::equal(views::take(inputData->NN_TRIGCME, inputData->NN_TRIGCM),
303 views::take(inputData->NN_TRIGFME, inputData->NN_TRIGFM)));
304}
305
307{
308 if (!is_triggered_ || inputData->NN_TRIGCM == 0 || inputData->NN_TRIGFM == 0)
309 {
310 return true;
311 }
312
313 if (!Checkondition(error_log_, inputData))
314 {
315 return false;
316 }
317
318 const auto module_size = inputData->NN_TRIGCM;
319 const auto signal_size = inputData->NN_TRIGC;
320 auto const trigger_signals_view =
321 Zip_from([](const auto& item) { return span(item); }, inputData->NN_TRIGCv, inputData->NN_TRIGFv);
322 auto const moduleNum_divider_view = ranges::zip_view(span(inputData->NN_TRIGCMI), span(inputData->NN_TRIGCME));
323 FillData(ranges::views::take(trigger_signals_view, signal_size),
324 ranges::views::take(moduleNum_divider_view, module_size),
325 [&](const auto& signal_pack, const auto& module_num)
326 {
327 const auto& [coarse_time, fine_time] = signal_pack;
328 auto trigDatum = mappedTrigData_.emplace(module_num, R3BPaddleTamexTrigMappedData{}).first;
329 trigDatum->second.module_num = module_num;
330 trigDatum->second.signal.fine = fine_time;
331 trigDatum->second.signal.coarse = coarse_time;
332 R3BLOG(debug3,
333 fmt::format("Writing a trig signal: module ID: {}, fine time: {}, coarse_time: {}",
334 module_num,
335 fine_time,
336 coarse_time));
337 // std::cout << "trig signal: " << module_num << "\t" << fine_time << "\t" << coarse_time << "\n";
338 });
339 return true;
340}
341
343{
344 if (!(ReadSignals(inputData_) && ReadTriggerSignals(inputData_)))
345 {
346 return false;
347 }
348 if (fair::Logger::GetConsoleSeverity() <= fair::Severity::info && ++counter_ == max_limit_)
349 {
350 counter_ = 0;
351 print_error();
352 }
353 return true;
354}
355
356auto R3BNeulandTamexReader2::check_trigger_needed(std::string_view item_name) const -> bool
357{
358 // TODO: not the exact regex, but it suffices
359 const auto neuland_trigger_regex = boost::regex{ "^NN_TRIG(C|F)(v|M)?(I|E)?$" };
360 auto res = is_triggered_ && boost::regex_match(item_name.data(), neuland_trigger_regex);
361 return res;
362}
363
364auto R3BNeulandTamexReader2::check_bar_needed(std::string_view item_name) const -> bool
365{
366 const auto neuland_bar_regex = boost::regex{ R"(^NN_P(\d*)t.*$)" };
367 auto result = boost::cmatch{};
368 if (boost::regex_search(item_name.data(), result, neuland_bar_regex))
369 {
370 const auto plane_num = std::stoi(result.str(1));
371 if (plane_num != 0 and plane_num <= numPlanes_)
372 {
373 return true;
374 }
375 }
376 return false;
377}
378
379auto R3BNeulandTamexReader2::MismappedItemRequired(std::string_view item_name) const -> bool
380{
381 if (numPlanes_ == 0)
382 {
383 throw R3B::logic_error(
384 "The plane number of NeuLAND is not set. Please use R3BNeulandTamexReader2::SetMaxNbPalnes to set it.");
385 }
386
387 return check_trigger_needed(item_name) || check_bar_needed(item_name);
388}
389
391{
392 mappedData_.clear();
393 mappedTrigData_.clear();
394}
395
396void R3BNeulandTamexReader2::print_error()
397{
398 fmt::print("----------Tamex Reader Error Summary:--------------\n");
399 fmt::print("{0:^30}|{1:^10}\n", "Causes", "Counts");
400 for (const auto& [key, counts] : error_log_)
401 {
402 fmt::print("{0:<30}|{1:^10}\n", errorStrings.at(key), counts);
403 }
404 fmt::print("---------------------------------------------------\n");
405}
406
#define R3BLOG(severity, x)
Definition R3BLogger.h:35
auto Checkondition(ErrorLog &log, EXT_STR_h101_raw_nnp_tamex_onion *inputData)
ClassImp(R3BNeulandTamexReader2)
auto CheckCondition(ErrorLog &log, const Items &... items) -> bool
R3BNeulandTamexReader2::Errors Errors
R3B::PaddleTamexMappedData R3BPaddleTamexMappedData2
R3B::PaddleTamexTrigMappedData R3BPaddleTamexTrigMappedData
auto add_hist(std::unique_ptr< TH1 > hist) -> TH1 *
auto get(const std::string &histName) -> TH1 *
auto R3BRead() -> bool override
auto ReadSignals(EXT_STR_h101_raw_nnp_tamex_onion *inputData) -> bool
R3BNeulandTamexReader2(EXT_STR_h101_raw_nnp_tamex_onion *, size_t)
auto ReadTriggerSignals(EXT_STR_h101_raw_nnp_tamex_onion *inputData) -> bool
auto Init(ext_data_struct_info *) -> bool override
auto MismappedItemRequired(std::string_view item_name) const -> bool override
R3BReader(TString const &)
Definition R3BReader.cxx:16
struct EXT_STR_h101_raw_nnp_tamex_onion_t EXT_STR_h101_raw_nnp_tamex_onion
struct EXT_STR_h101_raw_nnp_tamex_t EXT_STR_h101_raw_nnp_tamex
#define EXT_STR_h101_raw_nnp_tamex_ITEMS_INFO(ok, si, offset, struct_t, printerr)