16#include <FairRuntimeDb.h>
20#include <FairRunAna.h>
30 auto CheckOverlapping(
const T& peak, std::vector<T>& peaks) ->
decltype(peaks.begin());
32 void ReOverlapping(
typename std::vector<T>::iterator v_iter, std::vector<T>& peaks);
34 void RemovePeakAt(
typename std::vector<T>::iterator v_iter, std::vector<T>& peaks);
36 void set_par_with_hit_module_par(Tamex::Params& par,
37 const R3B::Neuland::HitModulePar& module_par,
71 time_ = (time_ < other.time_) ? time_ : other.time_;
78 , channel_ptr_(channel)
80 if (channel_ptr_ ==
nullptr)
82 LOG(fatal) <<
"channel is not bound to FQTPeak object!";
88 trailing_edge_time_ = leading_edge_time_ + width_;
93 if (other.leading_edge_time_ == 0 && leading_edge_time_ == 0)
95 LOG(warn) <<
"the times of both PMT signals are 0!";
97 return (leading_edge_time_ <= (other.leading_edge_time_ + other.width_)) &&
98 (other.leading_edge_time_ <= (leading_edge_time_ + width_));
103 if (channel_ptr_ ==
nullptr)
108 (leading_edge_time_ < other.leading_edge_time_) ? leading_edge_time_ : other.leading_edge_time_;
109 trailing_edge_time_ =
110 (trailing_edge_time_ > other.trailing_edge_time_) ? trailing_edge_time_ : other.trailing_edge_time_;
111 width_ = trailing_edge_time_ - leading_edge_time_;
112 qdc_ =
WidthToQdc(width_, channel_ptr_->GetParConstRef());
120 , pileup_strategy_{ strategy }
121 , neuland_hit_par_{ cal_to_hit_par }
135 if (paddle ==
nullptr)
139 if (CheckPaddleIDInHitPar())
141 const auto& module_par = neuland_hit_par_->GetModuleParAt(paddle->
GetPaddleID());
142 set_par_with_hit_module_par(par_, module_par,
GetSide());
146 auto Channel::CheckPaddleIDInHitPar() const ->
bool
148 auto is_valid =
false;
149 if (neuland_hit_par_ ==
nullptr)
153 if (not neuland_hit_par_->hasChanged())
155 R3BLOG(warn,
"Can't setup parameter in the root file correctly!.");
160 if (
GetPaddle()->GetPaddleID() > PaddleId_max)
162 LOG(warn) <<
"Paddle id " <<
GetPaddle()->GetPaddleID() <<
" exceeds the id " << PaddleId_max
163 <<
" in the parameter file!";
176 if (newHit.
time < par_.fTimeMin || newHit.
time > par_.fTimeMax)
182 pmt_peaks_.emplace_back(newHit, *
this);
187 auto peakQdc = peak.GetQDC();
188 auto peakTime = peak.GetLETime();
189 auto qdc = ToQdc(peakQdc);
191 LOG(debug) <<
"qdc Signal " << qdc <<
" and tdc " << peakTime <<
"\n";
194 signal.qdcUnSat = ToUnSatQdc(qdc);
196 signal.tdc = ToTdc(peakTime);
198 LOG(debug) <<
"R3BDigitizingTamex: Create a signal with qdc " << signal.qdc <<
" and tdc " << signal.tdc
205 auto peakQdc = peak.GetQDC();
206 auto peakTime = peak.GetLETime();
207 auto qdc = ToQdc(peakQdc);
209 LOG(debug) <<
"qdc Cal " << qdc <<
" and tdc " << peakTime <<
"\n";
212 signal.tot = CalculateTOT(qdc);
213 signal.tle = peakTime;
215 LOG(debug) <<
"R3BDigitizingTamex: Create a CalSignal with tot " << signal.tot <<
" and let " << signal.tle
216 <<
"\n qdc: " << qdc <<
"\n";
220 auto Channel::CalculateTOT(
const double& qdc)
const ->
double
237 auto par = GetParConstRef();
241 template <
typename Peak>
242 void Channel::PeakPileUp( std::vector<Peak>& peaks)
244 if (peaks.size() <= 1)
249 std::sort(peaks.begin(), peaks.end(), std::less{});
250 for (
auto front_peak = peaks.begin(); front_peak != peaks.end(); ++front_peak)
252 auto end_peak = std::remove_if(front_peak + 1,
254 [&front_peak](
auto& peak)
256 if (*front_peak == peak)
258 (*front_peak) += peak;
263 peaks.erase(end_peak, peaks.end());
267 void Channel::PeakPileUpWithDistance( std::vector<FQTPeak>& peaks,
double distance)
273 std::sort(peaks.begin(), peaks.end(), std::less{});
275 for (
auto front_peak = peaks.begin(); front_peak != peaks.end(); ++front_peak)
277 auto last_leading_time = front_peak->GetLETime();
278 auto end_peak = std::remove_if(front_peak + 1,
280 [&distance, &front_peak, &last_leading_time](FQTPeak& peak)
282 if ((peak - last_leading_time) < distance)
284 front_peak->AddQDC(peak.GetQDC());
285 last_leading_time = peak.GetLETime();
290 peaks.erase(end_peak, peaks.end());
294 void Channel::PeakPileUpInTimeWindow( std::vector<FQTPeak>& peaks,
double time_window)
300 std::sort(peaks.begin(), peaks.end(), std::less{});
302 auto& front_peak = peaks.front();
303 std::for_each(peaks.begin() + 1,
305 [&front_peak, time_window](FQTPeak& peak)
307 if ((peak - front_peak) < time_window)
309 front_peak.AddQDC(peak.GetQDC());
312 peaks.erase(peaks.begin() + 1, peaks.end());
315 void Channel::FQTPeakPileUp( std::vector<FQTPeak>& peaks)
317 switch (pileup_strategy_)
319 case PeakPileUpStrategy::width:
322 case PeakPileUpStrategy::distance:
323 PeakPileUpWithDistance(peaks, par_.fPileUpDistance);
325 case PeakPileUpStrategy::time_window:
326 PeakPileUpInTimeWindow(peaks, par_.fPileUpTimeWindow);
333 template <
typename Peak>
334 void Channel::ApplyThreshold(std::vector<Peak>& peaks)
338 std::remove_if(peaks.begin(),
340 [
this](
const auto& peak) { return peak.GetQDC() < this->GetParConstRef().fPMTThresh; });
341 peaks.erase(it_end, peaks.end());
344 auto Channel::ConstructFQTPeaks(std::vector<PMTPeak>& pmtPeaks) -> std::vector<FQTPeak>
346 auto FQTPeaks = std::vector<FQTPeak>{};
347 FQTPeaks.reserve(pmtPeaks.size());
350 std::sort(pmtPeaks.begin(), pmtPeaks.end());
352 PeakPileUp(pmtPeaks);
353 ApplyThreshold(pmtPeaks);
354 for (
auto const& peak : pmtPeaks)
356 FQTPeaks.emplace_back(peak,
this);
363 fqt_peaks_ = ConstructFQTPeaks(pmt_peaks_);
365 FQTPeakPileUp(fqt_peaks_);
368 auto signals = std::vector<Signal>{};
369 signals.reserve(fqt_peaks_.size());
371 for (
const auto& peak : fqt_peaks_)
380 fqt_peaks_ = ConstructFQTPeaks(pmt_peaks_);
382 FQTPeakPileUp(fqt_peaks_);
385 auto cal_signals = std::vector<CalSignal>{};
386 cal_signals.reserve(fqt_peaks_.size());
388 for (
const auto& peak : fqt_peaks_)
416 auto Channel::ToQdc(
double qdc)
const ->
double
419 qdc = par_.fRnd.get().Gaus(qdc, par_.fEResRel * qdc);
423 auto Channel::ToTdc(
double time)
const ->
double {
return time + par_.fRnd.get().Gaus(0., par_.fTimeRes); }
425 auto Channel::ToUnSatQdc(
double qdc)
const ->
double
428 if (par_.fExperimentalDataIsCorrectedForSaturation)
430 qdc = qdc / (1 - par_.fSaturationCoefficient * qdc);
431 LOG(debug) <<
"ToUnSatQdc: fSaturationCoefficient = " << par_.fSaturationCoefficient <<
'\n';
#define R3BLOG(severity, x)
virtual auto ConstructCalSignals() -> CalSignals
virtual auto GetCalSignals() -> CalSignals
ChannelCalSignal CalSignal
std::vector< Signal > Signals
virtual auto ConstructSignals() -> Signals=0
auto Is_ValidSignals() -> bool
auto GetSide() const -> ChannelSide
auto GetPaddle() const -> Paddle *
void InvalidateTrigTime()
std::vector< CalSignal > CalSignals
auto GetParConstRef() const -> const Tamex::Params &
auto GetFQTPeaks() -> const std::vector< FQTPeak > &
auto GetPMTPeaks() -> const std::vector< PMTPeak > &
void AttachToPaddle(Digitizing::Paddle *paddle) override
auto CreateSignal(const FQTPeak &peak) const -> Signal
auto ConstructCalSignals() -> CalSignals override
void AddHit(Hit) override
auto ConstructSignals() -> Signals override
Channel(ChannelSide, PeakPileUpStrategy strategy, TRandom3 &)
auto CreateCalSignal(const FQTPeak &peak) const -> CalSignal
FQTPeak(const PMTPeak &pmtPeak, Channel *channel)
auto GetLETime() const -> double
static auto QdcToWidth(double qdc, const Par &par) -> double
auto operator==(const FQTPeak &other) const -> bool
auto GetQDC() const -> double
void operator+=(const FQTPeak &other)
static auto WidthToQdc(double width, const Par &par) -> double
auto operator+=(const PMTPeak &other) -> PMTPeak &
auto GetPaddleID() const -> int
auto GetNumModulePar() const
const size_t TmxPeaksInitialCapacity
std::reference_wrapper< TRandom3 > fRnd
double fSaturationCoefficient
LRPair< ValueError< double > > pedestal
LRPair< ValueError< double > > pmt_threshold
LRPair< ValueError< double > > energy_gain
LRPair< ValueError< double > > pmt_saturation