R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BNeulandCalToHitTask.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
15#include "R3BDataMonitor.h"
16#include "R3BException.h"
17#include "R3BNeulandCalData2.h"
20#include "R3BNeulandCommon.h"
21#include "R3BNeulandHit.h"
23#include "R3BValueError.h"
24#include <FairRootManager.h>
25#include <FairRuntimeDb.h>
26#include <Math/Vector3Dfwd.h>
28#include <R3BShared.h>
29#include <cmath>
30#include <fairlogger/Logger.h>
31#include <fmt/core.h>
32#include <string_view>
33#include <vector>
34
35namespace
36{
37 using R3B::ValueErrorD;
40 using ROOT::Math::XYZVector;
41
42 inline auto get_hit_energy(double first_e, double second_e, const HitModulePar& par)
43 {
44 // const auto attenuation_value = std::exp(R3B::Neuland::TotalBarLength / par.lightAttenuationLength.value);
45 return par.light_attenuation_factor.value * std::sqrt(first_e * second_e);
46 }
47
48 inline auto get_hit_position(double tdc_left, double tdc_right, const HitModulePar& par)
49 {
50 const auto plane_id = ::R3B::Neuland::ModuleID2PlaneID(static_cast<int>(par.module_num - 1));
51 const auto bar_num = par.module_num % ::R3B::Neuland::BarsPerPlane;
52 LOGP(debug2,
53 "Calculating position with left tdc: {}, right tdc {}, effective speed: {}, tdc_diff: {}",
54 tdc_left,
55 tdc_right,
56 par.effective_speed,
57 tdc_right - tdc_left);
58 const auto pos_along_bar = par.effective_speed.value * (tdc_right - tdc_left) / 2.;
59 const auto pos_perp_bar = (bar_num - 0.5 - ::R3B::Neuland::BarsPerPlane * 0.5) * ::R3B::Neuland::BarSize_XY;
60 const auto pos_z = (plane_id + 0.5) * ::R3B::Neuland::BarSize_Z;
61 LOGP(debug2, "pos along the bar: {} cm, pos perp to bar {} cm, z: {} cm", pos_along_bar, pos_perp_bar, pos_z);
62
63 auto is_horizontal = ::R3B::Neuland::IsPlaneIDHorizontal(plane_id);
64 return is_horizontal ? XYZVector{ pos_along_bar, pos_perp_bar, pos_z }
65 : XYZVector{ pos_perp_bar, pos_along_bar, pos_z };
66 }
67
68 inline auto get_hit_pixel(const XYZVector& position)
69 {
70 const auto pixel_x =
71 std::floor(position.X() / ::R3B::Neuland::BarSize_XY) + (::R3B::Neuland::BarsPerPlane / 2.);
72 const auto pixel_y =
73 std::floor(position.Y() / ::R3B::Neuland::BarSize_XY) + (::R3B::Neuland::BarsPerPlane / 2.);
74 const auto pixel_z = std::floor(position.Z() / ::R3B::Neuland::BarSize_Z);
75
76 return XYZVector{ pixel_x, pixel_y, pixel_z };
77 }
78} // namespace
79
80namespace R3B::Neuland
81{
82
83 Cal2HitTask::Cal2HitTask(std::string_view input_cal_data_name,
84 std::string_view input_cal_2_hit_par_name,
85 std::string_view output_hit_data_name)
86 : CalibrationTask("R3BNeulandCal2Hit", 1)
87 , cal_data_{ input_cal_data_name }
88 , hit_data_{ output_hit_data_name }
89 , cal_to_hit_par_{ input_cal_2_hit_par_name }
90 {
91 }
92
94
95 void Cal2HitTask::ExtraInit(FairRootManager* /*rootMan*/)
96 {
97 cal_data_.init();
98 hit_data_.init(not IsHistDisabled());
99 if (cal_to_hit_par_->GetModulePars().empty())
100 {
101 throw R3B::logic_error("Cal2HitPar has no modules!");
102 }
103 }
104
105 void Cal2HitTask::SetExtraPar(FairRuntimeDb* /*rtdb*/) { cal_to_hit_par_.init(this); }
106
108
110 {
111 for (const auto& calBar : cal_data_)
112 {
113 temp_left_signals_.clear();
114 temp_right_signals_.clear();
115
116 LOGP(debug1, "Input calBar: {}", calBar);
117 if (calBar.module_num == 0)
118 {
119 throw R3B::runtime_error("cal-level bar signal has invalid moudule number 0!");
120 }
121
124
125 const auto& module_par = cal_to_hit_par_->GetModuleParAt(calBar.module_num);
127 }
128 }
129
131 /* inout */ std::vector<CalibratedSignal>& signals,
132 Side side)
133 {
134 const auto calBar_signals = (side == Side::left) ? calBar.left : calBar.right;
135
136 const auto& module_par = cal_to_hit_par_->GetModuleParAt(calBar.module_num);
137
138 for (const auto& cal_signal : calBar_signals)
139 {
140 signals.push_back(to_calibrated_signal(cal_signal, module_par, side));
141 }
142 }
143
145 const HitModulePar& par) const -> R3BNeulandHit
146 {
147 auto hit = R3BNeulandHit{};
148
149 LOGP(debug2,
150 "Input left calibrated signal: {} and right calibrated signal: {}",
151 signalPair.left(),
152 signalPair.right());
153 // hit module id is 0-based
154 hit.module_id = static_cast<int>(par.module_num - 1);
155 hit.tdc_left = signalPair.left().time.value;
156 hit.tdc_right = signalPair.right().time.value;
157 hit.time = get_hit_time(hit.tdc_left, hit.tdc_right);
158 hit.qdc_left = signalPair.left().energy.value;
159 hit.qdc_right = signalPair.right().energy.value;
160 hit.energy = get_hit_energy(hit.qdc_left, hit.qdc_right, par);
161 hit.position = get_hit_position(hit.tdc_left, hit.tdc_right, par);
162 hit.pixel = get_hit_pixel(hit.position);
163 LOGP(debug, "Adding a new NeulandHit: {}\n", hit);
164 return hit;
165 }
166
167 void Cal2HitTask::construct_hits(const std::vector<CalibratedSignal>& left_signals,
168 const std::vector<CalibratedSignal>& right_signals,
169 const HitModulePar& par,
170 /* inout */ std::vector<R3BNeulandHit>& hits)
171 {
172 // TODO: Multi-hits needs to be implemented here
173 if (left_signals.size() == 1 and right_signals.size() == 1)
174 {
175 const auto& left_signal = left_signals.front();
176 const auto& right_signal = right_signals.front();
177 // signal_match_checking(left_signal, right_signal, par);
178 hits.push_back(construct_hit(R3B::LRPair<CalibratedSignal>{ left_signal, right_signal }, par));
179 }
180 }
181
183 const CalibratedSignal& second_signal,
184 const HitModulePar& par) -> bool
185 {
186 const auto first_input =
187 SignalMatcher::Input{ .time = first_signal.time.value, .energy = first_signal.energy.value };
188 const auto second_input =
189 SignalMatcher::Input{ .time = second_signal.time.value, .energy = second_signal.energy.value };
190
191 const auto match_par = SignalMatcher::Par{ .attenuation = BarLength / par.light_attenuation_length.value,
192 .c_medium = par.effective_speed.value };
193 const auto match_goodness = SignalMatcher::GetGoodnessOfMatch(first_input, second_input, match_par);
194 const auto match_result = std::log10(match_goodness);
195 // FIXME: BAD comparison values. They should be 0. Why? Need fixing
196 GetHistMonitor().get("match_values")->Fill(match_result);
197 return true;
198 }
199
201
202 auto Cal2HitTask::CheckConditions() const -> bool
203 {
205 {
206 const auto t_start = GetEventHeader()->GetTStart();
207 const auto is_beam_on = not std::isnan(t_start);
208 return is_beam_on;
209 }
210 return true;
211 }
212
213 auto Cal2HitTask::get_hit_time(double first_t, double second_t) const -> double
214 {
215 auto larger_t = (first_t > second_t) ? first_t : second_t;
216 auto smaller_t = (first_t < second_t) ? first_t : second_t;
217
218 // check if the smaller value is overflowed
219 // TODO: overflow should be checked in cal level for better time calibration. But the cal level calibration
220 // doesn't have singal paring. Solution: Do it in cal level only for one hit bar signal and calibration should
221 // only use those with one hit.
222 if (larger_t - smaller_t > 0.5 * R3B::Neuland::MaxCalTime)
223 {
224 larger_t -= R3B::Neuland::MaxCalTime;
225 }
226 return std::remainder(((larger_t + smaller_t) / 2.) - global_time_offset_ - GetEventHeader()->GetTStart(),
228 }
229
231 const HitModulePar& par,
232 R3B::Side side) -> ValueErrorD
233 {
234 const auto tot_no_offset = calSignal.time_over_threshold - par.pedestal.get(side);
235
236 const auto denominator = par.energy_gain.get(side) - par.pmt_saturation.get(side) * tot_no_offset;
237
238 if (denominator.value == 0.)
239 {
240 return ValueErrorD{};
241 }
242
243 // apply minimum 1 ns:
244 return (tot_no_offset.value < 1) ? ValueErrorD{} : tot_no_offset / denominator;
245 }
246
248 const HitModulePar& par,
249 R3B::Side side) -> ValueErrorD
250 {
251 // TODO: why positive for left?
252 const auto time_offset =
253 (side == R3B::Side::left) ? (par.t_sync - par.t_diff / 2) : (par.t_sync + par.t_diff / 2);
254 return calSignal.leading_time - calSignal.trigger_time - time_offset;
255 }
256
258 const HitModulePar& par,
260 {
261 const auto energy = get_calibrated_energy(calSignal, par, side);
262 const auto time = get_calibrated_time(calSignal, par, side);
263 return CalibratedSignal{ .energy = energy, .time = time };
264 }
265} // namespace R3B::Neuland
static auto get_calibrated_energy(const CalDataSignal &calSignal, const HitModulePar &par, R3B::Side side) -> ValueErrorD
auto construct_hit(const LRPair< CalibratedSignal > &signalPair, const HitModulePar &par) const -> R3BNeulandHit
void SetExtraPar(FairRuntimeDb *rtdb) override
void ExtraInit(FairRootManager *rootMan) override
InputParView< Cal2HitPar > cal_to_hit_par_
Cal2HitTask(std::string_view input_cal_data_name="NeulandCalData", std::string_view input_cal_2_hit_par_name="NeulandHitPar", std::string_view output_hit_data_name="NeulandHits")
static auto get_calibrated_time(const CalDataSignal &calSignal, const HitModulePar &par, R3B::Side side) -> ValueErrorD
static auto to_calibrated_signal(const CalDataSignal &calSignal, const HitModulePar &par, R3B::Side side) -> CalibratedSignal
std::vector< CalibratedSignal > temp_left_signals_
void calculate_calibrated_signals(const BarCalData &calBar, std::vector< CalibratedSignal > &signals, Side side)
OutputVectorConnector< R3BNeulandHit > hit_data_
auto signal_match_checking(const CalibratedSignal &first_signal, const CalibratedSignal &second_signal, const HitModulePar &par) -> bool
void HistogramInit(DataMonitor &histograms) override
void construct_hits(const std::vector< CalibratedSignal > &left_signals, const std::vector< CalibratedSignal > &right_signals, const HitModulePar &par, std::vector< R3BNeulandHit > &hits)
InputVectorConnector< BarCalData > cal_data_
auto get_hit_time(double first_t, double second_t) const -> double
std::vector< CalibratedSignal > temp_right_signals_
auto CheckConditions() const -> bool override
auto GetTrigger() const -> CalTrigger
Simulation of NeuLAND Bar/Paddle.
constexpr auto BarsPerPlane
constexpr auto ModuleID2PlaneID(int moduleID) -> int
constexpr auto BarLength
constexpr auto BarSize_Z
constexpr auto BarSize_XY
constexpr auto IsPlaneIDHorizontal(int plane_id) -> bool
constexpr auto MaxCalTime
ValueError< double > ValueErrorD
std::vector< CalDataSignal > left
std::vector< CalDataSignal > right
ValueError< double > light_attenuation_factor
exp(alpha*L/2)
static auto GetGoodnessOfMatch(const Input &firstSignal, const Input &secondSignal, const Par &par) -> float