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];
724 if (mDoAdhocCorrectionZ2X) {
733 if (mAdhocScalingX[iSec >= 18] != 0) {
734 const float aDX = resVox.
DS[
ResX] * mAdhocScalingX[iSec >= 18];
735 resVox.
D[
ResX] += aDX;
739 resVox.
D[
ResZ] += aDX * z2x;
740 resVox.
DS[
ResZ] += aDX * z2x;
752 std::array<int, VoxDim> minPointsDir{0};
753 const float kTrialStep = 0.5;
754 std::array<bool, ResDim> doDim{
false};
756 doDim[
i] = (whichDim & (0x1 <<
i)) > 0;
762 int matSize = sSmtLinDim;
765 if (mSmoothPol2[
i]) {
773 std::vector<VoxRes>& secData = mVoxelResults[iSec];
775 VoxRes& voxCenter = secData[binCenter];
776 LOG(
debug) <<
"getting smooth estimate around voxel " << binCenter;
780 std::array<std::array<double, sMaxSmtDim*(sMaxSmtDim + 1) / 2>,
ResDim> cmat;
781 int maxNeighb = 10 * 10 * 10;
782 std::vector<VoxRes*> currVox;
783 currVox.reserve(maxNeighb);
784 std::vector<float> currCache;
785 currCache.reserve(maxNeighb *
VoxHDim);
787 std::array<int, VoxDim> maxTrials;
788 maxTrials[
VoxZ] = mNZ2XBins / 2;
789 maxTrials[
VoxF] = mNY2XBins / 2;
792 std::array<int, VoxDim> trial{0};
795 std::fill(mLastSmoothingRes.begin(), mLastSmoothingRes.end(), 0);
796 memset(&cmat[0][0], 0,
sizeof(cmat));
800 float stepX = mStepKern[
VoxX] * (1. + kTrialStep * trial[
VoxX]);
801 float stepF = mStepKern[
VoxF] * (1. + kTrialStep * trial[
VoxF]);
802 float stepZ = mStepKern[
VoxZ] * (1. + kTrialStep * trial[
VoxZ]);
806 stepX += kTrialStep * mStepKern[
VoxX];
807 stepF += kTrialStep * mStepKern[
VoxF];
808 stepZ += kTrialStep * mStepKern[
VoxZ];
812 float kWXI =
getDXI(ix0) * mKernelWInv[
VoxX] * mStepKern[
VoxX] / stepX;
813 float kWFI =
getDY2XI(ix0, ip0) * mKernelWInv[
VoxF] * mStepKern[
VoxF] / stepF;
815 int iStepX =
static_cast<int>(nearbyint(stepX + 0.5));
816 int iStepF =
static_cast<int>(nearbyint(stepF + 0.5));
817 int iStepZ =
static_cast<int>(nearbyint(stepZ + 0.5));
818 int ixMin = ix0 - iStepX;
819 int ixMax = ix0 + iStepX;
822 ixMax = std::min(
static_cast<int>(nearbyint(ix0 + stepX * mKernelScaleEdge[
VoxX])), mNXBins - 1);
823 kWXI /= mKernelScaleEdge[
VoxX];
825 if (ixMax >= mNXBins) {
827 ixMin = std::max(
static_cast<int>(nearbyint(ix0 - stepX * mKernelScaleEdge[
VoxX])), 0);
828 kWXI /= mKernelScaleEdge[
VoxX];
831 int ipMin = ip0 - iStepF;
832 int ipMax = ip0 + iStepF;
835 ipMax = std::min(
static_cast<int>(nearbyint(ip0 + stepF * mKernelScaleEdge[
VoxF])), mNY2XBins - 1);
836 kWFI /= mKernelScaleEdge[
VoxF];
838 if (ipMax >= mNY2XBins) {
839 ipMax = mNY2XBins - 1;
840 ipMin = std::max(
static_cast<int>(nearbyint(ip0 - stepF * mKernelScaleEdge[
VoxF])), 0);
841 kWFI /= mKernelScaleEdge[
VoxF];
844 int izMin = iz0 - iStepZ;
845 int izMax = iz0 + iStepZ;
848 izMax = std::min(
static_cast<int>(nearbyint(iz0 + stepZ * mKernelScaleEdge[
VoxZ])), mNZ2XBins - 1);
849 kWZI /= mKernelScaleEdge[
VoxZ];
851 if (izMax >= mNZ2XBins) {
852 izMax = mNZ2XBins - 1;
853 izMin = std::max(
static_cast<int>(nearbyint(iz0 - stepZ * mKernelScaleEdge[
VoxZ])), 0);
854 kWZI /= mKernelScaleEdge[
VoxZ];
857 std::vector<unsigned short> nOccX(ixMax - ixMin + 1, 0);
858 std::vector<unsigned short> nOccF(ipMax - ipMin + 1, 0);
859 std::vector<unsigned short> nOccZ(izMax - izMin + 1, 0);
861 int nbCheck = (ixMax - ixMin + 1) * (ipMax - ipMin + 1) * (izMax - izMin + 1);
862 if (nbCheck >= maxNeighb) {
863 maxNeighb = nbCheck + 100;
864 currCache.reserve(maxNeighb *
VoxHDim);
865 currVox.reserve(maxNeighb);
867 std::array<double, 3> u2Vec;
870 for (
int ix = ixMin; ix <= ixMax; ++ix) {
871 for (
int ip = ipMin; ip <= ipMax; ++ip) {
872 for (
int iz = izMin; iz <= izMax; ++iz) {
874 VoxRes& voxNb = secData[binNb];
885 float dxw = dx * kWXI;
886 float dfw = df * kWFI;
887 float dzw = dz * kWZI;
888 u2Vec[0] = dxw * dxw;
889 u2Vec[1] = dfw * dfw;
890 u2Vec[2] = dzw * dzw;
892 if (kernelWeight < 1e-6) {
899 currVox[nbOK] = &voxNb;
910 std::array<int, VoxDim> nPoints{0};
911 for (
int i = ixMax - ixMin + 1;
i--;) {
916 for (
int i = ipMax - ipMin + 1;
i--;) {
921 for (
int i = izMax - izMin + 1;
i--;) {
926 bool enoughPoints =
true;
927 std::array<bool, VoxDim> incrDone{
false};
929 if (nPoints[
i] < minPointsDir[
i]) {
931 enoughPoints =
false;
932 if (trial[
i] < maxTrials[
i] && !incrDone[
i]) {
936 }
else if (trial[
i] == maxTrials[
i]) {
939 if (
i !=
j && trial[
j] < maxTrials[
j] && !incrDone[
j]) {
949 if (!(incrDone[
VoxX] || incrDone[
VoxF] || incrDone[
VoxZ])) {
950 LOG(error) << fmt::format(
"trial limit reached, skipping this voxel: incrDone[VoxX] {}, incrDone[VoxF] {}, incrDone[VoxZ] {}", incrDone[
VoxX], incrDone[
VoxF], incrDone[
VoxZ]);
953 LOG(
debug) <<
"sector " << iSec <<
": increasing filter bandwidth around voxel " << binCenter;
961 for (
int iNb = 0; iNb < nbOK; ++iNb) {
966 double dxi2 = dxi * dxi;
967 double dfi2 = dfi * dfi;
968 double dzi2 = dzi * dzi;
969 const VoxRes* voxNb = currVox[iNb];
970 for (
int iDim = 0; iDim <
ResDim; ++iDim) {
974 double vi = voxNb->
D[iDim];
976 if (mUseErrInSmoothing && fabs(voxNb->
E[iDim]) > 1e-6) {
978 wi /= (voxNb->
E[iDim] * voxNb->
E[iDim]);
980 std::array<double, sMaxSmtDim*(sMaxSmtDim + 1) / 2>& cmatD = cmat[iDim];
981 double* rhsD = &mLastSmoothingRes[iDim * sMaxSmtDim];
982 unsigned short iMat = 0;
983 unsigned short iRhs = 0;
986 rhsD[iRhs++] += wi * vi;
988 cmatD[iMat++] += wi * dxi;
989 cmatD[iMat++] += wi * dxi2;
990 rhsD[iRhs++] += wi * dxi * vi;
992 cmatD[iMat++] += wi * dfi;
993 cmatD[iMat++] += wi * dxi * dfi;
994 cmatD[iMat++] += wi * dfi2;
995 rhsD[iRhs++] += wi * dfi * vi;
997 cmatD[iMat++] += wi * dzi;
998 cmatD[iMat++] += wi * dxi * dzi;
999 cmatD[iMat++] += wi * dfi * dzi;
1000 cmatD[iMat++] += wi * dzi2;
1001 rhsD[iRhs++] += wi * dzi * vi;
1004 if (mSmoothPol2[
VoxX]) {
1005 cmatD[iMat++] += wi * dxi2;
1006 cmatD[iMat++] += wi * dxi * dxi2;
1007 cmatD[iMat++] += wi * dfi * dxi2;
1008 cmatD[iMat++] += wi * dzi * dxi2;
1009 cmatD[iMat++] += wi * dxi2 * dxi2;
1010 rhsD[iRhs++] += wi * dxi2 * vi;
1012 if (mSmoothPol2[
VoxF]) {
1013 cmatD[iMat++] += wi * dfi2;
1014 cmatD[iMat++] += wi * dxi * dfi2;
1015 cmatD[iMat++] += wi * dfi * dfi2;
1016 cmatD[iMat++] += wi * dzi * dfi2;
1017 cmatD[iMat++] += wi * dxi2 * dfi2;
1018 cmatD[iMat++] += wi * dfi2 * dfi2;
1019 rhsD[iRhs++] += wi * dfi2 * vi;
1021 if (mSmoothPol2[
VoxZ]) {
1022 cmatD[iMat++] += wi * dzi2;
1023 cmatD[iMat++] += wi * dxi * dzi2;
1024 cmatD[iMat++] += wi * dfi * dzi2;
1025 cmatD[iMat++] += wi * dzi * dzi2;
1026 cmatD[iMat++] += wi * dxi2 * dzi2;
1027 cmatD[iMat++] += wi * dfi2 * dzi2;
1028 cmatD[iMat++] += wi * dzi2 * dzi2;
1029 rhsD[iRhs++] += wi * dzi2 * vi;
1038 TMatrixDSym matrix(matSize);
1039 TDecompChol chol(matSize);
1040 TVectorD rhsVec(matSize);
1041 for (
int iDim = 0; iDim <
ResDim; ++iDim) {
1046 std::array<double, sMaxSmtDim*(sMaxSmtDim + 1) / 2>& cmatD = cmat[iDim];
1047 double* rhsD = &mLastSmoothingRes[iDim * sMaxSmtDim];
1052 matrix(++
row, 0) = cmatD[++iMat];
1053 matrix(++
row, 0) = cmatD[++iMat];
1054 matrix(
row, 1) = cmatD[++iMat];
1055 matrix(0,
row) = matrix(
row, 0);
1056 matrix(++
row, 0) = cmatD[++iMat];
1057 matrix(
row, 1) = cmatD[++iMat];
1058 matrix(
row, 2) = cmatD[++iMat];
1059 matrix(0,
row) = matrix(
row, 0);
1060 matrix(1,
row) = matrix(
row, 1);
1061 matrix(++
row, 0) = cmatD[++iMat];
1062 matrix(
row, 1) = cmatD[++iMat];
1063 matrix(
row, 2) = cmatD[++iMat];
1064 matrix(
row, 3) = cmatD[++iMat];
1065 matrix(0,
row) = matrix(
row, 0);
1066 matrix(1,
row) = matrix(
row, 1);
1067 matrix(2,
row) = matrix(
row, 2);
1069 if (mSmoothPol2[
VoxX]) {
1070 const int colLim = (++
row) + 1;
1071 for (
int iCol = 0; iCol < colLim; ++iCol) {
1072 matrix(
row, iCol) = cmatD[++iMat];
1073 matrix(iCol,
row) = matrix(
row, iCol);
1076 if (mSmoothPol2[
VoxF]) {
1077 const int colLim = (++
row) + 1;
1078 for (
int iCol = 0; iCol < colLim; ++iCol) {
1079 matrix(
row, iCol) = cmatD[++iMat];
1080 matrix(iCol,
row) = matrix(
row, iCol);
1083 if (mSmoothPol2[
VoxZ]) {
1084 const int colLim = (++
row) + 1;
1085 for (
int iCol = 0; iCol < colLim; ++iCol) {
1086 matrix(
row, iCol) = cmatD[++iMat];
1087 matrix(iCol,
row) = matrix(
row, iCol);
1090 rhsVec.SetElements(rhsD);
1091 chol.SetMatrix(matrix);
1093 fitRes = chol.Solve(rhsVec);
1098 LOG(error) <<
"solution for smoothing failed, trying to increase filter bandwidth";
1101 res[iDim] = rhsVec[0];
1114 for (
size_t i = u2vec.size();
i--;) {
1118 w *= 3. / 4. * (1. - u2vec[
i]);
1122 for (
size_t i = u2vec.size();
i--;) {
1139 if (
x.size() !=
y.size()) {
1140 LOG(error) <<
"x and y must not have different sizes for fitPoly1Robust (" <<
x.size() <<
" != " <<
y.size() <<
")";
1142 size_t nPoints =
x.size();
1147 std::array<float, 7> yResults;
1148 std::vector<size_t> indY(nPoints);
1157 int nPointsUsed = std::lrint(yResults[0]);
1158 int vecOffset = std::lrint(yResults[5]);
1161 medFit(nPointsUsed, vecOffset,
x,
y,
a,
b, err);
1163 std::vector<float> ycm(nPoints);
1164 for (
size_t i = nPoints;
i-- > 0;) {
1165 ycm[
i] =
y[
i] - (
a +
b *
x[
i]);
1167 std::vector<size_t>
indices(nPoints);
1174 float sigMAD =
getMAD2Sigma({ycm.begin() + vecOffset, ycm.begin() + vecOffset + nPointsUsed});
1180 nPointsUsed = std::lrint(yResults[0]);
1181 vecOffset = std::lrint(yResults[5]);
1182 medFit(nPointsUsed, vecOffset,
x,
y,
a,
b, err);
1193 float aa,
bb, chi2 = 0.f;
1196 err[0] = err[1] = err[2] = 999.f;
1200 float sx = 0.f, sxx = 0.f, sy = 0.f, sxy = 0.f;
1207 float del = nPoints * sxx - sx * sx;
1208 float delI = 1. / del;
1209 aa = (sxx * sy - sx * sxy) * delI;
1210 bb = (nPoints * sxy - sx * sy) * delI;
1211 err[0] = sxx * delI;
1213 err[2] = nPoints * delI;
1216 float tmp =
y[
j] - (aa +
bb *
x[
j]);
1219 float sigb = std::sqrt(chi2 * delI);
1223 float b2 =
bb + std::copysign(3.f * sigb, f1);
1225 if (fabs(f1 - f2) < sFloatEps) {
1230 while (f1 * f2 > 0.f) {
1231 bb = b2 + 1.6f * (b2 - b1);
1238 while (fabs(b2 - b1) > sigb) {
1239 bb = b1 + .5f * (b2 - b1);
1240 if (
bb == b1 ||
bb == b2) {
1244 if (
f * f1 >= .0f) {
1261 std::vector<float> vecTmp(nPoints);
1263 for (
int j = nPoints;
j-- > 0;) {
1266 int nPointsHalf = nPoints / 2;
1268 for (
int i = 1;
i < nPoints;
i++) {
1269 float v = vecTmp[
i];
1272 if (vecTmp[
j] >
v) {
1273 vecTmp[
j + 1] = vecTmp[
j];
1280 aa = (nPoints & 0x1) ? vecTmp[nPointsHalf] : .5f * (vecTmp[nPointsHalf - 1] + vecTmp[nPointsHalf]);
1282 std::vector<float>::iterator nth = vecTmp.begin() + vecTmp.size() / 2;
1283 if (nPoints & 0x1) {
1284 std::nth_element(vecTmp.begin(), nth, vecTmp.end());
1287 std::nth_element(vecTmp.begin(), nth - 1, vecTmp.end());
1288 std::nth_element(nth, nth, vecTmp.end());
1289 aa = 0.5 * (*(nth - 1) + *(nth));
1293 for (
int j = nPoints;
j-- > 0;) {
1298 if (fabs(d) > sFloatEps) {
1326 mid = (l +
ir) >> 1;
1375 int nPoints =
data.size();
1382 std::vector<float>::iterator nth =
data.begin() +
data.size() / 2;
1383 if (nPoints & 0x1) {
1384 std::nth_element(
data.begin(), nth,
data.end());
1385 medianOfData = *nth;
1387 std::nth_element(
data.begin(), nth - 1,
data.end());
1388 std::nth_element(nth, nth,
data.end());
1389 medianOfData = .5f * (*(nth - 1) + (*nth));
1398 float medianOfAbsDeviations;
1399 if (nPoints & 0x1) {
1400 std::nth_element(
data.begin(), nth,
data.end());
1401 medianOfAbsDeviations = *nth;
1403 std::nth_element(
data.begin(), nth - 1,
data.end());
1404 std::nth_element(nth, nth,
data.end());
1405 medianOfAbsDeviations = .5f * (*(nth - 1) + (*nth));
1409 return k * medianOfAbsDeviations;
1412void 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)
1419 for (
int i = nCl;
i--;) {
1426 float su2 = 0.f, sv2 = 0.f, suv = 0.f, su3 = 0.f, sv3 = 0.f, su2v = 0.f, suv2 = 0.f;
1427 for (
int i = nCl;
i--;) {
1428 float ui =
x[
i] - xMean;
1429 float vi =
y[
i] - yMean;
1430 float ui2 = ui * ui;
1431 float vi2 = vi * vi;
1440 float rhsU = .5f * (su3 + suv2);
1441 float rhsV = .5f * (sv3 + su2v);
1442 float det = su2 * sv2 - suv * suv;
1443 float uc = (rhsU * sv2 - rhsV * suv) / det;
1444 float vc = (su2 * rhsV - suv * rhsU) / det;
1445 float r2 = uc * uc + vc * vc + (su2 + sv2) / nCl;
1450 for (
int i = nCl;
i--;) {
1451 float dx =
x[
i] - xc;
1452 float dxr = r2 - dx * dx;
1453 float ys = dxr > 0 ? sqrt(dxr) : 0.f;
1454 float dy =
y[
i] - yc;
1455 float dysp = dy - ys;
1456 float dysm = dy + ys;
1457 residHelixY[
i] = fabsf(dysp) < fabsf(dysm) ? dysp : dysm;
1472 float sumX = 0.f, sumY = 0.f, sumXY = 0.f, sumX2 = 0.f, nInv = 1.f / nCl;
1473 for (
int i = nCl;
i--;) {
1476 sumXY +=
x[
i] *
y[
i];
1477 sumX2 +=
x[
i] *
x[
i];
1479 float det = sumX2 - nInv * sumX * sumX;
1480 if (fabsf(det) < 1e-12f) {
1483 res[0] = (sumXY - nInv * sumX * sumY) / det;
1484 res[1] = nInv * sumY - nInv *
res[0] * sumX;
1497 LOG(warn) <<
"For the tree aliases to work you must initialize the binning before calling createOutputFile()";
1499 mFileOut = std::make_unique<TFile>(
filename,
"recreate");
1500 mTreeOut = std::make_unique<TTree>(
"voxResTree",
"Voxel results and statistics");
1501 mTreeOut->SetAlias(
"z2xBin",
"bvox[0]");
1502 mTreeOut->SetAlias(
"y2xBin",
"bvox[1]");
1503 mTreeOut->SetAlias(
"xBin",
"bvox[2]");
1504 mTreeOut->SetAlias(
"z2xAV",
"stat[0]");
1505 mTreeOut->SetAlias(
"y2xAV",
"stat[1]");
1506 mTreeOut->SetAlias(
"xAV",
"stat[2]");
1507 mTreeOut->SetAlias(
"fsector",
"bsec+0.5+9.*(y2xAV)/pi");
1508 mTreeOut->SetAlias(
"phi",
"(bsec%18+0.5+9.*(stat[1])/pi)/9*pi");
1509 mTreeOut->SetAlias(
"r",
"stat[2]");
1510 mTreeOut->SetAlias(
"z",
"z2xAV*xAV");
1511 mTreeOut->SetAlias(
"dX",
"D[0]");
1512 mTreeOut->SetAlias(
"dY",
"D[1]");
1513 mTreeOut->SetAlias(
"dZ",
"D[2]");
1514 mTreeOut->SetAlias(
"dXS",
"DS[0]");
1515 mTreeOut->SetAlias(
"dYS",
"DS[1]");
1516 mTreeOut->SetAlias(
"dZS",
"DS[2]");
1517 mTreeOut->SetAlias(
"dXE",
"E[0]");
1518 mTreeOut->SetAlias(
"dYE",
"E[1]");
1519 mTreeOut->SetAlias(
"dZE",
"E[2]");
1521 mTreeOut->SetAlias(
"entries",
"stat[3]");
1522 mTreeOut->SetAlias(
"fitOK", Form(
"(flags & %u) == %u",
DistDone,
DistDone));
1523 mTreeOut->SetAlias(
"dispOK", Form(
"(flags & %u) == %u",
DispDone,
DispDone));
1525 mTreeOut->SetAlias(
"masked", Form(
"(flags & %u) == %u",
Masked,
Masked));
1526 mTreeOut->Branch(
"voxRes", &mVoxelResultsOutPtr);
1541 printf(
"Dumping results for sector %i. Don't forget the call to closeOutputFile() in the end...\n", iSec);
1542 for (
int i = 0;
i < mNVoxPerSector; ++
i) {
1543 mVoxelResultsOut = mVoxelResults[iSec][
i];
1551 static float mres = 0, mvir = 0, mres0 = 0, mvir0 = 0;
1552 static ProcInfo_t procInfo;
1553 static TStopwatch
sw;
1554 const Long_t kMB = 1024;
1555 gSystem->GetProcInfo(&procInfo);
1556 mres = float(procInfo.fMemResident) / kMB;
1557 mvir = float(procInfo.fMemVirtual) / kMB;
1559 printf(
"RSS: %.3f(%.3f) VMEM: %.3f(%.3f) MB | CpuTime:%.3f RealTime:%.3f s\n",
1560 mres, mres - mres0, mvir, mvir - mvir0,
sw.CpuTime(),
sw.RealTime());
1569 mInitResultsContainer.reset();
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)
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
@ VoxDim
dimensionality of the voxels
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)
@ ResD
index for dispersions
@ DispDone
voxel dispersions have been processed
@ DistDone
voxel residuals have been processed
@ SmoothDone
voxel has been smoothed
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)