R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BNeulandTSyncAnalysis.cxx
Go to the documentation of this file.
2#include "R3BDataMonitor.h"
3#include "R3BException.h"
5#include "R3BNeulandCommon.h"
7#include "R3BValueError.h"
8#include <array>
9#include <cstdlib>
10#include <fairlogger/Logger.h>
11#include <fmt/format.h>
12#include <functional>
13#include <magic_enum/magic_enum.hpp>
14#include <root/TH1.h>
15#include <root/TH2.h>
16#include <unordered_map>
17#include <utility>
18#include <vector>
19
20// NOLINTBEGIN(misc-include-cleaner)
21#include <R3BFormatters.h>
22#include <fmt/ranges.h>
23#include <range/v3/algorithm/adjacent_find.hpp>
24#include <range/v3/algorithm/all_of.hpp>
25#include <range/v3/algorithm/any_of.hpp>
26#include <range/v3/algorithm/count_if.hpp>
27#include <range/v3/algorithm/find.hpp>
28#include <range/v3/algorithm/find_if.hpp>
29#include <range/v3/algorithm/for_each.hpp>
30#include <range/v3/algorithm/max_element.hpp>
31#include <range/v3/algorithm/sort.hpp>
32#include <range/v3/range/conversion.hpp>
33#include <range/v3/view/drop.hpp>
34#include <range/v3/view/enumerate.hpp>
35#include <range/v3/view/filter.hpp>
36#include <range/v3/view/iota.hpp>
37#include <range/v3/view/map.hpp>
38#include <range/v3/view/transform.hpp>
39// NOLINTEND(misc-include-cleaner)
40
42{
43 namespace
44 {
45 auto extract_mean_value(TH2D* histogram, int module_num) -> R3B::ValueErrorD
46 {
47 // use 0.9 quantiles to remove outliners
48 static constexpr auto quantile_ratio = 0.9;
49 auto* hist_y_proj = histogram->ProjectionY("_py", module_num, module_num);
50 if (hist_y_proj->GetEntries() == 0)
51 {
52 LOGP(warn, "Histogram {} has not entry at the bar number {}", histogram->GetName(), module_num);
53 return {};
54 }
55 const auto x_pos = calculate_hist_quantiles(hist_y_proj, quantile_ratio);
56 hist_y_proj->GetXaxis()->SetRangeUser(x_pos[0], x_pos[1]);
57 return { hist_y_proj->GetMean(), hist_y_proj->GetStdDev() };
58 }
59
60 void offset_to_tsync_ref_bar(Cal2HitPar& hit_par)
61 {
62 const auto ref_t_sync = hit_par.GetModuleParAt(DEFAULT_TSYNC_REFERENCE_BAR_NUM).t_sync;
63
64 for (auto& [module_number, module_par] : hit_par.GetListOfModuleParRef())
65 {
66 module_par.t_sync -= ref_t_sync;
67 }
68 }
69
70 template <typename ViewType>
71 auto check_all_same_view(ViewType view) -> bool
72 {
73 auto is_ok = ranges::adjacent_find(view, std::not_equal_to{}) == view.end();
74 return is_ok;
75 }
76 } // namespace
77
79 {
80 if (num_of_modules_ == 0)
81 {
82 throw R3B::logic_error("Number of modules is not set!");
83 }
84
86
87 for (const auto double_plane_id : ranges::views::iota(0, num_of_dp_))
88 {
89 const auto plane_id = double_plane_id * 2;
90 const auto local_ref_module_num = (plane_id + 1) * BarsPerPlane;
91 ref_bars_in_planes_.try_emplace(plane_id, local_ref_module_num);
92 }
93 }
94
96 {
97 hist_horizontal_plane_ = data_monitor.add_hist<TH2D>("hist_horizontal_plane",
98 "Time diff values of the bars in a horizontal plane",
100 0.5,
101 0.5 + num_of_modules_,
105 hist_horizontal_dp_ = data_monitor.add_hist<TH2D>("hist_horizontal_dp",
106 "Time diff values of the bars in a horizontal double plane",
108 0.5,
109 0.5 + num_of_modules_,
113 hist_vertical_dp_ = data_monitor.add_hist<TH2D>("hist_vertical_dp",
114 "Time diff values of the bars in a vertical double plane",
116 0.5,
117 0.5 + num_of_modules_,
121
122 hist_record_type_ = data_monitor.add_hist<TH1I>("hist_record_type", "TSync record types", 1, 0., 0.);
123 }
124
125 void TSyncEngine::add_point(double t_sum, int module_num)
126 {
127 if (module_num == 0)
128 {
129 return;
130 }
131 buffer_points_.emplace_back(Point{ module_num, t_sum / 2 });
132 }
133
135 {
137
138 if (hist_record_type_ == nullptr)
139 {
140 return;
141 }
142 hist_record_type_->Fill(magic_enum::enum_name(record_type_).data(), 1);
144 {
145 LOGP(debug,
146 "Filling data of record type {:?} with bar numbers: [{}]",
147 magic_enum::enum_name(record_type_),
148 fmt::join(
149 buffer_points_ | ranges::views::transform([](const Point& point) { return point.module_num; }),
150 ", "));
152 }
153 }
154
156 {
157 if (buffer_ref_time_ == 0.)
158 {
159 LOGP(error, "reference time is still 0.");
160 }
161 LOGP(debug, "reference time is {}", buffer_ref_time_);
162 LOGP(debug,
163 "Filling data of record type {:?} with time values: [{}]",
164 magic_enum::enum_name(record_type_),
165 fmt::join(buffer_points_ | ranges::views::transform([](const Point& point) { return point.t_mean; }),
166 ", "));
167
168 for (const auto& point : buffer_points_)
169 {
170 // calculate difference to the reference bar
171 const auto reduced_t_mean = point.t_mean - buffer_ref_time_;
172
173 if (max_time_difference_ > 0. and std::abs(reduced_t_mean) > max_time_difference_)
174 {
175 continue;
176 }
177
178 switch (record_type)
179 {
181 {
182 fill_one_plane_histogram(reduced_t_mean, point.module_num);
183 break;
184 }
187 {
188 fill_two_planes_histogram(reduced_t_mean, point.module_num);
189 break;
190 }
191 default:
192 {
193 return;
194 }
195 }
196 }
197 }
198
199 void TSyncEngine::fill_one_plane_histogram(double time_val, int module_num)
200 {
201 hist_horizontal_plane_->Fill(module_num, time_val);
202 }
203
204 void TSyncEngine::fill_two_planes_histogram(double time_val, int module_num)
205 {
206 if (IsModuleNumHorizontal(module_num))
207 {
208 hist_horizontal_plane_->Fill(module_num, time_val);
209 }
210 else
211 {
212 switch (record_type_)
213 {
215 {
216 hist_horizontal_dp_->Fill(module_num, time_val);
217 break;
218 }
220 {
221 hist_vertical_dp_->Fill(module_num, time_val);
222 break;
223 }
224 default:
225 {
226 return;
227 }
228 }
229 }
230 }
231
239
240 void TSyncEngine::set_plane_ref_bar_time(const std::vector<Point>& collection, int plane_num)
241 {
242 const auto module_num = ref_bars_in_planes_.at(plane_num - 1);
243 auto ref_bar_iter = ranges::find(collection, module_num, &Point::module_num);
244 if (ref_bar_iter != collection.end())
245 {
246 buffer_ref_time_ = ref_bar_iter->t_mean;
247 }
248 else
249 {
250 LOGP(error,
251 "module numbers [{}] doesn't contain any reference numbers: [{}]",
252 fmt::join(collection | ranges::views::transform([](const Point& point) { return point.module_num; }),
253 ", "),
254 fmt::join(ref_bars_in_planes_ | ranges::views::values, ", "));
255 }
256 }
257
258 auto TSyncEngine::try_in_xy_plane(const std::vector<Point>& collection) -> bool
259 {
260 const auto plane_num = ModuleID2PlaneNum(collection.front().module_num - 1);
261
262 if (not IsPlaneIDHorizontal(plane_num - 1))
263 {
264 return false;
265 }
266
267 // check all bars are in the same plane
268 if (not ranges::all_of(collection,
269 [plane_num](const auto& point) -> bool
270 { return ModuleID2PlaneNum(point.module_num - 1) == plane_num; }))
271 {
272 return false;
273 }
274
275 // check if contains ref bar
276 auto ref_bar_iter = ranges::find(collection, ref_bars_in_planes_.at(plane_num - 1), &Point::module_num);
277 if (ref_bar_iter != collection.end())
278 {
279 event_ref_module_num_ = ref_bar_iter->module_num;
280 set_plane_ref_bar_time(collection, plane_num);
281 return true;
282 }
283 return false;
284 }
285
286 auto TSyncEngine::try_in_same_dp(const std::vector<Point>& collection, int offset) -> bool
287 {
288 const auto ref_dp_plane_id = ((ModuleID2PlaneID(collection.front().module_num - 1) + offset) / 2);
289
290 if (ref_dp_plane_id >= num_of_dp_)
291 {
292 return false;
293 }
294
295 // check all bars are in the same double plane
296 if (not ranges::all_of(collection,
297 [ref_dp_plane_id, offset](const auto& point) -> bool
298 { return (ModuleID2PlaneID(point.module_num - 1) + offset) / 2 == ref_dp_plane_id; }))
299 {
300 return false;
301 }
302
303 // check if contains any local reference bar
304 auto ref_bar_iter = ranges::find(collection, ref_bars_in_planes_.at(ref_dp_plane_id * 2), &Point::module_num);
305 if (ref_bar_iter != collection.end())
306 {
307 event_ref_module_num_ = ref_bar_iter->module_num;
308 buffer_ref_time_ = ref_bar_iter->t_mean;
309 return true;
310 }
311 return false;
312 }
313
315 {
316 if (buffer_points_.empty())
317 {
318 return;
319 }
320
322 {
324 }
326 {
328 }
329 else if (try_in_same_dp(buffer_points_, 1))
330 {
332 }
333 else
334 {
336 }
337 }
338
340 {
341 auto vertical_entry = [this](int vertical_number)
342 {
343 auto sum = 0.;
344 for (int dp_id{}; dp_id < num_of_dp_; ++dp_id)
345 {
346 auto plane_num = ((dp_id * 2 + 1) * BarsPerPlane) + vertical_number;
347 sum += hist_horizontal_dp_->Integral(plane_num, plane_num, -1, -1);
348 sum += hist_vertical_dp_->Integral(plane_num, plane_num, -1, -1);
349 }
350 return sum;
351 };
352
353 auto vertical_bar_num_entries_view =
354 ranges::views::iota(1, BarsPerPlane + 1) |
355 ranges::views::transform(
356 [vertical_entry](auto vertical_offset_number)
357 { return std::make_pair(vertical_offset_number, vertical_entry(vertical_offset_number)); });
358 auto element = ranges::max_element(vertical_bar_num_entries_view, std::less{}, &std::pair<int, double>::second);
359 return (*element).first;
360 }
361
362 auto TSyncEngine::calculate_time_diff_to_prev_ref(int plane_id, int best_vert_bar_num) const -> ValueErrorD
363 {
364 const auto module_num = ((plane_id - 1) * BarsPerPlane) + best_vert_bar_num;
365 const auto t_diff_prev = extract_mean_value(hist_horizontal_dp_, module_num);
366 const auto t_diff_after = extract_mean_value(hist_vertical_dp_, module_num);
367
368 return t_diff_prev - t_diff_after;
369 }
370
371 auto TSyncEngine::calculate_time_diffs_to_first() const -> std::unordered_map<int, ValueErrorD>
372 {
373 const auto best_vert_bar_num = calculate_best_vertical_bar_num();
374 LOGP(info, "Best vertical bar number: {}", best_vert_bar_num);
375
376 using EntryPair = std::pair<int, ValueErrorD>;
377 auto ref_plane_consecutive_t_diff =
378 ref_bars_in_planes_ | ranges::views::keys |
379 ranges::views::transform(
380 [best_vert_bar_num, this](auto plane_id)
381 {
382 return (plane_id == 0)
383 ? std::make_pair(plane_id, ValueErrorD{})
384 : std::make_pair(plane_id, calculate_time_diff_to_prev_ref(plane_id, best_vert_bar_num));
385 }) |
386 ranges::to<std::vector<EntryPair>>();
387 ranges::sort(ref_plane_consecutive_t_diff, std::less{}, &EntryPair::first);
388 auto time_diff = ValueErrorD{};
389 return ref_plane_consecutive_t_diff |
390 ranges::views::transform(
391 [&time_diff](const auto& entry_pair)
392 {
393 time_diff += entry_pair.second;
394 return std::make_pair(entry_pair.first, time_diff);
395 }) |
396 ranges::to<std::unordered_map<int, ValueErrorD>>();
397 }
398
400 {
401 LOGP(info, "Begin time synchronization calibration ...");
402 auto ref_time_diff_to_first = calculate_time_diffs_to_first();
403
404 LOGP(info, "TSync diffs from the top horizontal bars: {}", fmt::join(ref_time_diff_to_first, ", "));
405
406 for (auto& [key, module_par] : hit_par.GetListOfModuleParRef())
407 {
408 const auto module_num = module_par.module_num;
409 const auto dp_id = ModuleID2PlaneID(module_num - 1) / 2;
410 const auto t_sync_corr = ref_time_diff_to_first.at(dp_id * 2);
411
412 const auto t_sync_val = [this](int p_module_num)
413 {
414 if (IsModuleNumHorizontal(p_module_num))
415 {
416 static constexpr auto top_bar_number = 50;
417 const auto vert_dist_diff =
418 GetBarVerticalDisplacement(top_bar_number) - GetBarVerticalDisplacement(p_module_num);
419 return extract_mean_value(hist_horizontal_plane_, p_module_num) - vert_dist_diff / CLight;
420 }
421 return extract_mean_value(hist_horizontal_dp_, p_module_num);
422 }(module_num);
423
424 module_par.t_sync = t_sync_val + t_sync_corr;
425 }
426 offset_to_tsync_ref_bar(hit_par);
427 LOGP(info, "Time synchronization calibration ends.");
428 }
429} // namespace R3B::Neuland::Calibration
auto add_hist(std::unique_ptr< TH1 > hist) -> TH1 *
void fill_one_plane_histogram(double time_val, int module_num)
auto calculate_time_diff_to_prev_ref(int plane_id, int best_vert_bar_num) const -> ValueErrorD
void end_of_event()
Actions in the end of the event.
auto try_in_same_dp(const std::vector< Point > &collection, int offset=0) -> bool
Check if all points are in the same horizontal or vertical double plane.
@ same_vertical_dp
All the points within vertical plane followed by horizontal one.
@ xy_plane
All points within one single horizontal plane.
@ same_horizontal_dp
All the points within horizontal plane followed by vertical one.
void init_hist(DataMonitor &data_monitor)
set histograms.
std::unordered_map< int, int > ref_bars_in_planes_
key: plane_id, value: global module number
auto try_in_xy_plane(const std::vector< Point > &collection) -> bool
auto calculate_time_diffs_to_first() const -> std::unordered_map< int, ValueErrorD >
void fill_two_planes_histogram(double time_val, int module_num)
void add_point(double t_sum, int module_num)
Add the t_sum value from a bar.
void set_plane_ref_bar_time(const std::vector< Point > &collection, int plane_num)
constexpr auto DEFAULT_TSYNC_REFERENCE_BAR_NUM
auto calculate_hist_quantiles(TH1 *histogram, double quantile_ratio) -> std::array< double, 2 >
constexpr auto BarsPerPlane
constexpr auto ModuleID2PlaneID(int moduleID) -> int
constexpr auto GetBarVerticalDisplacement(int module_num) -> double
constexpr auto ModuleID2PlaneNum(int moduleID) -> int
constexpr auto CLight
constexpr auto IsModuleNumHorizontal(int module_num) -> bool
constexpr auto IsPlaneIDHorizontal(int plane_id) -> bool
ValueError< double > ValueErrorD