Project
Loading...
Searching...
No Matches
MeanVertexCalibrator.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
12#include "Framework/Logger.h"
14#include "MathUtils/fit.h"
16#include "CCDB/CcdbApi.h"
19
20namespace o2
21{
22namespace calibration
23{
24
30
32{
33 // Here we initialize the vector of our output objects
34 mMeanVertexVector.clear();
35 mInfoVector.clear();
36 return;
37}
38
39//_____________________________________________
41{
42 for (int i = 0; i < hpar.nBins; ++i) {
43 LOG(info) << "i-th bin [" << hpar.minRange + i * hpar.binWidth << ", " << hpar.minRange + (i + 1) * hpar.binWidth << "] = " << i << ", content of histogram = " << vect[i];
44 }
45 LOG(info) << "Printing to be used as a vector holding the content";
46 for (int i = 0; i < hpar.nBins; ++i) {
47 LOG(info) << "vect[" << i << "] = " << vect[i] << ";";
48 }
49 LOG(info) << "Printing to be used to fill a ROOT histogram";
50 for (int i = 0; i < hpar.nBins; ++i) {
51 if (vect[i] != 0) {
52 LOG(info) << "h->SetBinContent(" << i + 1 << ", " << vect[i] << ");";
53 }
54 }
55}
56
57//_____________________________________________
58void MeanVertexCalibrator::printVector(const std::vector<float>& vect, const MeanVertexCalibrator::HistoParams& hpar)
59{
60 printVector(vect.data(), hpar);
61}
62
63//_____________________________________________
64MeanVertexCalibrator::HistoParams MeanVertexCalibrator::binVector(std::vector<float>& vectOut, const std::vector<float>& vectIn, o2::calibration::MeanVertexData* c, int dim)
65{
66 const char* dimName[3] = {"X", "Y", "Z"};
67 vectOut.clear();
68 // define binning
69 const auto& params = MeanVertexParams::Instance();
70 float mean = c->getMean(dim), rms = c->getRMS(dim);
71 if (rms < params.minSigma[dim]) {
72 LOGP(alarm, "Too small RMS = {} for dimension {} ({} entries), override to {}", rms, dimName[dim], c->entries, params.minSigma[dim]);
73 rms = params.minSigma[dim];
74 }
75 float minD = mean - params.histoNSigma[dim] * rms;
76 float maxD = mean + params.histoNSigma[dim] * rms;
77 int nBins = std::max(1.f, (maxD - minD) / params.histoBinSize[dim]);
78 float binWidth = (maxD - minD) / nBins, binWidthInv = 1. / binWidth;
79 if (mVerbose) {
80 LOGP(info, "Histo for dim:{} with {} entries: mean:{} rms:{} -> {} bins in range {}:{} ", dimName[dim], c->entries, mean, rms, nBins, minD, maxD, nBins);
81 }
82 vectOut.resize(nBins);
83 for (int i = 0; i < vectIn.size(); ++i) {
84 if (vectIn[i] < minD) {
85 continue;
86 }
87 int bin = (vectIn[i] - minD) * binWidthInv;
88 if (bin >= nBins) {
89 continue;
90 }
91 vectOut[bin]++;
92 }
93 return {nBins, binWidth, minD, maxD};
94}
95
96//_____________________________________________
98{
99 // now we do the fits in slices of Z
100 // we fit as soon as we have enough entries in z
101 const auto& params = MeanVertexParams::Instance();
102 double fitres;
103 // first we order the vector
104 std::sort(c->histoVtx.begin(), c->histoVtx.end(), [](std::array<float, 3> a, std::array<float, 3> b) { return b[2] > a[2]; });
105 if (mVerbose) {
106 LOG(info) << "Printing ordered vertices";
107 for (int i = 0; i < c->histoVtx.size(); ++i) {
108 LOG(info) << "x = " << c->histoVtx[i][0] << ", y = " << c->histoVtx[i][1] << ", z = " << c->histoVtx[i][2];
109 }
110 }
111
112 std::vector<float> htmpX;
113 std::vector<float> htmpY;
114 std::vector<float> htmpZ;
115 std::vector<std::array<double, 3>> fitResSlicesX;
116 std::vector<CovMatrix> covMatrixX;
117 std::vector<std::array<double, 3>> fitResSlicesY;
118 std::vector<CovMatrix> covMatrixY;
119 std::vector<float> binnedVect;
120 std::vector<double> meanZvect;
121 int startZ = 0, nBinsOK = 0;
122 auto minEntriesPerPoint = std::max((unsigned long int)params.minEntries, c->histoVtx.size() / params.nPointsForSlope);
123 if (mVerbose) {
124 LOGP(info, "Beginning: startZ = {} c->histoVtx.size() = {}, will process {} Z slices with {} entries each", startZ, c->histoVtx.size(), params.nPointsForSlope, minEntriesPerPoint);
125 }
126 auto dumpNonEmpty = [&binnedVect](const std::string& msg) {
127 if (!msg.empty()) {
128 LOG(info) << msg;
129 }
130 for (size_t i = 0; i < binnedVect.size(); i++) {
131 if (binnedVect[i]) {
132 LOGP(info, "bin:{} {}", i, binnedVect[i]);
133 }
134 }
135 };
136
137 for (int counter = 0; counter < params.nPointsForSlope; counter++) {
138 if (mVerbose) {
139 LOG(info) << "Beginning of while: startZ = " << startZ << " c->histoVtx.size() = " << c->histoVtx.size();
140 }
141 double meanZ = 0;
142 int counts = 0;
143 for (int ii = startZ; ii < c->histoVtx.size(); ++ii) {
144 bool failed = false;
145 if (++counts < minEntriesPerPoint) {
146 htmpX.push_back(c->histoVtx[ii][0]);
147 htmpY.push_back(c->histoVtx[ii][1]);
148 meanZ += c->histoVtx[ii][2];
149 } else {
150 counts--;
151 if (mVerbose) {
152 LOGP(info, "fitting after collecting {} entries for Z slice {} of {}", htmpX.size(), counter, params.nPointsForSlope);
153 }
154 // we can fit and restart filling
155 // X:
156 fitResSlicesX.push_back({});
157 covMatrixX.push_back({});
158 auto hparX = binVector(binnedVect, htmpX, c, 0);
159 if (mVerbose) {
160 LOG(info) << "Fitting X for counter " << counter << ", will use " << hparX.nBins << " bins, from " << hparX.minRange << " to " << hparX.maxRange;
161 for (int i = 0; i < htmpX.size(); ++i) {
162 LOG(info) << "vect[" << i << "] = " << htmpX[i] << ";";
163 }
164 }
165 if (mVerbose) {
166 LOG(info) << " Printing output binned vector for X:";
167 printVector(binnedVect, hparX);
168 } else if (params.dumpNonEmptyBins) {
169 dumpNonEmpty(fmt::format("X{} nonEmpty bins", counter));
170 }
171 fitres = fitGaus(hparX.nBins, binnedVect.data(), hparX.minRange, hparX.maxRange, fitResSlicesX.back(), &covMatrixX.back());
172 if (fitres != -10) {
173 LOG(info) << "X, counter " << counter << ": Fit result (z slice [" << c->histoVtx[startZ][2] << ", " << c->histoVtx[ii][2] << "]) => " << fitres << ". Mean = " << fitResSlicesX[counter][1] << " Sigma = " << fitResSlicesX[counter][2] << ", covMatrix = " << covMatrixX[counter](2, 2) << " entries = " << counts;
174 } else {
175 LOG(error) << "X, counter " << counter << ": Fit failed with result = " << fitres << " entries = " << counts;
176 failed = true;
177 }
178 htmpX.clear();
179
180 // Y:
181 fitResSlicesY.push_back({});
182 covMatrixY.push_back({});
183 binnedVect.clear();
184 auto hparY = binVector(binnedVect, htmpY, c, 1);
185 if (mVerbose) {
186 LOG(info) << "Fitting Y for counter " << counter << ", will use " << hparY.nBins << " bins, from " << hparY.minRange << " to " << hparY.maxRange;
187 for (int i = 0; i < htmpY.size(); ++i) {
188 LOG(info) << i << " : " << htmpY[i];
189 }
190 }
191 if (mVerbose) {
192 LOG(info) << " Printing output binned vector for Y:";
193 printVector(binnedVect, hparY);
194 } else if (params.dumpNonEmptyBins) {
195 dumpNonEmpty(fmt::format("Y{} nonEmpty bins", counter));
196 }
197 fitres = fitGaus(hparY.nBins, binnedVect.data(), hparY.minRange, hparY.maxRange, fitResSlicesY.back(), &covMatrixY.back());
198 if (fitres != -10) {
199 LOG(info) << "Y, counter " << counter << ": Fit result (z slice [" << c->histoVtx[startZ][2] << ", " << c->histoVtx[ii][2] << "]) => " << fitres << ". Mean = " << fitResSlicesY[counter][1] << " Sigma = " << fitResSlicesY[counter][2] << ", covMatrix = " << covMatrixY[counter](2, 2) << " entries = " << counts;
200 } else {
201 LOG(error) << "Y, counter " << counter << ": Fit failed with result = " << fitres << " entries = " << counts;
202 failed = true;
203 }
204 htmpY.clear();
205
206 // Z: let's calculate the mean position
207 if (mVerbose) {
208 LOGP(info, "Z, counter {} {} ({}/{})", counter, meanZ / counts, meanZ, counts);
209 }
210
211 if (failed) {
212 fitResSlicesX.pop_back();
213 covMatrixX.pop_back();
214 fitResSlicesY.pop_back();
215 covMatrixY.pop_back();
216 } else {
217 meanZvect.push_back(meanZ / counts);
218 nBinsOK++;
219 }
220 startZ += counts;
221 break;
222 }
223 }
224 if (mVerbose) {
225 LOG(info) << "End of while: startZ = " << startZ << " c->histoVtx.size() = " << c->histoVtx.size();
226 }
227 }
228
229 // fitting main mean vtx Z
230 for (int ii = 0; ii < c->histoVtx.size(); ++ii) {
231 htmpZ.push_back(c->histoVtx[ii][2]);
232 }
233 auto hparZ = binVector(binnedVect, htmpZ, c, 2);
234 fitMeanVertexCoord(2, binnedVect.data(), hparZ, mvo);
235 htmpZ.clear();
236 binnedVect.clear();
237
238 // now we update the error on x
239 double sumX = 0, sumY = 0, weightSumX = 0, weightSumY = 0;
240 for (int iFit = 0; iFit < nBinsOK; ++iFit) {
241 if (mVerbose) {
242 LOG(info) << "SigmaX = " << fitResSlicesX[iFit][2] << " error = " << covMatrixX[iFit](2, 2);
243 LOG(info) << "SigmaY = " << fitResSlicesY[iFit][2] << " error = " << covMatrixY[iFit](2, 2);
244 }
245 double weightSigmaX = covMatrixX[iFit](2, 2) > 0 ? 1. / covMatrixX[iFit](2, 2) : 1.; // covMatrix is already an error squared
246 sumX += (fitResSlicesX[iFit][2] * weightSigmaX);
247 weightSumX += weightSigmaX;
248
249 double weightSigmaY = covMatrixY[iFit](2, 2) > 0 ? 1. / covMatrixY[iFit](2, 2) : 1.; // covMatrix is already an error squared
250 sumY += (fitResSlicesY[iFit][2] * weightSigmaY);
251 weightSumY += weightSigmaY;
252 }
253 if (mVerbose) {
254 LOG(info) << "sumX = " << sumX;
255 LOG(info) << "weightSumX = " << weightSumX;
256 LOG(info) << "sumY = " << sumY;
257 LOG(info) << "weightSumY = " << weightSumY;
258 }
259
260 double sigmaX = 0;
261 if (weightSumX != 0) {
262 sigmaX = sumX / weightSumX;
263 }
264 double sigmaY = 0;
265 if (weightSumY != 0) {
266 sigmaY = sumY / weightSumY;
267 }
268 if (mVerbose) {
269 LOG(info) << "SigmaX for MeanVertex = " << sigmaX;
270 LOG(info) << "SigmaY for MeanVertex = " << sigmaY;
271 }
272 if (sigmaX == 0 || sigmaY == 0 || mvo.getSigmaZ() == 0 || nBinsOK < 2) {
273 LOGP(error, "Fit with {} valid slices produced wrong vertex parameters: SigmaX={}, SigmaY={}, SigmaZ={}", nBinsOK, sigmaX, sigmaY, mvo.getSigmaZ());
274 return false;
275 }
276 mvo.setSigmaX(sigmaX);
277 mvo.setSigmaY(sigmaY);
278
279 // now we get the slope for the x-coordinate dependence on z
280 TLinearFitter lf(1, "pol1");
281 lf.StoreData(kFALSE);
282 for (int i = 0; i < nBinsOK; ++i) {
283 if (mVerbose) {
284 LOG(info) << "Adding point " << i << ": zvtx = " << meanZvect[i] << " xvtx = " << fitResSlicesX[i][2];
285 }
286 lf.AddPoint(&meanZvect[i], fitResSlicesX[i][1]);
287 }
288 lf.Eval();
289 double slopeX = lf.GetParameter(1);
290 mvo.setSlopeX(slopeX);
291 mvo.setX(mvo.getZ() * slopeX + lf.GetParameter(0));
292 lf.ClearPoints();
293
294 // now slope for the y-coordinate dependence on z
295 for (int i = 0; i < nBinsOK; ++i) {
296 if (mVerbose) {
297 LOG(info) << "Adding point " << i << ": zvtx = " << meanZvect[i] << " yvtx = " << fitResSlicesY[i][2];
298 }
299 lf.AddPoint(&meanZvect[i], fitResSlicesY[i][1]);
300 }
301 lf.Eval();
302 double slopeY = lf.GetParameter(1);
303 mvo.setSlopeY(slopeY);
304 mvo.setY(mvo.getZ() * slopeY + lf.GetParameter(0));
305 if (mVerbose) {
306 LOG(info) << "slope X = " << slopeX;
307 LOG(info) << "slope Y = " << slopeY;
308 }
309 LOG(info) << "Fitted meanVertex: " << mvo.asString();
310 return true;
311}
312//_____________________________________________
314{
315 // fit mean vertex coordinate icoord
316 std::vector<float> fitValues;
317 float binWidth = 0;
318 if (mVerbose) {
319 LOG(info) << "**** Printing content of MeanVertex object for coordinate " << icoord;
320 printVector(array, hpar);
321 }
322 double fitres = fitGaus(hpar.nBins, array, hpar.minRange, hpar.maxRange, fitValues);
323 if (fitres != -4) {
324 LOG(info) << "coordinate " << icoord << ": Fit result of full statistics => " << fitres << ". Mean = " << fitValues[1] << " Sigma = " << fitValues[2];
325 } else {
326 LOG(error) << "coordinate " << icoord << ": Fit failed with result = " << fitres;
327 }
328 switch (icoord) {
329 case 0:
330 mvo.setX(fitValues[1]);
331 mvo.setSigmaX(fitValues[2]);
332 break;
333 case 1:
334 mvo.setY(fitValues[1]);
335 mvo.setSigmaY(fitValues[2]);
336 break;
337 case 2:
338 mvo.setZ(fitValues[1]);
339 mvo.setSigmaZ(fitValues[2]);
340 break;
341 }
342}
343
344//_____________________________________________
346{
347 // Extract results for the single slot
348 const auto& params = MeanVertexParams::Instance();
350 LOG(info) << "Finalize slot " << slot.getTFStart() << " <= TF <= " << slot.getTFEnd() << " with "
351 << c->getEntries() << " entries";
353 // fitting
354 if (!fitMeanVertex(c, mvo)) {
355 return;
356 }
357 mTmpMVobjDqTime.emplace_back(slot.getStartTimeMS(), slot.getEndTimeMS());
358 // now we add the object to the deque
359 mTmpMVobjDq.push_back(std::move(mvo));
360
361 // moving average
362 doSimpleMovingAverage(mTmpMVobjDq, mSMAMVobj);
363
364 if (mTmpMVobjDqTime.size() > params.nSlots4SMA) {
365 mTmpMVobjDqTime.pop_front();
366 }
367 long offset = (slot.getEndTimeMS() - slot.getStartTimeMS()) / 2;
368 long startValidity = (mTmpMVobjDqTime.front().getMin() + mTmpMVobjDqTime.back().getMax()) / 2 - offset;
369 LOG(info) << "start validity = " << startValidity;
370 std::map<std::string, std::string> md;
371 auto clName = o2::utils::MemFileHelper::getClassName(mSMAMVobj);
372 auto flName = o2::ccdb::CcdbApi::generateFileName(clName);
373 mInfoVector.emplace_back("GLO/Calib/MeanVertex", clName, flName, md, startValidity - 10 * o2::ccdb::CcdbObjectInfo::SECOND, startValidity + offset + 10 * o2::ccdb::CcdbObjectInfo::SECOND);
374 mMeanVertexVector.emplace_back(mSMAMVobj);
375 if (mVerbose) {
376 LOG(info) << "Printing MeanVertex Object:";
377 mSMAMVobj.print();
378 }
379
380 slot.print();
381}
382
383//_____________________________________________
384void MeanVertexCalibrator::doSimpleMovingAverage(std::deque<float>& dq, float& sma)
385{
386
387 // doing simple moving average
388 if (dq.size() <= MeanVertexParams::Instance().nSlots4SMA) {
389 sma = std::accumulate(dq.begin(), dq.end(), 0.0) / dq.size();
390 //avg = (avg * (vect.size() - 1) + vect.back()) / vect.size();
391 return;
392 }
393
394 // if the vector has size > mSMAslots, we calculate the SMA, and then we drop 1 element
395 // (note that it can have a size > mSMAslots only of 1 element!)
396 sma += (dq[dq.size() - 1] - dq[0]) / MeanVertexParams::Instance().nSlots4SMA;
397 dq.pop_front();
398
399 return;
400}
401
402//_____________________________________________
403void MeanVertexCalibrator::doSimpleMovingAverage(std::deque<MVObject>& dq, MVObject& sma)
404{
405
406 // doing simple moving average
407 const auto& params = MeanVertexParams::Instance();
408 if (dq.size() <= params.nSlots4SMA) {
409 sma.setX((sma.getX() * (dq.size() - 1) + dq.back().getX()) / dq.size());
410 sma.setY((sma.getY() * (dq.size() - 1) + dq.back().getY()) / dq.size());
411 sma.setZ((sma.getZ() * (dq.size() - 1) + dq.back().getZ()) / dq.size());
412 sma.setSigmaX((sma.getSigmaX() * (dq.size() - 1) + dq.back().getSigmaX()) / dq.size());
413 sma.setSigmaY((sma.getSigmaY() * (dq.size() - 1) + dq.back().getSigmaY()) / dq.size());
414 sma.setSigmaZ((sma.getSigmaZ() * (dq.size() - 1) + dq.back().getSigmaZ()) / dq.size());
415 sma.setSlopeX((sma.getSlopeX() * (dq.size() - 1) + dq.back().getSlopeX()) / dq.size());
416 sma.setSlopeY((sma.getSlopeY() * (dq.size() - 1) + dq.back().getSlopeY()) / dq.size());
417 if (mVerbose) {
418 LOG(info) << "Printing from simple moving average, when we have not collected enough objects yet:";
419 sma.print();
420 }
421 return;
422 }
423
424 // if the vector has size > mSMAslots, we calculate the SMA, and then we drop 1 element
425 // (note that it can have a size > mSMAslots only of 1 element!)
426 sma.setX(sma.getX() + (dq[dq.size() - 1].getX() - dq[0].getX()) / params.nSlots4SMA);
427 sma.setY(sma.getY() + (dq[dq.size() - 1].getY() - dq[0].getY()) / params.nSlots4SMA);
428 sma.setZ(sma.getZ() + (dq[dq.size() - 1].getZ() - dq[0].getZ()) / params.nSlots4SMA);
429 sma.setSigmaX(sma.getSigmaX() + (dq[dq.size() - 1].getSigmaX() - dq[0].getSigmaX()) / params.nSlots4SMA);
430 sma.setSigmaY(sma.getSigmaY() + (dq[dq.size() - 1].getSigmaY() - dq[0].getSigmaY()) / params.nSlots4SMA);
431 sma.setSigmaZ(sma.getSigmaZ() + (dq[dq.size() - 1].getSigmaZ() - dq[0].getSigmaZ()) / params.nSlots4SMA);
432 sma.setSlopeX(sma.getSlopeX() + (dq[dq.size() - 1].getSlopeX() - dq[0].getSlopeX()) / params.nSlots4SMA);
433 sma.setSlopeY(sma.getSlopeY() + (dq[dq.size() - 1].getSlopeY() - dq[0].getSlopeY()) / params.nSlots4SMA);
434
435 dq.pop_front();
436
437 if (mVerbose) {
438 LOG(info) << "Printing from simple moving average:";
439 sma.print();
440 }
441
442 return;
443}
444
445//_____________________________________________
447{
448 auto& cont = getSlots();
449 auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend);
450 slot.setContainer(std::make_unique<MeanVertexData>());
451 return slot;
452}
453
455{
456 auto minReq = MeanVertexParams::Instance().minEntries * MeanVertexParams::Instance().nPointsForSlope;
457 if (mVerbose) {
458 LOG(info) << "container * " << (void*)slot.getContainer();
459 LOG(info) << "container entries = " << slot.getContainer()->entries << ", minEntries = " << minReq;
460 }
461 return slot.getContainer()->entries >= minReq;
462}
463
464} // end namespace calibration
465} // end namespace o2
Utils and constants for calibration and related workflows.
int32_t i
#define failed(...)
Definition Utils.h:42
uint32_t c
Definition RawData.h:2
Slot & emplaceNewSlot(bool front, TFType tstart, TFType tend) final
void printVector(const std::vector< float > &vect, const HistoParams &hpar)
void fitMeanVertexCoord(int icoord, const float *array, const HistoParams &hpar, o2::dataformats::MeanVertexObject &mvo)
bool hasEnoughData(const Slot &slot) const final
bool fitMeanVertex(o2::calibration::MeanVertexData *c, o2::dataformats::MeanVertexObject &mvo)
void doSimpleMovingAverage(std::deque< float > &dq, float &sma)
HistoParams binVector(std::vector< float > &vectOut, const std::vector< float > &vectIn, o2::calibration::MeanVertexData *c, int dim)
TFType getTFEnd() const
Definition TimeSlot.h:47
long getStartTimeMS() const
Definition TimeSlot.h:50
long getEndTimeMS() const
Definition TimeSlot.h:51
const Container * getContainer() const
Definition TimeSlot.h:53
TFType getTFStart() const
Definition TimeSlot.h:46
static std::string generateFileName(const std::string &inp)
Definition CcdbApi.cxx:798
static constexpr long SECOND
GLenum array
Definition glcorearb.h:4274
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLenum const GLfloat * params
Definition glcorearb.h:272
GLintptr offset
Definition glcorearb.h:660
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLuint counter
Definition glcorearb.h:3987
Double_t fitGaus(const size_t nBins, const T *arr, const T xMin, const T xMax, std::vector< T > &param)
Definition fit.h:231
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
static std::string getClassName(const T &obj)
get the class name of the object
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
uint64_t const void const *restrict const msg
Definition x9.h:153