Project
Loading...
Searching...
No Matches
PHOSEnergyCalibrator.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
18#include <fairlogger/Logger.h>
19#include <fstream> // std::ifstream
20
21using namespace o2::phos;
22
24{
25 mHistos = std::make_unique<ETCalibHistos>();
26 mBuffer = std::make_unique<RingBuffer>();
27 mGeom = Geometry::GetInstance();
28}
30{
31 mRunStartTime = other.mRunStartTime;
32 mBuffer = std::make_unique<RingBuffer>();
33 mEvBC = other.mEvBC;
34 mEvOrbit = other.mEvOrbit;
35 mEvent = 0;
36 mPtMin = other.mPtMin;
37 mEminHGTime = other.mEminHGTime;
38 mEminLGTime = other.mEminLGTime;
39 mFillDigitsTree = other.mFillDigitsTree;
40 mDigits.clear();
41 mHistos = std::make_unique<ETCalibHistos>();
42}
43
45{
46 LOG(info) << "Collected " << mDigits.size() << " CalibDigits";
47}
48
49void PHOSEnergySlot::fill(const gsl::span<const Cluster>& clusters, const gsl::span<const CluElement>& cluelements, const gsl::span<const TriggerRecord>& cluTR)
50{
51 // Scan current list of clusters
52 // Fill time, non-linearity and mgg histograms
53 // Fill list of re-calibraiable digits
54 if (mFillDigitsTree) {
55 mDigits.clear();
56 }
57 for (auto& tr : cluTR) {
58
59 if (mFillDigitsTree) {
60 // Mark new event
61 // First goes new event marker + BC (16 bit), next word orbit (32 bit)
62 EventHeader h = {0};
63 h.mMarker = 16383;
64 h.mBC = tr.getBCData().bc;
65 mDigits.push_back(h.mDataWord);
66 mDigits.push_back(tr.getBCData().orbit);
67 }
68 mEvBC = tr.getBCData().bc;
69
70 int firstCluInEvent = tr.getFirstEntry();
71 int lastCluInEvent = firstCluInEvent + tr.getNumberOfObjects();
72
73 // event is good if a) 2 and more clusters; b) at least one cluster with E>1.5 GeV
74 const float minCluE = 1.5;
75 bool good = false;
76 for (int i = firstCluInEvent; i < lastCluInEvent; i++) {
77 const Cluster& clu = clusters[i];
78 if (checkCluster(clu) && clu.getEnergy() > minCluE) {
79 good = true;
80 break;
81 }
82 }
83 good &= (lastCluInEvent - firstCluInEvent > 1);
84 if (!good) {
85 continue;
86 }
87
88 mBuffer->startNewEvent(); // mark stored clusters to be used for Mixing
89 for (int i = firstCluInEvent; i < lastCluInEvent; i++) {
90 const Cluster& clu = clusters[i];
91 if (clu.getEnergy() < mClusterEmin) { // There was problem in unfolding and cluster parameters not calculated
92 continue;
93 }
94 fillTimeMassHisto(clu, cluelements);
95
96 if (!mFillDigitsTree) {
97 continue;
98 }
99
100 uint32_t firstCE = clu.getFirstCluEl();
101 uint32_t lastCE = clu.getLastCluEl();
102 for (uint32_t idig = firstCE; idig < lastCE; idig++) {
103 const CluElement& ce = cluelements[idig];
104 // if (ce.energy < mDigitEmin) {
105 // continue;
106 // }
107 short absId = ce.absId;
108 // Fill cells from cluster for next iterations
109 short adcCounts = ce.energy / mCalibParams->getGain(absId);
110 // Need to chale LG gain too to fit dynamic range
111 if (!ce.isHG) {
112 adcCounts /= mCalibParams->getHGLGRatio(absId);
113 }
114 CalibDigit d = {0};
115 d.mAddress = absId;
116 d.mAdcAmp = adcCounts;
117 d.mHgLg = ce.isHG;
118 d.mCluster = (i - firstCluInEvent) % kMaxCluInEvent;
119 mDigits.push_back(d.mDataWord);
120 if (i - firstCluInEvent > kMaxCluInEvent) {
121 // Normally this is not critical as indexes are used "locally", i.e. are compared to previous/next
122 LOG(important) << "Too many clusters per event:" << i - firstCluInEvent << ", apply more strict selection; clusters with same indexes will appear";
123 }
124 }
125 }
126 }
127}
129{
130 mHistos->reset();
131 mDigits.clear();
132}
133
134void PHOSEnergySlot::fillTimeMassHisto(const Cluster& clu, const gsl::span<const CluElement>& cluelements)
135{
136 // Fill time distributions only for cells in cluster
137 uint32_t firstCE = clu.getFirstCluEl();
138 uint32_t lastCE = clu.getLastCluEl();
139
140 short absIdMax = 0;
141 float maxE = 0.;
142 for (uint32_t idig = firstCE; idig < lastCE; idig++) {
143 const CluElement& ce = cluelements[idig];
144 short absId = ce.absId;
145 if (ce.energy > maxE) {
146 maxE = ce.energy;
147 absIdMax = absId;
148 }
149 if (ce.isHG) {
150 if (ce.energy > mEminHGTime) {
151 mHistos->fill(ETCalibHistos::kTimeHGPerCell, absId, ce.time);
152 char relid[3];
153 Geometry::absToRelNumbering(absId, relid);
154 int ddl = (relid[0] - 1) * 4 + (relid[1] - 1) / 16 - 2;
155 mHistos->fill(ETCalibHistos::kTimeDDL, int(ddl * 4 + mEvBC % 4), ce.time);
156 }
157 if (mBadMap->isChannelGood(absId)) {
158 mHistos->fill(ETCalibHistos::kTimeHGSlewing, ce.time, ce.energy);
159 }
160 } else {
161 if (ce.energy > mEminLGTime) {
162 mHistos->fill(ETCalibHistos::kTimeLGPerCell, absId, ce.time);
163 }
164 if (!mBadMap->isChannelGood(absId)) {
165 mHistos->fill(ETCalibHistos::kTimeLGSlewing, ce.time, ce.energy);
166 }
167 }
168 }
169
170 // Real and Mixed inv mass distributions
171 // prepare TLorentsVector
172 float posX, posZ;
173 clu.getLocalPosition(posX, posZ);
174
175 // Correction for the depth of the shower starting point (TDR p 127)
176 const float para = 0.925;
177 const float parb = 6.52;
178 float depth = para * TMath::Log(clu.getEnergy()) + parb;
179 posX -= posX * depth / 460.;
180 posZ -= posZ * depth / 460.;
181
182 TVector3 vec3;
183 mGeom->local2Global(clu.module(), posX, posZ, vec3);
184 // float e = clu.getEnergy();
185 float e = Nonlinearity(clu.getCoreEnergy());
186 // Non-perp inc., nonlin
187 vec3 *= e / vec3.Mag();
188 TLorentzVector v(vec3.X(), vec3.Y(), vec3.Z(), e);
189 // Fill calibration histograms for all cells, even bad, but partners in inv, mass should be good
190 bool isGood = checkCluster(clu);
191 for (short ip = mBuffer->size(); ip--;) {
192 const TLorentzVector& vp = mBuffer->getEntry(ip);
193 TLorentzVector sum = v + vp;
194 if (mBuffer->isCurrentEvent(ip)) { // same (real) event
195 if (isGood) {
196 mHistos->fill(ETCalibHistos::kReInvMassNonlin, e, sum.M());
197 }
198 if (sum.Pt() > mPtMin) {
199 mHistos->fill(ETCalibHistos::kReInvMassPerCell, absIdMax, sum.M());
200 }
201 } else { // Mixed
202 if (isGood) {
203 mHistos->fill(ETCalibHistos::kMiInvMassNonlin, e, sum.M());
204 }
205 if (sum.Pt() > mPtMin) {
206 mHistos->fill(ETCalibHistos::kMiInvMassPerCell, absIdMax, sum.M());
207 }
208 }
209 }
210
211 // Add to list ot partners only if cluster is good
212 if (isGood && e > 0.2) {
213 mBuffer->addEntry(v);
214 }
215}
216
217bool PHOSEnergySlot::checkCluster(const Cluster& clu)
218{
219 // First check BadMap
220 float posX, posZ;
221 clu.getLocalPosition(posX, posZ);
222 short absId;
223 Geometry::relPosToAbsId(clu.module(), posX, posZ, absId);
224 if (!mBadMap->isChannelGood(absId)) {
225 return false;
226 }
227
228 return (clu.getEnergy() > 0.3 && clu.getMultiplicity() > 1);
229}
230float PHOSEnergySlot::Nonlinearity(float en)
231{
232 // Correct for non-linearity
233 const double a = 9.34913e-01;
234 const double b = 2.33e-03;
235 const double c = -8.10e-05;
236 const double d = 3.2e-02;
237 const double f = -8.0e-03;
238 const double g = 1.e-01;
239 const double h = 2.e-01;
240 const double k = -1.48e-04;
241 const double l = 0.194;
242 const double m = 0.0025;
243
244 return en * (a + b * en + c * en * en + d / en + f / ((en - g) * (en - g) + h) + k / ((en - l) * (en - l) + m));
245}
246
247//==================================================
248
252{
253 // create final histos
254 mHistos = std::make_unique<ETCalibHistos>();
255}
256
258{
259 // Extract results for the single slot
260 es* c = slot.getContainer();
261 LOG(debug) << "Finalize slot " << slot.getTFStart() << " <= TF <= " << slot.getTFEnd();
262 // Add histos
263 mHistos->merge(c->getCollectedHistos());
264}
265
267{
268 auto& cont = getSlots();
269 auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend);
270 slot.setContainer(std::make_unique<es>());
271 slot.getContainer()->setFillDigitsTree(mFillDigitsTree);
272 slot.getContainer()->setBadMap(mBadMap);
273 slot.getContainer()->setCalibration(mCalibParams);
274 slot.getContainer()->setCuts(mPtMin, mEminHGTime, mEminLGTime, mDigitEmin, mClusterEmin);
275 return slot;
276}
277
278bool PHOSEnergyCalibrator::process(uint64_t tf, const gsl::span<const Cluster>& clusters,
279 const gsl::span<const CluElement>& cluelements,
280 const gsl::span<const TriggerRecord>& cluTR,
281 std::vector<uint32_t>& outputDigits)
282{
283 // process current TF
284 // First receive bad map and calibration if not received yet
285 auto& slotTF = getSlotForTF(tf);
286 slotTF.getContainer()->setRunStartTime(tf);
287 slotTF.getContainer()->fill(clusters, cluelements, cluTR);
288 // Add collected Digits
289 if (mFillDigitsTree) {
290 auto tmpD = slotTF.getContainer()->getCollectedDigits();
291 outputDigits.insert(outputDigits.end(), tmpD.begin(), tmpD.end());
292 }
293 return true;
294}
295
Utils and constants for calibration and related workflows.
int32_t i
uint32_t c
Definition RawData.h:2
std::ostringstream debug
Class for time synchronization of RawReader instances.
TFType getTFEnd() const
Definition TimeSlot.h:47
const Container * getContainer() const
Definition TimeSlot.h:53
TFType getTFStart() const
Definition TimeSlot.h:46
bool isChannelGood(short channelID) const
Get the status of a certain cell.
float getHGLGRatio(short cellID) const
Get High Gain to Low Gain ratio calibration coefficients.
Definition CalibParams.h:69
float getGain(short cellID) const
Get High Gain energy calibration coefficients.
Definition CalibParams.h:53
Contains PHOS cluster parameters.
Definition Cluster.h:39
float getEnergy() const
Definition Cluster.h:56
uint32_t getFirstCluEl() const
Definition Cluster.h:104
int getMultiplicity() const
Definition Cluster.h:86
char module() const
Definition Cluster.h:92
void getLocalPosition(float &posX, float &posZ) const
Definition Cluster.h:76
uint32_t getLastCluEl() const
Definition Cluster.h:105
float getCoreEnergy() const
Definition Cluster.h:59
static void relPosToAbsId(char module, float x, float z, short &absId)
Definition Geometry.cxx:220
void local2Global(char module, float x, float z, TVector3 &globaPos) const
Definition Geometry.cxx:234
static bool absToRelNumbering(short absId, char *relid)
Definition Geometry.cxx:65
static Geometry * GetInstance()
Definition Geometry.h:63
bool process(uint64_t tf, const gsl::span< const Cluster > &clusters, const gsl::span< const CluElement > &cluelements, const gsl::span< const TriggerRecord > &cluTR, std::vector< uint32_t > &outputDigits)
Slot & emplaceNewSlot(bool front, TFType tstart, TFType tend) final
static constexpr short kMaxCluInEvent
PHOSEnergySlot()
maximal number of clusters per event to separate digits from them (7 bits in digit map)
void fill(const gsl::span< const Cluster > &clusters, const gsl::span< const CluElement > &cluelements, const gsl::span< const TriggerRecord > &cluTR)
float sum(float s, o2::dcs::DataPointValue v)
Definition dcs-ccdb.cxx:39
const GLfloat * m
Definition glcorearb.h:4066
const GLdouble * v
Definition glcorearb.h:832
GLdouble f
Definition glcorearb.h:310
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLboolean GLboolean g
Definition glcorearb.h:1233
GLint GLint GLsizei GLsizei GLsizei depth
Definition glcorearb.h:470
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
std::unique_ptr< GPUReconstructionTimeframe > tf
VectorOfTObjectPtrs other
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
Cluster clu
std::vector< Cluster > clusters
uint32_t mHgLg
Bit 24: LG/HG.
uint32_t mCluster
Bits 25-32: index of cluster in event.
uint32_t mAddress
Bits 0 - 13: Hardware address.
uint32_t mAdcAmp
Bits 14 - 23: ADC counts.