24#include "TMatrixDSym.h"
25#include "TDecompChol.h"
33#include "TStopwatch.h"
40#include <fairlogger/Logger.h>
53 mSmoothPol2[
VoxX] =
true;
54 mSmoothPol2[
VoxF] =
true;
58 mIsInitialized =
true;
65 LOG(info) <<
"Initialization complete";
72 LOG(error) <<
"Binning already initialized, not changing y/x binning";
77 LOGP(info,
"Empty binning provided, will use default uniform y/x binning with {} bins", mNY2XBins);
79 }
else if (
binning.size() == 1) {
82 LOGP(info,
"Setting uniform binning for y/x with {} bins",
bins - 1);
86 const int nBins =
binning.size() - 1;
87 if (fabsf(
binning[0] + 1.f) > param::sEps || fabsf(
binning[nBins] - 1.f) > param::sEps) {
88 LOG(error) <<
"Provided binning for y/x not in range -1 to 1: " <<
binning[0] <<
" - " <<
binning[nBins] <<
". Not changing y/x binning";
92 LOGP(info,
"Setting custom binning for y/x with {} bins", nBins);
94 mUniformBins[
VoxF] =
false;
97 mY2XBinsCenter.clear();
98 for (
int iBin = 0; iBin < nBins; ++iBin) {
100 mY2XBinsDI.push_back(.5f / mY2XBinsDH[iBin]);
101 mY2XBinsCenter.push_back(
binning[iBin] + mY2XBinsDH[iBin]);
102 LOGF(info,
"Bin %i: center (%.3f), half bin width (%.3f)", iBin, mY2XBinsCenter.back(), mY2XBinsDH.back());
109 if (mIsInitialized) {
110 LOG(error) <<
"Binning already initialized, not changing z/x binning";
115 LOGP(info,
"Empty binning provided, will use default uniform z/x binning with {} bins", mNZ2XBins);
117 }
else if (
binning.size() == 1) {
120 LOGP(info,
"Setting uniform binning for z/x with {} bins",
bins);
124 int nBins =
binning.size() - 1;
125 if (fabsf(
binning[0]) > param::sEps || fabsf(
binning[nBins] - 1.f) > param::sEps) {
126 LOG(error) <<
"Provided binning for z/x not in range 0 to 1: " <<
binning[0] <<
" - " <<
binning[nBins] <<
". Not changing z/x binning";
130 LOGP(info,
"Setting custom binning for z/x with {} bins", nBins);
132 mUniformBins[
VoxZ] =
false;
135 mZ2XBinsCenter.clear();
136 for (
int iBin = 0; iBin < nBins; ++iBin) {
137 mZ2XBinsDH.push_back(.5f * (
binning[iBin + 1] -
binning[iBin]) * mMaxZ2X);
138 mZ2XBinsDI.push_back(.5f / mZ2XBinsDH[iBin]);
139 mZ2XBinsCenter.push_back(
binning[iBin] * mMaxZ2X + mZ2XBinsDH[iBin]);
140 LOGF(info,
"Bin %i: center (%.3f), half bin width (%.3f)", iBin, mZ2XBinsCenter.back(), mZ2XBinsDH.back());
150 if (mNXBins > 0 && mNXBins < param::NPadRows) {
152 LOGF(info,
"X-binning is uniform with %i bins from %.2f to %.2f", mNXBins, param::MinX, param::MaxX);
153 mDXI = mNXBins / (param::MaxX - param::MinX);
155 mUniformBins[
VoxX] =
true;
158 LOGF(info,
"X-binning is per pad-row");
159 mNXBins = param::NPadRows;
160 mUniformBins[
VoxX] =
false;
161 mDX = param::RowDX[0];
166 mMaxY2X.resize(mNXBins);
167 mDY2XI.resize(mNXBins);
168 mDY2X.resize(mNXBins);
170 for (
int ix = 0; ix < mNXBins; ++ix) {
173 mDY2XI[ix] = mNY2XBins / (2.f * mMaxY2X[ix]);
174 mDY2X[ix] = 1.f / mDY2XI[ix];
176 if (mUniformBins[
VoxF]) {
177 LOGF(info,
"Y/X-binning is uniform with %i bins from -MaxY2X to +MaxY2X (values depend on X-bin)", mNY2XBins);
178 for (
int ip = 0; ip < mNY2XBins; ++ip) {
179 mY2XBinsDH.push_back(1.f / mNY2XBins);
180 mY2XBinsDI.push_back(.5f / mY2XBinsDH[ip]);
181 mY2XBinsCenter.push_back(-1.f + (ip + 0.5f) * 2.f * mY2XBinsDH[ip]);
182 LOGF(info,
"Bin %i: center (%.3f), half bin width (%.3f)", ip, mY2XBinsCenter.back(), mY2XBinsDH.back());
187 mDZ2XI = mNZ2XBins / mMaxZ2X;
188 mDZ2X = 1.0f / mDZ2XI;
189 if (mUniformBins[
VoxZ]) {
190 LOGF(info,
"Z/X-binning is uniform with %i bins from 0 to %f", mNZ2XBins, mMaxZ2X);
191 for (
int iz = 0; iz < mNZ2XBins; ++iz) {
192 mZ2XBinsDH.push_back(.5f * mDZ2X);
193 mZ2XBinsDI.push_back(mDZ2XI);
194 mZ2XBinsCenter.push_back((iz + 0.5f) * mDZ2X);
195 LOGF(info,
"Bin %i: center (%.3f), half bin width (%.3f)", iz, mZ2XBinsCenter.back(), mZ2XBinsDH.back());
199 mNVoxPerSector = mNY2XBins * mNZ2XBins * mNXBins;
200 LOGF(info,
"Each TPC sector is divided into %i voxels", mNVoxPerSector);
206 if (mInitResultsContainer.test(iSec)) {
209 mInitResultsContainer.set(iSec);
210 mVoxelResults[iSec].resize(mNVoxPerSector);
211 for (
int ix = 0; ix < mNXBins; ++ix) {
212 for (
int ip = 0; ip < mNY2XBins; ++ip) {
213 for (
int iz = 0; iz < mNZ2XBins; ++iz) {
215 VoxRes& resVox = mVoxelResults[iSec][binGlb];
223 LOG(
debug) <<
"initialized the container for the main results";
230 mXBinsIgnore[iSec].reset();
231 std::fill(mVoxelResults[iSec].
begin(), mVoxelResults[iSec].
end(),
VoxRes());
232 std::fill(mValidFracXBins[iSec].
begin(), mValidFracXBins[iSec].
end(), 0);
240 if (
x < param::RowX[param::NRowsAccumulated[0] - 1] + param::RowDX[0]) {
242 ix = (
x - (param::RowX[0] - .5f * param::RowDX[0])) / param::RowDX[0];
247 }
else if (
x >= param::RowX[param::NRowsAccumulated[param::NROCTypes - 2]] - .5f * param::RowDX[param::NROCTypes - 1]) {
249 ix = (
x - (param::RowX[param::NRowsAccumulated[param::NROCTypes - 2]] - .5f * param::RowDX[param::NROCTypes - 1])) / param::RowDX[param::NROCTypes - 1] + param::NRowsAccumulated[param::NROCTypes - 2];
250 if (ix >= param::NPadRows) {
254 }
else if (
x > param::RowX[param::NRowsAccumulated[0]] - .5f * param::RowDX[1] &&
x < param::RowX[param::NRowsAccumulated[1] - 1] + .5f * param::RowDX[1]) {
256 ix = (
x - (param::RowX[param::NRowsAccumulated[0]] - .5f * param::RowDX[1])) / param::RowDX[1] + param::NRowsAccumulated[0];
257 }
else if (
x > param::RowX[param::NRowsAccumulated[1]] - .5f * param::RowDX[2] &&
x < param::RowX[param::NRowsAccumulated[2] - 1] + .5f * param::RowDX[2]) {
259 ix = (
x - (param::RowX[param::NRowsAccumulated[1]] - .5f * param::RowDX[2])) / param::RowDX[2] + param::NRowsAccumulated[1];
270 if (fabs(
z /
x) > mMaxZ2X) {
279 if (bx < 0 || bx >= mNXBins) {
284 if (bp < 0 || bp >= mNY2XBins) {
297 mKernelType = kernel;
299 mKernelScaleEdge[
VoxX] = scX;
300 mKernelScaleEdge[
VoxF] = scP;
301 mKernelScaleEdge[
VoxZ] = scZ;
303 mKernelWInv[
VoxX] = (bwX > 0) ? 1. / bwX : 1.;
304 mKernelWInv[
VoxF] = (bwP > 0) ? 1. / bwP : 1.;
305 mKernelWInv[
VoxZ] = (bwZ > 0) ? 1. / bwZ : 1.;
309 mStepKern[
VoxX] =
static_cast<int>(nearbyint(bwX + 0.5));
310 mStepKern[
VoxF] =
static_cast<int>(nearbyint(bwP + 0.5));
311 mStepKern[
VoxZ] =
static_cast<int>(nearbyint(bwZ + 0.5));
314 mStepKern[
VoxX] =
static_cast<int>(nearbyint(bwX * 5. + 0.5));
315 mStepKern[
VoxF] =
static_cast<int>(nearbyint(bwP * 5. + 0.5));
316 mStepKern[
VoxZ] =
static_cast<int>(nearbyint(bwZ * 5. + 0.5));
318 LOG(error) <<
"given kernel type is not defined";
321 if (mStepKern[
i] < 1) {
336 std::vector<VoxRes>& secDataTmp = mVoxelResults[iSec];
337 for (
int iVox = 0; iVox < mNVoxPerSector; ++iVox) {
338 secDataTmp[iVox].stat[
VoxX] = statsIn[iVox].meanPos[
VoxX];
339 secDataTmp[iVox].stat[
VoxF] = statsIn[iVox].meanPos[
VoxF];
340 secDataTmp[iVox].stat[
VoxZ] = statsIn[iVox].meanPos[
VoxZ];
341 secDataTmp[iVox].stat[
VoxDim] = statsIn[iVox].nEntries;
348 std::vector<VoxRes>& secDataTmp = mVoxelResults[iSec];
349 for (
int iVox = 0; iVox < mNVoxPerSector; ++iVox) {
350 const auto& voxStat = mVoxStatsIn[iVox];
351 VoxRes& resVox = secDataTmp[iVox];
352 for (
int iDim =
VoxDim; iDim--;) {
353 const auto sumStat = (resVox.
stat[
VoxDim] + voxStat.nEntries);
357 double norm = 1. / sumStat;
358 resVox.
stat[iDim] = (resVox.
stat[iDim] * resVox.
stat[
VoxDim] + voxStat.meanPos[iDim] * voxStat.nEntries) * norm;
367 LOGP(info,
"Processing {} voxel residuals for sector {}", mLocalResidualsIn.size(), iSec);
370 float effT0corr = (iSec <
SECTORSPERSIDE) ? mEffT0Corr : -1. * mEffT0Corr;
371 std::vector<size_t> binData;
372 for (
const auto&
res : mLocalResidualsIn) {
376 std::vector<size_t> binIndices(binData.size());
379 std::vector<VoxRes>& secData = mVoxelResults[iSec];
382 std::vector<float> dyVec;
383 std::vector<float> dzVec;
384 std::vector<float> tgVec;
389 size_t currVoxBin = -1;
390 unsigned int nPointsInVox = 0;
391 unsigned int nProcessed = 0;
392 while (nProcessed < binData.size()) {
394 int idx = binIndices[nProcessed];
395 if (currVoxBin != binData[idx]) {
397 VoxRes& resVox = secData[currVoxBin];
400 currVoxBin = binData[idx];
406 dyVec.push_back(mLocalResidualsIn[idx].dy * param::MaxResid / 0x7fff);
407 dzVec.push_back(mLocalResidualsIn[idx].dz * param::MaxResid / 0x7fff -
408 mEffVdriftCorr * secData[currVoxBin].stat[
VoxZ] * secData[currVoxBin].stat[
VoxX] -
410 tgVec.push_back(mLocalResidualsIn[idx].tgSlp * param::MaxTgSlp / 0x7fff);
417 VoxRes& resVox = secData[currVoxBin];
420 LOG(info) <<
"extracted residuals for sector " << iSec;
423 LOG(info) <<
"number of validated X rows: " << nRowsOK;
425 LOG(warning) <<
"sector " << iSec <<
": all X-bins disabled, abandon smoothing";
437 while (nProcessed < binData.size()) {
438 int idx = binIndices[nProcessed];
439 if (currVoxBin != binData[idx]) {
441 VoxRes& resVox = secData[currVoxBin];
446 currVoxBin = binData[idx];
451 dyVec.push_back(mLocalResidualsIn[idx].dy * param::MaxResid / 0x7fff);
452 tgVec.push_back(mLocalResidualsIn[idx].tgSlp * param::MaxTgSlp / 0x7fff);
458 VoxRes& resVox = secData[currVoxBin];
464 for (
int ix = 0; ix < mNXBins; ++ix) {
468 for (
int iz = 0; iz < mNZ2XBins; ++iz) {
469 for (
int ip = 0; ip < mNY2XBins; ++ip) {
471 VoxRes& resVox = secData[voxBin];
476 LOG(info) <<
"Done processing residuals for sector " << iSec;
483 int nPoints = dy.size();
484 if (nPoints < mParams->minEntriesPerVoxel) {
490 std::array<float, 7> zResults;
492 std::vector<size_t>
indices(dz.size());
498 std::array<float, 2>
res{0.f};
499 std::array<float, 3> err{0.f};
502 LOG(
debug) <<
"failed robust linear fit, sigMAD = " << sigMAD;
505 float corrErr = err[0] * err[2];
506 corrErr = corrErr > 0 ? err[1] / std::sqrt(corrErr) : -999;
510 resVox.
D[
ResZ] = zResults[1];
511 resVox.
E[
ResX] = std::sqrt(err[2]);
512 resVox.
E[
ResY] = std::sqrt(err[0]);
513 resVox.
E[
ResZ] = zResults[4];
520 std::array<float, 7> yResults;
521 std::vector<size_t> indicesY(dy.size());
527 resVox.
D[
ResY] = yResults[1];
528 resVox.
D[
ResZ] = zResults[1];
530 resVox.
E[
ResY] = yResults[4];
531 resVox.
E[
ResZ] = zResults[4];
537 LOGF(
debug,
"D[0]=%.2f, D[1]=%.2f, D[2]=%.2f, E[0]=%.2f, E[1]=%.2f, E[2]=%.2f, EXYCorr=%.4f, dYSigMAD=%.3f, dZSigLTM=%.3f",
547 size_t nPoints = tg.size();
548 LOG(
debug) <<
"processing voxel dispersions for vox " <<
getGlbVoxBin(resVox.
bvox) <<
" with " << nPoints <<
" points";
552 for (
size_t i = nPoints;
i--;) {
556 resVox.
E[
ResD] = resVox.
D[
ResD] / sqrt(2.f * nPoints);
567 mXBinsIgnore[iSec].reset();
568 std::vector<VoxRes>& secData = mVoxelResults[iSec];
570 int cntMaskedFit = 0;
571 int cntMaskedSigma = 0;
574 for (
int ix = 0; ix < mNXBins; ++ix) {
576 for (
int ip = 0; ip < mNY2XBins; ++ip) {
577 for (
int iz = 0; iz < mNZ2XBins; ++iz) {
579 VoxRes& resVox = secData[binGlb];
607 mValidFracXBins[iSec][ix] =
static_cast<float>(cntValid) / (mNY2XBins * mNZ2XBins);
608 LOGP(
debug,
"Sector {}: xBin {} has {} % of voxels valid. Total masked due to fit: {} ,and sigma: {}",
609 iSec, ix, mValidFracXBins[iSec][ix] * 100., cntMaskedFit, cntMaskedSigma);
615 std::array<short, param::NPadRows> badStart;
616 std::array<short, param::NPadRows> badEnd;
617 bool prevBad =
false;
618 float fracBadRows = 0.f;
619 for (
int ix = 0; ix < mNXBins; ++ix) {
621 LOG(
debug) <<
"row " << ix <<
" is bad";
624 badEnd[nBadReg] = ix;
626 badStart[nBadReg] = ix;
627 badEnd[nBadReg] = ix;
640 fracBadRows /= mNXBins;
642 LOG(warning) <<
"sector " << iSec <<
": Fraction of bad X-bins: " << fracBadRows <<
" -> masking whole sector";
643 mXBinsIgnore[iSec].set();
645 for (
int iBad = 0; iBad < nBadReg; ++iBad) {
646 LOG(
debug) <<
"masking bad region " << iBad;
647 short badInReg = badEnd[iBad] - badStart[iBad] + 1;
648 short badInNextReg = iBad < (nBadReg - 1) ? badEnd[iBad] - badStart[iBad] + 1 : 0;
651 for (
int i = 0;
i < badInReg; ++
i) {
652 LOG(
debug) <<
"disabling too large patch in bad region " << iBad <<
", badStart(" << badStart[iBad] <<
"), i(" <<
i <<
")";
653 mXBinsIgnore[iSec].set(badStart[iBad] +
i);
658 for (
int i = badEnd[iBad] + 1;
i < badStart[iBad + 1]; ++
i) {
659 LOG(
debug) <<
"disabling too small good patch before bad region " << iBad + 1 <<
", badStart(" << badEnd[iBad] <<
"), badEnd(" << badStart[iBad + 1] <<
")";
660 mXBinsIgnore[iSec].set(
i);
667 for (
int i = 0;
i < badStart[0]; ++
i) {
668 LOG(
debug) <<
"disabling too small first good patch badStart(0), badEnd(" << badStart[0] <<
")";
669 mXBinsIgnore[iSec].set(
i);
672 if (mXBinsIgnore[iSec].
test(badStart[nBadReg - 1]) && (mNXBins - badEnd[nBadReg - 1] - 1) < mParams->
minGoodXBinsToCover) {
674 for (
int i = badEnd[nBadReg - 1] + 1;
i < mNXBins; ++
i) {
675 LOG(
debug) <<
"disabling too small last good patch badStart(" << badEnd[nBadReg - 1] <<
"), badEnd(" << mNXBins <<
")";
676 mXBinsIgnore[iSec].set(
i);
682 int nMaskedRows = mXBinsIgnore[iSec].count();
683 LOGP(info,
"Sector {}: out of {} voxels {} are masked. {} (low stat), {} (invalid fit) and {} (raw distrib sigma)",
684 iSec, mNVoxPerSector, cntMasked, cntLowStat, cntMaskedFit, cntMaskedSigma);
686 return mNXBins - nMaskedRows;
691 std::vector<VoxRes>& secData = mVoxelResults[iSec];
692 for (
int ix = 0; ix < mNXBins; ++ix) {
696 for (
int ip = 0; ip < mNY2XBins; ++ip) {
697 for (
int iz = 0; iz < mNZ2XBins; ++iz) {
699 VoxRes& resVox = secData[voxBin];
700 resVox.
flags &= ~SmoothDone;
703 mNSmoothingFailedBins[iSec]++;
711 for (
int ix = 0; ix < mNXBins; ++ix) {
715 for (
int ip = 0; ip < mNY2XBins; ++ip) {
716 for (
int iz = 0; iz < mNZ2XBins; ++iz) {
718 VoxRes& resVox = secData[voxBin];
734 std::array<int, VoxDim> minPointsDir{0};
735 const float kTrialStep = 0.5;
736 std::array<bool, ResDim> doDim{
false};
738 doDim[
i] = (whichDim & (0x1 <<
i)) > 0;
744 int matSize = sSmtLinDim;
747 if (mSmoothPol2[
i]) {
755 std::vector<VoxRes>& secData = mVoxelResults[iSec];
757 VoxRes& voxCenter = secData[binCenter];
758 LOG(
debug) <<
"getting smooth estimate around voxel " << binCenter;
762 std::array<std::array<double, sMaxSmtDim*(sMaxSmtDim + 1) / 2>,
ResDim> cmat;
763 int maxNeighb = 10 * 10 * 10;
764 std::vector<VoxRes*> currVox;
765 currVox.reserve(maxNeighb);
766 std::vector<float> currCache;
767 currCache.reserve(maxNeighb *
VoxHDim);
769 std::array<int, VoxDim> maxTrials;
770 maxTrials[
VoxZ] = mNZ2XBins / 2;
771 maxTrials[
VoxF] = mNY2XBins / 2;
774 std::array<int, VoxDim> trial{0};
777 std::fill(mLastSmoothingRes.begin(), mLastSmoothingRes.end(), 0);
778 memset(&cmat[0][0], 0,
sizeof(cmat));
782 float stepX = mStepKern[
VoxX] * (1. + kTrialStep * trial[
VoxX]);
783 float stepF = mStepKern[
VoxF] * (1. + kTrialStep * trial[
VoxF]);
784 float stepZ = mStepKern[
VoxZ] * (1. + kTrialStep * trial[
VoxZ]);
788 stepX += kTrialStep * mStepKern[
VoxX];
789 stepF += kTrialStep * mStepKern[
VoxF];
790 stepZ += kTrialStep * mStepKern[
VoxZ];
794 float kWXI =
getDXI(ix0) * mKernelWInv[
VoxX] * mStepKern[
VoxX] / stepX;
795 float kWFI =
getDY2XI(ix0, ip0) * mKernelWInv[
VoxF] * mStepKern[
VoxF] / stepF;
797 int iStepX =
static_cast<int>(nearbyint(stepX + 0.5));
798 int iStepF =
static_cast<int>(nearbyint(stepF + 0.5));
799 int iStepZ =
static_cast<int>(nearbyint(stepZ + 0.5));
800 int ixMin = ix0 - iStepX;
801 int ixMax = ix0 + iStepX;
804 ixMax = std::min(
static_cast<int>(nearbyint(ix0 + stepX * mKernelScaleEdge[
VoxX])), mNXBins - 1);
805 kWXI /= mKernelScaleEdge[
VoxX];
807 if (ixMax >= mNXBins) {
809 ixMin = std::max(
static_cast<int>(nearbyint(ix0 - stepX * mKernelScaleEdge[
VoxX])), 0);
810 kWXI /= mKernelScaleEdge[
VoxX];
813 int ipMin = ip0 - iStepF;
814 int ipMax = ip0 + iStepF;
817 ipMax = std::min(
static_cast<int>(nearbyint(ip0 + stepF * mKernelScaleEdge[
VoxF])), mNY2XBins - 1);
818 kWFI /= mKernelScaleEdge[
VoxF];
820 if (ipMax >= mNY2XBins) {
821 ipMax = mNY2XBins - 1;
822 ipMin = std::max(
static_cast<int>(nearbyint(ip0 - stepF * mKernelScaleEdge[
VoxF])), 0);
823 kWFI /= mKernelScaleEdge[
VoxF];
826 int izMin = iz0 - iStepZ;
827 int izMax = iz0 + iStepZ;
830 izMax = std::min(
static_cast<int>(nearbyint(iz0 + stepZ * mKernelScaleEdge[
VoxZ])), mNZ2XBins - 1);
831 kWZI /= mKernelScaleEdge[
VoxZ];
833 if (izMax >= mNZ2XBins) {
834 izMax = mNZ2XBins - 1;
835 izMin = std::max(
static_cast<int>(nearbyint(iz0 - stepZ * mKernelScaleEdge[
VoxZ])), 0);
836 kWZI /= mKernelScaleEdge[
VoxZ];
839 std::vector<unsigned short> nOccX(ixMax - ixMin + 1, 0);
840 std::vector<unsigned short> nOccF(ipMax - ipMin + 1, 0);
841 std::vector<unsigned short> nOccZ(izMax - izMin + 1, 0);
843 int nbCheck = (ixMax - ixMin + 1) * (ipMax - ipMin + 1) * (izMax - izMin + 1);
844 if (nbCheck >= maxNeighb) {
845 maxNeighb = nbCheck + 100;
846 currCache.reserve(maxNeighb *
VoxHDim);
847 currVox.reserve(maxNeighb);
849 std::array<double, 3> u2Vec;
852 for (
int ix = ixMin; ix <= ixMax; ++ix) {
853 for (
int ip = ipMin; ip <= ipMax; ++ip) {
854 for (
int iz = izMin; iz <= izMax; ++iz) {
856 VoxRes& voxNb = secData[binNb];
867 float dxw = dx * kWXI;
868 float dfw = df * kWFI;
869 float dzw = dz * kWZI;
870 u2Vec[0] = dxw * dxw;
871 u2Vec[1] = dfw * dfw;
872 u2Vec[2] = dzw * dzw;
874 if (kernelWeight < 1e-6) {
881 currVox[nbOK] = &voxNb;
892 std::array<int, VoxDim> nPoints{0};
893 for (
int i = ixMax - ixMin + 1;
i--;) {
898 for (
int i = ipMax - ipMin + 1;
i--;) {
903 for (
int i = izMax - izMin + 1;
i--;) {
908 bool enoughPoints =
true;
909 std::array<bool, VoxDim> incrDone{
false};
911 if (nPoints[
i] < minPointsDir[
i]) {
913 enoughPoints =
false;
914 if (trial[
i] < maxTrials[
i] && !incrDone[
i]) {
918 }
else if (trial[
i] == maxTrials[
i]) {
921 if (
i !=
j && trial[
j] < maxTrials[
j] && !incrDone[
j]) {
931 if (!(incrDone[
VoxX] || incrDone[
VoxF] || incrDone[
VoxZ])) {
932 LOG(error) << fmt::format(
"trial limit reached, skipping this voxel: incrDone[VoxX] {}, incrDone[VoxF] {}, incrDone[VoxZ] {}", incrDone[
VoxX], incrDone[
VoxF], incrDone[
VoxZ]);
935 LOG(
debug) <<
"sector " << iSec <<
": increasing filter bandwidth around voxel " << binCenter;
943 for (
int iNb = 0; iNb < nbOK; ++iNb) {
948 double dxi2 = dxi * dxi;
949 double dfi2 = dfi * dfi;
950 double dzi2 = dzi * dzi;
951 const VoxRes* voxNb = currVox[iNb];
952 for (
int iDim = 0; iDim <
ResDim; ++iDim) {
956 double vi = voxNb->
D[iDim];
958 if (mUseErrInSmoothing && fabs(voxNb->
E[iDim]) > 1e-6) {
960 wi /= (voxNb->
E[iDim] * voxNb->
E[iDim]);
962 std::array<double, sMaxSmtDim*(sMaxSmtDim + 1) / 2>& cmatD = cmat[iDim];
963 double* rhsD = &mLastSmoothingRes[iDim * sMaxSmtDim];
964 unsigned short iMat = 0;
965 unsigned short iRhs = 0;
968 rhsD[iRhs++] += wi * vi;
970 cmatD[iMat++] += wi * dxi;
971 cmatD[iMat++] += wi * dxi2;
972 rhsD[iRhs++] += wi * dxi * vi;
974 cmatD[iMat++] += wi * dfi;
975 cmatD[iMat++] += wi * dxi * dfi;
976 cmatD[iMat++] += wi * dfi2;
977 rhsD[iRhs++] += wi * dfi * vi;
979 cmatD[iMat++] += wi * dzi;
980 cmatD[iMat++] += wi * dxi * dzi;
981 cmatD[iMat++] += wi * dfi * dzi;
982 cmatD[iMat++] += wi * dzi2;
983 rhsD[iRhs++] += wi * dzi * vi;
986 if (mSmoothPol2[
VoxX]) {
987 cmatD[iMat++] += wi * dxi2;
988 cmatD[iMat++] += wi * dxi * dxi2;
989 cmatD[iMat++] += wi * dfi * dxi2;
990 cmatD[iMat++] += wi * dzi * dxi2;
991 cmatD[iMat++] += wi * dxi2 * dxi2;
992 rhsD[iRhs++] += wi * dxi2 * vi;
994 if (mSmoothPol2[
VoxF]) {
995 cmatD[iMat++] += wi * dfi2;
996 cmatD[iMat++] += wi * dxi * dfi2;
997 cmatD[iMat++] += wi * dfi * dfi2;
998 cmatD[iMat++] += wi * dzi * dfi2;
999 cmatD[iMat++] += wi * dxi2 * dfi2;
1000 cmatD[iMat++] += wi * dfi2 * dfi2;
1001 rhsD[iRhs++] += wi * dfi2 * vi;
1003 if (mSmoothPol2[
VoxZ]) {
1004 cmatD[iMat++] += wi * dzi2;
1005 cmatD[iMat++] += wi * dxi * dzi2;
1006 cmatD[iMat++] += wi * dfi * dzi2;
1007 cmatD[iMat++] += wi * dzi * dzi2;
1008 cmatD[iMat++] += wi * dxi2 * dzi2;
1009 cmatD[iMat++] += wi * dfi2 * dzi2;
1010 cmatD[iMat++] += wi * dzi2 * dzi2;
1011 rhsD[iRhs++] += wi * dzi2 * vi;
1020 TMatrixDSym matrix(matSize);
1021 TDecompChol chol(matSize);
1022 TVectorD rhsVec(matSize);
1023 for (
int iDim = 0; iDim <
ResDim; ++iDim) {
1028 std::array<double, sMaxSmtDim*(sMaxSmtDim + 1) / 2>& cmatD = cmat[iDim];
1029 double* rhsD = &mLastSmoothingRes[iDim * sMaxSmtDim];
1034 matrix(++
row, 0) = cmatD[++iMat];
1035 matrix(++
row, 0) = cmatD[++iMat];
1036 matrix(
row, 1) = cmatD[++iMat];
1037 matrix(0,
row) = matrix(
row, 0);
1038 matrix(++
row, 0) = cmatD[++iMat];
1039 matrix(
row, 1) = cmatD[++iMat];
1040 matrix(
row, 2) = cmatD[++iMat];
1041 matrix(0,
row) = matrix(
row, 0);
1042 matrix(1,
row) = matrix(
row, 1);
1043 matrix(++
row, 0) = cmatD[++iMat];
1044 matrix(
row, 1) = cmatD[++iMat];
1045 matrix(
row, 2) = cmatD[++iMat];
1046 matrix(
row, 3) = cmatD[++iMat];
1047 matrix(0,
row) = matrix(
row, 0);
1048 matrix(1,
row) = matrix(
row, 1);
1049 matrix(2,
row) = matrix(
row, 2);
1051 if (mSmoothPol2[
VoxX]) {
1052 const int colLim = (++
row) + 1;
1053 for (
int iCol = 0; iCol < colLim; ++iCol) {
1054 matrix(
row, iCol) = cmatD[++iMat];
1055 matrix(iCol,
row) = matrix(
row, iCol);
1058 if (mSmoothPol2[
VoxF]) {
1059 const int colLim = (++
row) + 1;
1060 for (
int iCol = 0; iCol < colLim; ++iCol) {
1061 matrix(
row, iCol) = cmatD[++iMat];
1062 matrix(iCol,
row) = matrix(
row, iCol);
1065 if (mSmoothPol2[
VoxZ]) {
1066 const int colLim = (++
row) + 1;
1067 for (
int iCol = 0; iCol < colLim; ++iCol) {
1068 matrix(
row, iCol) = cmatD[++iMat];
1069 matrix(iCol,
row) = matrix(
row, iCol);
1072 rhsVec.SetElements(rhsD);
1073 chol.SetMatrix(matrix);
1075 fitRes = chol.Solve(rhsVec);
1080 LOG(error) <<
"solution for smoothing failed, trying to increase filter bandwidth";
1083 res[iDim] = rhsVec[0];
1096 for (
size_t i = u2vec.size();
i--;) {
1100 w *= 3. / 4. * (1. - u2vec[
i]);
1104 for (
size_t i = u2vec.size();
i--;) {
1121 if (
x.size() !=
y.size()) {
1122 LOG(error) <<
"x and y must not have different sizes for fitPoly1Robust (" <<
x.size() <<
" != " <<
y.size() <<
")";
1124 size_t nPoints =
x.size();
1129 std::array<float, 7> yResults;
1130 std::vector<size_t> indY(nPoints);
1139 int nPointsUsed = std::lrint(yResults[0]);
1140 int vecOffset = std::lrint(yResults[5]);
1143 medFit(nPointsUsed, vecOffset,
x,
y,
a,
b, err);
1145 std::vector<float> ycm(nPoints);
1146 for (
size_t i = nPoints;
i-- > 0;) {
1147 ycm[
i] =
y[
i] - (
a +
b *
x[
i]);
1149 std::vector<size_t>
indices(nPoints);
1156 float sigMAD =
getMAD2Sigma({ycm.begin() + vecOffset, ycm.begin() + vecOffset + nPointsUsed});
1162 nPointsUsed = std::lrint(yResults[0]);
1163 vecOffset = std::lrint(yResults[5]);
1164 medFit(nPointsUsed, vecOffset,
x,
y,
a,
b, err);
1175 float aa,
bb, chi2 = 0.f;
1178 err[0] = err[1] = err[2] = 999.f;
1182 float sx = 0.f, sxx = 0.f, sy = 0.f, sxy = 0.f;
1189 float del = nPoints * sxx - sx * sx;
1190 float delI = 1. / del;
1191 aa = (sxx * sy - sx * sxy) * delI;
1192 bb = (nPoints * sxy - sx * sy) * delI;
1193 err[0] = sxx * delI;
1195 err[2] = nPoints * delI;
1198 float tmp =
y[
j] - (
aa +
bb *
x[
j]);
1201 float sigb = std::sqrt(chi2 * delI);
1205 float b2 =
bb + std::copysign(3.f * sigb, f1);
1207 if (fabs(f1 - f2) < sFloatEps) {
1212 while (f1 * f2 > 0.f) {
1213 bb = b2 + 1.6f * (b2 -
b1);
1220 while (fabs(b2 -
b1) > sigb) {
1221 bb =
b1 + .5f * (b2 -
b1);
1222 if (
bb ==
b1 ||
bb == b2) {
1226 if (
f * f1 >= .0f) {
1243 std::vector<float> vecTmp(nPoints);
1245 for (
int j = nPoints;
j-- > 0;) {
1248 int nPointsHalf = nPoints / 2;
1250 for (
int i = 1;
i < nPoints;
i++) {
1251 float v = vecTmp[
i];
1254 if (vecTmp[
j] >
v) {
1255 vecTmp[
j + 1] = vecTmp[
j];
1262 aa = (nPoints & 0x1) ? vecTmp[nPointsHalf] : .5f * (vecTmp[nPointsHalf - 1] + vecTmp[nPointsHalf]);
1264 std::vector<float>::iterator nth = vecTmp.begin() + vecTmp.size() / 2;
1265 if (nPoints & 0x1) {
1266 std::nth_element(vecTmp.begin(), nth, vecTmp.end());
1269 std::nth_element(vecTmp.begin(), nth - 1, vecTmp.end());
1270 std::nth_element(nth, nth, vecTmp.end());
1271 aa = 0.5 * (*(nth - 1) + *(nth));
1275 for (
int j = nPoints;
j-- > 0;) {
1280 if (fabs(d) > sFloatEps) {
1308 mid = (l +
ir) >> 1;
1357 int nPoints =
data.size();
1364 std::vector<float>::iterator nth =
data.begin() +
data.size() / 2;
1365 if (nPoints & 0x1) {
1366 std::nth_element(
data.begin(), nth,
data.end());
1367 medianOfData = *nth;
1369 std::nth_element(
data.begin(), nth - 1,
data.end());
1370 std::nth_element(nth, nth,
data.end());
1371 medianOfData = .5f * (*(nth - 1) + (*nth));
1380 float medianOfAbsDeviations;
1381 if (nPoints & 0x1) {
1382 std::nth_element(
data.begin(), nth,
data.end());
1383 medianOfAbsDeviations = *nth;
1385 std::nth_element(
data.begin(), nth - 1,
data.end());
1386 std::nth_element(nth, nth,
data.end());
1387 medianOfAbsDeviations = .5f * (*(nth - 1) + (*nth));
1391 return k * medianOfAbsDeviations;
1394void TrackResiduals::fitCircle(
int nCl, std::array<float, param::NPadRows>&
x, std::array<float, param::NPadRows>&
y,
float& xc,
float& yc,
float&
r, std::array<float, param::NPadRows>& residHelixY)
1401 for (
int i = nCl;
i--;) {
1408 float su2 = 0.f, sv2 = 0.f, suv = 0.f, su3 = 0.f, sv3 = 0.f, su2v = 0.f, suv2 = 0.f;
1409 for (
int i = nCl;
i--;) {
1410 float ui =
x[
i] - xMean;
1411 float vi =
y[
i] - yMean;
1412 float ui2 = ui * ui;
1413 float vi2 = vi * vi;
1422 float rhsU = .5f * (su3 + suv2);
1423 float rhsV = .5f * (sv3 + su2v);
1424 float det = su2 * sv2 - suv * suv;
1425 float uc = (rhsU * sv2 - rhsV * suv) / det;
1426 float vc = (su2 * rhsV - suv * rhsU) / det;
1427 float r2 = uc * uc + vc * vc + (su2 + sv2) / nCl;
1432 for (
int i = nCl;
i--;) {
1433 float dx =
x[
i] - xc;
1434 float dxr = r2 - dx * dx;
1435 float ys = dxr > 0 ? sqrt(dxr) : 0.f;
1436 float dy =
y[
i] - yc;
1437 float dysp = dy - ys;
1438 float dysm = dy + ys;
1439 residHelixY[
i] = fabsf(dysp) < fabsf(dysm) ? dysp : dysm;
1454 float sumX = 0.f, sumY = 0.f, sumXY = 0.f, sumX2 = 0.f, nInv = 1.f / nCl;
1455 for (
int i = nCl;
i--;) {
1458 sumXY +=
x[
i] *
y[
i];
1459 sumX2 +=
x[
i] *
x[
i];
1461 float det = sumX2 - nInv * sumX * sumX;
1462 if (fabsf(det) < 1e-12f) {
1465 res[0] = (sumXY - nInv * sumX * sumY) / det;
1466 res[1] = nInv * sumY - nInv *
res[0] * sumX;
1479 LOG(warn) <<
"For the tree aliases to work you must initialize the binning before calling createOutputFile()";
1481 mFileOut = std::make_unique<TFile>(
filename,
"recreate");
1482 mTreeOut = std::make_unique<TTree>(
"voxResTree",
"Voxel results and statistics");
1483 mTreeOut->SetAlias(
"z2xBin",
"bvox[0]");
1484 mTreeOut->SetAlias(
"y2xBin",
"bvox[1]");
1485 mTreeOut->SetAlias(
"xBin",
"bvox[2]");
1486 mTreeOut->SetAlias(
"z2xAV",
"stat[0]");
1487 mTreeOut->SetAlias(
"y2xAV",
"stat[1]");
1488 mTreeOut->SetAlias(
"xAV",
"stat[2]");
1489 mTreeOut->SetAlias(
"fsector",
"bsec+0.5+9.*(y2xAV)/pi");
1490 mTreeOut->SetAlias(
"phi",
"(bsec%18+0.5+9.*(stat[1])/pi)/9*pi");
1491 mTreeOut->SetAlias(
"r",
"stat[2]");
1492 mTreeOut->SetAlias(
"z",
"z2xAV*xAV");
1493 mTreeOut->SetAlias(
"dX",
"D[0]");
1494 mTreeOut->SetAlias(
"dY",
"D[1]");
1495 mTreeOut->SetAlias(
"dZ",
"D[2]");
1496 mTreeOut->SetAlias(
"dXS",
"DS[0]");
1497 mTreeOut->SetAlias(
"dYS",
"DS[1]");
1498 mTreeOut->SetAlias(
"dZS",
"DS[2]");
1499 mTreeOut->SetAlias(
"dXE",
"E[0]");
1500 mTreeOut->SetAlias(
"dYE",
"E[1]");
1501 mTreeOut->SetAlias(
"dZE",
"E[2]");
1503 mTreeOut->SetAlias(
"entries",
"stat[3]");
1504 mTreeOut->SetAlias(
"fitOK", Form(
"(flags & %u) == %u",
DistDone,
DistDone));
1505 mTreeOut->SetAlias(
"dispOK", Form(
"(flags & %u) == %u",
DispDone,
DispDone));
1507 mTreeOut->SetAlias(
"masked", Form(
"(flags & %u) == %u",
Masked,
Masked));
1508 mTreeOut->Branch(
"voxRes", &mVoxelResultsOutPtr);
1523 printf(
"Dumping results for sector %i. Don't forget the call to closeOutputFile() in the end...\n", iSec);
1524 for (
int i = 0;
i < mNVoxPerSector; ++
i) {
1525 mVoxelResultsOut = mVoxelResults[iSec][
i];
1533 static float mres = 0, mvir = 0, mres0 = 0, mvir0 = 0;
1534 static ProcInfo_t procInfo;
1535 static TStopwatch
sw;
1536 const Long_t kMB = 1024;
1537 gSystem->GetProcInfo(&procInfo);
1538 mres = float(procInfo.fMemResident) / kMB;
1539 mvir = float(procInfo.fMemVirtual) / kMB;
1541 printf(
"RSS: %.3f(%.3f) VMEM: %.3f(%.3f) MB | CpuTime:%.3f RealTime:%.3f s\n",
1542 mres, mres - mres0, mvir, mvir - mvir0,
sw.CpuTime(),
sw.RealTime());
1551 mInitResultsContainer.reset();
const GPUTPCGMMerger::trackCluster & b1
Definition of the TrackResiduals class.
static const SpacePointsCalibConfParam & Instance()
std::vector< LocalResid > & getLocalResVec()
float getDZ2XI(int iz=0) const
void setKernelType(KernelType kernel=KernelType::Epanechnikov, float bwX=2.1f, float bwP=2.1f, float bwZ=1.7f, float scX=1.f, float scP=1.f, float scZ=1.f)
bool getSmoothEstimate(int iSec, float x, float p, float z, std::array< float, ResDim > &res, int whichDim=0)
int getXBinExact(float x) const
void setY2XBinning(const std::vector< float > &binning)
@ DispDone
voxel dispersions have been processed
@ DistDone
voxel residuals have been processed
@ SmoothDone
voxel has been smoothed
void dumpResults(int iSec)
void processSectorResiduals(Int_t iSec)
static bool fitPoly1(int nCl, std::array< float, param::NPadRows > &x, std::array< float, param::NPadRows > &y, std::array< float, 2 > &res)
size_t getGlbVoxBin(int ix, int ip, int iz) const
void setStats(const std::vector< TrackResiduals::VoxStats > &statsIn, int iSec)
Set the voxel statistics directly from outside.
void closeOutputFile()
Closes the file with the debug output.
void clear()
clear member to be able to process new sector or new input files
void fillStats(int iSec)
Fill statistics from TTree.
void printMem() const
Prints the current memory usage.
void setZ2XBinning(const std::vector< float > &binning)
void initResultsContainer(int iSec)
int getNVoxelsPerSector() const
Get the total number of voxels per TPC sector (mNXBins * mNY2XBins * mNZ2XBins)
int getRowID(float x) const
void createOutputFile(const char *filename="debugVoxRes.root")
Creates a file for the debug output.
float getDY2XI(int ix, int iy=0) const
void findVoxel(float x, float y2x, float z2x, int &ix, int &ip, int &iz) const
float roFunc(int nPoints, int offset, const std::vector< float > &x, const std::vector< float > &y, float b, float &aa) const
void medFit(int nPoints, int offset, const std::vector< float > &x, const std::vector< float > &y, float &a, float &b, std::array< float, 3 > &err) const
static void fitCircle(int nCl, std::array< float, param::NPadRows > &x, std::array< float, param::NPadRows > &y, float &xc, float &yc, float &r, std::array< float, param::NPadRows > &residHelixY)
float getDXI(int ix) const
float fitPoly1Robust(std::vector< float > &x, std::vector< float > &y, std::array< float, 2 > &res, std::array< float, 3 > &err, float cutLTM) const
int getY2XBinExact(float y2x, int ix) const
bool findVoxelBin(int secID, float x, float y, float z, std::array< unsigned char, VoxDim > &bvox) const
Calculates the bin indices for given x, y, z in sector coordinates.
bool getXBinIgnored(int iSec, int bin) const
void initBinning()
Initializes the binning in X, Y/X and Z.
float getMAD2Sigma(std::vector< float > data) const
void reset()
Resets all (also intermediate) results.
int getZ2XBinExact(float z2x) const
double getKernelWeight(std::array< double, 3 > u2vec) const
void processVoxelDispersions(std::vector< float > &tg, std::vector< float > &dy, VoxRes &resVox)
void init(bool doBinning=true)
@ VoxDim
dimensionality of the voxels
@ ResD
index for dispersions
float selectKthMin(const int k, std::vector< float > &data) const
void setNY2XBins(int nBins)
void setNZ2XBins(int nBins)
int validateVoxels(int iSec)
void processVoxelResiduals(std::vector< float > &dy, std::vector< float > &dz, std::vector< float > &tg, VoxRes &resVox)
GLboolean GLboolean GLboolean b
GLsizei GLenum const void * indices
GLboolean GLboolean GLboolean GLboolean a
GLubyte GLubyte GLubyte GLubyte w
GLdouble GLdouble GLdouble z
void Reorder(std::vector< T > &data, const std::vector< size_t > &index)
bool LTMUnbinnedSig(const std::vector< T > &data, std::vector< size_t > &index, std::array< float, 7 > ¶ms, float fracKeepMin, float sigTgt, bool sorted=false)
void SortData(std::vector< T > const &values, std::vector< size_t > &index)
bool LTMUnbinned(const std::vector< T > &data, std::vector< size_t > &index, std::array< float, 7 > ¶ms, float fracKeep)
Global TPC definitions and constants.
constexpr double SECPHIWIDTH
constexpr unsigned char SECTORSPERSIDE
Enum< T >::Iterator begin(Enum< T >)
constexpr unsigned char SIDES
DataT sum(const Vector< DataT, N > &a)
FIXME: do not use data model tables.
float minFracLTM
minimum fraction of points to keep when trimming data to fit expected sigma
float maxFitErrX2
maximum fit error for X2
float minValidVoxFracDrift
if more than this fraction of bins are bad for one pad row the whole pad row is declared bad
float maxGaussStdDev
maximum number of sigmas to be considered for gaussian kernel smoothing
int minEntriesPerVoxel
minimum number of points in voxel for processing
float LTMCut
fraction op points to keep when trimming input data
int maxBadXBinsToCover
a lower number of consecutive bad X bins will not be declared bad
float maxFitErrY2
maximum fit error for Y2
float maxSigY
maximum sigma for y of the voxel
float maxFitCorrXY
maximum fit correlation for x and y
float maxSigZ
maximum sigma for z of the voxel
int minGoodXBinsToCover
minimum number of consecutive good bins, otherwise bins are declared bad
float maxFracBadRowsPerSector
maximum fraction of bad rows before whole sector is masked
bool isBfieldZero
for B=0 we set the radial distortions to zero and don't fit dy vs tgSlp
Structure which gets filled with the results for each voxel.
std::array< unsigned char, VoxDim > bvox
voxel identifier: VoxZ, VoxF, VoxX
std::array< float, ResDim > E
their errors
float dYSigMAD
MAD estimator of dY sigma (dispersion after slope removal)
std::array< float, ResDim > D
values of extracted distortions
float dZSigLTM
Z sigma from unbinned LTM estimator.
unsigned char flags
status flag
std::array< float, ResDim > DS
smoothed residual
unsigned char bsec
sector ID (0-35)
float EXYCorr
correlation between extracted X and Y
std::array< float, VoxHDim > stat
statistics: averages of each voxel dimension + entries
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)