R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BNeulandPredecessor.cxx
Go to the documentation of this file.
2#include "R3BDataMonitor.h"
3#include "R3BLogger.h"
6#include "R3BNeulandCommon.h"
7#include "R3BValueError.h"
9#include <TF1.h>
10#include <TFitResult.h>
11#include <TFitResultPtr.h>
12#include <TH1.h>
13#include <TH2.h>
14#include <array>
15#include <fmt/core.h>
16#include <vector>
17
19{
20
21 namespace
22 {
23 constexpr auto FITTING_RANGE_RATIO = 0.9;
24
25 struct ParResult
26 {
27 ValueErrorD t_offset;
28 ValueErrorD effective_speed;
29 };
30
31 auto calculate_toffset_speed(TH1D* histogram, int bar_id) -> ParResult
32 {
33 histogram->Scale(1 / histogram->GetEntries());
34 auto* cumulative = histogram->GetCumulative();
35 constexpr auto QUANTILES_NUM = 2;
36 const auto quantiles =
37 std::array<double, QUANTILES_NUM>{ 0.5 - (FITTING_RANGE_RATIO / 2.), 0.5 + (FITTING_RANGE_RATIO / 2.) };
38 auto x_pos = std::array<double, QUANTILES_NUM>{};
39 histogram->GetQuantiles(QUANTILES_NUM, x_pos.data(), quantiles.data());
40
41 // First fit to determine the values of the slope and offset
42 auto first_fit_res = cumulative->Fit("pol1", "SQ", "", x_pos[0], x_pos[1]);
43 if (first_fit_res.Get() == nullptr)
44 {
45 R3BLOG(warn,
46 fmt::format("First linear fitting on time_diff CFD failed for the bar with id {}", bar_id));
47 return {};
48 }
49 const auto slope = first_fit_res->Parameter(1);
50 const auto offset = first_fit_res->Parameter(0);
51
52 // Second fit to determine parameters and their errors. The slope and offset values are used for their
53 // initial values. The reason why the second fit is needed is because the error of the t_offset value is
54 // dependent on both offset and slope, which are not independent. By redefining the fitting parameter, the
55 // error of t_offset can be directly given by the fitting algorithm.
56 auto fit_fun = TF1{ "fit_fun", "[1]*x + 0.5 - [0] * [1]", x_pos[0], x_pos[1] };
57 fit_fun.SetParameter(0, (0.5 - offset) / slope);
58 fit_fun.SetParameter(1, slope);
59 auto second_fit_res = cumulative->Fit(&fit_fun, "SQ", "", x_pos[0], x_pos[1]);
60 if (second_fit_res.Get() == nullptr)
61 {
62 R3BLOG(warn, fmt::format("Second fitting on time_diff CFD failed for the bar with id {}", bar_id));
63 return {};
64 }
65
66 auto par_result = ParResult();
67 par_result.t_offset.value = second_fit_res->Parameter(0);
68 par_result.t_offset.error = second_fit_res->Error(0);
69 par_result.effective_speed.value = second_fit_res->Parameter(1) * 2 * BarLength;
70 par_result.effective_speed.error = second_fit_res->Error(1) * 2 * BarLength;
71 return par_result;
72 }
73 } // namespace
74
76 {
77 const auto module_size = GetModuleSize();
78
79 static constexpr auto TIME_DIFF_MAX = 100.; // ns
80 static constexpr auto TIME_DIFF_BIN_NUM = 500;
81 // static constexpr auto TIME_SUM_MAX = 800; // ns
82 // static constexpr auto TIME_SUM_BIN_NUM = 400;
83
84 hist_time_diff_ = histograms.add_hist<TH2D>("hist_time_diff",
85 "Time differences between two adjacent PMTs",
86 module_size,
87 0.5,
88 0.5 + module_size,
89 TIME_DIFF_BIN_NUM,
90 -TIME_DIFF_MAX,
91 TIME_DIFF_MAX);
92
93 // hist_time_sum_ = histograms.add_hist<TH2D>("hist_time_sum",
94 // "Time summation between two adjacent PMTs",
95 // module_size,
96 // 0.5,
97 // 0.5 + module_size,
98 // TIME_SUM_BIN_NUM,
99 // 0.,
100 // TIME_SUM_MAX + 0.);
101 }
102
103 void Predecessor::Init() { cal_to_hit_par_ = GetTask()->GetCal2HitPar(); }
104
105 void Predecessor::AddSignals(const std::vector<BarCalData>& signals)
106 {
107 // all bar signal must have one signal on both sides
108 for (const auto& signal : signals)
109 {
110 if (signal.left.size() != 1 or signal.right.size() != 1)
111 {
112 continue;
113 }
114 fill_hist(signal);
115 }
116 }
117
118 void Predecessor::fill_hist(const BarCalData& signal)
119 {
120 const auto& left_signal = signal.left.front();
121 const auto& right_signal = signal.right.front();
122
123 const auto module_num = signal.module_num;
124 const auto t_diff = right_signal.leading_time - left_signal.leading_time;
125 // const auto t_sum = right_signal.leading_time + left_signal.leading_time;
126
127 hist_time_diff_->Fill(static_cast<int>(module_num), t_diff.value);
128 // hist_time_sum_->Fill(static_cast<int>(module_num), t_sum.value);
129 }
130
131 auto Predecessor::SignalFilter(const std::vector<BarCalData>& signals) -> bool
132 {
133 // select out rays with few hits
134 return signals.size() >= minimum_hit_;
135 }
136
138 {
139 const auto module_size = GetModuleSize();
140
141 for (int bar_id{}; bar_id < module_size; ++bar_id)
142 {
143 auto* hist_t_diff_py = hist_time_diff_->ProjectionY("_py", bar_id + 1, bar_id + 1);
144 const auto par_res = calculate_toffset_speed(hist_t_diff_py, bar_id);
145
146 auto module_par = HitModulePar{};
147 module_par.module_num = bar_id + 1;
148 module_par.t_diff = par_res.t_offset;
149 module_par.effective_speed = par_res.effective_speed;
150
151 hit_par.AddModulePar(module_par);
152 }
153 }
154} // namespace R3B::Neuland::Calibration
#define R3BLOG(severity, x)
Definition R3BLogger.h:35
auto add_hist(std::unique_ptr< TH1 > hist) -> TH1 *
void AddModulePar(const HitModulePar &module_par)
void Calibrate(Cal2HitPar &hit_par) override
auto SignalFilter(const std::vector< BarCalData > &signals) -> bool override
void AddSignals(const std::vector< BarCalData > &signals) override
void HistInit(DataMonitor &histograms) override
constexpr auto BarLength
ValueError< double > ValueErrorD
std::vector< CalDataSignal > left
std::vector< CalDataSignal > right