R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BNeulandCal2Hit.cxx
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH *
3 * Copyright (C) 2019-2025 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
14#include "R3BNeulandCal2Hit.h"
15#include "FairRootManager.h"
16#include "FairRuntimeDb.h"
17#include "R3BEventHeader.h"
18#include "R3BNeulandCalData.h"
19#include "R3BNeulandCommon.h"
20#include "R3BNeulandHit.h"
21#include "R3BNeulandHitPar.h"
22#include "TMath.h"
23#include <FairTask.h>
24#include <Math/Vector3Dfwd.h>
25#include <R3BLogger.h>
26
27#include <Rtypes.h>
28#include <RtypesCore.h>
29#include <TVector3.h>
30#include <algorithm>
31#include <array>
32#include <cmath>
33#include <fairlogger/Logger.h>
34#include <fmt/core.h>
35#include <iostream>
36#include <ostream>
37#include <stdexcept>
38
39namespace Neuland = R3B::Neuland;
40
41R3BNeulandCal2Hit::R3BNeulandCal2Hit(const char* name, const Int_t iVerbose)
42 : FairTask(name, iVerbose)
43 , fEventHeader(nullptr)
44 , fCalData("NeulandCalData")
45 , fHits("NeulandHits")
50 , fWalkEnabled(kFALSE)
51{
52}
53
55{
56 auto ioman = FairRootManager::Instance();
57 if (ioman == nullptr)
58 {
59 throw std::runtime_error("R3BNeulandCal2Hit: No FairRootManager");
60 }
61
62 fEventHeader = dynamic_cast<R3BEventHeader*>(ioman->GetObject("EventHeader."));
63 if (fEventHeader == nullptr)
64 {
65 throw std::runtime_error("R3BNeulandCal2Hit: No R3BEventHeader");
66 }
67
68 fCalData.Init();
69 fHits.Init();
70
72 return kSUCCESS;
73}
74
76{
77 fPar = dynamic_cast<R3BNeulandHitPar*>(FairRuntimeDb::instance()->getContainer("NeulandHitPar"));
78}
79
81{
82 fParMap.clear();
83
84 if (std::isnan(fDistanceToTarget))
85 {
86 fDistanceToTarget = fPar->GetDistanceToTarget();
87 }
88 else
89 {
90 fPar->SetDistanceToTarget(fDistanceToTarget);
91 }
92
93 if (std::isnan(fGlobalTimeOffset))
94 {
95 fGlobalTimeOffset = fPar->GetGlobalTimeOffset();
96 }
97 else
98 {
99 fPar->SetGlobalTimeOffset(fGlobalTimeOffset);
100 }
101
102 if (std::isnan(fEnergyCutoff))
103 {
104 fEnergyCutoff = fPar->GetEnergyCutoff();
105 }
106 else
107 {
108 fPar->SetEnergyCutoff(fEnergyCutoff);
109 }
110
111 fNumberOfPlanes = fPar->GetNumberOfPlanes();
112 fDistancesToFirstPlane = fPar->GetDistancesToFirstPlane();
114 const auto nPars = fPar->GetNumModulePar();
115
116 for (auto i = 0; i < nPars; i++)
117 {
118 const auto id = fPar->GetModuleParAt(i)->GetModuleId() - 1;
119 fParMap[id] = *fPar->GetModuleParAt(i);
120 fAttenuationValues[id] = exp(Neuland::TotalBarLength / fParMap[id].GetLightAttenuationLength());
121 }
122
123 LOG(info) << "R3BNeulandCal2Hit::SetParameter : Number of Parameters: " << fPar->GetNumModulePar();
124}
125
127{
129 SetParameter();
130 return kSUCCESS;
131}
132
134{
135
136 if (fVerbose > 0 && ++fEventNumber % 10000 == 0)
137 std::cout << "\rR3BNeulandCal2Hit " << fEventNumber << " Events converted." << std::flush;
138
139 fHits.Reset();
140 fHitMap.clear();
141
142 auto calData = fCalData.Retrieve();
143
144 const auto start = fEventHeader->GetTStart();
145 const bool beam = !std::isnan(start);
146
147 for (auto calDataPtrPtr = calData.begin(); calDataPtrPtr != calData.end(); calDataPtrPtr++)
148 {
149 const auto barID = (*calDataPtrPtr)->GetBarId() - 1;
150
151 R3BLOG(debug2,
152 fmt::format("Input calData barID: {}, side: {}, time: {}, fTriggerTime: {}, fQdc: {}",
153 (*calDataPtrPtr)->GetBarId(),
154 (*calDataPtrPtr)->GetSide(),
155 (*calDataPtrPtr)->GetTime(),
156 (*calDataPtrPtr)->GetTriggerTime(),
157 (*calDataPtrPtr)->GetQdc()));
158
159 if (fParMap.find(barID) == fParMap.end())
160 continue; // We do not have parameters for this module
161
162 if (fHitMap.find(barID) == fHitMap.end()) // TODO what about multi hit?
163 {
164 // This is the first PMT of this bar, store the pointer and go to next cal entry
165 fHitMap[barID] = *calDataPtrPtr;
166 continue;
167 }
168
169 const auto& parameter = fParMap[barID];
170
171 std::array<const R3BNeulandCalData*, 2> cal;
172 if ((*calDataPtrPtr)->GetSide() == 1)
173 cal = { *calDataPtrPtr, fHitMap[barID] };
174 else
175 cal = { fHitMap[barID], *calDataPtrPtr };
176
177 const std::array<double, 2> qdc = { std::max(cal[0]->GetQdc() - parameter.GetPedestal(1), 1.),
178 std::max(cal[1]->GetQdc() - parameter.GetPedestal(2), 1.) };
179
180 const std::array<Double_t, 2> unsatEnergy = {
181 GetUnsaturatedEnergy(qdc[0], parameter.GetEnergyGain(1), parameter.GetPMTSaturation(1)),
182 GetUnsaturatedEnergy(qdc[1], parameter.GetEnergyGain(2), parameter.GetPMTSaturation(2))
183 };
184
185 const auto energy = TMath::Sqrt(fAttenuationValues[barID] * unsatEnergy[0] * unsatEnergy[1]);
186
187 if (energy < fEnergyCutoff)
188 continue;
189
190 std::array<Double_t, 2> tdc;
191
192 if (std::isnan(cal[0]->GetTriggerTime()) || std::isnan(cal[0]->GetTriggerTime()))
193 {
194 tdc = { cal[0]->GetTime() + parameter.GetTimeOffset(1), cal[1]->GetTime() + parameter.GetTimeOffset(2) };
195 }
196 else
197 {
198 tdc = { cal[0]->GetTime() - cal[0]->GetTriggerTime() + parameter.GetTimeOffset(1),
199 cal[1]->GetTime() - cal[1]->GetTriggerTime() + parameter.GetTimeOffset(2) };
200 // fmt::print("time0: {}, trigger0: {}, timeOffset: {}\n",
201 // cal[0]->GetTime(),
202 // cal[0]->GetTriggerTime(),
203 // parameter.GetTimeOffset(1));
204 // fmt::print("time1: {}, trigger1: {}, timeOffset: {}\n",
205 // cal[1]->GetTime(),
206 // cal[1]->GetTriggerTime(),
207 // parameter.GetTimeOffset(2));
208 }
209
210 // FIXME: this should be done in Mapped2Cal
211 // In Cal2Hit the difference between all bars should be checked
212 if (tdc[0] - tdc[1] < -0.5 * Neuland::MaxCalTime)
213 tdc[1] -= Neuland::MaxCalTime;
214 else if (tdc[0] - tdc[1] > 0.5 * Neuland::MaxCalTime)
215 tdc[0] -= Neuland::MaxCalTime;
216
217 auto time = (tdc[0] + tdc[1]) * 0.5 - fGlobalTimeOffset;
218
219 // NOTE: Walk correction has already been done in map2cal. Why here again?
220 if (fWalkEnabled)
221 time = time + WalkCorrection(energy);
222
223 if (beam)
224 {
225 // the shift is to get fmod to work as indented: 4 peaks -> 1 peak w/o stray data (e.g. at 5 * 2048)
226 // fmod gives the time between 0 and 5*2048
227 // remainder() gives the time between -0.5*5*2048 and +0.5*5*2048
228 fmt::print("time: {}, start: {}\n", time, start);
229 time = remainder(time - start, Neuland::MaxCalTime);
230 }
231 else
232 {
233 time = Neuland::NaN;
234 }
235
236 const auto plane = Neuland::ModuleID2PlaneID(barID);
237 const auto bar = (barID) % 50;
238
239 TVector3 pos;
240 TVector3 pixel;
241
242 // NOTE: First plane horizontal or not should be decided by IsPlaneHorizontal
244 {
245 pos[0] = parameter.GetEffectiveSpeed() * (tdc[1] - tdc[0]);
246 pos[1] = (bar + 0.5 - Neuland::BarsPerPlane * 0.5) * Neuland::BarSize_XY;
247
248 pixel[0] = std::min(std::max(0., pos[0] / 5. + 25), 49.);
249 pixel[1] = bar;
250 }
251 else
252 {
253 pos[0] = (bar + 0.5 - Neuland::BarsPerPlane * 0.5) * Neuland::BarSize_XY;
254 pos[1] = parameter.GetEffectiveSpeed() * (tdc[1] - tdc[0]);
255
256 pixel[0] = bar;
257 pixel[1] = std::min(std::max(0., pos[1] / 5. + 25), 49.);
258 }
259
261 pixel[2] = plane;
262
263 auto hit = R3BNeulandHit{ barID + 1,
264 tdc[0],
265 tdc[1],
266 time,
267 unsatEnergy[0],
268 unsatEnergy[1],
269 energy,
270 ROOT::Math::XYZVector{ pos },
271 ROOT::Math::XYZVector{ pixel } };
272 R3BLOG(debug1, fmt::format("Neuland hit: {}", hit));
273 fHits.Insert(hit);
274 }
275}
276
278{
279 if (fVerbose > 0)
280 std::cout << "\rR3BNeulandCal2Hit " << fEventNumber << " Events converted." << std::endl;
281}
282
283Double_t R3BNeulandCal2Hit::GetUnsaturatedEnergy(const Int_t qdc, const Double_t gain, const Double_t saturation) const
284{
285 return qdc / (gain - saturation * qdc);
286}
287
289{
290 Double_t y = 0;
291
292 // if (x<=12.) y=24.78;
293
294 if (x <= 12.)
295 y = 35. - 7.1897575 * log(x) + 1.2 * log(x) * log(x) + 0.23616;
296
297 if (x > 12.)
298 y = 25.5 - 0.055 * x;
299
300 return 24.78 - y;
301}
302
#define R3BLOG(severity, x)
Definition R3BLogger.h:32
ClassImp(R3B::Neuland::Cal2HitPar)
InitStatus Init() override
std::vector< Double_t > fAttenuationValues
std::map< Int_t, R3BNeulandHitModulePar > fParMap
R3BNeulandCal2Hit(const char *name="R3BNeulandCal2Hit", const Int_t iVerbose=0)
std::vector< Double_t > fDistancesToFirstPlane
void SetParContainers() override
InitStatus ReInit() override
void FinishTask() override
R3BNeulandHitPar * fPar
R3BEventHeader * fEventHeader
TCAInputConnector< R3BNeulandCalData > fCalData
Double_t WalkCorrection(Double_t)
Double_t GetUnsaturatedEnergy(const Int_t qdc, const Double_t gain, const Double_t saturation) const
void Exec(Option_t *) override
std::map< Int_t, R3BNeulandCalData * > fHitMap
TCAOutputConnector< R3BNeulandHit > fHits
Simulation of NeuLAND Bar/Paddle.
constexpr auto BarsPerPlane
constexpr auto ModuleID2PlaneID(int moduleID) -> int
constexpr auto BarSize_XY
constexpr auto TotalBarLength
constexpr auto NaN
constexpr auto IsPlaneIDHorizontal(int plane_id) -> bool
constexpr auto MaxCalTime