R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BNeulandMilleCalDataProcessor.cxx
Go to the documentation of this file.
2#include "R3BLogger.h"
4#include <Fit/BinData.h>
5#include <Math/WrappedMultiTF1.h>
6#include <R3BNeulandCommon.h>
7#include <TError.h>
8#include <algorithm>
9#include <fmt/core.h>
10#include <numeric>
11#include <range/v3/algorithm/find_if.hpp>
12#include <vector>
13
14// NOLINTNEXTLINE
15#include <fmt/ranges.h>
16
18{
20 {
21 init_data_registers(num_of_modules);
22 fitter_.SetFunction(
23 ROOT::Math::WrappedMultiTF1{ fit_function_, static_cast<unsigned int>(fit_function_.GetNdim()) }, true);
24 fitter_.Config().SetMinimizer("Linear");
25 }
26
27 void MilleDataProcessor::init_data_registers(int num_of_modules)
28 {
29 const auto num_of_planes = num_of_modules / BarsPerPlane;
30 for (int plane_id{}; plane_id < num_of_planes; ++plane_id)
31 {
32 auto data_iter = data_regsiters_.insert_or_assign(plane_id, std::vector<MilleCalData>{}).first;
33 data_iter->second.reserve(BarsPerPlane);
34 }
35 }
36
37 void MilleDataProcessor::reset_fitpars()
38 {
39 fitter_.Config().ParSettings(0).SetValue(0.);
40 fitter_.Config().ParSettings(1).SetValue(0.);
41 }
42
44 {
45 for (auto& [plane_id, bar_data] : data_regsiters_)
46 {
47 bar_data.clear();
48 }
49 fit_result_.x_z = FitPar{};
50 fit_result_.y_z = FitPar{};
51 x_z_vals_.clear();
52 y_z_vals_.clear();
53 reset_fitpars();
54 }
55
56 auto MilleDataProcessor::filter(const std::vector<BarCalData>& signals) -> bool
57 {
58 // fill only the bar_cal_data with only one pmt signal on both sides
59 for (const auto& signal : signals)
60 {
61 if (signal.left.size() == 1 && signal.right.size() == 1)
62 {
63 const auto bar_num = static_cast<int>(signal.module_num);
64 const auto plane_id = ModuleID2PlaneID(bar_num - 1);
65 data_regsiters_[plane_id].emplace_back(signal);
66 }
67 }
68
69 remove_isolated_bar_signal();
70
71 return fit_planes();
72 }
73
74 void MilleDataProcessor::remove_isolated_bar_signal()
75 {
76 namespace rng = ranges;
77 for (auto& [plane_id, bar_data] : data_regsiters_)
78 {
79 if (bar_data.size() < 2)
80 {
81 continue;
82 }
83
84 const auto& bar_signals = bar_data;
85 auto check_if_isolated = [&bar_signals](const auto& signal) -> bool
86 {
87 const auto module_num = static_cast<int>(signal.module_num);
88 return (rng::find_if(bar_signals,
89 [module_num](const auto& bar_signal)
90 { return bar_signal.module_num == module_num - 1; }) == bar_signals.end()) and
91 (rng::find_if(bar_signals,
92 [module_num](const auto& bar_signal)
93 { return bar_signal.module_num == module_num + 1; }) == bar_signals.end());
94 };
95
96 bar_data.erase(std::remove_if(bar_data.begin(), bar_data.end(), check_if_isolated), bar_data.end());
97 }
98 }
99
100 auto MilleDataProcessor::fit_planes() -> bool
101 {
102 fill_fit_data();
103
104 return fit_plane_data();
105 }
106
107 void MilleDataProcessor::fill_fit_data()
108 {
109 for (auto& [plane_id, bar_data] : data_regsiters_)
110 {
111 if (bar_data.empty())
112 {
113 continue;
114 }
115 const auto is_plane_horizontal = IsPlaneIDHorizontal(plane_id);
116 auto& fit_data = is_plane_horizontal ? y_z_vals_ : x_z_vals_;
117 const auto z_val = PlaneID2ZPos(plane_id);
118
119 const auto displacement =
120 std::accumulate(bar_data.begin(),
121 bar_data.end(),
122 0.,
123 [](double sum, const MilleCalData& signal)
124 { return sum + GetBarVerticalDisplacement(static_cast<int>(signal.module_num)); }) /
125 static_cast<double>(bar_data.size());
126 fit_data.z_vals.push_back(z_val);
127 fit_data.z_errs.push_back(BarSize_Z / 2.);
128 fit_data.errs.push_back(BarSize_XY / 2.);
129 fit_data.vals.push_back(displacement);
130 }
131 }
132
133 auto MilleDataProcessor::fit_plane_data() -> bool
134 {
135 return linear_fit(x_z_vals_, fit_result_.x_z) and linear_fit(y_z_vals_, fit_result_.y_z);
136 }
137
138 auto MilleDataProcessor::calculate_residual(double val, int module_num) const -> double
139 {
140 const auto z_val = ModuleNum2ZPos(module_num);
141 const auto is_plane_horizontal = IsPlaneIDHorizontal(ModuleID2PlaneID(module_num - 1));
142 const auto& fit_result = is_plane_horizontal ? fit_result_.x_z : fit_result_.y_z;
143 const auto diff = val - (fit_result.slope * z_val) - fit_result.offset;
144 return diff * diff;
145 }
146
147 auto MilleDataProcessor::linear_fit(const FitData& data, FitPar& fit_par) -> bool
148 {
149
150 const auto bin_data = ROOT::Fit::BinData{ static_cast<unsigned int>(data.size()),
151 data.z_vals.data(),
152 data.vals.data(),
153 data.z_errs.data(),
154 data.errs.data() };
155 reset_fitpars();
156
157 // disable annoying root printouts
158 auto old_var = gErrorIgnoreLevel;
159 gErrorIgnoreLevel = kFatal;
160 auto res = fitter_.Fit(bin_data);
161 gErrorIgnoreLevel = old_var;
162
163 if (not res)
164 {
165 R3BLOG(debug, "Linear fitting on x_z data failed");
166 return false;
167 }
168 fit_par.slope = fitter_.Result().Parameter(0);
169 fit_par.offset = fitter_.Result().Parameter(1);
170 if (fitter_.Result().Prob() < p_value_cut_)
171 {
172 R3BLOG(debug,
173 fmt::format("p-value ({}) is too small from the fit.\n\
174 x = np.array({}) \n\
175 x_err = np.array({}) \n\
176 y = np.array({}) \n\
177 y_err = np.array({})",
178 fitter_.Result().Prob(),
179 data.z_vals,
180 data.z_errs,
181 data.vals,
182 data.errs));
183 return false;
184 }
185 return true;
186 }
187} // namespace R3B::Neuland::Calibration
#define R3BLOG(severity, x)
Definition R3BLogger.h:35
auto calculate_residual(double val, int module_num) const -> double
auto filter(const std::vector< BarCalData > &signals) -> bool
constexpr auto BarsPerPlane
constexpr auto ModuleID2PlaneID(int moduleID) -> int
constexpr auto BarSize_Z
constexpr auto BarSize_XY
constexpr auto ModuleNum2ZPos(int module_num) -> T
constexpr auto IsPlaneIDHorizontal(int plane_id) -> bool
constexpr auto PlaneID2ZPos(int plane_id) -> T