Project
Loading...
Searching...
No Matches
Digitizer.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
17#include "CCDB/CcdbApi.h"
18
19#include <TRandom.h>
20#include <fairlogger/Logger.h> // for LOG
21
23
24using o2::phos::Hit;
25
26using namespace o2::phos;
27
28//_______________________________________________________________________
30{
31}
32//_______________________________________________________________________
34
35//_______________________________________________________________________
36void Digitizer::processHits(const std::vector<Hit>* hits, const std::vector<Digit>& digitsBg,
37 std::vector<Digit>& digitsOut, o2::dataformats::MCTruthContainer<MCLabel>& labels,
38 int collId, int source, double dt)
39{
40 // Convert list of hits + possible Bg digits to digits:
41 // Add hits with energy deposition in same cell and same time
42 // Add energy corrections
43 // Apply time smearing
44
45 if (!mCalibParams) {
46 // By default MC simulations are performed with realistic but not real calibration parameters
47 // This allows to account digitization detorioration and revert energy assuming ideal calibration
48 // or one can use modified calibration in clusterer to emulate inaccuracy of calibration.
49 // However, one can request digitization with special calibration parameters, e.g. real ones
50 // by pointing to proper CCDB
51 if (o2::phos::PHOSSimParams::Instance().mDigitizationCalibPath.compare("default") == 0) {
52 // Use default calibration
53 mCalibParams.reset(new CalibParams(1)); // test default calibration
54 LOG(info) << "Use default calibration";
55 } else {
57 std::map<std::string, std::string> metadata;
58 ccdb.init(o2::phos::PHOSSimParams::Instance().mDigitizationCalibPath);
59 mCalibParams.reset(ccdb.retrieveFromTFileAny<CalibParams>("PHS/Calib/CalibParams", metadata, mRunStartTime));
60 if (mCalibParams) {
61 LOG(info) << "Use calibration from CCDB " << o2::phos::PHOSSimParams::Instance().mDigitizationCalibPath;
62 } else {
63 LOG(fatal) << "Can not get calibration object from ccdb " << o2::phos::PHOSSimParams::Instance().mDigitizationCalibPath;
64 }
65 }
66 }
67 if (!mTrigUtils) {
68 if (o2::phos::PHOSSimParams::Instance().mDigitizationTrigPath.compare("default") == 0) {
69 mTrigUtils.reset(new TriggerMap(0)); // test default calibration
70 LOG(info) << "Use default trigger map and turn-on curves";
71 } else {
73 std::map<std::string, std::string> metadata;
74 ccdb.init(o2::phos::PHOSSimParams::Instance().mDigitizationTrigPath);
75 mTrigUtils.reset(ccdb.retrieveFromTFileAny<TriggerMap>("PHS/Calib/Trigger", metadata, mRunStartTime));
76 if (mTrigUtils) {
77 LOG(info) << "Use trigger map and turn-on curves from " << o2::phos::PHOSSimParams::Instance().mDigitizationTrigPath;
78 } else {
79 LOG(fatal) << "Can not get trigger object from ccdb " << o2::phos::PHOSSimParams::Instance().mDigitizationTrigPath;
80 }
81 }
82 }
83
84 // Despite sorting in Detector::EndEvent(), hits still can be unsorted due to splitting of processing different bunches of primary
85 for (int i = NCHANNELS; i--;) {
86 mArrayD[i].reset();
87 }
88 int nBgTrigFirst = digitsOut.size(); // Bg trigger digits will be directly copied to output
89
90 if (digitsBg.size() == 0) { // no digits provided: try simulate noise
91 for (int i = NCHANNELS; i--;) {
92 float energy = simulateNoiseEnergy(i + OFFSET);
93 energy = uncalibrate(energy, i + OFFSET);
94 if (energy > o2::phos::PHOSSimParams::Instance().mDigitThreshold) {
95 float time = simulateNoiseTime();
96 mArrayD[i].setAmplitude(energy);
97 mArrayD[i].setTime(time);
98 mArrayD[i].setAbsId(i + OFFSET);
99 }
100 }
101 } else { // if digits exist, no noise should be added
102 for (auto& dBg : digitsBg) { // digits are sorted and unique
103 if (dBg.isTRU()) {
104 digitsOut.emplace_back(dBg); // tileId, sum2x2[ix][iz], tt, true, -1);
105 } else {
106 mArrayD[dBg.getAbsId() - OFFSET] = dBg;
107 }
108 }
109 }
110
111 // add Hits
112 for (auto& h : *hits) {
113 short absId = h.GetDetectorID();
114 short i = absId - OFFSET;
115 float energy = h.GetEnergyLoss();
117 energy = nonLinearity(energy);
118 }
119 float time = h.GetTime() + dt * 1.e-9;
120 if (o2::phos::PHOSSimParams::Instance().mApplyTimeResolution) {
121 time = uncalibrateT(timeResolution(time, energy), absId);
122 }
123 energy = uncalibrate(energy, absId);
124 if (mArrayD[i].getAmplitude() > 0) {
125 // update energy and time
126 if (mArrayD[i].isHighGain()) {
127 mArrayD[i].addEnergyTime(energy, time);
128 // if overflow occured?
129 if (mArrayD[i].getAmplitude() > o2::phos::PHOSSimParams::Instance().mMCOverflow) { // 10bit ADC
130 float hglgratio = mCalibParams->getHGLGRatio(absId);
131 mArrayD[i].setAmplitude(mArrayD[i].getAmplitude() / hglgratio);
132 mArrayD[i].setHighGain(false);
133 }
134 } else { // digit already in LG
135 float hglgratio = mCalibParams->getHGLGRatio(absId);
136 energy /= hglgratio;
137 mArrayD[i].addEnergyTime(energy, time);
138 }
139 } else {
140 mArrayD[i].setHighGain(energy < o2::phos::PHOSSimParams::Instance().mMCOverflow); // 10bit ADC
141 if (mArrayD[i].isHighGain()) {
142 mArrayD[i].setAmplitude(energy);
143 } else {
144 float hglgratio = mCalibParams->getHGLGRatio(absId);
145 mArrayD[i].setAmplitude(energy / hglgratio);
146 }
147 mArrayD[i].setTime(time);
148 mArrayD[i].setAbsId(absId);
149 }
150 // Add MC info
151 if (mProcessMC) {
152 int labelIndex = mArrayD[i].getLabel();
153 if (labelIndex == -1) { // no digit or noisy
154 labelIndex = labels.getIndexedSize();
155 MCLabel label(h.GetTrackID(), collId, source, false, h.GetEnergyLoss());
156 labels.addElement(labelIndex, label);
157 mArrayD[i].setLabel(labelIndex);
158 } else { // check if lable already exist
159 MCLabel label(h.GetTrackID(), collId, source, false, h.GetEnergyLoss());
160 gsl::span<MCLabel> sp = labels.getLabels(labelIndex);
161 bool found = false;
162 for (MCLabel& te : sp) {
163 if (te == label) {
164 found = true;
165 te.add(label, 1.);
166 break;
167 }
168 }
169 if (!found) {
170 // Highly inefficient management of Labels: commenting line below reeduces WHOLE digitization time by factor ~30
171 labels.addElementRandomAccess(labelIndex, label);
172 // sort MCLabels according to eDeposited
173 sp = labels.getLabels(labelIndex);
174 std::sort(sp.begin(), sp.end(),
175 [](o2::phos::MCLabel a, o2::phos::MCLabel b) { return a.getEdep() > b.getEdep(); });
176 }
177 }
178 } else {
179 mArrayD[i].setLabel(-1);
180 }
181 }
182 // Calculate trigger tiles 2*2 and 4*4
183 bool mL0Fired = false;
184 float sum2x2[65][57];
185 float time2x2[65][57];
186 float tt = 0;
187 for (short module = 1; module < 5; module++) {
188 short xmin = (module == 1) ? 33 : 1;
189 for (short ix = xmin; ix < 64; ix++) {
190 for (short iz = 1; iz < 56; iz++) {
191 char relId[3] = {char(module), char(ix), char(iz)};
192 short tileId = Geometry::truRelToAbsNumbering(relId, 0);
193 if (!mTrigUtils->isGood2x2(tileId)) {
194 continue;
195 }
196 short i1, i2, i3, i4;
198 relId[1] = relId[1] + 1;
200 relId[2] = relId[2] + 1;
202 relId[1] = relId[1] - 1;
204 sum2x2[ix][iz] = mArrayD[i1 - OFFSET].getAmplitude() + mArrayD[i2 - OFFSET].getAmplitude() +
205 mArrayD[i3 - OFFSET].getAmplitude() + mArrayD[i4 - OFFSET].getAmplitude();
206 float ampMax = mArrayD[i1 - OFFSET].getAmplitude();
207 tt = mArrayD[i1 - OFFSET].getTime();
208 if (mArrayD[i2 - OFFSET].getAmplitude() > ampMax) {
209 ampMax = mArrayD[i2 - OFFSET].getAmplitude();
210 tt = mArrayD[i2 - OFFSET].getTime();
211 }
212 if (mArrayD[i3 - OFFSET].getAmplitude() > ampMax) {
213 ampMax = mArrayD[i3 - OFFSET].getAmplitude();
214 tt = mArrayD[i3 - OFFSET].getTime();
215 }
216 if (mArrayD[i4 - OFFSET].getAmplitude() > ampMax) {
217 tt = mArrayD[i4 - OFFSET].getTime();
218 }
219 time2x2[ix][iz] = tt;
220 if (mTrig2x2) {
221 if (sum2x2[ix][iz] > PHOSSimParams::Instance().mTrig2x2MinThreshold) { // do not test (slow) probability function with soft tiles
222 mL0Fired |= mTrigUtils->isFiredMC2x2(sum2x2[ix][iz], module, short(ix), short(iz));
223 // add TRU digit. Note that only tiles with E>mTrigMinThreshold added!
224 // Check that this tile does not exist yet in Bg
225 // Number of trigger tiles is small, plain loop is OK
226 bool added = false;
227 for (int ibgTr = nBgTrigFirst; ibgTr < digitsOut.size(); ibgTr++) {
228 Digit& bgTr = digitsOut[ibgTr];
229 if (bgTr.getTRUId() == tileId && bgTr.is2x2Tile()) {
230 // assign time to the larger tile
231 if (sum2x2[ix][iz] > bgTr.getAmplitude()) {
232 bgTr.setTime(tt);
233 }
234 bgTr.setAmplitude(bgTr.getAmplitude() + sum2x2[ix][iz]);
235 added = true;
236 break;
237 }
238 }
239 if (!added) {
240 digitsOut.emplace_back(tileId, sum2x2[ix][iz], tt, true, -1); // true for 2x2 trigger
241 }
242 }
243 }
244 }
245 }
246
247 if (mTrig4x4) {
248 for (short ix = xmin; ix < 62; ix++) {
249 for (short iz = 1; iz < 54; iz++) {
250 char relId[3] = {char(module), char(ix), char(iz)};
251 short tileId = Geometry::truRelToAbsNumbering(relId, 1); // 1 for 4x4 trigger
252 if (!mTrigUtils->isGood4x4(tileId)) {
253 continue;
254 }
255 float sum4x4 = sum2x2[ix][iz] + sum2x2[ix][iz + 2] + sum2x2[ix + 2][iz] + sum2x2[ix + 2][iz + 2];
256 if (sum4x4 > PHOSSimParams::Instance().mTrig4x4MinThreshold) { // do not test (slow) probability function with soft tiles
257 mL0Fired |= mTrigUtils->isFiredMC4x4(sum4x4, module, short(ix), short(iz));
258 // Add TRU digit short cell, float amplitude, float time, int label
259 tt = time2x2[ix][iz];
260 float ampMax = sum2x2[ix][iz];
261 if (sum2x2[ix][iz + 2] > ampMax) {
262 ampMax = sum2x2[ix][iz + 2];
263 tt = sum2x2[ix][iz + 2];
264 }
265 if (sum2x2[ix + 2][iz] > ampMax) {
266 ampMax = sum2x2[ix + 2][iz];
267 tt = sum2x2[ix + 2][iz];
268 }
269 if (sum2x2[ix + 2][iz + 2] > ampMax) {
270 tt = sum2x2[ix][iz + 2];
271 }
272 // Check that this tile does not exist yet in Bg
273 // Number of trigger tiles is small, plain loop is OK
274 bool added = false;
275 for (int ibgTr = nBgTrigFirst; ibgTr < digitsOut.size(); ibgTr++) {
276 Digit& bgTr = digitsOut[ibgTr];
277 if (bgTr.getTRUId() == tileId && !bgTr.is2x2Tile()) {
278 // assign time to the larger tile
279 if (sum2x2[ix][iz] > bgTr.getAmplitude()) {
280 bgTr.setTime(tt);
281 }
282 bgTr.setAmplitude(bgTr.getAmplitude() + sum4x4);
283 added = true;
284 break;
285 }
286 }
287 if (!added) {
288 digitsOut.emplace_back(tileId, sum4x4, tt, false, -1); // false for 4x4 trigger tile
289 }
290 }
291 }
292 }
293 }
294 }
295 for (int i = 0; i < NCHANNELS; i++) {
296 if (mArrayD[i].getAmplitude() > PHOSSimParams::Instance().mZSthreshold) {
297 digitsOut.push_back(mArrayD[i]);
298 }
299 }
300}
301
302//_______________________________________________________________________
303float Digitizer::nonLinearity(const float e)
304{
308 return e * c * (1. + a * exp(-e * e / (2. * b * b)));
309}
310//_______________________________________________________________________
311float Digitizer::uncalibrate(const float e, const int absId)
312{
313 // Decalibrate EMC digit, i.e. transform from energy to ADC counts a factor read from CDB
314 float calib = mCalibParams->getGain(absId);
315 if (calib > 0) {
316 return floor(e / calib);
317 } else {
318 return 0;
319 }
320}
321//_______________________________________________________________________
322float Digitizer::uncalibrateT(const float time, const int absId)
323{
324 // Decalibrate EMC digit, i.e. transform from energy to ADC counts a factor read from CDB
325 // note time in seconds
326 return time + mCalibParams->getHGTimeCalib(absId);
327}
328//_______________________________________________________________________
329float Digitizer::timeResolution(const float time, const float e)
330{
331 // apply time resolution
332 // time measured in seconds
333
336 std::max(float(e), o2::phos::PHOSSimParams::Instance().mTimeResThreshold);
337 return gRandom->Gaus(time, timeResolution);
338}
339//_______________________________________________________________________
341{
342 return gRandom->Gaus(0., o2::phos::PHOSSimParams::Instance().mAPDNoise);
343}
344//_______________________________________________________________________
345float Digitizer::simulateNoiseTime() { return gRandom->Uniform(o2::phos::PHOSSimParams::Instance().mMinNoiseTime,
346 o2::phos::PHOSSimParams::Instance().mMaxNoiseTime); }
uint64_t exp(uint64_t base, uint8_t exp) noexcept
int16_t time
Definition RawEventData.h:4
int32_t i
ClassImp(o2::phos::Digitizer)
uint32_t c
Definition RawData.h:2
Class for time synchronization of RawReader instances.
void init(std::string const &hosts)
Definition CcdbApi.cxx:165
std::enable_if<!std::is_base_of< o2::conf::ConfigurableParam, T >::value, T * >::type retrieveFromTFileAny(std::string const &path, std::map< std::string, std::string > const &metadata, long timestamp=-1, std::map< std::string, std::string > *headers=nullptr, std::string const &etag="", const std::string &createdNotAfter="", const std::string &createdNotBefore="") const
Definition CcdbApi.h:660
A container to hold and manage MC truth information/labels.
gsl::span< TruthElement > getLabels(uint32_t dataindex)
void addElement(uint32_t dataindex, TruthElement const &element, bool noElement=false)
void addElementRandomAccess(uint32_t dataindex, TruthElement const &element)
void setAmplitude(float amplitude)
Definition Digit.h:114
short getTRUId() const
Definition Digit.h:109
float getAmplitude() const
Energy deposited in a cell.
Definition Digit.h:113
bool is2x2Tile() const
Definition Digit.h:124
void setTime(float time)
Definition Digit.h:118
float simulateNoiseEnergy(int absId)
float timeResolution(float time, float e)
void processHits(const std::vector< Hit > *mHits, const std::vector< Digit > &digitsBg, std::vector< Digit > &digitsOut, o2::dataformats::MCTruthContainer< MCLabel > &mLabels, int source, int entry, double dt)
Steer conversion of hits to digits.
Definition Digitizer.cxx:36
float uncalibrate(float e, int absId)
float uncalibrateT(float t, int absId)
float nonLinearity(float e)
static short truRelToAbsNumbering(const char *relId, short trigType)
Definition Geometry.cxx:118
static bool relToAbsNumbering(const char *RelId, short &AbsId)
Definition Geometry.cxx:207
PHOS simulation hit information.
Definition Hit.h:25
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLsizei GLsizei GLchar * source
Definition glcorearb.h:798
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
float mCellNonLineaityB
Energy scale of cel non-linearity.
bool mApplyNonLinearity
Apply energy non-linearity in digitization.
float mCellNonLineaityC
Overall calibration.
float mTimeResolutionB
Time resolution parameter B (in sec/GeV)
std::string mDigitizationCalibPath
use "default" to use default calibration or use ccdb.cern.ch
float mTimeResolutionA
Time resolution parameter A (in sec)
float mCellNonLineaityA
Amp of cel non-linearity.
std::string mDigitizationTrigPath
use "default" to use default map and turn-on or use ccdb.cern.ch
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"