R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BNeulandMapToCalTask.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 "R3BNeulandCalData2.h"
18#include "R3BNeulandCommon.h"
22#include "R3BShared.h"
23#include "R3BValueError.h"
24#include <FairRootManager.h>
25#include <R3BEventHeader.h>
26#include <R3BException.h>
27#include <TH1.h>
28#include <TH2.h>
29#include <algorithm>
30#include <cmath>
31#include <fairlogger/Logger.h>
32#include <fmt/core.h>
33#include <fmt/format.h>
34#include <fmt/ranges.h>
35#include <iterator>
36#include <range/v3/view/map.hpp>
37#include <string_view>
38#include <utility>
39#include <vector>
40
41namespace
42{
43 // NOLINTBEGIN
44 auto GetWalkCorrection(double value) -> double
45 {
46 value = value * 17.2278 / 162.464;
47 const auto veronika3 = -4.29359 + 17.3841 / sqrt(value) + 0.073181; // veronika 3
48 const auto veronika2 = 1.59667 + 78.5274 * pow(value, -1.97051) - 4.00192 / value - 0.125473 * value +
49 0.00130958 * value * value; // veronika 2
50 const auto result = (value > 25.0000) ? veronika3 : (veronika3 + veronika2) / 2.;
51 return -1. * result;
52 }
53 // NOLINTEND
54
55} // namespace
56
57namespace R3B::Neuland
58{
60 : CalibrationTask(config.name, 1)
61 , config_{ config }
62 , map_data_{ get_from_sep_string(0, config.read) }
63 , trig_map_data_{ get_from_sep_string(1, config.read) }
64 , calibration_par_{ get_from_sep_string(2, config.read) }
65 , calibration_trig_par_{ get_from_sep_string(3, config.read) }
66 , cal_data_{ get_from_sep_string(0, config.write) }
67 {
68 SetTrigger(config.mode);
69 }
70
71 void Map2CalTask::SetExtraPar(FairRuntimeDb* /*rtdb*/)
72 {
73 calibration_par_.init(this);
74 calibration_trig_par_.init(this);
75 }
76
78 {
79 const auto total_bar_num = plane_num_ * BarsPerPlane;
80 constexpr auto BINSIZE_TOT = 1000;
81 constexpr auto BINSIZE_LT = 1000;
82 constexpr auto BINSIZE_TIME = 8000;
83 constexpr auto HIST_MAX_TIME = 6000.;
84 constexpr auto HIST_MIN_TIME = -5000.;
85 constexpr auto HIST_MAX_TOT = 600.;
86 constexpr auto HIST_MAX_LT = 2000.;
87
88 histograms.add_hist<TH1D>("module_num", "Counts with module ids", total_bar_num, -0.5, total_bar_num + 0.5);
89 histograms.add_hist<TH1D>("ToT", "Time over threshold", BINSIZE_TOT * 2, 0., BINSIZE_TOT + 0.);
90 histograms.add_hist<TH1D>("LeadingTime", "Leading time", BINSIZE_LT, 0., HIST_MAX_LT);
91 histograms.add_hist<TH1D>("TriggerTime", "Trigger time", BINSIZE_LT, 0., HIST_MAX_LT);
92 histograms.add_hist<TH1D>("Leading_minus_trigger", "Time", BINSIZE_TIME, HIST_MIN_TIME, HIST_MAX_TIME);
93 histograms.add_hist<TH1I>(
94 "Bar_hitNum_l", "Number of hits on the left PMT per bar", total_bar_num, 0.5, 0.5 + total_bar_num);
95 histograms.add_hist<TH1I>(
96 "Bar_hitNum_r", "Number of hits on the right PMT per bar", total_bar_num, 0.5, 0.5 + total_bar_num);
97
98 histograms.add_hist<TH2D>("TimeLVsBar",
99 "Time_vs_bar_left",
100 total_bar_num,
101 0.5,
102 0.5 + total_bar_num,
103 BINSIZE_TIME,
104 HIST_MIN_TIME,
105 HIST_MAX_TIME);
106 histograms.add_hist<TH2D>("TimeRVsBar",
107 "Time_vs_bar_right",
108 total_bar_num,
109 0.5,
110 0.5 + total_bar_num,
111 BINSIZE_TIME,
112 HIST_MIN_TIME,
113 HIST_MAX_TIME);
114
115 histograms.add_hist<TH2D>(
116 "ToTLVsBar", "ToT_vs_bar_left", total_bar_num, 0.5, 0.5 + total_bar_num, BINSIZE_TOT, 0., HIST_MAX_TOT);
117 histograms.add_hist<TH2D>(
118 "ToTRVsBar", "ToT_vs_bar_right", total_bar_num, 0.5, 0.5 + total_bar_num, BINSIZE_TOT, 0., HIST_MAX_TOT);
119 }
120
121 void Map2CalTask::ExtraInit(FairRootManager* /*rootMan*/)
122 {
123 map_data_.init();
124 trig_map_data_.init();
125 cal_data_.init(not IsHistDisabled());
126 set_pmt_num();
127 set_ct_freq();
128 }
129
131 {
132 if (plane_num_ = GetBasePar()->get_num_of_planes(); plane_num_ == 0)
133 {
134 LOGP(warn, "plane number obtained from the calibration parameters is 0!");
135 }
136 else
137 {
139 LOGP(info, "total number of PMTs set to be {}", total_pmt_nums_);
140 }
141
142 if (total_pmt_nums_ == 0)
143 {
144 throw R3B::runtime_error("The number of PMTs cannot be zero!");
145 }
146 }
147
149 {
150 if (auto ct_freq = calibration_par_->GetSlowClockFrequency(); ct_freq == 0)
151 {
152 LOGP(warn, "Coarse time frequency obtained from parameters is 0! Use default value.");
154 }
155 else
156 {
157 coarse_time_frequency_ = ct_freq;
159 LOGP(info, "Coarse time frequency set to be {} MHz", ct_freq);
160 }
161 }
162
163 auto Map2CalTask::CheckConditions([[maybe_unused]] TH1L* hist_condition) const -> bool
164 {
165
166 auto signal_size = map_data_.size();
167 LOGP(debug2,
168 "Minimal signal size: {}. Current signal size: {}. Number of PMTs: {}",
169 config_.min_stat,
170 signal_size,
172 if (std::cmp_less(signal_size, config_.min_stat))
173 {
174 LOGP(debug2,
175 "condition of the minimal size is not met with current paddle signal size. Skip the "
176 "current event.");
177 ConditionFillToHist(hist_condition, "undersized");
178 return false;
179 }
180 return config_.enable_pulse_mode ? signal_size > total_pmt_nums_ : signal_size < total_pmt_nums_ / 2;
181 }
182
184
186 SingleEdgeSignal signal,
187 FTType ftType,
188 int module_num) const -> ValueError<double>
189 {
190 const auto& modulePar = calPar->GetParamAt(module_num);
191 const auto fineTime = modulePar.GetFineTime(ftType, signal.fine);
192
193 // signal time in ns
194 const auto coarseTime = 1000. / coarse_time_frequency_ * static_cast<float>(signal.coarse + 1);
195 return { coarseTime - fineTime.value, fineTime.error };
196 }
197
198 auto Map2CalTask::get_trigger_time(int module_num, Side side) const -> ValueError<double>
199 {
200
201 const auto& triggerMap = GetBasePar()->get_trig_id_map();
202 auto triggerIDPair = triggerMap.find(module_num);
203 if (triggerIDPair == triggerMap.end())
204 {
205 const auto eventNum = GetEventHeader()->GetEventno();
206 LOGP(error, "Can't find the trigger ID for the module ID {} in the event {}", module_num, eventNum);
207 return { -1., 0 };
208 }
209 const auto triggerID = (side == Side::left) ? triggerIDPair->second.first : triggerIDPair->second.second;
210 const auto trigData = std::ranges::find_if(
211 trig_map_data_, [&triggerID](const auto& ele) -> bool { return ele.first == triggerID; });
212 if (trigData == trig_map_data_.end())
213 {
214 const auto eventNum = GetEventHeader()->GetEventno();
215 LOGP(error,
216 "No such trigger ID {} in mappedTrigData for moduleNum {} in the event {}!",
217 triggerID,
218 module_num,
219 eventNum);
220 LOGP(error, "Available trigIDs: {}", fmt::join(trig_map_data_ | ranges::views::keys, ", "));
221 return { -1., 0 };
222 }
224 calibration_trig_par_.get(), trigData->second.signal, FTType::trigger, trigData->first);
225 }
226
227 auto Map2CalTask::get_tot(const DoubleEdgeSignal& pmtSignal, int module_num, R3B::Side module_side) const
229 {
230 const auto leadFType = (module_side == Side::left) ? FTType::leftleading : FTType::rightleading;
231 const auto trailFType = (module_side == Side::left) ? FTType::lefttrailing : FTType::righttrailing;
232 const auto leadingT = convert_to_real_time(calibration_par_.get(), pmtSignal.leading, leadFType, module_num);
233 const auto trailingT = convert_to_real_time(calibration_par_.get(), pmtSignal.trailing, trailFType, module_num);
234 const auto time_over_thresh = trailingT - leadingT;
235 LOGP(debug3, "leading :{} trailing: {}", leadingT.value, trailingT.value);
236 return (time_over_thresh.value > 0) ? time_over_thresh : time_over_thresh + max_coarse_time_;
237 }
238
240 {
241 // trigger time should come after signal time
242 if (calSignal.leading_time.value > calSignal.trigger_time.value)
243 {
244 calSignal.leading_time -= max_coarse_time_;
245 }
246 }
247
249 R3B::Side side,
250 int module_num) const -> CalDataSignal
251 {
252 auto calDataSignal = CalDataSignal{};
253 const auto ftType = (side == R3B::Side::left) ? FTType::leftleading : FTType::rightleading;
254 calDataSignal.time_over_threshold = get_tot(double_edge_signal, module_num, side);
255 const auto walk_correction =
256 (config_.enable_walk_effect) ? GetWalkCorrection(calDataSignal.time_over_threshold.value) : 0.;
257 calDataSignal.leading_time =
258 convert_to_real_time(calibration_par_.get(), double_edge_signal.leading, ftType, module_num) +
259 walk_correction;
260 calDataSignal.trigger_time = get_trigger_time(module_num, side);
261 overflow_correct(calDataSignal);
262 LOGP(debug, "Adding a new cal signal: {}", calDataSignal);
263 return calDataSignal;
264 }
265
267 int module_num,
268 R3B::Side side) const -> std::vector<CalDataSignal>
269 {
270 const auto& signals = (side == Side::left) ? map_bar_signals.left : map_bar_signals.right;
271 auto calSignals = std::vector<CalDataSignal>{};
272 calSignals.reserve(signals.size());
273 std::ranges::transform(signals,
274 std::back_inserter(calSignals),
275 [module_num, side, this](const auto& dESignal) -> CalDataSignal
276 { return doubleEdgeSignal_to_calSignal(dESignal, side, module_num); });
277 return calSignals;
278 }
279
281 {
284
285 if (not IsHistDisabled())
286 {
289 }
290 }
291
293 {
294 LOGP(debug2, "mapped Data size: {}", map_data_.size());
295
296 if (trig_map_data_.size() == 0)
297 {
298 return;
299 }
300 for (const auto& [plane_num, plane_signals] : map_data_)
301 {
302 for (const auto& [bar_num, bar_signals] : plane_signals.bars)
303 {
304 if (not IsHistDisabled())
305 {
306 GetHistMonitor().get("module_num")->Fill(bar_num);
307 }
308 const auto module_num = Neuland_PlaneBar2ModuleNum(plane_num, bar_num);
309 auto& cal = cal_data_.get().emplace_back(module_num);
310 fill_cal_data(cal, bar_signals);
311 }
312 }
313 }
314
316 {
317 auto& histograms = GetHistMonitor();
318 const auto module_num = cal.module_num;
319 const auto& calSignals = (side == Side::left) ? cal.left : cal.right;
320
321 for (const auto& signal : calSignals)
322 {
323 const auto lTime = signal.leading_time.value;
324 const auto time_over_thresh = signal.time_over_threshold.value;
325 const auto triggerTime = signal.trigger_time.value;
326 histograms.get("ToT")->Fill(time_over_thresh);
327 histograms.get("LeadingTime")->Fill(lTime);
328 histograms.get("TriggerTime")->Fill(triggerTime);
329 histograms.get("Leading_minus_trigger")->Fill(lTime - triggerTime);
330 if (side == Side::left)
331 {
332 histograms.get("TimeLVsBar")->Fill(module_num, lTime - triggerTime);
333 histograms.get("ToTLVsBar")->Fill(module_num, time_over_thresh);
334 histograms.get("Bar_hitNum_l")->Fill(module_num);
335 }
336 else
337 {
338 histograms.get("TimeRVsBar")->Fill(module_num, lTime - triggerTime);
339 histograms.get("ToTRVsBar")->Fill(module_num, time_over_thresh);
340 histograms.get("Bar_hitNum_r")->Fill(module_num);
341 }
342 }
343 }
344
346} // namespace R3B::Neuland
R3B::Map2CalPar R3BTCalPar2
auto add_hist(std::unique_ptr< TH1 > hist) -> TH1 *
static void ConditionFillToHist(TH1L *hist_condition, std::string_view condition)
void HistogramInit(DataMonitor &histograms) override
auto mapBarSignal_to_calSignals(const MapBarSignal &map_bar_signals, int module_num, R3B::Side side) const -> std::vector< CalDataSignal >
OutputVectorConnector< BarCalData > cal_data_
auto CheckConditions(TH1L *hist_condition) const -> bool override
auto convert_to_real_time(R3BTCalPar2 *calPar, SingleEdgeSignal signal, FTType ftType, int module_num) const -> ValueError< double >
InputMapConnector< int, PaddleTamexMappedData > map_data_
auto get_trigger_time(int module_num, Side side) const -> ValueError< double >
InputMapConnector< int, PaddleTamexTrigMappedData > trig_map_data_
void overflow_correct(R3B::Neuland::CalDataSignal &calSignal) const
auto doubleEdgeSignal_to_calSignal(const DoubleEdgeSignal &double_edge_signal, R3B::Side side, int module_num) const -> CalDataSignal
void ExtraInit(FairRootManager *rootMan) override
void fill_cal_data(BarCalData &cal, const MapBarSignal &signals)
void SetExtraPar(FairRuntimeDb *rtdb) override
InputParView< Map2CalPar > calibration_par_
auto get_tot(const DoubleEdgeSignal &pmtSignal, int module_num, R3B::Side module_side) const -> ValueError< double >
void histogram_monitor(const BarCalData &cal, Side side)
InputParView< Map2CalPar > calibration_trig_par_
Simulation of NeuLAND Bar/Paddle.
constexpr auto COARSE_TIME_CLOCK_FREQUENCY_MHZ
constexpr auto BarsPerPlane
constexpr auto Neuland_PlaneBar2ModuleNum(int planeNum, int barNum) -> int
std::vector< CalDataSignal > left
std::vector< CalDataSignal > right
ValueError< double > trigger_time
ValueError< double > leading_time