diff --git a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackResiduals.h b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackResiduals.h index e4d0a3a053728..ab871dc3bd3d0 100644 --- a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackResiduals.h +++ b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackResiduals.h @@ -318,9 +318,14 @@ class TrackResiduals void getVoxelCoordinates(int isec, int ix, int ip, int iz, float& x, float& p, float& z) const; /// Calculates the x-coordinate for given x bin. - /// \param i Bin index + /// \param ix Bin index in x /// \return Coordinate in X - float getX(int i) const; + float getX(int ix) const; + + /// Calculates the max y/x-coordinate for given x bin taking the dead zone into account. + /// \param ix Bin index in x + /// \return Max coordinate in Y/X + float getMaxY2X(int ix) const; /// Calculates the y/x-coordinate. /// \param ix Bin index in X @@ -552,9 +557,15 @@ inline float TrackResiduals::getDXI(int ix) const } //_____________________________________________________ -inline float TrackResiduals::getX(int i) const +inline float TrackResiduals::getX(int ix) const +{ + return mUniformBins[VoxX] ? param::MinX + (ix + 0.5) * mDX : param::RowX[ix]; +} + +//_____________________________________________________ +inline float TrackResiduals::getMaxY2X(int ix) const { - return mUniformBins[VoxX] ? param::MinX + (i + 0.5) * mDX : param::RowX[i]; + return mMaxY2X[ix]; } //_____________________________________________________ diff --git a/Detectors/TPC/calibration/include/TPCCalibration/TPCFastSpaceChargeCorrectionHelper.h b/Detectors/TPC/calibration/include/TPCCalibration/TPCFastSpaceChargeCorrectionHelper.h index eff4972679ed8..40c5634b4f1e8 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/TPCFastSpaceChargeCorrectionHelper.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/TPCFastSpaceChargeCorrectionHelper.h @@ -85,16 +85,28 @@ class TPCFastSpaceChargeCorrectionHelper const int nKnotsY = 10, const int nKnotsZ = 20); /// Create SpaceCharge correction out of the voxel tree + /// \param trackResiduals TrackResiduals object + /// \param voxResTree TTree with voxel residuals + /// \param voxResTreeInverse TTree with inverse voxel residuals + /// \param useSmoothed if true, use smoothed residuals + /// \param invertSigns if true, invert the signs of the residuals + /// \param fitPointsDirect debug: pointer to the data used for the direct correction + /// \param fitPointsInverse debug: pointer to the data used for the inverse correction + /// \return pointer to the created TPCFastSpaceChargeCorrection object + /// \note voxel trees wont be changed. They are read as non-const because of the ROOT::TTreeProcessorMT interface + /// std::unique_ptr createFromTrackResiduals( - const o2::tpc::TrackResiduals& trackResiduals, TTree* voxResTree, bool useSmoothed = false, bool invertSigns = false); + const o2::tpc::TrackResiduals& trackResiduals, TTree* voxResTree, TTree* voxResTreeInverse, // + bool useSmoothed, bool invertSigns, // + TPCFastSpaceChargeCorrectionMap* fitPointsDirect = nullptr, + TPCFastSpaceChargeCorrectionMap* fitPointsInverse = nullptr); + /// _______________ Utilities ________________________ const TPCFastTransformGeo& getGeometry() { return mGeo; } TPCFastSpaceChargeCorrectionMap& getCorrectionMap() { return mCorrectionMap; } - void fillSpaceChargeCorrectionFromMap(TPCFastSpaceChargeCorrection& correction); - void testGeometry(const TPCFastTransformGeo& geo) const; /// initialise inverse transformation @@ -103,15 +115,39 @@ class TPCFastSpaceChargeCorrectionHelper /// initialise inverse transformation from linear combination of several input corrections void initInverse(std::vector& corrections, const std::vector& scaling, bool prn); + /// merge several corrections + /// \param mainCorrection main correction + /// \param scale scaling factor for the main correction + /// \param additionalCorrections vector of pairs of additional corrections and their scaling factors + /// \param prn printout flag + /// \return main correction merged with additional corrections + void mergeCorrections( + o2::gpu::TPCFastSpaceChargeCorrection& mainCorrection, float scale, + const std::vector>& additionalCorrections, bool prn); + + /// how far the voxel mean is allowed to be outside of the voxel (1.1 means 10%) + void setVoxelMeanValidityRange(double range) + { + mVoxelMeanValidityRange = range; + } + + double getVoxelMeanValidityRange() const { return mVoxelMeanValidityRange; } + + /// debug: if true, use voxel centers instead of the fitted positions for correction + void setDebugUseVoxelCenters(); + + bool isDebugUseVoxelCenters() const { return mDebugUseVoxelCenters; } + + /// debug: if true, mirror the data from the A side to the C side of the TPC + void setDebugMirrorAdata2C(); + + bool isDebugMirrorAdata2C() const { return mDebugMirrorAdata2C; } + private: /// geometry initialization void initGeometry(); - /// get space charge correction in internal TPCFastTransform coordinates u,v->dx,du,dv - void getSpaceChargeCorrection(const TPCFastSpaceChargeCorrection& correction, int slice, int row, o2::gpu::TPCFastSpaceChargeCorrectionMap::CorrectionPoint p, double& su, double& sv, double& dx, double& du, double& dv); - - /// initialise max drift length - void initMaxDriftLength(o2::gpu::TPCFastSpaceChargeCorrection& correction, bool prn); + void fillSpaceChargeCorrectionFromMap(TPCFastSpaceChargeCorrection& correction, bool processingInverseCorrection); static TPCFastSpaceChargeCorrectionHelper* sInstance; ///< singleton instance bool mIsInitialized = 0; ///< initialization flag @@ -120,6 +156,11 @@ class TPCFastSpaceChargeCorrectionHelper TPCFastSpaceChargeCorrectionMap mCorrectionMap{0, 0}; + double mVoxelMeanValidityRange{1.1}; ///< debug: how far the voxel mean is allowed to be outside of the voxel (1.1 means 10%) + + bool mDebugUseVoxelCenters{false}; ///< debug: if true, use voxel centers instead of the fitted positions for correction + bool mDebugMirrorAdata2C{false}; ///< debug: if true, mirror the data from the A side to the C side of the TPC + ClassDefNV(TPCFastSpaceChargeCorrectionHelper, 0); }; diff --git a/Detectors/TPC/calibration/src/TPCFastSpaceChargeCorrectionHelper.cxx b/Detectors/TPC/calibration/src/TPCFastSpaceChargeCorrectionHelper.cxx index e2960c73e4d50..7622c40001e1d 100644 --- a/Detectors/TPC/calibration/src/TPCFastSpaceChargeCorrectionHelper.cxx +++ b/Detectors/TPC/calibration/src/TPCFastSpaceChargeCorrectionHelper.cxx @@ -29,6 +29,11 @@ #include #include #include "TStopwatch.h" +#include "TTreeReader.h" +#include "TTreeReaderValue.h" +#include "ROOT/TTreeProcessorMT.hxx" +#include +#include using namespace o2::gpu; @@ -60,12 +65,8 @@ void TPCFastSpaceChargeCorrectionHelper::initGeometry() mGeo.startConstruction(nRows); auto& detParam = ParameterDetector::Instance(); - float tpcZlengthSideA = detParam.TPClength; - float tpcZlengthSideC = detParam.TPClength; - mGeo.setTPCzLength(tpcZlengthSideA, tpcZlengthSideC); - - mGeo.setTPCalignmentZ(0.); + mGeo.setTPCzLength(detParam.TPClength); for (int iRow = 0; iRow < mGeo.getNumberOfRows(); iRow++) { Sector sector = 0; @@ -113,11 +114,13 @@ void TPCFastSpaceChargeCorrectionHelper::setNthreadsToMaximum() } } -void TPCFastSpaceChargeCorrectionHelper::fillSpaceChargeCorrectionFromMap(TPCFastSpaceChargeCorrection& correction) +void TPCFastSpaceChargeCorrectionHelper::fillSpaceChargeCorrectionFromMap(TPCFastSpaceChargeCorrection& correction, bool processingInverseCorrection) { // calculate correction map: dx,du,dv = ( origTransform() -> x,u,v) - fastTransformNominal:x,u,v // for the future: switch TOF correction off for a while + TStopwatch watch; + if (!mIsInitialized) { initGeometry(); } @@ -129,36 +132,67 @@ void TPCFastSpaceChargeCorrectionHelper::fillSpaceChargeCorrectionFromMap(TPCFas LOG(info) << "fast space charge correction helper: init from data points"; - for (int slice = 0; slice < correction.getGeometry().getNumberOfSlices(); slice++) { + for (int sector = 0; sector < correction.getGeometry().getNumberOfSectors(); sector++) { auto myThread = [&](int iThread) { for (int row = iThread; row < correction.getGeometry().getNumberOfRows(); row += mNthreads) { - TPCFastSpaceChargeCorrection::SplineType& spline = correction.getSpline(slice, row); + TPCFastSpaceChargeCorrection::SplineType& spline = correction.getSpline(sector, row); Spline2DHelper helper; - float* splineParameters = correction.getSplineData(slice, row); - const std::vector& data = mCorrectionMap.getPoints(slice, row); + std::vector splineParameters; + splineParameters.resize(spline.getNumberOfParameters()); + + const std::vector& data = mCorrectionMap.getPoints(sector, row); int nDataPoints = data.size(); + auto& info = correction.getSectorRowInfo(sector, row); + if (!processingInverseCorrection) { + info.resetMaxValues(); + } + info.updateMaxValues(1., 1., 1.); + info.updateMaxValues(-1., -1., -1.); + if (nDataPoints >= 4) { - std::vector pointSU(nDataPoints); - std::vector pointSV(nDataPoints); + std::vector pointGU(nDataPoints); + std::vector pointGV(nDataPoints); + std::vector pointWeight(nDataPoints); std::vector pointCorr(3 * nDataPoints); // 3 dimensions for (int i = 0; i < nDataPoints; ++i) { - double su, sv, dx, du, dv; - getSpaceChargeCorrection(correction, slice, row, data[i], su, sv, dx, du, dv); - pointSU[i] = su; - pointSV[i] = sv; - pointCorr[3 * i + 0] = dx; - pointCorr[3 * i + 1] = du; - pointCorr[3 * i + 2] = dv; + o2::gpu::TPCFastSpaceChargeCorrectionMap::CorrectionPoint p = data[i]; + // not corrected grid coordinates + auto [gu, gv, scale] = correction.convLocalToGrid(sector, row, p.mY, p.mZ); + if (scale - 1.f > 1.e-6) { // point is outside the grid + continue; + } + pointGU[i] = gu; + pointGV[i] = gv; + pointWeight[i] = p.mWeight; + pointCorr[3 * i + 0] = p.mDx; + pointCorr[3 * i + 1] = p.mDy; + pointCorr[3 * i + 2] = p.mDz; + info.updateMaxValues(5. * p.mDx, 5. * p.mDy, 5. * p.mDz); } - helper.approximateDataPoints(spline, splineParameters, 0., spline.getGridX1().getNumberOfKnots() - 1, 0., spline.getGridX2().getNumberOfKnots() - 1, &pointSU[0], - &pointSV[0], &pointCorr[0], nDataPoints); + helper.approximateDataPoints(spline, splineParameters.data(), 0., spline.getGridX1().getUmax(), 0., spline.getGridX2().getUmax(), pointGU.data(), + pointGV.data(), pointCorr.data(), pointWeight.data(), nDataPoints); } else { for (int i = 0; i < spline.getNumberOfParameters(); i++) { splineParameters[i] = 0.f; } } + + if (processingInverseCorrection) { + float* splineX = correction.getCorrectionDataInvX(sector, row); + float* splineYZ = correction.getCorrectionDataInvYZ(sector, row); + for (int i = 0; i < spline.getNumberOfParameters() / 3; i++) { + splineX[i] = splineParameters[3 * i + 0]; + splineYZ[2 * i + 0] = splineParameters[3 * i + 1]; + splineYZ[2 * i + 1] = splineParameters[3 * i + 2]; + } + } else { + float* splineXYZ = correction.getCorrectionData(sector, row); + for (int i = 0; i < spline.getNumberOfParameters(); i++) { + splineXYZ[i] = splineParameters[i]; + } + } } // row }; // thread @@ -174,53 +208,30 @@ void TPCFastSpaceChargeCorrectionHelper::fillSpaceChargeCorrectionFromMap(TPCFas th.join(); } - } // slice + } // sector - initInverse(correction, 0); -} + watch.Stop(); -void TPCFastSpaceChargeCorrectionHelper::getSpaceChargeCorrection(const TPCFastSpaceChargeCorrection& correction, int slice, int row, o2::gpu::TPCFastSpaceChargeCorrectionMap::CorrectionPoint p, - double& su, double& sv, double& dx, double& du, double& dv) -{ - // get space charge correction in internal TPCFastTransform coordinates su,sv->dx,du,dv - - if (!mIsInitialized) { - initGeometry(); - } - - // not corrected coordinates in u,v - float u = 0.f, v = 0.f, fsu = 0.f, fsv = 0.f; - mGeo.convLocalToUV(slice, p.mY, p.mZ, u, v); - correction.convUVtoGrid(slice, row, u, v, fsu, fsv); - // mGeo.convUVtoScaledUV(slice, row, u, v, fsu, fsv); - su = fsu; - sv = fsv; - // corrected coordinates in u,v - float u1 = 0.f, v1 = 0.f; - mGeo.convLocalToUV(slice, p.mY + p.mDy, p.mZ + p.mDz, u1, v1); - - dx = p.mDx; - du = u1 - u; - dv = v1 - v; -} + LOGP(info, "Space charge correction tooks: {}s", watch.RealTime()); +} // fillSpaceChargeCorrectionFromMap std::unique_ptr TPCFastSpaceChargeCorrectionHelper::createFromGlobalCorrection( - std::function correctionGlobal, const int nKnotsY, const int nKnotsZ) { /// creates TPCFastSpaceChargeCorrection object from a continious space charge correction in global coordinates - auto correctionLocal = [&](int roc, int irow, double ly, double lz, + auto correctionLocal = [&](int sector, int irow, double ly, double lz, double& dlx, double& dly, double& dlz) { double lx = mGeo.getRowInfo(irow).x; float gx, gy, gz; - mGeo.convLocalToGlobal(roc, lx, ly, lz, gx, gy, gz); + mGeo.convLocalToGlobal(sector, lx, ly, lz, gx, gy, gz); double dgx, dgy, dgz; - correctionGlobal(roc, gx, gy, gz, dgx, dgy, dgz); + correctionGlobal(sector, gx, gy, gz, dgx, dgy, dgz); float lx1, ly1, lz1; - mGeo.convGlobalToLocal(roc, gx + dgx, gy + dgy, gz + dgz, lx1, ly1, lz1); + mGeo.convGlobalToLocal(sector, gx + dgx, gy + dgy, gz + dgz, lx1, ly1, lz1); dlx = lx1 - lx; dly = ly1 - ly; dlz = lz1 - lz; @@ -229,7 +240,7 @@ std::unique_ptr TPCFastSpaceChargeCorrectionHelper } std::unique_ptr TPCFastSpaceChargeCorrectionHelper::createFromLocalCorrection( - std::function correctionLocal, + std::function correctionLocal, const int nKnotsY, const int nKnotsZ) { /// creates TPCFastSpaceChargeCorrection object from a continious space charge correction in local coordinates @@ -251,12 +262,14 @@ std::unique_ptr TPCFastSpaceChargeCorrectionHelper correction.startConstruction(mGeo, nCorrectionScenarios); // assign spline type for TPC rows - for (int row = 0; row < mGeo.getNumberOfRows(); row++) { - int scenario = row / 10; - if (scenario >= nCorrectionScenarios) { - scenario = nCorrectionScenarios - 1; + for (int sector = 0; sector < mGeo.getNumberOfSectors(); sector++) { + for (int row = 0; row < mGeo.getNumberOfRows(); row++) { + int scenario = row / 10; + if (scenario >= nCorrectionScenarios) { + scenario = nCorrectionScenarios - 1; + } + correction.setRowScenarioID(sector, row, scenario); } - correction.setRowScenarioID(row, scenario); } for (int scenario = 0; scenario < nCorrectionScenarios; scenario++) { @@ -274,28 +287,24 @@ std::unique_ptr TPCFastSpaceChargeCorrectionHelper /// set space charge correction in the local coordinates /// as a continious function - int nRocs = mGeo.getNumberOfSlices(); + int nSectors = mGeo.getNumberOfSectors(); int nRows = mGeo.getNumberOfRows(); - mCorrectionMap.init(nRocs, nRows); + mCorrectionMap.init(nSectors, nRows); - for (int iRoc = 0; iRoc < nRocs; iRoc++) { + for (int iSector = 0; iSector < nSectors; iSector++) { auto myThread = [&](int iThread) { for (int iRow = iThread; iRow < nRows; iRow += mNthreads) { const auto& info = mGeo.getRowInfo(iRow); - double vMax = mGeo.getTPCzLength(iRoc); - double dv = vMax / (6. * (nKnotsZ - 1)); - + double dl = mGeo.getTPCzLength() / (6. * (nKnotsZ - 1)); double dpad = info.maxPad / (6. * (nKnotsY - 1)); for (double pad = 0; pad < info.maxPad + .5 * dpad; pad += dpad) { - float u = mGeo.convPadToU(iRow, pad); - for (double v = 0.; v < vMax + .5 * dv; v += dv) { - float ly, lz; - mGeo.convUVtoLocal(iRoc, u, v, ly, lz); + for (double l = 0.; l < mGeo.getTPCzLength() + .5 * dl; l += dl) { + auto [y, z] = mGeo.convPadDriftLengthToLocal(iSector, iRow, pad, l); double dx, dy, dz; - correctionLocal(iRoc, iRow, ly, lz, dx, dy, dz); - mCorrectionMap.addCorrectionPoint(iRoc, iRow, - ly, lz, dx, dy, dz); + correctionLocal(iSector, iRow, y, z, dx, dy, dz); + mCorrectionMap.addCorrectionPoint(iSector, iRow, + y, z, dx, dy, dz, 1.); } } } // row @@ -313,20 +322,21 @@ std::unique_ptr TPCFastSpaceChargeCorrectionHelper th.join(); } - } // roc + } // sector - fillSpaceChargeCorrectionFromMap(correction); + fillSpaceChargeCorrectionFromMap(correction, false); + initInverse(correction, false); } return std::move(correctionPtr); -} +} // createFromLocalCorrection void TPCFastSpaceChargeCorrectionHelper::testGeometry(const TPCFastTransformGeo& geo) const { const Mapper& mapper = Mapper::instance(); - if (geo.getNumberOfSlices() != Sector::MAXSECTOR) { - LOG(fatal) << "Wrong number of sectors :" << geo.getNumberOfSlices() << " instead of " << Sector::MAXSECTOR << std::endl; + if (geo.getNumberOfSectors() != Sector::MAXSECTOR) { + LOG(fatal) << "Wrong number of sectors :" << geo.getNumberOfSectors() << " instead of " << Sector::MAXSECTOR << std::endl; } if (geo.getNumberOfRows() != mapper.getNumberOfRows()) { @@ -350,15 +360,14 @@ void TPCFastSpaceChargeCorrectionHelper::testGeometry(const TPCFastTransformGeo& for (int pad = 0; pad < nPads; pad++) { const GlobalPadNumber p = mapper.globalPadNumber(PadPos(row, pad)); const PadCentre& c = mapper.padCentre(p); - double u = geo.convPadToU(row, pad); - + auto [y, z] = geo.convPadDriftLengthToLocal(0, row, pad, 0.); const double dx = x - c.X(); - const double dy = u - (-c.Y()); // diferent sign convention for Y coordinate in the map + const double dy = y - (-c.Y()); // diferent sign convention for Y coordinate in the map if (fabs(dx) >= 1.e-6 || fabs(dy) >= 1.e-5) { LOG(warning) << "wrong calculated pad position:" << " row " << row << " pad " << pad << " x calc " << x << " x in map " << c.X() << " dx " << (x - c.X()) - << " y calc " << u << " y in map " << -c.Y() << " dy " << dy << std::endl; + << " y calc " << y << " y in map " << -c.Y() << " dy " << dy << std::endl; } if (fabs(maxDx) < fabs(dx)) { maxDx = dx; @@ -376,281 +385,520 @@ void TPCFastSpaceChargeCorrectionHelper::testGeometry(const TPCFastTransformGeo& } std::unique_ptr TPCFastSpaceChargeCorrectionHelper::createFromTrackResiduals( - const o2::tpc::TrackResiduals& trackResiduals, TTree* voxResTree, bool useSmoothed, bool invertSigns) + const o2::tpc::TrackResiduals& trackResiduals, TTree* voxResTree, TTree* voxResTreeInverse, bool useSmoothed, bool invertSigns, + TPCFastSpaceChargeCorrectionMap* fitPointsDirect, + TPCFastSpaceChargeCorrectionMap* fitPointsInverse) { // create o2::gpu::TPCFastSpaceChargeCorrection from o2::tpc::TrackResiduals::VoxRes voxel tree - LOG(info) << "fast space charge correction helper: create correction using " << mNthreads << " threads"; + LOG(info) << "fast space charge correction helper: create correction from track residuals using " << mNthreads << " threads"; + + TStopwatch watch, watch1; std::unique_ptr correctionPtr(new o2::gpu::TPCFastSpaceChargeCorrection); o2::gpu::TPCFastSpaceChargeCorrection& correction = *correctionPtr; - // o2::tpc::TrackResiduals::VoxRes* v = nullptr; - // voxResTree->SetBranchAddress("voxRes", &v); - - o2::tpc::TrackResiduals::VoxRes* v = nullptr; - TBranch* branch = voxResTree->GetBranch("voxRes"); - branch->SetAddress(&v); - branch->SetAutoDelete(kTRUE); - auto* helper = o2::tpc::TPCFastSpaceChargeCorrectionHelper::instance(); const o2::gpu::TPCFastTransformGeo& geo = helper->getGeometry(); - o2::gpu::TPCFastSpaceChargeCorrectionMap& map = helper->getCorrectionMap(); - map.init(geo.getNumberOfSlices(), geo.getNumberOfRows()); - int nY2Xbins = trackResiduals.getNY2XBins(); int nZ2Xbins = trackResiduals.getNZ2XBins(); - int nKnotsY = nY2Xbins / 2; - int nKnotsZ = nZ2Xbins / 2; + std::vector knotsDouble[3]; + + knotsDouble[0].reserve(nY2Xbins); + knotsDouble[1].reserve(nZ2Xbins); + knotsDouble[2].reserve(nZ2Xbins); + + // to get enouth measurements, make a spline knot at every second bin. Boundary bins are always included. + + for (int i = 0, j = nY2Xbins - 1; i <= j; i += 2, j -= 2) { + knotsDouble[0].push_back(trackResiduals.getY2X(0, i)); + if (j >= i + 1) { + knotsDouble[0].push_back(trackResiduals.getY2X(0, j)); + } + } - if (nKnotsY < 2) { - nKnotsY = 2; + for (int i = 0, j = nZ2Xbins - 1; i <= j; i += 2, j -= 2) { + knotsDouble[1].push_back(trackResiduals.getZ2X(i)); + knotsDouble[2].push_back(-trackResiduals.getZ2X(i)); + if (j >= i + 1) { + knotsDouble[1].push_back(trackResiduals.getZ2X(j)); + knotsDouble[2].push_back(-trackResiduals.getZ2X(j)); + } } - if (nKnotsZ < 2) { - nKnotsZ = 2; + std::vector knotsInt[3]; + + for (int dim = 0; dim < 3; dim++) { + auto& knotsD = knotsDouble[dim]; + std::sort(knotsD.begin(), knotsD.end()); + + double pitch = knotsD[1] - knotsD[0]; // min distance between the knots + for (int i = 2; i < knotsD.size(); i++) { + double d = knotsD[i] - knotsD[i - 1]; + if (d < pitch) { + pitch = d; + } + } + // spline knots must be positioned on the grid with an integer internal coordinate + // we set the knot positioning accuracy to 0.1*pitch + pitch = 0.1 * pitch; + auto& knotsI = knotsInt[dim]; + knotsI.reserve(knotsD.size()); + double u0 = knotsD[0]; + double u1 = knotsD[knotsD.size() - 1]; + for (auto& u : knotsD) { + u -= u0; + int iu = int(u / pitch + 0.5); + knotsI.push_back(iu); + // debug printout: corrected vs original knot positions, scaled to [-1,1] interval + double uorig = u / (u1 - u0) * 2 - 1.; + u = (iu * pitch) / (u1 - u0) * 2 - 1.; + LOG(info) << "TPC SC splines: convert " << (dim == 0 ? "y" : (dim == 1 ? "z" : "-z")) << " bin to the knot: " << uorig << " -> " << u << " -> " << iu; + } + + if (knotsI.size() < 2) { // minimum 2 knots + knotsI.clear(); + knotsI.push_back(0); + knotsI.push_back(1); + } } + auto& yKnotsInt = knotsInt[0]; + auto& zKnotsIntA = knotsInt[1]; + auto& zKnotsIntC = knotsInt[2]; + + int nKnotsY = yKnotsInt.size(); + int nKnotsZA = zKnotsIntA.size(); + int nKnotsZC = zKnotsIntC.size(); + // std::cout << "n knots Y: " << nKnotsY << std::endl; - // std::cout << "n knots Z: " << nKnotsZ << std::endl; + // std::cout << "n knots Z: " << nKnotsZA << ", " << nKnotsZC << std::endl; + + const int nRows = geo.getNumberOfRows(); + const int nSectors = geo.getNumberOfSectors(); { // create the correction object - const int nRows = geo.getNumberOfRows(); - const int nCorrectionScenarios = 1; + const int nCorrectionScenarios = 2; // different grids for TPC A and TPC C sides correction.startConstruction(geo, nCorrectionScenarios); // init rows - for (int row = 0; row < geo.getNumberOfRows(); row++) { - correction.setRowScenarioID(row, 0); + for (int iSector = 0; iSector < nSectors; iSector++) { + int id = iSector < geo.getNumberOfSectorsA() ? 0 : 1; + for (int row = 0; row < geo.getNumberOfRows(); row++) { + correction.setRowScenarioID(iSector, row, id); + } } { // init spline scenario TPCFastSpaceChargeCorrection::SplineType spline; - spline.recreate(nKnotsY, nKnotsZ); + spline.recreate(nKnotsY, &yKnotsInt[0], nKnotsZA, &zKnotsIntA[0]); correction.setSplineScenario(0, spline); + spline.recreate(nKnotsY, &yKnotsInt[0], nKnotsZC, &zKnotsIntC[0]); + correction.setSplineScenario(1, spline); } correction.finishConstruction(); } // .. create the correction object - // set the grid borders in Z to Z/X==1 - for (int iRoc = 0; iRoc < geo.getNumberOfSlices(); iRoc++) { + // set the grid borders + for (int iSector = 0; iSector < geo.getNumberOfSectors(); iSector++) { for (int iRow = 0; iRow < geo.getNumberOfRows(); iRow++) { - auto rowInfo = geo.getRowInfo(iRow); - o2::gpu::TPCFastSpaceChargeCorrection::SliceRowInfo& info = correction.getSliceRowInfo(iRoc, iRow); - double len = geo.getTPCzLength(iRoc); - info.gridV0 = len - rowInfo.x; - if (info.gridV0 < 0.) { - info.gridV0 = 0.; + auto& info = correction.getSectorRowInfo(iSector, iRow); + const auto& spline = correction.getSpline(iSector, iRow); + double rowX = geo.getRowInfo(iRow).x; + double yMin = rowX * trackResiduals.getY2X(iRow, 0); + double yMax = rowX * trackResiduals.getY2X(iRow, trackResiduals.getNY2XBins() - 1); + double zMin = rowX * trackResiduals.getZ2X(0); + double zMax = rowX * trackResiduals.getZ2X(trackResiduals.getNZ2XBins() - 1); + double zOut = zMax; + if (iSector >= geo.getNumberOfSectorsA()) { + // TPC C side + zOut = -zOut; + zMax = -zMin; + zMin = zOut; } + info.gridMeasured.set(yMin, spline.getGridX1().getUmax() / (yMax - yMin), // y + zMin, spline.getGridX2().getUmax() / (zMax - zMin), // z + zOut, geo.getZreadout(iSector)); // correction scaling region + + info.gridReal = info.gridMeasured; + + // std::cout << " iSector " << iSector << " iRow " << iRow << " uMin: " << uMin << " uMax: " << uMax << " vMin: " << vMin << " vMax: " << vMax + //<< " grid scale u "<< info.scaleUtoGrid << " grid scale v "<< info.scaleVtoGrid<< std::endl; } } - LOG(info) << "fast space charge correction helper: fill data points from track residuals"; + LOG(info) << "fast space charge correction helper: preparation took " << watch1.RealTime() << "s"; - for (int iVox = 0; iVox < voxResTree->GetEntriesFast(); iVox++) { + for (int processingInverseCorrection = 0; processingInverseCorrection <= 1; processingInverseCorrection++) { - voxResTree->GetEntry(iVox); - auto xBin = - v->bvox[o2::tpc::TrackResiduals::VoxX]; // bin number in x (= pad row) - auto y2xBin = - v->bvox[o2::tpc::TrackResiduals::VoxF]; // bin number in y/x 0..14 - auto z2xBin = - v->bvox[o2::tpc::TrackResiduals::VoxZ]; // bin number in z/x 0..4 + TTree* currentTree = (processingInverseCorrection) ? voxResTreeInverse : voxResTree; - int iRoc = (int)v->bsec; - int iRow = (int)xBin; + if (!currentTree) { + continue; + } + const char* directionName = (processingInverseCorrection) ? "inverse" : "direct"; + LOG(info) << "\n fast space charge correction helper: Process " << directionName + << " correction: fill data points from track residuals.. "; - // x,y,z of the voxel in local TPC coordinates + TStopwatch watch3; + o2::gpu::TPCFastSpaceChargeCorrectionMap& map = helper->getCorrectionMap(); + map.init(geo.getNumberOfSectors(), geo.getNumberOfRows()); - double x = trackResiduals.getX(xBin); // radius of the pad row - double y2x = trackResiduals.getY2X( - xBin, y2xBin); // y/x coordinate of the bin ~-0.15 ... 0.15 - double z2x = - trackResiduals.getZ2X(z2xBin); // z/x coordinate of the bin 0.1 .. 0.9 - double y = x * y2x; - double z = x * z2x; + // read the data Sector by Sector - if (iRoc >= geo.getNumberOfSlicesA()) { - z = -z; - // y = -y; - } + // data in the tree is not sorted by row + // first find which data belong to which row - { - float sx, sy, sz; - trackResiduals.getVoxelCoordinates(iRoc, xBin, y2xBin, z2xBin, sx, sy, sz); - sy *= x; - sz *= x; - if (fabs(sx - x) + fabs(sy - y) + fabs(sz - z) > 1.e-4) { - std::cout << "wrong coordinates: " << x << " " << y << " " << z << " / " << sx << " " << sy << " " << sz << std::endl; - } + struct VoxelData { + int mNentries{0}; // number of entries + float mX, mY, mZ; // mean position in the local coordinates + float mCx, mCy, mCz; // corrections to the local coordinates + }; + + std::vector vSectorData[nRows * nSectors]; + for (int ir = 0; ir < nRows * nSectors; ir++) { + vSectorData[ir].resize(nY2Xbins * nZ2Xbins); } - // skip empty voxels - float voxEntries = v->stat[o2::tpc::TrackResiduals::VoxV]; - if (voxEntries < 1.) { // no statistics - continue; + { // read data from the tree to vSectorData + + ROOT::TTreeProcessorMT processor(*currentTree, mNthreads); + std::string errMsg = std::string("Error reading ") + directionName + " track residuals: "; + auto myThread = [&](TTreeReader& readerSubRange) { + TTreeReaderValue v(readerSubRange, "voxRes"); + while (readerSubRange.Next()) { + int iSector = (int)v->bsec; + if (iSector < 0 || iSector >= nSectors) { + LOG(fatal) << errMsg << "Sector number " << iSector << " is out of range"; + continue; + } + int iRow = (int)v->bvox[o2::tpc::TrackResiduals::VoxX]; // bin number in x (= pad row) + if (iRow < 0 || iRow >= nRows) { + LOG(fatal) << errMsg << "Row number " << iRow << " is out of range"; + } + double rowX = trackResiduals.getX(iRow); // X of the pad row + int iy = v->bvox[o2::tpc::TrackResiduals::VoxF]; // bin number in y/x 0..14 + int iz = v->bvox[o2::tpc::TrackResiduals::VoxZ]; // bin number in z/x 0..4 + auto& data = vSectorData[iSector * nRows + iRow][iy * nZ2Xbins + iz]; + data.mNentries = (int)v->stat[o2::tpc::TrackResiduals::VoxV]; + data.mX = v->stat[o2::tpc::TrackResiduals::VoxX]; + data.mY = v->stat[o2::tpc::TrackResiduals::VoxF] * rowX; + data.mZ = v->stat[o2::tpc::TrackResiduals::VoxZ] * rowX; + data.mCx = useSmoothed ? v->DS[o2::tpc::TrackResiduals::ResX] : v->D[o2::tpc::TrackResiduals::ResX]; + data.mCy = useSmoothed ? v->DS[o2::tpc::TrackResiduals::ResY] : v->D[o2::tpc::TrackResiduals::ResY]; + data.mCz = useSmoothed ? v->DS[o2::tpc::TrackResiduals::ResZ] : v->D[o2::tpc::TrackResiduals::ResZ]; + if (invertSigns) { + data.mCx *= -1.; + data.mCy *= -1.; + data.mCz *= -1.; + } + } + }; + processor.Process(myThread); } - // double statX = v->stat[o2::tpc::TrackResiduals::VoxX]; // weight - // double statY = v->stat[o2::tpc::TrackResiduals::VoxF]; // weight - // double statZ = v->stat[o2::tpc::TrackResiduals::VoxZ]; // weight - - // double dx = 1. / trackResiduals.getDXI(xBin); - double dy = x / trackResiduals.getDY2XI(xBin, y2xBin); - double dz = x * trackResiduals.getDZ2X(z2xBin); - - double correctionX = useSmoothed ? v->DS[o2::tpc::TrackResiduals::ResX] : v->D[o2::tpc::TrackResiduals::ResX]; - double correctionY = useSmoothed ? v->DS[o2::tpc::TrackResiduals::ResY] : v->D[o2::tpc::TrackResiduals::ResY]; - double correctionZ = useSmoothed ? v->DS[o2::tpc::TrackResiduals::ResZ] : v->D[o2::tpc::TrackResiduals::ResZ]; - if (invertSigns) { - correctionX *= -1.; - correctionY *= -1.; - correctionZ *= -1.; + // debug: mirror the data for TPC C side + + if (mDebugMirrorAdata2C) { + for (int iSector = 0; iSector < geo.getNumberOfSectorsA(); iSector++) { + for (int iRow = 0; iRow < nRows; iRow++) { + for (int iy = 0; iy < nY2Xbins; iy++) { + for (int iz = 0; iz < nZ2Xbins; iz++) { + auto& dataA = vSectorData[iSector * nRows + iRow][iy * nZ2Xbins + iz]; + auto& dataC = vSectorData[(iSector + geo.getNumberOfSectorsA()) * nRows + iRow][iy * nZ2Xbins + iz]; + dataC = dataA; // copy the data + dataC.mZ = -dataC.mZ; // mirror the Z coordinate + dataC.mCz = -dataC.mCz; // mirror the Z correction + } + } + } + } } - // add one point per voxel - // map.addCorrectionPoint(iRoc, iRow, y, z, correctionX, correctionY, - // correctionZ); + double maxError[3] = {0., 0., 0.}; + int nErrors = 0; + + for (int iSector = 0; iSector < nSectors; iSector++) { + + // now process the data row-by-row + + auto myThread = [&](int iThread, int nTreads) { + struct Voxel { + float mY, mZ; // non-distorted local coordinates + float mDy, mDz; // voxel size + int mSmoothingStep{100}; // is the voxel data original or smoothed at this step + }; + + std::vector vRowVoxels(nY2Xbins * nZ2Xbins); + + for (int iRow = iThread; iRow < nRows; iRow += nTreads) { + // LOG(info) << "Processing Sector " << iSector << " row " << iRow; + + // complete the voxel data + { + int xBin = iRow; + double x = trackResiduals.getX(xBin); // radius of the pad row + double dx = 1. / trackResiduals.getDXI(xBin); + bool isDataFound = false; + for (int iy = 0; iy < nY2Xbins; iy++) { + for (int iz = 0; iz < nZ2Xbins; iz++) { + auto& data = vSectorData[iSector * nRows + iRow][iy * nZ2Xbins + iz]; + auto& vox = vRowVoxels[iy * nZ2Xbins + iz]; + // y/x coordinate of the bin ~-0.15 ... 0.15 + double y2x = trackResiduals.getY2X(xBin, iy); + // z/x coordinate of the bin 0.1 .. 0.9 + double z2x = trackResiduals.getZ2X(iz); + vox.mY = x * y2x; + vox.mZ = x * z2x; + vox.mDy = x / trackResiduals.getDY2XI(xBin, iy); + vox.mDz = x * trackResiduals.getDZ2X(iz); + if (iSector >= geo.getNumberOfSectorsA()) { + vox.mZ = -vox.mZ; + } + if (data.mNentries > 0) { // voxel contains data + vox.mSmoothingStep = 0; // take original data + isDataFound = true; + + // correct the mean position if it is outside the voxel + std::stringstream msg; + if (fabs(x - data.mX) > mVoxelMeanValidityRange * dx / 2.) { + msg << "\n x: center " << x << " dx " << data.mX - x << " half bin size " << dx / 2; + } + + if (fabs(vox.mY - data.mY) > mVoxelMeanValidityRange * vox.mDy / 2.) { + msg << "\n y: center " << vox.mY << " dy " << data.mY - vox.mY << " half bin size " << vox.mDy / 2; + data.mY = vox.mY; + } + + if (fabs(vox.mZ - data.mZ) > mVoxelMeanValidityRange * vox.mDz / 2.) { + msg << "\n z: center " << vox.mZ << " dz " << data.mZ - vox.mZ << " half bin size " << vox.mDz / 2; + data.mZ = vox.mZ; + } + + if (!msg.str().empty()) { + bool isMaxErrorExceeded = (fabs(data.mX - x) / dx > maxError[0]) || + (fabs(data.mY - vox.mY) / vox.mDy > maxError[1]) || + (fabs(data.mZ - vox.mZ) / vox.mDz > maxError[2]); + static std::mutex mutex; + mutex.lock(); + nErrors++; + if (nErrors < 20 || isMaxErrorExceeded) { + LOG(warning) << directionName << " correction: error N " << nErrors << "fitted voxel position is outside the voxel: " + << " sector " << iSector << " row " << iRow << " bin y " << iy << " bin z " << iz + << msg.str(); + maxError[0] = GPUCommonMath::Max(maxError[0], fabs(data.mX - x) / dx); + maxError[1] = GPUCommonMath::Max(maxError[1], fabs(data.mY - vox.mY) / vox.mDy); + maxError[2] = GPUCommonMath::Max(maxError[2], fabs(data.mZ - vox.mZ) / vox.mDz); + } + mutex.unlock(); + } + + } else { // no data, take voxel center position + data.mCx = 0.; + data.mCy = 0.; + data.mCz = 0.; + data.mX = x; + data.mY = vox.mY; + data.mZ = vox.mZ; + vox.mSmoothingStep = 100; // fill this data point with smoothed values from the neighbours + } + if (mDebugUseVoxelCenters) { // debug: always use voxel center instead of the mean position + data.mY = vox.mY; + data.mZ = vox.mZ; + } + } + } + + if (!isDataFound) { // fill everything with 0 + for (int iy = 0; iy < nY2Xbins; iy++) { + for (int iz = 0; iz < nZ2Xbins; iz++) { + vRowVoxels[iy * nZ2Xbins + iz].mSmoothingStep = 0; + } + } + } + } // complete the voxel data + + // repare the voxel data: fill empty voxels + + int nRepairs = 0; + + for (int ismooth = 1; ismooth <= 2; ismooth++) { + for (int iy = 0; iy < nY2Xbins; iy++) { + for (int iz = 0; iz < nZ2Xbins; iz++) { + auto& data = vSectorData[iSector * nRows + iRow][iy * nZ2Xbins + iz]; + auto& vox = vRowVoxels[iy * nZ2Xbins + iz]; + if (vox.mSmoothingStep <= ismooth) { // already filled + continue; + } + nRepairs++; + data.mCx = 0.; + data.mCy = 0.; + data.mCz = 0.; + double w = 0.; + bool filled = false; + auto update = [&](int iy1, int iz1) { + auto& data1 = vSectorData[iSector * nRows + iRow][iy1 * nZ2Xbins + iz1]; + auto& vox1 = vRowVoxels[iy1 * nZ2Xbins + iz1]; + if (vox1.mSmoothingStep >= ismooth) { + return false; + } + double w1 = 1. / (abs(iy - iy1) + abs(iz - iz1) + 1); + data.mCx += w1 * data1.mCx; + data.mCy += w1 * data1.mCy; + data.mCz += w1 * data1.mCz; + w += w1; + filled = true; + return true; + }; + + for (int iy1 = iy - 1; iy1 >= 0 && !update(iy1, iz); iy1--) { + } + for (int iy1 = iy + 1; iy1 < nY2Xbins && !update(iy1, iz); iy1++) { + } + for (int iz1 = iz - 1; iz1 >= 0 && !update(iy, iz1); iz1--) { + } + for (int iz1 = iz + 1; iz1 < nZ2Xbins && !update(iy, iz1); iz1++) { + } + + if (filled) { + data.mCx /= w; + data.mCy /= w; + data.mCz /= w; + vox.mSmoothingStep = ismooth; + } + } // iz + } // iy + } // ismooth + + if (nRepairs > 0) { + LOG(debug) << "Sector " << iSector << " row " << iRow << ": " << nRepairs << " voxel repairs for " << nY2Xbins * nZ2Xbins << " voxels"; + } - // add several points per voxel, - // extend values of the edge voxels to the edges of the TPC row - // + // feed the row data to the helper - double yFirst = y - dy / 2.; - double yLast = y + dy / 2.; + auto& info = correction.getSectorRowInfo(iSector, iRow); + const auto& spline = correction.getSpline(iSector, iRow); - if (y2xBin == 0) { // extend value of the first Y bin to the row edge - float u, v; - if (iRoc < geo.getNumberOfSlicesA()) { - geo.convScaledUVtoUV(iRoc, iRow, 0., 0., u, v); - } else { - geo.convScaledUVtoUV(iRoc, iRow, 1., 0., u, v); - } - float py, pz; - geo.convUVtoLocal(iRoc, u, v, py, pz); - yFirst = py; - } + auto addVoxel = [&](int iy, int iz, double weight) { + auto& vox = vRowVoxels[iy * nZ2Xbins + iz]; + if (vox.mSmoothingStep > 2) { + LOG(fatal) << "empty voxel is not repared: y " << iy << " z " << iz; + } + auto& data = vSectorData[iSector * nRows + iRow][iy * nZ2Xbins + iz]; + map.addCorrectionPoint(iSector, iRow, data.mY, data.mZ, data.mCx, data.mCy, data.mCz, weight); + }; + + auto addEdge = [&](int iy1, int iz1, int iy2, int iz2, int nPoints) { + // add n points on the edge between two voxels excluding the voxel points + if (nPoints < 1) { + return; + } + if (iy1 < 0 || iy1 >= nY2Xbins || iz1 < 0 || iz1 >= nZ2Xbins) { + return; + } + if (iy2 < 0 || iy2 >= nY2Xbins || iz2 < 0 || iz2 >= nZ2Xbins) { + return; + } + auto& data1 = vSectorData[iSector * nRows + iRow][iy1 * nZ2Xbins + iz1]; + auto& vox1 = vRowVoxels[iy1 * nZ2Xbins + iz1]; + auto& data2 = vSectorData[iSector * nRows + iRow][iy2 * nZ2Xbins + iz2]; + auto& vox2 = vRowVoxels[iy2 * nZ2Xbins + iz2]; + double y1 = data1.mY; + double z1 = data1.mZ; + double cx1 = data1.mCx; + double cy1 = data1.mCy; + double cz1 = data1.mCz; + double y2 = data2.mY; + double z2 = data2.mZ; + double cx2 = data2.mCx; + double cy2 = data2.mCy; + double cz2 = data2.mCz; + + for (int is = 1; is <= nPoints; is++) { + double s2 = is / (double)(nPoints + 1); + double s1 = 1. - s2; + double y = s1 * y1 + s2 * y2; + double z = s1 * z1 + s2 * z2; + double cx = s1 * cx1 + s2 * cx2; + double cy = s1 * cy1 + s2 * cy2; + double cz = s1 * cz1 + s2 * cz2; + map.addCorrectionPoint(iSector, iRow, y, z, cx, cy, cz, 1.); + } + }; + + // original measurements weighted by 8 at each voxel and 8 additional artificial measurements around each voxel + // + // (y+1, z) 8 1 1 8 (y+1, z+1) + // 1 1 1 1 1 + // 1 1 1 1 1 + // (y,z) 8 1 1 8 1 + // 1 1 1 1 1 + + for (int iy = 0; iy < nY2Xbins; iy++) { + for (int iz = 0; iz < nZ2Xbins; iz++) { + addVoxel(iy, iz, 8); + addEdge(iy, iz, iy, iz + 1, 2); + addEdge(iy, iz, iy + 1, iz, 2); + addEdge(iy, iz, iy + 1, iz + 1, 2); + addEdge(iy + 1, iz, iy, iz + 1, 2); + } + } - if (y2xBin == trackResiduals.getNY2XBins() - 1) { // extend value of the last Y bin to the row edge - float u, v; - if (iRoc < geo.getNumberOfSlicesA()) { - geo.convScaledUVtoUV(iRoc, iRow, 1., 0., u, v); - } else { - geo.convScaledUVtoUV(iRoc, iRow, 0., 0., u, v); - } - float py, pz; - geo.convUVtoLocal(iRoc, u, v, py, pz); - yLast = py; - } + } // iRow + }; // myThread - double z0 = 0.; - if (iRoc < geo.getNumberOfSlicesA()) { - z0 = geo.getTPCzLengthA(); - } else { - z0 = -geo.getTPCzLengthC(); - } + // run n threads - double yStep = (yLast - yFirst) / 2; + int nThreads = mNthreads; + // nThreads = 1; - for (double py = yFirst; py <= yLast + yStep / 2.; py += yStep) { + std::vector threads(nThreads); - for (double pz = z - dz / 2.; pz <= z + dz / 2. + 1.e-4; pz += dz / 2.) { - map.addCorrectionPoint(iRoc, iRow, py, pz, correctionX, correctionY, - correctionZ); + for (int i = 0; i < nThreads; i++) { + threads[i] = std::thread(myThread, i, nThreads); } - if (z2xBin == trackResiduals.getNZ2XBins() - 1) { - // extend value of the first Z bin to the readout, linear decrease of all values to 0. - int nZsteps = 3; - for (int is = 0; is < nZsteps; is++) { - double pz = z + (z0 - z) * (is + 1.) / nZsteps; - double s = (nZsteps - 1. - is) / nZsteps; - map.addCorrectionPoint(iRoc, iRow, py, pz, s * correctionX, - s * correctionY, s * correctionZ); - } + // wait for the threads to finish + for (auto& th : threads) { + th.join(); } - } - } - helper->fillSpaceChargeCorrectionFromMap(correction); - return std::move(correctionPtr); -} + } // iSector -void TPCFastSpaceChargeCorrectionHelper::initMaxDriftLength(o2::gpu::TPCFastSpaceChargeCorrection& correction, bool prn) -{ - /// initialise max drift length + LOGP(info, "Reading & reparing of the track residuals tooks: {}s", watch3.RealTime()); - double tpcR2min = mGeo.getRowInfo(0).x - 1.; - tpcR2min = tpcR2min * tpcR2min; - double tpcR2max = mGeo.getRowInfo(mGeo.getNumberOfRows() - 1).x; - tpcR2max = tpcR2max / cos(2 * M_PI / mGeo.getNumberOfSlicesA() / 2) + 1.; - tpcR2max = tpcR2max * tpcR2max; + LOG(info) << "fast space charge correction helper: create space charge from the map of data points.."; - ChebyshevFit1D chebFitter; + TStopwatch watch4; - for (int slice = 0; slice < mGeo.getNumberOfSlices(); slice++) { - if (prn) { - LOG(info) << "init MaxDriftLength for slice " << slice; + if (!processingInverseCorrection && fitPointsDirect) { + *fitPointsDirect = helper->getCorrectionMap(); } - double vLength = (slice < mGeo.getNumberOfSlicesA()) ? mGeo.getTPCzLengthA() : mGeo.getTPCzLengthC(); - TPCFastSpaceChargeCorrection::SliceInfo& sliceInfo = correction.getSliceInfo(slice); - sliceInfo.vMax = 0.f; - - for (int row = 0; row < mGeo.getNumberOfRows(); row++) { - TPCFastSpaceChargeCorrection::RowActiveArea& area = correction.getSliceRowInfo(slice, row).activeArea; - area.cvMax = 0; - area.vMax = 0; - area.cuMin = mGeo.convPadToU(row, 0.f); - area.cuMax = -area.cuMin; - chebFitter.reset(4, 0., mGeo.getRowInfo(row).maxPad); - double x = mGeo.getRowInfo(row).x; - for (int pad = 0; pad < mGeo.getRowInfo(row).maxPad; pad++) { - float u = mGeo.convPadToU(row, (float)pad); - float v0 = 0; - float v1 = 1.1 * vLength; - float vLastValid = -1; - float cvLastValid = -1; - while (v1 - v0 > 0.1) { - float v = 0.5 * (v0 + v1); - float dx, du, dv; - correction.getCorrection(slice, row, u, v, dx, du, dv); - double cx = x + dx; - double cu = u + du; - double cv = v + dv; - double r2 = cx * cx + cu * cu; - if (cv < 0) { - v0 = v; - } else if (cv <= vLength && r2 >= tpcR2min && r2 <= tpcR2max) { - v0 = v; - vLastValid = v; - cvLastValid = cv; - } else { - v1 = v; - } - } - if (vLastValid > 0.) { - chebFitter.addMeasurement(pad, vLastValid); - } - if (area.vMax < vLastValid) { - area.vMax = vLastValid; - } - if (area.cvMax < cvLastValid) { - area.cvMax = cvLastValid; - } - } - chebFitter.fit(); - for (int i = 0; i < 5; i++) { - area.maxDriftLengthCheb[i] = chebFitter.getCoefficients()[i]; - } - if (sliceInfo.vMax < area.vMax) { - sliceInfo.vMax = area.vMax; - } - } // row - } // slice -} + if (processingInverseCorrection && fitPointsInverse) { + *fitPointsInverse = helper->getCorrectionMap(); + } + + helper->fillSpaceChargeCorrectionFromMap(correction, processingInverseCorrection); + + LOG(info) << "fast space charge correction helper: creation from the data map took " << watch4.RealTime() << "s"; + + } // processingInverseCorrection + + if (voxResTree && !voxResTreeInverse) { + LOG(info) << "fast space charge correction helper: init inverse correction from direct correction.."; + TStopwatch watch4; + helper->initInverse(correction, false); + LOG(info) << "fast space charge correction helper: init inverse correction took " << watch4.RealTime() << "s"; + } + + LOGP(info, "Creation from track residuals tooks in total: {}s", watch.RealTime()); + + return std::move(correctionPtr); + +} // createFromTrackResiduals void TPCFastSpaceChargeCorrectionHelper::initInverse(o2::gpu::TPCFastSpaceChargeCorrection& correction, bool prn) { @@ -670,128 +918,93 @@ void TPCFastSpaceChargeCorrectionHelper::initInverse(std::vector helper; std::vector splineParameters; - ChebyshevFit1D chebFitterX, chebFitterU, chebFitterV; for (int row = iThread; row < mGeo.getNumberOfRows(); row += mNthreads) { - TPCFastSpaceChargeCorrection::SplineType spline = correction.getSpline(slice, row); - helper.setSpline(spline, 10, 10); - std::vector dataPointCU, dataPointCV, dataPointF; - - float u0, u1, v0, v1; - mGeo.convScaledUVtoUV(slice, row, 0., 0., u0, v0); - mGeo.convScaledUVtoUV(slice, row, 1., 1., u1, v1); - - double x = mGeo.getRowInfo(row).x; - int nPointsU = (spline.getGridX1().getNumberOfKnots() - 1) * 10; - int nPointsV = (spline.getGridX2().getNumberOfKnots() - 1) * 10; + auto& sectorRowInfo = correction.getSectorRowInfo(sector, row); + sectorRowInfo.gridReal = sectorRowInfo.gridMeasured; - double stepU = (u1 - u0) / (nPointsU - 1); - double stepV = (v1 - v0) / (nPointsV - 1); + TPCFastSpaceChargeCorrection::SplineType spline = correction.getSpline(sector, row); + helper.setSpline(spline, 10, 10); - if (prn) { - LOG(info) << "u0 " << u0 << " u1 " << u1 << " v0 " << v0 << " v1 " << v1; - } - TPCFastSpaceChargeCorrection::RowActiveArea& area = correction.getSliceRowInfo(slice, row).activeArea; - area.cuMin = 1.e10; - area.cuMax = -1.e10; - - /* - v1 = area.vMax; - stepV = (v1 - v0) / (nPointsU - 1); - if (stepV < 1.f) { - stepV = 1.f; - } - */ - - for (double u = u0; u < u1 + stepU; u += stepU) { - for (double v = v0; v < v1 + stepV; v += stepV) { - float dx, du, dv; - correction.getCorrection(slice, row, u, v, dx, du, dv); - dx *= scaling[0]; - du *= scaling[0]; - dv *= scaling[0]; - // add remaining corrections - for (int i = 1; i < corrections.size(); ++i) { - float dxTmp, duTmp, dvTmp; - corrections[i]->getCorrection(slice, row, u, v, dxTmp, duTmp, dvTmp); - dx += dxTmp * scaling[i]; - du += duTmp * scaling[i]; - dv += dvTmp * scaling[i]; + std::vector gridU; + { + const auto& grid = spline.getGridX1(); + for (int i = 0; i < grid.getNumberOfKnots(); i++) { + if (i == grid.getNumberOfKnots() - 1) { + gridU.push_back(grid.getKnot(i).u); + break; } - double cx = x + dx; - double cu = u + du; - double cv = v + dv; - if (cu < area.cuMin) { - area.cuMin = cu; + for (double s = 1.; s > 0.; s -= 0.1) { + gridU.push_back(s * grid.getKnot(i).u + (1. - s) * grid.getKnot(i + 1).u); } - if (cu > area.cuMax) { - area.cuMax = cu; + } + } + std::vector gridV; + { + const auto& grid = spline.getGridX2(); + for (int i = 0; i < grid.getNumberOfKnots(); i++) { + if (i == grid.getNumberOfKnots() - 1) { + gridV.push_back(grid.getKnot(i).u); + break; } - - dataPointCU.push_back(cu); - dataPointCV.push_back(cv); - dataPointF.push_back(dx); - dataPointF.push_back(du); - dataPointF.push_back(dv); - - if (prn) { - LOG(info) << "measurement cu " << cu << " cv " << cv << " dx " << dx << " du " << du << " dv " << dv; + for (double s = 1.; s > 0.; s -= 0.1) { + gridV.push_back(s * grid.getKnot(i).u + (1. - s) * grid.getKnot(i + 1).u); } - } // v - } // u - - if (area.cuMax - area.cuMin < 0.2) { - area.cuMax = .1; - area.cuMin = -.1; - } - if (area.cvMax < 0.1) { - area.cvMax = .1; - } - if (prn) { - LOG(info) << "slice " << slice << " row " << row << " max drift L = " << correction.getMaxDriftLength(slice, row) - << " active area: cuMin " << area.cuMin << " cuMax " << area.cuMax << " vMax " << area.vMax << " cvMax " << area.cvMax; + } } - TPCFastSpaceChargeCorrection::SliceRowInfo& info = correction.getSliceRowInfo(slice, row); - info.gridCorrU0 = area.cuMin; - info.scaleCorrUtoGrid = spline.getGridX1().getUmax() / (area.cuMax - area.cuMin); - info.scaleCorrVtoGrid = spline.getGridX2().getUmax() / area.cvMax; + std::vector dataPointGridU, dataPointGridV, dataPointF, dataPointWeight; + dataPointGridU.reserve(gridU.size() * gridV.size()); + dataPointGridV.reserve(gridU.size() * gridV.size()); + dataPointF.reserve(3 * gridU.size() * gridV.size()); + dataPointWeight.reserve(gridU.size() * gridV.size()); + + for (int iu = 0; iu < gridU.size(); iu++) { + for (int iv = 0; iv < gridV.size(); iv++) { - info.gridCorrU0 = u0; - info.gridCorrV0 = info.gridV0; - info.scaleCorrUtoGrid = spline.getGridX1().getUmax() / (u1 - info.gridCorrU0); - info.scaleCorrVtoGrid = spline.getGridX2().getUmax() / (v1 - info.gridCorrV0); + auto [y, z] = correction.convGridToLocal(sector, row, gridU[iu], gridV[iv]); + double dx = 0, dy = 0, dz = 0; - int nDataPoints = dataPointCU.size(); - for (int i = 0; i < nDataPoints; i++) { - dataPointCU[i] = (dataPointCU[i] - info.gridCorrU0) * info.scaleCorrUtoGrid; - dataPointCV[i] = (dataPointCV[i] - info.gridCorrV0) * info.scaleCorrVtoGrid; + // add corrections + for (int i = 0; i < corrections.size(); ++i) { + auto [dxTmp, dyTmp, dzTmp] = corrections[i]->getCorrectionLocal(sector, row, y, z); + dx += dxTmp * scaling[i]; + dy += dyTmp * scaling[i]; + dz += dzTmp * scaling[i]; + } + auto [gridU, gridV, scale] = correction.convRealLocalToGrid(sector, row, y + dy, z + dz); + dataPointGridU.push_back(gridU); + dataPointGridV.push_back(gridV); + dataPointF.push_back(scale * dx); + dataPointF.push_back(scale * dy); + dataPointF.push_back(scale * dz); + dataPointWeight.push_back(1.); + } } + int nDataPoints = dataPointGridU.size(); splineParameters.resize(spline.getNumberOfParameters()); helper.approximateDataPoints(spline, splineParameters.data(), 0., spline.getGridX1().getUmax(), 0., spline.getGridX2().getUmax(), - dataPointCU.data(), dataPointCV.data(), - dataPointF.data(), dataPointCU.size()); + dataPointGridU.data(), dataPointGridV.data(), + dataPointF.data(), dataPointWeight.data(), nDataPoints); - float* splineX = correction.getSplineData(slice, row, 1); - float* splineUV = correction.getSplineData(slice, row, 2); + float* splineX = correction.getCorrectionDataInvX(sector, row); + float* splineUV = correction.getCorrectionDataInvYZ(sector, row); for (int i = 0; i < spline.getNumberOfParameters() / 3; i++) { splineX[i] = splineParameters[3 * i + 0]; splineUV[2 * i + 0] = splineParameters[3 * i + 1]; @@ -812,9 +1025,164 @@ void TPCFastSpaceChargeCorrectionHelper::initInverse(std::vector>& additionalCorrections, bool /*prn*/) +{ + /// merge several corrections + + TStopwatch watch; + LOG(info) << "fast space charge correction helper: Merge corrections"; + + const auto& geo = mainCorrection.getGeometry(); + + for (int sector = 0; sector < geo.getNumberOfSectors(); sector++) { + + auto myThread = [&](int iThread) { + for (int row = iThread; row < geo.getNumberOfRows(); row += mNthreads) { + const auto& spline = mainCorrection.getSpline(sector, row); + + float* splineParameters = mainCorrection.getCorrectionData(sector, row); + float* splineParametersInvX = mainCorrection.getCorrectionDataInvX(sector, row); + float* splineParametersInvYZ = mainCorrection.getCorrectionDataInvYZ(sector, row); + + auto& secRowInfo = mainCorrection.getSectorRowInfo(sector, row); + + constexpr int nKnotPar1d = 4; + constexpr int nKnotPar2d = nKnotPar1d * 2; + constexpr int nKnotPar3d = nKnotPar1d * 3; + + { // scale the main correction + for (int i = 0; i < 3; i++) { + secRowInfo.maxCorr[i] *= mainScale; + secRowInfo.minCorr[i] *= mainScale; + } + double parscale[4] = {mainScale, mainScale, mainScale, mainScale * mainScale}; + for (int iknot = 0, ind = 0; iknot < spline.getNumberOfKnots(); iknot++) { + for (int ipar = 0; ipar < nKnotPar1d; ++ipar) { + for (int idim = 0; idim < 3; idim++, ind++) { + splineParameters[ind] *= parscale[ipar]; + } + } + } + for (int iknot = 0, ind = 0; iknot < spline.getNumberOfKnots(); iknot++) { + for (int ipar = 0; ipar < nKnotPar1d; ++ipar) { + for (int idim = 0; idim < 1; idim++, ind++) { + splineParametersInvX[ind] *= parscale[ipar]; + } + } + } + for (int iknot = 0, ind = 0; iknot < spline.getNumberOfKnots(); iknot++) { + for (int ipar = 0; ipar < nKnotPar1d; ++ipar) { + for (int idim = 0; idim < 2; idim++, ind++) { + splineParametersInvYZ[ind] *= parscale[ipar]; + } + } + } + } + + // add the other corrections + + const auto& gridU = spline.getGridX1(); + const auto& gridV = spline.getGridX2(); + + for (int icorr = 0; icorr < additionalCorrections.size(); ++icorr) { + const auto& corr = *(additionalCorrections[icorr].first); + double scale = additionalCorrections[icorr].second; + auto& linfo = corr.getSectorRowInfo(sector, row); + secRowInfo.updateMaxValues(linfo.getMaxValues(), scale); + secRowInfo.updateMaxValues(linfo.getMinValues(), scale); + + double scaleU = secRowInfo.gridMeasured.getYscale() / linfo.gridMeasured.getYscale(); + double scaleV = secRowInfo.gridMeasured.getZscale() / linfo.gridMeasured.getZscale(); + double scaleRealU = secRowInfo.gridReal.getYscale() / linfo.gridReal.getYscale(); + double scaleRealV = secRowInfo.gridReal.getZscale() / linfo.gridReal.getZscale(); + + for (int iu = 0; iu < gridU.getNumberOfKnots(); iu++) { + double u = gridU.getKnot(iu).u; + for (int iv = 0; iv < gridV.getNumberOfKnots(); iv++) { + double v = gridV.getKnot(iv).u; + int knotIndex = spline.getKnotIndex(iu, iv); + float P[nKnotPar3d]; + + { // direct correction + auto [y, z] = mainCorrection.convGridToLocal(sector, row, u, v); + // return values: u, v, scaling factor + auto [lu, lv, ls] = corr.convLocalToGrid(sector, row, y, z); + ls *= scale; + double parscale[4] = {ls, ls * scaleU, ls * scaleV, ls * ls * scaleU * scaleV}; + const auto& spl = corr.getSpline(sector, row); + spl.interpolateParametersAtU(corr.getCorrectionData(sector, row), lu, lv, P); + for (int ipar = 0, ind = 0; ipar < nKnotPar1d; ++ipar) { + for (int idim = 0; idim < 3; idim++, ind++) { + splineParameters[knotIndex * nKnotPar3d + ind] += parscale[ipar] * P[ind]; + } + } + } + + auto [y, z] = mainCorrection.convGridToRealLocal(sector, row, u, v); + // return values: u, v, scaling factor + auto [lu, lv, ls] = corr.convRealLocalToGrid(sector, row, y, z); + ls *= scale; + double parscale[4] = {ls, ls * scaleRealU, ls * scaleRealV, ls * ls * scaleRealU * scaleRealV}; + + { // inverse X correction + corr.getSplineInvX(sector, row).interpolateParametersAtU(corr.getCorrectionDataInvX(sector, row), lu, lv, P); + for (int ipar = 0, ind = 0; ipar < nKnotPar1d; ++ipar) { + for (int idim = 0; idim < 1; idim++, ind++) { + splineParametersInvX[knotIndex * nKnotPar1d + ind] += parscale[ipar] * P[ind]; + } + } + } + + { // inverse YZ correction + corr.getSplineInvYZ(sector, row).interpolateParametersAtU(corr.getCorrectionDataInvYZ(sector, row), lu, lv, P); + for (int ipar = 0, ind = 0; ipar < nKnotPar1d; ++ipar) { + for (int idim = 0; idim < 2; idim++, ind++) { + splineParametersInvYZ[knotIndex * nKnotPar2d + ind] += parscale[ipar] * P[ind]; + } + } + } + + } // iv + } // iu + } // corrections + + } // row + }; // thread + + std::vector threads(mNthreads); + + // run n threads + for (int i = 0; i < mNthreads; i++) { + threads[i] = std::thread(myThread, i); + } + + // wait for the threads to finish + for (auto& th : threads) { + th.join(); + } + + } // sector + float duration = watch.RealTime(); + LOGP(info, "Merge of corrections tooks: {}s", duration); +} + +void TPCFastSpaceChargeCorrectionHelper::setDebugUseVoxelCenters() +{ + LOG(info) << "fast space charge correction helper: use voxel centers for correction"; + mDebugUseVoxelCenters = true; +} + +void TPCFastSpaceChargeCorrectionHelper::setDebugMirrorAdata2C() +{ + LOG(info) << "fast space charge correction helper: mirror A data to C data"; + mDebugMirrorAdata2C = true; } } // namespace tpc diff --git a/Detectors/TPC/reconstruction/macro/createTPCSpaceChargeCorrection.C b/Detectors/TPC/reconstruction/macro/createTPCSpaceChargeCorrection.C index 723cf2ee30491..af066598d1317 100644 --- a/Detectors/TPC/reconstruction/macro/createTPCSpaceChargeCorrection.C +++ b/Detectors/TPC/reconstruction/macro/createTPCSpaceChargeCorrection.C @@ -397,10 +397,9 @@ void debugInterpolation(utils::TreeStreamRedirector& pcstream, const o2::gpu::TPCFastTransformGeo& geo, TPCFastTransform* fastTransform) { - for (int slice = 0; slice < geo.getNumberOfSlices(); slice += 1) { - // for (int slice = 21; slice < 22; slice += 1) { - std::cout << "debug slice " << slice << " ... " << std::endl; - const o2::gpu::TPCFastTransformGeo::SliceInfo& sliceInfo = geo.getSliceInfo(slice); + for (int sector = 0; sector < geo.getNumberOfSectors(); sector += 1) { + // for (int sector = 21; sector < 22; sector += 1) { + std::cout << "debug sector " << sector << " ... " << std::endl; for (int row = 0; row < geo.getNumberOfRows(); row++) { int nPads = geo.getRowInfo(row).maxPad + 1; @@ -411,28 +410,28 @@ void debugInterpolation(utils::TreeStreamRedirector& pcstream, // non-corrected point fastTransform->setApplyCorrectionOff(); float lx, ly, lz; - fastTransform->Transform(slice, row, pad, time, lx, ly, lz); + fastTransform->Transform(sector, row, pad, time, lx, ly, lz); float gx, gy, gz, r, phi; - geo.convLocalToGlobal(slice, lx, ly, lz, gx, gy, gz); + geo.convLocalToGlobal(sector, lx, ly, lz, gx, gy, gz); r = std::sqrt(lx * lx + ly * ly); phi = std::atan2(gy, gx); fastTransform->setApplyCorrectionOn(); // fast transformation float lxT, lyT, lzT; - fastTransform->Transform(slice, row, pad, time, lxT, lyT, lzT); + fastTransform->Transform(sector, row, pad, time, lxT, lyT, lzT); float gxT, gyT, gzT, rT; - geo.convLocalToGlobal(slice, lxT, lyT, lzT, gxT, gyT, gzT); + geo.convLocalToGlobal(sector, lxT, lyT, lzT, gxT, gyT, gzT); rT = std::sqrt(lxT * lxT + lyT * lyT); // the original correction double gdC[3] = {0, 0, 0}; - Side side = slice < geo.getNumberOfSlicesA() ? Side::A : Side::C; + Side side = sector < geo.getNumberOfSectorsA() ? Side::A : Side::C; if (spaceCharge) { spaceCharge->getCorrections(gx, gy, gz, side, gdC[0], gdC[1], gdC[2]); } float ldxC, ldyC, ldzC; - geo.convGlobalToLocal(slice, gdC[0], gdC[1], gdC[2], ldxC, ldyC, ldzC); + geo.convGlobalToLocal(sector, gdC[0], gdC[1], gdC[2], ldxC, ldyC, ldzC); double rC = std::sqrt((gx + gdC[0]) * (gx + gdC[0]) + (gy + gdC[1]) * (gy + gdC[1])); @@ -466,7 +465,7 @@ void debugInterpolation(utils::TreeStreamRedirector& pcstream, if (spaceChargeExB) { double gdC_ExB[3] = {0, 0, 0}; spaceChargeExB->getCorrections(gx, gy, gz, side, gdC_ExB[0], gdC_ExB[1], gdC_ExB[2]); - geo.convGlobalToLocal(slice, gdC_ExB[0], gdC_ExB[1], gdC_ExB[2], ldxC_ExB, ldyC_ExB, ldzC_ExB); + geo.convGlobalToLocal(sector, gdC_ExB[0], gdC_ExB[1], gdC_ExB[2], ldxC_ExB, ldyC_ExB, ldzC_ExB); } // static distortions @@ -474,18 +473,18 @@ void debugInterpolation(utils::TreeStreamRedirector& pcstream, if (spaceChargeStack) { double gdC_static[3] = {0, 0, 0}; spaceChargeStack->getCorrections(gx, gy, gz, side, gdC_static[0], gdC_static[1], gdC_static[2]); - geo.convGlobalToLocal(slice, gdC_static[0], gdC_static[1], gdC_static[2], ldxC_static, ldyC_static, ldzC_static); + geo.convGlobalToLocal(sector, gdC_static[0], gdC_static[1], gdC_static[2], ldxC_static, ldyC_static, ldzC_static); } // get combined corrections double dx_comb = 0, dy_comb = 0, dz_comb = 0; - getGlobalSpaceChargeCorrectionLinearCombination(slice, gx, gy, gz, dx_comb, dy_comb, dz_comb); + getGlobalSpaceChargeCorrectionLinearCombination(sector, gx, gy, gz, dx_comb, dy_comb, dz_comb); float ldxC_comb, ldyC_comb, ldzC_comb; - geo.convGlobalToLocal(slice, dx_comb, dy_comb, dz_comb, ldxC_comb, ldyC_comb, ldzC_comb); + geo.convGlobalToLocal(sector, dx_comb, dy_comb, dz_comb, ldxC_comb, ldyC_comb, ldzC_comb); pcstream << "fastTransform" // internal coordinates - << "slice=" << slice + << "sector=" << sector << "row=" << row << "pad=" << pad << "time=" << time @@ -613,10 +612,9 @@ void debugGridpoints(utils::TreeStreamRedirector& pcstream, const o2::gpu::TPCFa break; } } - float u = 0.f, v = 0.f; - geo.convLocalToUV(sector, y0, z0, u, v); + float pad = 0.f, time = 0.f; - fastTransform->convUVtoPadTime(sector, row, u, v, pad, time, 0.f); + fastTransform->convLocalToPadTime(sector, row, y0, z0, pad, time, 0.f); if (pad < 0) { continue; } diff --git a/Detectors/TPC/reconstruction/src/TPCFastTransformHelperO2.cxx b/Detectors/TPC/reconstruction/src/TPCFastTransformHelperO2.cxx index 7db84f0e94968..687d4ce707f11 100644 --- a/Detectors/TPC/reconstruction/src/TPCFastTransformHelperO2.cxx +++ b/Detectors/TPC/reconstruction/src/TPCFastTransformHelperO2.cxx @@ -56,12 +56,7 @@ void TPCFastTransformHelperO2::init() mGeo.startConstruction(nRows); auto& detParam = ParameterDetector::Instance(); - float tpcZlengthSideA = detParam.TPClength; - float tpcZlengthSideC = detParam.TPClength; - - mGeo.setTPCzLength(tpcZlengthSideA, tpcZlengthSideC); - - mGeo.setTPCalignmentZ(0.); + mGeo.setTPCzLength(detParam.TPClength); for (int iRow = 0; iRow < mGeo.getNumberOfRows(); iRow++) { Sector sector = 0; @@ -114,12 +109,8 @@ std::unique_ptr TPCFastTransformHelperO2::create(Long_t TimeSt // set some initial calibration values, will be reinitialised later int updateCalibration() const float t0 = 0.; const float vDrift = 0.f; - const float vdCorrY = 0.; - const float ldCorr = 0.; - const float tofCorr = 0.; - const float primVtxZ = 0.; const long int initTimeStamp = -1; - fastTransform.setCalibration(initTimeStamp, t0, vDrift, vdCorrY, ldCorr, tofCorr, primVtxZ); + fastTransform.setCalibration1(initTimeStamp, t0, vDrift); fastTransform.finishConstruction(); } @@ -171,19 +162,13 @@ int TPCFastTransformHelperO2::updateCalibration(TPCFastTransform& fastTransform, const double vDrift = elParam.ZbinWidth * vDriftRef * vDriftFactor; // cm/timebin // fast transform formula: - // L = (t-t0)*(mVdrift + mVdriftCorrY*yLab ) + mLdriftCorr - // Z = Z(L) + tpcAlignmentZ + // L = (t-t0)*mVdrift + // Z = Z(L) // spline corrections for xyz - // Time-of-flight correction: ldrift += dist-to-vtx*tofCorr const double t0 = (driftTimeOffset + elParam.getAverageShapingTime()) / elParam.ZbinWidth; - const double vdCorrY = 0.; - const double ldCorr = 0.; - const double tofCorr = 0.; - const double primVtxZ = 0.; - - fastTransform.setCalibration(TimeStamp, t0, vDrift, vdCorrY, ldCorr, tofCorr, primVtxZ); + fastTransform.setCalibration1(TimeStamp, t0, vDrift); return 0; } @@ -192,8 +177,8 @@ void TPCFastTransformHelperO2::testGeometry(const TPCFastTransformGeo& geo) cons { const Mapper& mapper = Mapper::instance(); - if (geo.getNumberOfSlices() != Sector::MAXSECTOR) { - LOG(fatal) << "Wrong number of sectors :" << geo.getNumberOfSlices() << " instead of " << Sector::MAXSECTOR << std::endl; + if (geo.getNumberOfSectors() != Sector::MAXSECTOR) { + LOG(fatal) << "Wrong number of sectors :" << geo.getNumberOfSectors() << " instead of " << Sector::MAXSECTOR << std::endl; } if (geo.getNumberOfRows() != mapper.getNumberOfRows()) { @@ -217,15 +202,16 @@ void TPCFastTransformHelperO2::testGeometry(const TPCFastTransformGeo& geo) cons for (int pad = 0; pad < nPads; pad++) { const GlobalPadNumber p = mapper.globalPadNumber(PadPos(row, pad)); const PadCentre& c = mapper.padCentre(p); - double u = geo.convPadToU(row, pad); + + auto [y, z] = geo.convPadDriftLengthToLocal(0, row, pad, 0.); const double dx = x - c.X(); - const double dy = u - (-c.Y()); // diferent sign convention for Y coordinate in the map + const double dy = y - (-c.Y()); // diferent sign convention for Y coordinate in the map if (fabs(dx) >= 1.e-6 || fabs(dy) >= 1.e-5) { LOG(warning) << "wrong calculated pad position:" << " row " << row << " pad " << pad << " x calc " << x << " x in map " << c.X() << " dx " << (x - c.X()) - << " y calc " << u << " y in map " << -c.Y() << " dy " << dy << std::endl; + << " y calc " << y << " y in map " << -c.Y() << " dy " << dy << std::endl; } if (fabs(maxDx) < fabs(dx)) { maxDx = dx; diff --git a/Detectors/TPC/reconstruction/test/testTPCFastTransform.cxx b/Detectors/TPC/reconstruction/test/testTPCFastTransform.cxx index 5e37bd608c4a1..fee63e9e38bc2 100644 --- a/Detectors/TPC/reconstruction/test/testTPCFastTransform.cxx +++ b/Detectors/TPC/reconstruction/test/testTPCFastTransform.cxx @@ -53,7 +53,7 @@ BOOST_AUTO_TEST_CASE(FastTransform_test1) BOOST_CHECK_EQUAL(geo.test(), 0); - BOOST_CHECK_EQUAL(geo.getNumberOfSlices(), Sector::MAXSECTOR); + BOOST_CHECK_EQUAL(geo.getNumberOfSectors(), Sector::MAXSECTOR); BOOST_CHECK_EQUAL(geo.getNumberOfRows(), mapper.getNumberOfRows()); double maxDx = 0, maxDy = 0; @@ -71,15 +71,16 @@ BOOST_AUTO_TEST_CASE(FastTransform_test1) for (int pad = 0; pad < nPads; pad++) { const GlobalPadNumber p = mapper.globalPadNumber(PadPos(row, pad)); const PadCentre& c = mapper.padCentre(p); - float u = 0, v = 0; - fastTransform.convPadTimeToUV(0, row, pad, 0, u, v, 0.); - + float y = 0, z = 0; + int sector = 0; + float time = 0.; + fastTransform.convPadTimeToLocal(sector, row, pad, time, y, z, 0.); double dx = x - c.X(); - double dy = u - (-c.Y()); // diferent sign convention for Y coordinate in the map + double dy = y - (-c.Y()); // diferent sign convention for Y coordinate in the map BOOST_CHECK(fabs(dx) < 1.e-6); BOOST_CHECK(fabs(dy) < 1.e-5); if (fabs(dy) >= 1.e-5) { - std::cout << "row " << row << " pad " << pad << " y calc " << u << " y in map " << -c.Y() << " dy " << dy << std::endl; + std::cout << "row " << row << " pad " << pad << " y calc " << y << " y in map " << -c.Y() << " dy " << dy << std::endl; } if (fabs(maxDx) < fabs(dx)) { maxDx = dx; @@ -104,46 +105,46 @@ BOOST_AUTO_TEST_CASE(FastTransform_test_setSpaceChargeCorrection) std::unique_ptr fastTransform0(TPCFastTransformHelperO2::instance()->create(0)); const TPCFastTransformGeo& geo = fastTransform0->getGeometry(); - auto correctionUV = [&](int roc, int /*row*/, const double u, const double v, double& dX, double& dU, double& dV) { + auto correctionUV = [&](int sector, int /*row*/, const double u, const double v, double& dX, double& dU, double& dV) { // float lx = geo.getRowInfo(row).x; dX = 1. + 1 * u + 0.1 * u * u; dU = 2. + 0.2 * u + 0.002 * u * u; // + 0.001 * u * u * u; dV = 3. + 0.1 * v + 0.01 * v * v; //+ 0.0001 * v * v * v; }; - auto correctionLocal = [&](int roc, int row, double ly, double lz, + auto correctionLocal = [&](int sector, int row, double ly, double lz, double& dx, double& dly, double& dlz) { float u, v; - geo.convLocalToUV(roc, ly, lz, u, v); + geo.convLocalToUV(sector, ly, lz, u, v); double du, dv; - correctionUV(roc, row, u, v, dx, du, dv); + correctionUV(sector, row, u, v, dx, du, dv); float ly1, lz1; - geo.convUVtoLocal(roc, u + du, v + dv, ly1, lz1); + geo.convUVtoLocal(sector, u + du, v + dv, ly1, lz1); dly = ly1 - ly; dlz = lz1 - lz; }; - int nRocs = geo.getNumberOfSlices(); + int nSectors = geo.getNumberOfSectors(); int nRows = geo.getNumberOfRows(); TPCFastSpaceChargeCorrectionMap& scData = TPCFastTransformHelperO2::instance()->getCorrectionMap(); - scData.init(nRocs, nRows); + scData.init(nSectors, nRows); - for (int iRoc = 0; iRoc < nRocs; iRoc++) { + for (int iSector = 0; iSector < nSectors; iSector++) { for (int iRow = 0; iRow < nRows; iRow++) { double dsu = 1. / (3 * 8 - 3); double dsv = 1. / (3 * 20 - 3); for (double su = 0.f; su < 1.f + .5 * dsu; su += dsv) { for (double sv = 0.f; sv < 1.f + .5 * dsv; sv += dsv) { float ly = 0.f, lz = 0.f; - geo.convScaledUVtoLocal(iRoc, iRow, su, sv, ly, lz); + geo.convScaledUVtoLocal(iSector, iRow, su, sv, ly, lz); double dx, dy, dz; - correctionLocal(iRoc, iRow, ly, lz, dx, dy, dz); - scData.addCorrectionPoint(iRoc, iRow, + correctionLocal(iSector, iRow, ly, lz, dx, dy, dz); + scData.addCorrectionPoint(iSector, iRow, ly, lz, dx, dy, dz); } } } // row - } // slice + } // sector std::unique_ptr fastTransform(TPCFastTransformHelperO2::instance()->create(0)); @@ -158,12 +159,12 @@ BOOST_AUTO_TEST_CASE(FastTransform_test_setSpaceChargeCorrection) double statDiff = 0., statN = 0.; double statDiffFile = 0., statNFile = 0.; - for (int slice = 0; slice < geo.getNumberOfSlices(); slice += 1) { - //std::cout << "slice " << slice << " ... " << std::endl; + for (int sector = 0; sector < geo.getNumberOfSectors(); sector += 1) { + // std::cout << "sector " << sector << " ... " << std::endl; - const TPCFastTransformGeo::SliceInfo& sliceInfo = geo.getSliceInfo(slice); + const TPCFastTransformGeo::SectorInfo& sectorInfo = geo.getSectorInfo(sector); - float lastTimeBin = fastTransform->getMaxDriftTime(slice, 0.f); + float lastTimeBin = fastTransform->getMaxDriftTime(sector, 0.f); for (int row = 0; row < geo.getNumberOfRows(); row++) { @@ -172,31 +173,31 @@ BOOST_AUTO_TEST_CASE(FastTransform_test_setSpaceChargeCorrection) for (int pad = 0; pad < nPads; pad += 10) { for (float time = 0; time < lastTimeBin; time += 30) { - //std::cout<<"slice "<setApplyCorrectionOff(); float x0, y0, z0; - fastTransform->Transform(slice, row, pad, time, x0, y0, z0); + fastTransform->Transform(sector, row, pad, time, x0, y0, z0); - BOOST_CHECK_EQUAL(geo.test(slice, row, y0, z0), 0); + BOOST_CHECK_EQUAL(geo.test(sector, row, y0, z0), 0); fastTransform->setApplyCorrectionOn(); float x1, y1, z1; - fastTransform->Transform(slice, row, pad, time, x1, y1, z1); + fastTransform->Transform(sector, row, pad, time, x1, y1, z1); // local to UV float u0, v0, u1, v1; - geo.convLocalToUV(slice, y0, z0, u0, v0); - geo.convLocalToUV(slice, y1, z1, u1, v1); + geo.convLocalToUV(sector, y0, z0, u0, v0); + geo.convLocalToUV(sector, y1, z1, u1, v1); double dx, du, dv; - correctionUV(slice, row, u0, v0, dx, du, dv); + correctionUV(sector, row, u0, v0, dx, du, dv); statDiff += fabs((x1 - x0) - dx) + fabs((u1 - u0) - du) + fabs((v1 - v0) - dv); statN += 3; - //std::cout << (x1 - x0) - dx << " " << (u1 - u0) - du << " " << (v1 - v0) - dv << std::endl; //": v0 " << v0 <<" z0 "<Transform(slice, row, pad, time, x1f, y1f, z1f); + fromFile->Transform(sector, row, pad, time, x1f, y1f, z1f); statDiffFile += fabs(x1f - x1) + fabs(y1f - y1) + fabs(z1f - z1); statNFile += 3; } diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx index 260781c17406b..d8b7bec4ff246 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx @@ -564,7 +564,7 @@ GPUd() int32_t GPUTPCGMMerger::RefitSectorTrack(GPUTPCGMSectorTrack& sectorTrack trk.SinPhi() = inTrack->Param().GetSinPhi(); trk.DzDs() = inTrack->Param().GetDzDs(); trk.QPt() = inTrack->Param().GetQPt(); - trk.TOffset() = Param().par.continuousTracking ? GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convZOffsetToVertexTime(sector, inTrack->Param().GetZOffset(), Param().continuousMaxTimeBin) : 0; + trk.TOffset() = Param().par.continuousTracking ? GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convZOffsetToVertexTime(inTrack->Param().GetZOffset(), Param().continuousMaxTimeBin) : 0; const auto tmp = sectorTrack.ClusterTN() > sectorTrack.ClusterT0() ? std::array{sectorTrack.ClusterTN(), sectorTrack.ClusterT0()} : std::array{sectorTrack.ClusterT0(), sectorTrack.ClusterTN()}; trk.ShiftZ(this, sector, tmp[0], tmp[1], inTrack->Param().GetX()); // We do not store the inner / outer cluster X, so we just use the track X instead sectorTrack.SetX2(0.f); @@ -1950,8 +1950,7 @@ GPUd() void GPUTPCGMMerger::MergeLoopersInit(int32_t nBlocks, int32_t nThreads, const auto& p = trk.GetParam(); const float qptabs = CAMath::Abs(p.GetQPt()); if (trk.OK() && trk.NClusters() && trk.Leg() == 0 && qptabs * Param().qptB5Scaler > 5.f && qptabs * Param().qptB5Scaler <= lowPtThresh) { - const int32_t sector = mClusters[trk.FirstClusterRef() + trk.NClusters() - 1].sector; - const float refz = p.GetZ() + (Param().par.continuousTracking ? GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(sector, p.GetTOffset(), Param().continuousMaxTimeBin) : 0) + (trk.CSide() ? -100 : 100); + const float refz = p.GetZ() + (Param().par.continuousTracking ? GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(p.GetTOffset(), Param().continuousMaxTimeBin) : 0) + (trk.CSide() ? -100 : 100); float sinA, cosA; CAMath::SinCos(trk.GetAlpha(), sinA, cosA); float gx = cosA * p.GetX() - sinA * p.GetY(); diff --git a/GPU/GPUTracking/Merger/GPUTPCGMSectorTrack.cxx b/GPU/GPUTracking/Merger/GPUTPCGMSectorTrack.cxx index 6042dec7d4931..48b7c7c7c9f10 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMSectorTrack.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMSectorTrack.cxx @@ -37,7 +37,7 @@ GPUd() void GPUTPCGMSectorTrack::Set(const GPUTPCGMMerger* merger, const GPUTPCT mParam.mSecPhi = 1.f / mParam.mCosPhi; mAlpha = alpha; mSector = sector; - mTOffset = merger->Param().par.continuousTracking ? merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convZOffsetToVertexTime(sector, t.GetZOffset(), merger->Param().continuousMaxTimeBin) : 0; + mTOffset = merger->Param().par.continuousTracking ? merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convZOffsetToVertexTime(t.GetZOffset(), merger->Param().continuousMaxTimeBin) : 0; mNClusters = sectorTr->NHits(); } @@ -323,7 +323,7 @@ GPUd() bool GPUTPCGMSectorTrack::TransportToX(GPUTPCGMMerger* merger, float x, f b.SetPar(2, ey1); b.SetPar(3, param.mDzDs); b.SetPar(4, param.mQPt); - b.SetZOffsetLinear(merger->Param().par.continuousTracking ? merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(mSector, mTOffset, merger->Param().continuousMaxTimeBin) : 0); + b.SetZOffsetLinear(merger->Param().par.continuousTracking ? merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(mTOffset, merger->Param().continuousMaxTimeBin) : 0); if (!doCov) { return (1); @@ -478,7 +478,7 @@ GPUd() bool GPUTPCGMSectorTrack::TransportToXAlpha(GPUTPCGMMerger* merger, float b.SetPar(2, ey1); b.SetPar(3, dzds); b.SetPar(4, qpt); - b.SetZOffsetLinear(merger->Param().par.continuousTracking ? merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(mSector, mTOffset, merger->Param().continuousMaxTimeBin) : 0); + b.SetZOffsetLinear(merger->Param().par.continuousTracking ? merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(mTOffset, merger->Param().continuousMaxTimeBin) : 0); b.SetCov(0, c00 + h2 * h2c22 + h4 * h4c44 + 2.f * (h2 * c20ph4c42 + h4 * c40)); b.SetCov(1, c11 + dS * (c31 + n7)); diff --git a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx index 70fb9cd1a769e..7fc0c6de672d7 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx @@ -502,7 +502,7 @@ GPUd() float GPUTPCGMTrackParam::AttachClusters(const GPUTPCGMMerger* GPUrestric return -1e6f; } - const float zOffset = param.par.continuousTracking ? Merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(sector, mTOffset, param.continuousMaxTimeBin) : 0; // TODO: do some validatiomns for the transform conv functions... + const float zOffset = param.par.continuousTracking ? Merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(mTOffset, param.continuousMaxTimeBin) : 0; // TODO: do some validatiomns for the transform conv functions... const float y0 = row.Grid().YMin(); const float stepY = row.HstepY(); const float z0 = row.Grid().ZMin() - zOffset; // We can use our own ZOffset, since this is only used temporarily anyway @@ -522,7 +522,7 @@ GPUd() float GPUTPCGMTrackParam::AttachClusters(const GPUTPCGMMerger* GPUrestric const float tubeMinSize2 = protect ? param.rec.tpc.tubeProtectMinSize2 : 0.f; float tubeSigma2 = protect ? param.rec.tpc.tubeProtectSigma2 : param.rec.tpc.tubeRemoveSigma2; uint32_t pad = CAMath::Float2UIntRn(GPUTPCGeometry::LinearY2Pad(sector, iRow, uncorrectedY)); - float time = Merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->InverseTransformInTimeFrame(sector, uncorrectedZ + (param.par.continuousTracking ? Merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(sector, mTOffset, param.continuousMaxTimeBin) : 0), param.continuousMaxTimeBin); // TODO: Simplify this call in TPCFastTransform + float time = Merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->InverseTransformInTimeFrame(sector, uncorrectedZ + (param.par.continuousTracking ? Merger->GetConstantMem()->calibObjects.fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(mTOffset, param.continuousMaxTimeBin) : 0), param.continuousMaxTimeBin); // TODO: Simplify this call in TPCFastTransform if (iRow < param.rec.tpc.tubeExtraProtectMinRow || pad < param.rec.tpc.tubeExtraProtectEdgePads || pad >= (uint32_t)(GPUTPCGeometry::NPads(iRow) - param.rec.tpc.tubeExtraProtectEdgePads) || param.GetUnscaledMult(time) / GPUTPCGeometry::Row2X(iRow) > param.rec.tpc.tubeExtraProtectMinOccupancy) { diff --git a/GPU/GPUTracking/display/render/GPUDisplayDraw.cxx b/GPU/GPUTracking/display/render/GPUDisplayDraw.cxx index 6447d30daefe3..322ac61483cb6 100644 --- a/GPU/GPUTracking/display/render/GPUDisplayDraw.cxx +++ b/GPU/GPUTracking/display/render/GPUDisplayDraw.cxx @@ -556,12 +556,12 @@ void GPUDisplay::DrawFinal(int32_t iSector, int32_t /*iCol*/, const GPUTPCGMProp auto cl = mIOPtrs->mergedTrackHits[track->FirstClusterRef() + lastCluster]; const auto& cln = mIOPtrs->clustersNative->clustersLinear[cl.num]; GPUTPCConvertImpl::convert(*mCalib->fastTransform, *mParam, cl.sector, cl.row, cln.getPad(), cln.getTime(), x, y, z); - ZOffset = mCalib->fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(iSector, track->GetParam().GetTOffset(), mParam->continuousMaxTimeBin); + ZOffset = mCalib->fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(track->GetParam().GetTOffset(), mParam->continuousMaxTimeBin); } else { uint8_t sector, row; auto cln = track->getCluster(mIOPtrs->outputClusRefsTPCO2, lastCluster, *mIOPtrs->clustersNative, sector, row); GPUTPCConvertImpl::convert(*mCalib->fastTransform, *mParam, sector, row, cln.getPad(), cln.getTime(), x, y, z); - ZOffset = mCalib->fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(sector, track->getTime0(), mParam->continuousMaxTimeBin); + ZOffset = mCalib->fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(track->getTime0(), mParam->continuousMaxTimeBin); } } else { const GPUTPCMCInfo& mc = mIOPtrs->mcInfosTPC[i]; @@ -593,7 +593,7 @@ void GPUDisplay::DrawFinal(int32_t iSector, int32_t /*iCol*/, const GPUTPCGMProp #ifdef GPUCA_TPC_GEOMETRY_O2 trkParam.Set(mclocal[0], mclocal[1], mc.z, mclocal[2], mclocal[3], mc.pZ, -charge); // TODO: DR: unclear to me why we need -charge here if (mParam->par.continuousTracking) { - ZOffset = fabsf(mCalib->fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(0, mc.t0, mParam->continuousMaxTimeBin)) * (mc.z < 0 ? -1 : 1); + ZOffset = fabsf(mCalib->fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(mc.t0, mParam->continuousMaxTimeBin)) * (mc.z < 0 ? -1 : 1); } #else if (fabsf(mc.z) > GPUTPCGeometry::TPCLength()) { diff --git a/GPU/GPUTracking/display/render/GPUDisplayImportEvent.cxx b/GPU/GPUTracking/display/render/GPUDisplayImportEvent.cxx index 9c516ebb960d7..78661a2cd7444 100644 --- a/GPU/GPUTracking/display/render/GPUDisplayImportEvent.cxx +++ b/GPU/GPUTracking/display/render/GPUDisplayImportEvent.cxx @@ -180,7 +180,7 @@ void GPUDisplay::DrawGLScene_updateEventData() while (mParam->par.continuousTracking && trdTriggerRecord < (int32_t)mIOPtrs->nTRDTriggerRecords - 1 && mIOPtrs->trdTrackletIdxFirst[trdTriggerRecord + 1] <= i) { trdTriggerRecord++; // This requires to go through the data in order I believe float trdTime = mIOPtrs->trdTriggerTimes[trdTriggerRecord] * 1e3 / o2::constants::lhc::LHCBunchSpacingNS / o2::tpc::constants::LHCBCPERTIMEBIN; - trdZoffset = fabsf(mCalib->fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(0, trdTime, mParam->continuousMaxTimeBin)); + trdZoffset = fabsf(mCalib->fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(trdTime, mParam->continuousMaxTimeBin)); } const auto& sp = mIOPtrs->trdSpacePoints[i]; int32_t iSec = trdGeometry()->GetSector(mIOPtrs->trdTracklets[i].GetDetector()); @@ -218,7 +218,7 @@ void GPUDisplay::DrawGLScene_updateEventData() float ZOffset = 0; if (mParam->par.continuousTracking) { float tofTime = mIOPtrs->tofClusters[i].getTime() * 1e-3 / o2::constants::lhc::LHCBunchSpacingNS / o2::tpc::constants::LHCBCPERTIMEBIN; - ZOffset = fabsf(mCalib->fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(0, tofTime, mParam->continuousMaxTimeBin)); + ZOffset = fabsf(mCalib->fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(tofTime, mParam->continuousMaxTimeBin)); ptr->z += ptr->z > 0 ? ZOffset : -ZOffset; } if (fabsf(ptr->z) > maxClusterZ) { @@ -249,7 +249,7 @@ void GPUDisplay::DrawGLScene_updateEventData() if (mParam->par.continuousTracking) { o2::InteractionRecord startIR = o2::InteractionRecord(0, mIOPtrs->settingsTF && mIOPtrs->settingsTF->hasTfStartOrbit ? mIOPtrs->settingsTF->tfStartOrbit : 0); float itsROFtime = mIOPtrs->itsClusterROF[j].getBCData().differenceInBC(startIR) / (float)o2::tpc::constants::LHCBCPERTIMEBIN; - ZOffset = fabsf(mCalib->fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(0, itsROFtime + itsROFhalfLen, mParam->continuousMaxTimeBin)); + ZOffset = fabsf(mCalib->fastTransformHelper->getCorrMap()->convVertexTimeToZOffset(itsROFtime + itsROFhalfLen, mParam->continuousMaxTimeBin)); } if (i != mIOPtrs->itsClusterROF[j].getFirstEntry()) { throw std::runtime_error("Inconsistent ITS data, number of clusters does not match ROF content"); diff --git a/GPU/TPCFastTransformation/Spline1D.h b/GPU/TPCFastTransformation/Spline1D.h index ccadaeed23b79..c7a4d927dec1d 100644 --- a/GPU/TPCFastTransformation/Spline1D.h +++ b/GPU/TPCFastTransformation/Spline1D.h @@ -77,7 +77,7 @@ namespace gpu /// One can store all F-dependent spline parameters outside of the spline object /// and provide them at each interpolation call. /// To do so, create a spline with nYdimensions=0; create spline parameters for F via Spline1DHelper class; -/// then use special interpolateU(..) methods for the interpolation. +/// then use special interpolateAtU(..) methods for the interpolation. /// /// This feature allows one to use the same spline object for the approximation of different functions /// on the same grid of knots. diff --git a/GPU/TPCFastTransformation/Spline1DSpec.h b/GPU/TPCFastTransformation/Spline1DSpec.h index 6462f291d1136..d72de5a446718 100644 --- a/GPU/TPCFastTransformation/Spline1DSpec.h +++ b/GPU/TPCFastTransformation/Spline1DSpec.h @@ -287,32 +287,52 @@ class Spline1DSpec : public Spline1DContainer /// Get interpolated value S(x) GPUd() void interpolate(DataT x, GPUgeneric() DataT S[/*mYdim*/]) const { - interpolateU(mYdim, mParameters, convXtoU(x), S); + interpolateAtU(mYdim, mParameters, convXtoU(x), S); } /// Get interpolated value for an nYdim-dimensional S(u) using spline parameters Parameters. template - GPUd() void interpolateU(int32_t inpYdim, GPUgeneric() const DataT Parameters[], - DataT u, GPUgeneric() DataT S[/*nYdim*/]) const + GPUd() void interpolateAtU(int32_t inpYdim, GPUgeneric() const DataT Parameters[], + DataT u, GPUgeneric() DataT S[/*nYdim*/]) const { const auto nYdimTmp = SplineUtil::getNdim(inpYdim); const auto nYdim = nYdimTmp.get(); int32_t iknot = TBase::template getLeftKnotIndexForU(u); const DataT* d = Parameters + (2 * nYdim) * iknot; - interpolateU(nYdim, getKnots()[iknot], &(d[0]), &(d[nYdim]), &(d[2 * nYdim]), &(d[3 * nYdim]), u, S); + interpolateAtU(nYdim, getKnots()[iknot], &(d[0]), &(d[nYdim]), &(d[2 * nYdim]), &(d[3 * nYdim]), u, S); } /// The main mathematical utility. /// Get interpolated value {S(u): 1D -> nYdim} at the segment [knotL, next knotR] /// using the spline values Sl, Sr and the slopes Dl, Dr template - GPUd() void interpolateU(int32_t inpYdim, const Knot& knotL, - GPUgeneric() const T Sl[/*mYdim*/], GPUgeneric() const T Dl[/*mYdim*/], - GPUgeneric() const T Sr[/*mYdim*/], GPUgeneric() const T Dr[/*mYdim*/], - DataT u, GPUgeneric() T S[/*mYdim*/]) const + GPUd() void interpolateAtU(int32_t inpYdim, const Knot& knotL, + GPUgeneric() const T Sl[/*mYdim*/], GPUgeneric() const T Dl[/*mYdim*/], + GPUgeneric() const T Sr[/*mYdim*/], GPUgeneric() const T Dr[/*mYdim*/], + DataT u, GPUgeneric() T S[/*mYdim*/]) const { const auto nYdimTmp = SplineUtil::getNdim(inpYdim); const auto nYdim = nYdimTmp.get(); + + auto val = getSderivativesOverParsAtU(knotL, u); + const auto& dSdSl = val[0]; + const auto& dSdDl = val[1]; + const auto& dSdSr = val[2]; + const auto& dSdDr = val[3]; + for (int32_t dim = 0; dim < nYdim; ++dim) { + S[dim] = dSdSr * Sr[dim] + dSdSl * Sl[dim] + dSdDl * Dl[dim] + dSdDr * Dr[dim]; + } + + /* + another way to calculate f(u): + + if (u < (DataT)0) { + u = (DataT)0; + } + if (u > (DataT)TBase::getUmax()) { + u = (DataT)TBase::getUmax(); + } + T uu = T(u - knotL.u); T li = T(knotL.Li); T v = uu * li; // scaled u @@ -322,36 +342,66 @@ class Spline1DSpec : public Spline1DContainer T b = df - Dl[dim] - a; S[dim] = ((a * v + b) * v + Dl[dim]) * uu + Sl[dim]; } - /* - another way to calculate f(u): - T uu = T(u - knotL.u); - T v = uu * T(knotL.Li); // scaled u - T vm1 = v-1; - T v2 = v * v; - float cSr = v2*(3-2*v); - float cSl = 1-cSr; - float cDl = v*vm1*vm1*knotL.L; - float cDr = v2*vm1*knotL.L; - return cSl*Sl + cSr*Sr + cDl*Dl + cDr*Dr; */ } template - GPUd() static void getUderivatives(const Knot& knotL, DataT u, - T& dSl, T& dDl, T& dSr, T& dDr) + GPUd() std::array getSderivativesOverParsAtU(const Knot& knotL, DataT u) const + { + /// Get derivatives of the interpolated value {S(u): 1D -> nYdim} at the segment [knotL, next knotR] + /// over the spline parameters Sl(eft), Sr(ight) and the slopes Dl, Dr + + if (u < (DataT)0) { + u = (DataT)0; + } + if (u > (DataT)TBase::getUmax()) { + u = (DataT)TBase::getUmax(); + } + + u = u - knotL.u; + T v = u * T(knotL.Li); // scaled u + T vm1 = v - T(1.); + T a = u * vm1; + T v2 = v * v; + T dSdSr = v2 * (T(3.) - v - v); + T dSdSl = T(1.) - dSdSr; + T dSdDl = vm1 * a; + T dSdDr = v * a; + // S(u) = dSdSl * Sl + dSdSr * Sr + dSdDl * Dl + dSdDr * Dr; + return {dSdSl, dSdDl, dSdSr, dSdDr}; + } + + template + GPUd() std::array getSDderivativesOverParsAtU(const Knot& knotL, DataT u) const { /// Get derivatives of the interpolated value {S(u): 1D -> nYdim} at the segment [knotL, next knotR] /// over the spline values Sl, Sr and the slopes Dl, Dr + + if (u < (DataT)0) { + u = (DataT)0; + } + if (u > (DataT)TBase::getUmax()) { + u = (DataT)TBase::getUmax(); + } + u = u - knotL.u; T v = u * T(knotL.Li); // scaled u - T vm1 = v - 1.; + T vm1 = v - T(1.); T a = u * vm1; T v2 = v * v; - dSr = v2 * (3. - 2 * v); - dSl = 1. - dSr; - dDl = vm1 * a; - dDr = v * a; - // F(u) = dSl * Sl + dSr * Sr + dDl * Dl + dDr * Dr; + T dSdSr = v2 * (T(3.) - v - v); + T dSdSl = T(1.) - dSdSr; + T dSdDl = vm1 * a; + T dSdDr = v * a; + + T dv = T(knotL.Li); + T dDdSr = 6. * v * (T(1.) - v) * dv; + T dDdSl = -dDdSr; + T dDdDl = vm1 * (v + v + vm1); + T dDdDr = v * (v + vm1 + vm1); + // S(u) = dSdSl * Sl + dSdSr * Sr + dSdDl * Dl + dSdDr * Dr; + // D(u) = dS(u)/du = dDdSl * Sl + dDdSr * Sr + dDdDl * Dl + dDdDr * Dr; + return {dSdSl, dSdDl, dSdSr, dSdDr, dDdSl, dDdDl, dDdSr, dDdDr}; } using TBase::convXtoU; @@ -430,21 +480,21 @@ class Spline1DSpec /// Get interpolated value for an YdimT-dimensional S(u) using spline parameters Parameters. template - GPUd() void interpolateU(GPUgeneric() const DataT Parameters[], - DataT u, GPUgeneric() DataT S[/*nYdim*/]) const + GPUd() void interpolateAtU(GPUgeneric() const DataT Parameters[], + DataT u, GPUgeneric() DataT S[/*nYdim*/]) const { - TBase::template interpolateU(YdimT, Parameters, u, S); + TBase::template interpolateAtU(YdimT, Parameters, u, S); } /// Get interpolated value for an YdimT-dimensional S(u) at the segment [knotL, next knotR] /// using the spline values Sl, Sr and the slopes Dl, Dr template - GPUd() void interpolateU(const typename TBase::Knot& knotL, - GPUgeneric() const T Sl[/*mYdim*/], GPUgeneric() const T Dl[/*mYdim*/], - GPUgeneric() const T Sr[/*mYdim*/], GPUgeneric() const T Dr[/*mYdim*/], - DataT u, GPUgeneric() T S[/*mYdim*/]) const + GPUd() void interpolateAtU(const typename TBase::Knot& knotL, + GPUgeneric() const T Sl[/*mYdim*/], GPUgeneric() const T Dl[/*mYdim*/], + GPUgeneric() const T Sr[/*mYdim*/], GPUgeneric() const T Dr[/*mYdim*/], + DataT u, GPUgeneric() T S[/*mYdim*/]) const { - TBase::interpolateU(YdimT, knotL, Sl, Dl, Sr, Dr, u, S); + TBase::interpolateAtU(YdimT, knotL, Sl, Dl, Sr, Dr, u, S); } using TBase::getNumberOfKnots; @@ -454,7 +504,7 @@ class Spline1DSpec #if !defined(GPUCA_GPUCODE) using TBase::recreate; #endif - using TBase::interpolateU; + using TBase::interpolateAtU; }; /// ================================================================================================== @@ -502,7 +552,7 @@ class Spline1DSpec /// _______ Expert tools: interpolation with given nYdim and external Parameters _______ - using TBase::interpolateU; + using TBase::interpolateAtU; ClassDefNV(Spline1DSpec, 0); }; diff --git a/GPU/TPCFastTransformation/Spline2DHelper.cxx b/GPU/TPCFastTransformation/Spline2DHelper.cxx index 03ecf4a3f1707..a93e753942dce 100644 --- a/GPU/TPCFastTransformation/Spline2DHelper.cxx +++ b/GPU/TPCFastTransformation/Spline2DHelper.cxx @@ -194,7 +194,7 @@ void Spline2DHelper::approximateFunction( for (int32_t ipu = 0; ipu < nDataPointsU; ipu++) { double splineF[Ndim]; double u = mHelperU1.getDataPoint(ipu).u; - mHelperU1.getSpline().interpolateU(Ndim, parUdbl.get(), u, splineF); + mHelperU1.getSpline().interpolateAtU(Ndim, parUdbl.get(), u, splineF); for (int32_t dim = 0; dim < Ndim; dim++) { rotDataPointF[(ipu * nDataPointsV + ipv) * Ndim + dim] = splineF[dim]; } @@ -241,6 +241,7 @@ void Spline2DHelper::approximateFunctionViaDataPoints( mFdimensions = spline.getYdimensions(); std::vector dataPointX1(getNumberOfDataPoints()); std::vector dataPointX2(getNumberOfDataPoints()); + std::vector dataPointWeight(getNumberOfDataPoints(), 1.); std::vector dataPointF(getNumberOfDataPoints() * mFdimensions); double scaleX1 = (x1Max - x1Min) / ((double)mHelperU1.getSpline().getUmax()); @@ -256,7 +257,8 @@ void Spline2DHelper::approximateFunctionViaDataPoints( F(x1, x2, &dataPointF[ind * mFdimensions]); } } - approximateDataPoints(spline, spline.getParameters(), x1Min, x1Max, x2Min, x2Max, &dataPointX1[0], &dataPointX2[0], &dataPointF[0], getNumberOfDataPoints()); + approximateDataPoints(spline, spline.getParameters(), x1Min, x1Max, x2Min, x2Max, dataPointX1.data(), dataPointX2.data(), dataPointF.data(), + dataPointWeight.data(), getNumberOfDataPoints()); } template @@ -326,7 +328,7 @@ template void Spline2DHelper::approximateDataPoints( Spline2DContainer& spline, DataT* splineParameters, double x1Min, double x1Max, double x2Min, double x2Max, const double dataPointX1[], const double dataPointX2[], const double dataPointF[/*getNumberOfDataPoints() x nFdim*/], - int32_t nDataPoints) + const double dataPointWeight[], int32_t nDataPoints) { /// Create best-fit spline parameters for a given input function F @@ -343,6 +345,10 @@ void Spline2DHelper::approximateDataPoints( for (int32_t iPoint = 0; iPoint < nDataPoints; ++iPoint) { double u = fGridU.convXtoU(dataPointX1[iPoint]); double v = fGridV.convXtoU(dataPointX2[iPoint]); + double weight = dataPointWeight[iPoint]; + if (!(weight > 0.)) { + continue; + } int32_t iu = fGridU.getLeftKnotIndexForU(u); int32_t iv = fGridV.getLeftKnotIndexForU(v); double c[16]; @@ -353,14 +359,14 @@ void Spline2DHelper::approximateDataPoints( for (int32_t i = 0; i < 16; i++) { for (int32_t j = i; j < 16; j++) { - solver.A(ind[i], ind[j]) += c[i] * c[j]; + solver.A(ind[i], ind[j]) += weight * c[i] * c[j]; } } for (int32_t iDim = 0; iDim < nFdim; iDim++) { double f = (double)dataPointF[iPoint * nFdim + iDim]; for (int32_t i = 0; i < 16; i++) { - solver.B(ind[i], iDim) += f * c[i]; + solver.B(ind[i], iDim) += weight * f * c[i]; } } } // data points diff --git a/GPU/TPCFastTransformation/Spline2DHelper.h b/GPU/TPCFastTransformation/Spline2DHelper.h index 7195bab925f85..aa52c306a1a53 100644 --- a/GPU/TPCFastTransformation/Spline2DHelper.h +++ b/GPU/TPCFastTransformation/Spline2DHelper.h @@ -74,7 +74,7 @@ class Spline2DHelper void approximateDataPoints( Spline2DContainer& spline, DataT* splineParameters, double x1Min, double x1Max, double x2Min, double x2Max, const double dataPointX1[/*nDataPoints*/], const double dataPointX2[/*nDataPoints*/], - const double dataPointF[/*nDataPoints x spline.getYdimensions*/], int32_t nDataPoints); + const double dataPointF[/*nDataPoints x spline.getYdimensions*/], const double dataPointWeight[/*nDataPoints*/], int32_t nDataPoints); /// _______________ Interface for a step-wise construction of the best-fit spline ________________________ diff --git a/GPU/TPCFastTransformation/Spline2DSpec.cxx b/GPU/TPCFastTransformation/Spline2DSpec.cxx index 055530b9314c2..4fbd4dc3d0110 100644 --- a/GPU/TPCFastTransformation/Spline2DSpec.cxx +++ b/GPU/TPCFastTransformation/Spline2DSpec.cxx @@ -29,8 +29,6 @@ #include "Riostream.h" #include "TMath.h" #include "Spline2DHelper.h" -#include "TCanvas.h" -#include "TNtuple.h" #include "TFile.h" #include "GPUCommonMath.h" diff --git a/GPU/TPCFastTransformation/Spline2DSpec.h b/GPU/TPCFastTransformation/Spline2DSpec.h index b4d351e8d0407..5681de2dc5fe9 100644 --- a/GPU/TPCFastTransformation/Spline2DSpec.h +++ b/GPU/TPCFastTransformation/Spline2DSpec.h @@ -239,13 +239,13 @@ class Spline2DSpec /// Get interpolated value S(x) GPUd() void interpolate(DataT x1, DataT x2, GPUgeneric() DataT S[/*mYdim*/]) const { - interpolateU(mYdim, mParameters, mGridX1.convXtoU(x1), mGridX2.convXtoU(x2), S); + interpolateAtU(mYdim, mParameters, mGridX1.convXtoU(x1), mGridX2.convXtoU(x2), S); } /// Get interpolated value for an inpYdim-dimensional S(u1,u2) using spline parameters Parameters. template - GPUd() void interpolateUold(int32_t inpYdim, GPUgeneric() const DataT Parameters[], - DataT u1, DataT u2, GPUgeneric() DataT S[/*inpYdim*/]) const + GPUd() void interpolateAtUold(int32_t inpYdim, GPUgeneric() const DataT Parameters[], + DataT u1, DataT u2, GPUgeneric() DataT S[/*inpYdim*/]) const { const auto nYdimTmp = SplineUtil::getNdim(inpYdim); @@ -295,7 +295,7 @@ class Spline2DSpec typedef Spline1DSpec TGridX1; const TGridX1& gridX1 = reinterpret_cast(mGridX1); - gridX1.interpolateU(nYdim4, knotU, Su0, Du0, Su1, Du1, u, parU); + gridX1.interpolateAtU(nYdim4, knotU, Su0, Du0, Su1, Du1, u, parU); const DataT* Sv0 = parU + 0; const DataT* Dv0 = parU + nYdim; @@ -304,13 +304,13 @@ class Spline2DSpec typedef Spline1DSpec TGridX2; const TGridX2& gridX2 = reinterpret_cast(mGridX2); - gridX2.interpolateU(nYdim, knotV, Sv0, Dv0, Sv1, Dv1, v, S); + gridX2.interpolateAtU(nYdim, knotV, Sv0, Dv0, Sv1, Dv1, v, S); } /// Get interpolated value for an inpYdim-dimensional S(u1,u2) using spline parameters Parameters. template - GPUd() void interpolateU(int32_t inpYdim, GPUgeneric() const DataT Parameters[], - DataT u1, DataT u2, GPUgeneric() DataT S[/*inpYdim*/]) const + GPUd() void interpolateAtU(int32_t inpYdim, GPUgeneric() const DataT Parameters[], + DataT u1, DataT u2, GPUgeneric() DataT S[/*inpYdim*/]) const { const auto nYdimTmp = SplineUtil::getNdim(inpYdim); @@ -334,10 +334,16 @@ class Spline2DSpec const DataT* A = Parameters + (nu * iv + iu) * nYdim4; // values { {Y1,Y2,Y3}, {Y1,Y2,Y3}'v, {Y1,Y2,Y3}'u, {Y1,Y2,Y3}''vu } at {u0, v0} const DataT* B = A + nYdim4 * nu; // values { ... } at {u0, v1} - DataT dSl, dDl, dSr, dDr; - mGridX1.getUderivatives(knotU, u, dSl, dDl, dSr, dDr); - DataT dSd, dDd, dSu, dDu; - mGridX2.getUderivatives(knotV, v, dSd, dDd, dSu, dDu); + auto val1 = mGridX1.template getSderivativesOverParsAtU(knotU, u); + auto val2 = mGridX2.template getSderivativesOverParsAtU(knotV, v); + const auto& dSl = val1[0]; + const auto& dDl = val1[1]; + const auto& dSr = val1[2]; + const auto& dDr = val1[3]; + const auto& dSd = val2[0]; + const auto& dDd = val2[1]; + const auto& dSu = val2[2]; + const auto& dDu = val2[3]; // when nYdim == 1: // S = dSl * (dSd * A[0] + dDd * A[1]) + dDl * (dSd * A[2] + dDd * A[3]) + @@ -360,6 +366,132 @@ class Spline2DSpec } } + /// Get interpolated parameters (like parameters stored at knots) for an inpYdim-dimensional S(u1,u2) using spline parameters Parameters. + template + GPUd() void interpolateParametersAtU(int32_t inpYdim, GPUgeneric() const DataT Parameters[], + DataT u1, DataT u2, GPUgeneric() DataT P[/* 4*inpYdim */]) const + { + + const auto nYdimTmp = SplineUtil::getNdim(inpYdim); + const int32_t nYdim = nYdimTmp.get(); + + // const auto maxYdim = SplineUtil::getMaxNdim(inpYdim); + // const int32_t maxYdim4 = 4 * maxYdim.get(); + + // const auto nYdim2 = nYdim * 2; + const auto nYdim4 = nYdim * 4; + + DataT *S = P, + *Q = P + nYdim, + *R = P + nYdim * 2, + *W = P + nYdim * 3; + + const DataT& u = u1; + const DataT& v = u2; + int32_t nu = mGridX1.getNumberOfKnots(); + int32_t iu = mGridX1.template getLeftKnotIndexForU(u); + int32_t iv = mGridX2.template getLeftKnotIndexForU(v); + + const typename TBase::Knot& knotU = mGridX1.template getKnot(iu); + const typename TBase::Knot& knotV = mGridX2.template getKnot(iv); + + const DataT* A = Parameters + (nu * iv + iu) * nYdim4; // values { {Y1,Y2,Y3}, {Y1,Y2,Y3}'v, {Y1,Y2,Y3}'u, {Y1,Y2,Y3}''vu } at {u0, v0} + const DataT* B = A + nYdim4 * nu; // values { ... } at {u0, v1} + + auto [dSdSl, dSdDl, dSdSr, dSdDr, dRdSl, dRdDl, dRdSr, dRdDr] = mGridX1.template getSDderivativesOverParsAtU(knotU, u); + auto [dSdSd, dSdDd, dSdSu, dSdDu, dQdSd, dQdDd, dQdSu, dQdDu] = mGridX2.template getSDderivativesOverParsAtU(knotV, v); + + // when nYdim == 1: + + // Function value S + // S = dSdSl * (dSdSd * A[0] + dSdDd * A[1]) + dSdDl * (dSdSd * A[2] + dSdDd * A[3]) + + // dSdSr * (dSdSd * A[4] + dSdDd * A[5]) + dSdDr * (dSdSd * A[6] + dSdDd * A[7]) + + // dSdSl * (dSdSu * B[0] + dSdDu * B[1]) + dSdDl * (dSdSu * B[2] + dSdDu * B[3]) + + // dSdSr * (dSdSu * B[4] + dSdDu * B[5]) + dSdDr * (dSdSu * B[6] + dSdDu * B[7]); + + { + DataT a[8] = {dSdSl * dSdSd, dSdSl * dSdDd, dSdDl * dSdSd, dSdDl * dSdDd, + dSdSr * dSdSd, dSdSr * dSdDd, dSdDr * dSdSd, dSdDr * dSdDd}; + DataT b[8] = {dSdSl * dSdSu, dSdSl * dSdDu, dSdDl * dSdSu, dSdDl * dSdDu, + dSdSr * dSdSu, dSdSr * dSdDu, dSdDr * dSdSu, dSdDr * dSdDu}; + + // S = sum a[i]*A[i] + b[i]*B[i] + + for (int32_t dim = 0; dim < nYdim; dim++) { + S[dim] = 0; + for (int32_t i = 0; i < 8; i++) { + S[dim] += a[i] * A[nYdim * i + dim] + b[i] * B[nYdim * i + dim]; + } + } + } + + // Derivative Q = dS / dv + // Q = dSdSl * (dQdSd * A[0] + dQdDd * A[1]) + dSdDl * (dQdSd * A[2] + dQdDd * A[3]) + + // dSdSr * (dQdSd * A[4] + dQdDd * A[5]) + dSdDr * (dQdSd * A[6] + dQdDd * A[7]) + + // dSdSl * (dQdSu * B[0] + dQdDu * B[1]) + dSdDl * (dQdSu * B[2] + dQdDu * B[3]) + + // dSdSr * (dQdSu * B[4] + dQdDu * B[5]) + dSdDr * (dQdSu * B[6] + dQdDu * B[7]); + + { + DataT a[8] = {dSdSl * dQdSd, dSdSl * dQdDd, dSdDl * dQdSd, dSdDl * dQdDd, + dSdSr * dQdSd, dSdSr * dQdDd, dSdDr * dQdSd, dSdDr * dQdDd}; + DataT b[8] = {dSdSl * dQdSu, dSdSl * dQdDu, dSdDl * dQdSu, dSdDl * dQdDu, + dSdSr * dQdSu, dSdSr * dQdDu, dSdDr * dQdSu, dSdDr * dQdDu}; + + // Q = sum a[i]*A[i] + b[i]*B[i] + + for (int32_t dim = 0; dim < nYdim; dim++) { + Q[dim] = 0; + for (int32_t i = 0; i < 8; i++) { + Q[dim] += a[i] * A[nYdim * i + dim] + b[i] * B[nYdim * i + dim]; + } + } + } + + // Derivative R = dS / du + // R = dRdSl * (dSdSd * A[0] + dSdDd * A[1]) + dRdDl * (dSdSd * A[2] + dSdDd * A[3]) + + // dRdSr * (dSdSd * A[4] + dSdDd * A[5]) + dRdDr * (dSdSd * A[6] + dSdDd * A[7]) + + // dRdSl * (dSdSu * B[0] + dSdDu * B[1]) + dRdDl * (dSdSu * B[2] + dSdDu * B[3]) + + // dRdSr * (dSdSu * B[4] + dSdDu * B[5]) + dRdDr * (dSdSu * B[6] + dSdDu * B[7]); + + { + DataT a[8] = {dRdSl * dSdSd, dRdSl * dSdDd, dRdDl * dSdSd, dRdDl * dSdDd, + dRdSr * dSdSd, dRdSr * dSdDd, dRdDr * dSdSd, dRdDr * dSdDd}; + DataT b[8] = {dRdSl * dSdSu, dRdSl * dSdDu, dRdDl * dSdSu, dRdDl * dSdDu, + dRdSr * dSdSu, dRdSr * dSdDu, dRdDr * dSdSu, dRdDr * dSdDu}; + + // R = sum a[i]*A[i] + b[i]*B[i] + + for (int32_t dim = 0; dim < nYdim; dim++) { + R[dim] = 0; + for (int32_t i = 0; i < 8; i++) { + R[dim] += a[i] * A[nYdim * i + dim] + b[i] * B[nYdim * i + dim]; + } + } + } + + // cross-derivative W = (dS)^2 / du / dv + // W = dRdSl * (dQdSd * A[0] + dQdDd * A[1]) + dRdDl * (dQdSd * A[2] + dQdDd * A[3]) + + // dRdSr * (dQdSd * A[4] + dQdDd * A[5]) + dRdDr * (dQdSd * A[6] + dQdDd * A[7]) + + // dRdSl * (dQdSu * B[0] + dQdDu * B[1]) + dRdDl * (dQdSu * B[2] + dQdDu * B[3]) + + // dRdSr * (dQdSu * B[4] + dQdDu * B[5]) + dRdDr * (dQdSu * B[6] + dQdDu * B[7]); + + { + DataT a[8] = {dRdSl * dQdSd, dRdSl * dQdDd, dRdDl * dQdSd, dRdDl * dQdDd, + dRdSr * dQdSd, dRdSr * dQdDd, dRdDr * dQdSd, dRdDr * dQdDd}; + DataT b[8] = {dRdSl * dQdSu, dRdSl * dQdDu, dRdDl * dQdSu, dRdDl * dQdDu, + dRdSr * dQdSu, dRdSr * dQdDu, dRdDr * dQdSu, dRdDr * dQdDu}; + + // W = sum a[i]*A[i] + b[i]*B[i] + + for (int32_t dim = 0; dim < nYdim; dim++) { + W[dim] = 0; + for (int32_t i = 0; i < 8; i++) { + W[dim] += a[i] * A[nYdim * i + dim] + b[i] * B[nYdim * i + dim]; + } + } + } + } + protected: using TBase::mGridX1; using TBase::mGridX2; @@ -430,18 +562,25 @@ class Spline2DSpec /// Get interpolated value for an YdimT-dimensional S(u1,u2) using spline parameters Parameters. template - GPUd() void interpolateU(GPUgeneric() const DataT Parameters[], - DataT u1, DataT u2, GPUgeneric() DataT S[/*nYdim*/]) const + GPUd() void interpolateAtU(GPUgeneric() const DataT Parameters[], + DataT u1, DataT u2, GPUgeneric() DataT S[/*YdimT*/]) const + { + TBase::template interpolateAtU(YdimT, Parameters, u1, u2, S); + } + + template + GPUd() void interpolateParametersAtU(GPUgeneric() const DataT Parameters[], + DataT u1, DataT u2, GPUgeneric() DataT P[/* 4*YdimT */]) const { - TBase::template interpolateU(YdimT, Parameters, u1, u2, S); + TBase::template interpolateParametersAtU(YdimT, Parameters, u1, u2, P); } /// Get interpolated value for an YdimT-dimensional S(u1,u2) using spline parameters Parameters. template - GPUd() void interpolateUold(GPUgeneric() const DataT Parameters[], - DataT u1, DataT u2, GPUgeneric() DataT S[/*nYdim*/]) const + GPUd() void interpolateAtUold(GPUgeneric() const DataT Parameters[], + DataT u1, DataT u2, GPUgeneric() DataT S[/*nYdim*/]) const { - TBase::template interpolateUold(YdimT, Parameters, u1, u2, S); + TBase::template interpolateAtUold(YdimT, Parameters, u1, u2, S); } using TBase::getNumberOfKnots; @@ -451,7 +590,7 @@ class Spline2DSpec #if !defined(GPUCA_GPUCODE) using TBase::recreate; #endif - using TBase::interpolateU; + using TBase::interpolateAtU; }; /// ================================================================================================== @@ -507,7 +646,7 @@ class Spline2DSpec /// _______ Expert tools: interpolation with given nYdim and external Parameters _______ - using TBase::interpolateU; + using TBase::interpolateAtU; }; /// ================================================================================================== diff --git a/GPU/TPCFastTransformation/SplineHelper.cxx b/GPU/TPCFastTransformation/SplineHelper.cxx index 6e1b53510e0d0..af3efb1c4817d 100644 --- a/GPU/TPCFastTransformation/SplineHelper.cxx +++ b/GPU/TPCFastTransformation/SplineHelper.cxx @@ -410,8 +410,8 @@ void SplineHelper::approximateFunction( } double splineF[mFdimensions]; double u = mHelpers[dimension].getDataPoint(i).u; - mHelpers[dimension].getSpline().interpolateU(mFdimensions, parD[dimension].get(), u, splineF); // recalculate at all datapoints of dimension - for (int32_t dim = 0; dim < mFdimensions; dim++) { // writing it in allParameters + mHelpers[dimension].getSpline().interpolateAtU(mFdimensions, parD[dimension].get(), u, splineF); // recalculate at all datapoints of dimension + for (int32_t dim = 0; dim < mFdimensions; dim++) { // writing it in allParameters // LOG(info)< : public SplineContainer for (int32_t i = 0; i < nXdim; i++) { u[i] = mGrid[i].convXtoU(x[i]); } - interpolateU(mXdim, mYdim, mParameters, u, S); + interpolateAtU(mXdim, mYdim, mParameters, u, S); } /// Get interpolated value for S(u):inpXdim->inpYdim using spline parameters Parameters template - GPUd() void interpolateU(int32_t inpXdim, int32_t inpYdim, GPUgeneric() const DataT Parameters[], - const DataT u[/*inpXdim*/], GPUgeneric() DataT S[/*inpYdim*/]) const + GPUd() void interpolateAtU(int32_t inpXdim, int32_t inpYdim, GPUgeneric() const DataT Parameters[], + const DataT u[/*inpXdim*/], GPUgeneric() DataT S[/*inpYdim*/]) const { const auto nXdimTmp = SplineUtil::getNdim(mXdim); const auto nXdim = nXdimTmp.get(); @@ -345,7 +345,7 @@ class SplineSpec : public SplineContainer DataT coordinate = u[d]; typedef Spline1DSpec TGridX; const TGridX& gridX = *((const TGridX*)&(mGrid[d])); - gridX.interpolateU(nInterpolations, knotL, S0, D0, S1, D1, coordinate, iParameters); + gridX.interpolateAtU(nInterpolations, knotL, S0, D0, S1, D1, coordinate, iParameters); nInterpolations /= 4; nKnots /= 2; } // end d (every dimension) @@ -354,7 +354,7 @@ class SplineSpec : public SplineContainer S[i] = iParameters[i]; // write into result-array // LOG(info)< /// Get interpolated value for an YdimT-dimensional S(u1,u2) using spline parameters Parameters. template - GPUd() void interpolateU(GPUgeneric() const DataT Parameters[], - const DataT u[/*XdimT*/], GPUgeneric() DataT S[/*YdimT*/]) const + GPUd() void interpolateAtU(GPUgeneric() const DataT Parameters[], + const DataT u[/*XdimT*/], GPUgeneric() DataT S[/*YdimT*/]) const { - TBase::template interpolateU(XdimT, YdimT, Parameters, u, S); + TBase::template interpolateAtU(XdimT, YdimT, Parameters, u, S); } /// _______________ Suppress some parent class methods ________________________ @@ -432,7 +432,7 @@ class SplineSpec #if !defined(GPUCA_GPUCODE) using TBase::recreate; #endif - using TBase::interpolateU; + using TBase::interpolateAtU; }; /// ================================================================================================== @@ -490,7 +490,7 @@ class SplineSpec /// _______ Expert tools: interpolation with given nYdim and external Parameters _______ - using TBase::interpolateU; + using TBase::interpolateAtU; /// Check dimensions void checkDimensions(int32_t& nXdim, int32_t& nYdim) diff --git a/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrection.cxx b/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrection.cxx index 5a7dffd2a753b..5f39e749f73d9 100644 --- a/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrection.cxx +++ b/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrection.cxx @@ -19,6 +19,7 @@ #if !defined(GPUCA_GPUCODE) #include +#include #include #include "Spline2DHelper.h" #endif @@ -29,15 +30,12 @@ ClassImp(TPCFastSpaceChargeCorrection); TPCFastSpaceChargeCorrection::TPCFastSpaceChargeCorrection() : FlatObject(), - mConstructionRowInfos(nullptr), mConstructionScenarios(nullptr), mNumberOfScenarios(0), mScenarioPtr(nullptr), - mRowInfoPtr(nullptr), - mSliceRowInfoPtr(nullptr), mTimeStamp(-1), - mSplineData{nullptr, nullptr, nullptr}, - mSliceDataSizeBytes{0, 0, 0} + mCorrectionData{nullptr, nullptr, nullptr}, + mCorrectionDataSize{0, 0, 0} { // Default Constructor: creates an empty uninitialized object } @@ -52,34 +50,27 @@ void TPCFastSpaceChargeCorrection::releaseConstructionMemory() { // release temporary arrays #if !defined(GPUCA_GPUCODE) - delete[] mConstructionRowInfos; delete[] mConstructionScenarios; #endif - mConstructionRowInfos = nullptr; mConstructionScenarios = nullptr; } void TPCFastSpaceChargeCorrection::destroy() { releaseConstructionMemory(); - mConstructionRowInfos = nullptr; mConstructionScenarios = nullptr; mNumberOfScenarios = 0; - mRowInfoPtr = nullptr; - mSliceRowInfoPtr = nullptr; mScenarioPtr = nullptr; mTimeStamp = -1; for (int32_t is = 0; is < 3; is++) { - mSplineData[is] = nullptr; - mSliceDataSizeBytes[is] = 0; + mCorrectionData[is] = nullptr; + mCorrectionDataSize[is] = 0; } FlatObject::destroy(); } void TPCFastSpaceChargeCorrection::relocateBufferPointers(const char* oldBuffer, char* newBuffer) { - mRowInfoPtr = FlatObject::relocatePointer(oldBuffer, newBuffer, mRowInfoPtr); - mSliceRowInfoPtr = FlatObject::relocatePointer(oldBuffer, newBuffer, mSliceRowInfoPtr); mScenarioPtr = FlatObject::relocatePointer(oldBuffer, newBuffer, mScenarioPtr); for (int32_t i = 0; i < mNumberOfScenarios; i++) { @@ -87,9 +78,9 @@ void TPCFastSpaceChargeCorrection::relocateBufferPointers(const char* oldBuffer, char* newSplineBuf = relocatePointer(oldBuffer, newBuffer, sp.getFlatBufferPtr()); sp.setActualBufferAddress(newSplineBuf); } - mSplineData[0] = relocatePointer(oldBuffer, newBuffer, mSplineData[0]); - mSplineData[1] = relocatePointer(oldBuffer, newBuffer, mSplineData[1]); - mSplineData[2] = relocatePointer(oldBuffer, newBuffer, mSplineData[2]); + mCorrectionData[0] = relocatePointer(oldBuffer, newBuffer, mCorrectionData[0]); + mCorrectionData[1] = relocatePointer(oldBuffer, newBuffer, mCorrectionData[1]); + mCorrectionData[2] = relocatePointer(oldBuffer, newBuffer, mCorrectionData[2]); } void TPCFastSpaceChargeCorrection::cloneFromObject(const TPCFastSpaceChargeCorrection& obj, char* newFlatBufferPtr) @@ -110,21 +101,21 @@ void TPCFastSpaceChargeCorrection::cloneFromObject(const TPCFastSpaceChargeCorre mTimeStamp = obj.mTimeStamp; - for (int32_t i = 0; i < TPCFastTransformGeo::getNumberOfSlices(); ++i) { - mSliceInfo[i] = obj.mSliceInfo[i]; - } - - mSliceDataSizeBytes[0] = obj.mSliceDataSizeBytes[0]; - mSliceDataSizeBytes[1] = obj.mSliceDataSizeBytes[1]; - mSliceDataSizeBytes[2] = obj.mSliceDataSizeBytes[2]; + mCorrectionDataSize[0] = obj.mCorrectionDataSize[0]; + mCorrectionDataSize[1] = obj.mCorrectionDataSize[1]; + mCorrectionDataSize[2] = obj.mCorrectionDataSize[2]; // variable-size data - mRowInfoPtr = obj.mRowInfoPtr; - mSliceRowInfoPtr = obj.mSliceRowInfoPtr; mScenarioPtr = obj.mScenarioPtr; - mSplineData[0] = obj.mSplineData[0]; - mSplineData[1] = obj.mSplineData[1]; - mSplineData[2] = obj.mSplineData[2]; + mCorrectionData[0] = obj.mCorrectionData[0]; + mCorrectionData[1] = obj.mCorrectionData[1]; + mCorrectionData[2] = obj.mCorrectionData[2]; + + mClassVersion = obj.mClassVersion; + + for (int32_t i = 0; i < TPCFastTransformGeo::getNumberOfSectors() * TPCFastTransformGeo::getMaxNumberOfRows(); i++) { + mSectorRowInfos[i] = obj.mSectorRowInfos[i]; + } relocateBufferPointers(oldFlatBufferPtr, mFlatBufferPtr); } @@ -138,28 +129,22 @@ void TPCFastSpaceChargeCorrection::moveBufferTo(char* newFlatBufferPtr) relocateBufferPointers(oldFlatBufferPtr, mFlatBufferPtr); } -void TPCFastSpaceChargeCorrection::setActualBufferAddress(char* actualFlatBufferPtr) +void TPCFastSpaceChargeCorrection::setActualBufferAddressOld(char* actualFlatBufferPtr) { - /// Sets the actual location of the external flat buffer after it has been moved (i.e. to another maschine) - - FlatObject::setActualBufferAddress(actualFlatBufferPtr); + /// Sets the actual location of the external flat buffer after it has been moved (e.g. to another maschine) - size_t rowsOffset = 0; - size_t rowsSize = sizeof(RowInfo) * mGeo.getNumberOfRows(); - - mRowInfoPtr = reinterpret_cast(mFlatBufferPtr + rowsOffset); - - size_t sliceRowsOffset = rowsOffset + rowsSize; - size_t sliceRowsSize = sizeof(SliceRowInfo) * mGeo.getNumberOfRows() * mGeo.getNumberOfSlices(); + if (mClassVersion != 4) { + LOG(error) << "TPCFastSpaceChargeCorrection::setActualBufferAddress() called with class version " << mClassVersion << ". This is not supported."; + return; + } - mSliceRowInfoPtr = reinterpret_cast(mFlatBufferPtr + sliceRowsOffset); + FlatObject::setActualBufferAddress(actualFlatBufferPtr); - size_t scOffset = alignSize(sliceRowsOffset + sliceRowsSize, SplineType::getClassAlignmentBytes()); size_t scSize = sizeof(SplineType) * mNumberOfScenarios; - mScenarioPtr = reinterpret_cast(mFlatBufferPtr + scOffset); + mScenarioPtr = reinterpret_cast(mFlatBufferPtr); - size_t scBufferOffset = alignSize(scOffset + scSize, SplineType::getBufferAlignmentBytes()); + size_t scBufferOffset = alignSize(scSize, SplineType::getBufferAlignmentBytes()); size_t scBufferSize = 0; for (int32_t i = 0; i < mNumberOfScenarios; i++) { @@ -169,12 +154,266 @@ void TPCFastSpaceChargeCorrection::setActualBufferAddress(char* actualFlatBuffer } size_t bufferSize = scBufferOffset + scBufferSize; for (int32_t is = 0; is < 3; is++) { - size_t sliceDataOffset = alignSize(bufferSize, SplineType::getParameterAlignmentBytes()); - mSplineData[is] = reinterpret_cast(mFlatBufferPtr + sliceDataOffset); - bufferSize = sliceDataOffset + mSliceDataSizeBytes[is] * mGeo.getNumberOfSlices(); + size_t correctionDataOffset = alignSize(bufferSize, SplineType::getParameterAlignmentBytes()); + mCorrectionData[is] = reinterpret_cast(mFlatBufferPtr + correctionDataOffset); + bufferSize = correctionDataOffset + mCorrectionDataSize[is]; } } +void TPCFastSpaceChargeCorrection::setActualBufferAddress(char* actualFlatBufferPtr) +{ + /// Sets the actual location of the external flat buffer after it has been moved (e.g. to another maschine) + + if (mClassVersion == 4) { + FlatObject::setActualBufferAddress(actualFlatBufferPtr); + + size_t scSize = sizeof(SplineType) * mNumberOfScenarios; + + mScenarioPtr = reinterpret_cast(mFlatBufferPtr); + + size_t scBufferOffset = alignSize(scSize, SplineType::getBufferAlignmentBytes()); + size_t scBufferSize = 0; + + for (int32_t i = 0; i < mNumberOfScenarios; i++) { + SplineType& sp = mScenarioPtr[i]; + sp.setActualBufferAddress(mFlatBufferPtr + scBufferOffset + scBufferSize); + scBufferSize = alignSize(scBufferSize + sp.getFlatBufferSize(), sp.getBufferAlignmentBytes()); + } + size_t bufferSize = scBufferOffset + scBufferSize; + for (int32_t is = 0; is < 3; is++) { + size_t correctionDataOffset = alignSize(bufferSize, SplineType::getParameterAlignmentBytes()); + mCorrectionData[is] = reinterpret_cast(mFlatBufferPtr + correctionDataOffset); + bufferSize = correctionDataOffset + mCorrectionDataSize[is]; + } + return; + } + + if (mClassVersion != 3) { + LOG(fatal) << "TPCFastSpaceChargeCorrection::setActualBufferAddress() called with class version " << mClassVersion << ". This is not supported."; + return; + } + + // Class version 3 + + struct RowInfoVersion3 { + int32_t splineScenarioID{0}; ///< scenario index (which of Spline2D splines to use) + size_t dataOffsetBytes[3]{0}; ///< offset for the spline data withing a TPC sector + }; + + struct RowActiveAreaVersion3 { + float maxDriftLengthCheb[5]{0.f}; + float vMax{0.f}; + float cuMin{0.f}; + float cuMax{0.f}; + float cvMax{0.f}; + }; + + struct SectorRowInfoVersion3 { + float gridV0{0.f}; ///< V coordinate of the V-grid start + float gridCorrU0{0.f}; ///< U coordinate of the U-grid start for corrected U + float gridCorrV0{0.f}; ///< V coordinate of the V-grid start for corrected V + float scaleCorrUtoGrid{0.f}; ///< scale corrected U to U-grid coordinate + float scaleCorrVtoGrid{0.f}; ///< scale corrected V to V-grid coordinate + RowActiveAreaVersion3 activeArea; + }; + + FlatObject::setActualBufferAddress(actualFlatBufferPtr); + + size_t oldRowsOffset = 0; + size_t oldRowsSize = sizeof(RowInfoVersion3) * mGeo.getNumberOfRows(); + + size_t oldSectorRowsOffset = oldRowsOffset + oldRowsSize; + size_t oldSectorRowsSize = sizeof(SectorRowInfoVersion3) * mGeo.getNumberOfRows() * mGeo.getNumberOfSectors(); + + size_t oldScenariosOffset = alignSize(oldSectorRowsOffset + oldSectorRowsSize, SplineType::getClassAlignmentBytes()); + size_t scenariosSize = sizeof(SplineType) * mNumberOfScenarios; + + SplineType* oldScenarioPtr = reinterpret_cast(mFlatBufferPtr + oldScenariosOffset); + + { // copy old-format sector and row parameters from the buffer to the arrays + + auto* oldRowInfos = reinterpret_cast(mFlatBufferPtr + oldRowsOffset); + auto* oldSectorRowInfos = reinterpret_cast(mFlatBufferPtr + oldSectorRowsOffset); + + size_t sectorDataSize[3]; + for (int32_t is = 0; is < 3; is++) { + sectorDataSize[is] = mCorrectionDataSize[is] / mGeo.getNumberOfSectors(); + } + + for (int32_t iSector = 0; iSector < mGeo.getNumberOfSectors(); iSector++) { + + for (int32_t iRow = 0; iRow < mGeo.getNumberOfRows(); iRow++) { + RowInfoVersion3& oldRowInfo = oldRowInfos[iRow]; + SectorRowInfoVersion3& oldSectorRowInfo = oldSectorRowInfos[mGeo.getNumberOfRows() * iSector + iRow]; + + // the spline buffer is not yet initialised, don't try to access knot positions etc + const auto& spline = oldScenarioPtr[oldRowInfo.splineScenarioID]; + + SectorRowInfo& newSectorRow = getSectorRowInfo(iSector, iRow); + + newSectorRow.splineScenarioID = oldRowInfo.splineScenarioID; + for (int32_t is = 0; is < 3; is++) { + newSectorRow.dataOffsetBytes[is] = sectorDataSize[is] * iSector + oldRowInfo.dataOffsetBytes[is]; + } + + { // grid for the measured coordinates + float y0 = mGeo.getRowInfo(iRow).yMin; + float yScale = spline.getGridX1().getUmax() / mGeo.getRowInfo(iRow).getYwidth(); + float zReadout = mGeo.getZreadout(iSector); + float zOut = mGeo.getTPCzLength() - oldSectorRowInfo.gridV0; + float z0 = -3.; + float zScale = spline.getGridX2().getUmax() / (zOut - z0); + if (iSector >= mGeo.getNumberOfSectorsA()) { + zOut = -zOut; + z0 = zOut; + } + newSectorRow.gridMeasured.set(y0, yScale, z0, zScale, zOut, zReadout); + } + + { // grid for the real coordinates + float y0 = oldSectorRowInfo.gridCorrU0; + float yScale = oldSectorRowInfo.scaleCorrUtoGrid; + float zReadout = mGeo.getZreadout(iSector); + float zOut = mGeo.getTPCzLength() - oldSectorRowInfo.gridCorrV0; + float zScale = oldSectorRowInfo.scaleCorrVtoGrid; + float z0 = zOut - spline.getGridX2().getUmax() / zScale; + if (iSector >= mGeo.getNumberOfSectorsA()) { + zOut = -zOut; + z0 = zOut; + } + newSectorRow.gridReal.set(y0, yScale, z0, zScale, zOut, zReadout); + } + + newSectorRow.resetMaxValues(); + newSectorRow.updateMaxValues(-50.f, -50.f, -50.f); + newSectorRow.updateMaxValues(50.f, 50.f, 50.f); + } + } + } + + // move spline scenarios to the new place in the buffer + + mScenarioPtr = reinterpret_cast(mFlatBufferPtr); + memmove((void*)mScenarioPtr, (const void*)oldScenarioPtr, scenariosSize); + + size_t oldScenariosBufferOffset = alignSize(oldScenariosOffset + scenariosSize, SplineType::getBufferAlignmentBytes()); + size_t scenariosBufferOffset = alignSize(scenariosSize, SplineType::getBufferAlignmentBytes()); + + size_t oldScenariosBufferSize = 0; + size_t scenariosBufferSize = 0; + for (int32_t i = 0; i < mNumberOfScenarios; i++) { + SplineType& sp = mScenarioPtr[i]; + char* oldAddress = mFlatBufferPtr + oldScenariosBufferOffset + oldScenariosBufferSize; + char* newAddress = mFlatBufferPtr + scenariosBufferOffset + scenariosBufferSize; + memmove(newAddress, oldAddress, sp.getFlatBufferSize()); + sp.setActualBufferAddress(newAddress); + oldScenariosBufferSize = alignSize(oldScenariosBufferSize + sp.getFlatBufferSize(), sp.getBufferAlignmentBytes()); + scenariosBufferSize = alignSize(scenariosBufferSize + sp.getFlatBufferSize(), sp.getBufferAlignmentBytes()); + } + + size_t oldBufferSize = oldScenariosBufferOffset + oldScenariosBufferSize; + size_t bufferSize = scenariosBufferOffset + scenariosBufferSize; + + // move spline data to the new place in the buffer + + for (int32_t is = 0; is < 3; is++) { + size_t oldCorrectionDataOffset = alignSize(oldBufferSize, SplineType::getParameterAlignmentBytes()); + size_t correctionDataOffset = alignSize(bufferSize, SplineType::getParameterAlignmentBytes()); + mCorrectionData[is] = reinterpret_cast(mFlatBufferPtr + correctionDataOffset); + memmove(mCorrectionData[is], mFlatBufferPtr + oldCorrectionDataOffset, mCorrectionDataSize[is]); + oldBufferSize = oldCorrectionDataOffset + mCorrectionDataSize[is]; + bufferSize = correctionDataOffset + mCorrectionDataSize[is]; + } + + mFlatBufferSize = bufferSize; + + // now convert the spline data to the new format + for (int32_t iSector = 0; iSector < mGeo.getNumberOfSectors(); iSector++) { + bool isAside = (iSector < mGeo.getNumberOfSectorsA()); + for (int32_t iRow = 0; iRow < mGeo.getNumberOfRows(); iRow++) { + + SectorRowInfo& sectorRow = getSectorRowInfo(iSector, iRow); + const auto& spline = mScenarioPtr[sectorRow.splineScenarioID]; + + int nSplineDimensions[3] = {3, 1, 2}; + + for (int iSpline = 0; iSpline < 3; iSpline++) { + int nDim = nSplineDimensions[iSpline]; + int nKnotParameters = 4 * nDim; + auto* data = getCorrectionData(iSector, iRow, iSpline); + + // lambda to swap parameters at two knots + auto swapKnots = [&](int i1, int j1, int i2, int j2) { + auto k1 = spline.getKnotIndex(i1, j1); + auto k2 = spline.getKnotIndex(i2, j2); + for (int ipar = 0; ipar < nKnotParameters; ipar++) { + std::swap(data[nKnotParameters * k1 + ipar], data[nKnotParameters * k2 + ipar]); + } + }; + + // reorder knots for the A side Y == old U, Z == - old V + if (isAside) { + for (int32_t i = 0; i < spline.getGridX1().getNumberOfKnots(); i++) { + for (int32_t j = 0; j < spline.getGridX2().getNumberOfKnots() / 2; j++) { + swapKnots(i, j, i, spline.getGridX2().getNumberOfKnots() - 1 - j); + } + } + } else { // reorder knots for the C side Y == - old U, Z == old V + for (int32_t i = 0; i < spline.getGridX1().getNumberOfKnots() / 2; i++) { + for (int32_t j = 0; j < spline.getGridX2().getNumberOfKnots(); j++) { + swapKnots(i, j, spline.getGridX1().getNumberOfKnots() - 1 - i, j); + } + } + } + + // correct sign of the parameters due to the coordinate swaps + + for (int32_t iKnot = 0; iKnot < spline.getNumberOfKnots(); iKnot++) { + // new grid directions for all corrections + for (int iDim = 0; iDim < nDim; iDim++) { + if (isAside) { + data[nKnotParameters * iKnot + nDim * 1 + iDim] *= -1; // invert Z derivatives on A side + } else { + data[nKnotParameters * iKnot + nDim * 2 + iDim] *= -1; // invert Y derivatives on C side + } + data[nKnotParameters * iKnot + nDim * 3 + iDim] *= -1; // invert cross derivatives on both sides + } + // new correction directions + if (iSpline == 0) { // dX,dU,dV -> dX,dY,dZ + if (isAside) { + data[nKnotParameters * iKnot + nDim * 0 + 2] *= -1; // invert correction in Z + data[nKnotParameters * iKnot + nDim * 1 + 2] *= -1; // invert correction in Z Z-derivative + data[nKnotParameters * iKnot + nDim * 2 + 2] *= -1; // invert correction in Z Y-derivative + data[nKnotParameters * iKnot + nDim * 3 + 2] *= -1; // invert correction in Z cross derivative + } else { + data[nKnotParameters * iKnot + nDim * 0 + 1] *= -1; // invert correction in Y + data[nKnotParameters * iKnot + nDim * 1 + 1] *= -1; // invert correction in Y Z-derivative + data[nKnotParameters * iKnot + nDim * 2 + 1] *= -1; // invert correction in Y Y-derivative + data[nKnotParameters * iKnot + nDim * 3 + 1] *= -1; // invert correction in Y cross derivative + } + } else if (iSpline == 2) { // dU,dV at real U,V -> dY,dZ at real Y,Z + if (isAside) { + data[nKnotParameters * iKnot + nDim * 0 + 1] *= -1; // invert correction in Z + data[nKnotParameters * iKnot + nDim * 1 + 1] *= -1; // invert correction in Z Z-derivative + data[nKnotParameters * iKnot + nDim * 2 + 1] *= -1; // invert correction in Z Y-derivative + data[nKnotParameters * iKnot + nDim * 3 + 1] *= -1; // invert correction in Z cross derivative + } else { + data[nKnotParameters * iKnot + nDim * 0 + 0] *= -1; // invert correction in Y + data[nKnotParameters * iKnot + nDim * 1 + 0] *= -1; // invert correction in Y Z-derivative + data[nKnotParameters * iKnot + nDim * 2 + 0] *= -1; // invert correction in Y Y-derivative + data[nKnotParameters * iKnot + nDim * 3 + 0] *= -1; // invert correction in Y cross derivative + } + } + } + + } // iSpline + } // iRow + } // iSector + + // set the class version to the current one + mClassVersion = 4; +} + void TPCFastSpaceChargeCorrection::setFutureBufferAddress(char* futureFlatBufferPtr) { /// Sets a future location of the external flat buffer before moving it to this location (i.e. when copying to GPU). @@ -187,18 +426,15 @@ void TPCFastSpaceChargeCorrection::setFutureBufferAddress(char* futureFlatBuffer char* oldBuffer = mFlatBufferPtr; char* newBuffer = futureFlatBufferPtr; - mRowInfoPtr = relocatePointer(oldBuffer, newBuffer, mRowInfoPtr); - mSliceRowInfoPtr = relocatePointer(oldBuffer, newBuffer, mSliceRowInfoPtr); - for (int32_t i = 0; i < mNumberOfScenarios; i++) { SplineType& sp = mScenarioPtr[i]; char* newSplineBuf = relocatePointer(oldBuffer, newBuffer, sp.getFlatBufferPtr()); sp.setFutureBufferAddress(newSplineBuf); } mScenarioPtr = relocatePointer(oldBuffer, newBuffer, mScenarioPtr); - mSplineData[0] = relocatePointer(oldBuffer, newBuffer, mSplineData[0]); - mSplineData[1] = relocatePointer(oldBuffer, newBuffer, mSplineData[1]); - mSplineData[2] = relocatePointer(oldBuffer, newBuffer, mSplineData[2]); + mCorrectionData[0] = relocatePointer(oldBuffer, newBuffer, mCorrectionData[0]); + mCorrectionData[1] = relocatePointer(oldBuffer, newBuffer, mCorrectionData[1]); + mCorrectionData[2] = relocatePointer(oldBuffer, newBuffer, mCorrectionData[2]); FlatObject::setFutureBufferAddress(futureFlatBufferPtr); } @@ -209,27 +445,21 @@ void TPCFastSpaceChargeCorrection::print() const mGeo.print(); LOG(info) << " mNumberOfScenarios = " << mNumberOfScenarios; LOG(info) << " mTimeStamp = " << mTimeStamp; - LOG(info) << " mSliceDataSizeBytes = " << mSliceDataSizeBytes[0] << " " << mSliceDataSizeBytes[1] << " " << mSliceDataSizeBytes[2]; - if (mRowInfoPtr) { - LOG(info) << " TPC rows: "; - for (int32_t i = 0; i < mGeo.getNumberOfRows(); i++) { - RowInfo& r = mRowInfoPtr[i]; - LOG(info) << " tpc row " << i << ": splineScenarioID = " << r.splineScenarioID << " dataOffsetBytes = " << r.dataOffsetBytes; - } - } + LOG(info) << " mCorrectionDataSize = " << mCorrectionDataSize[0] << " " << mCorrectionDataSize[1] << " " << mCorrectionDataSize[2]; + if (mScenarioPtr) { for (int32_t i = 0; i < mNumberOfScenarios; i++) { LOG(info) << " SplineScenario " << i << ": "; mScenarioPtr[i].print(); } } - if (mRowInfoPtr && mScenarioPtr && mSliceRowInfoPtr) { + if (mScenarioPtr) { LOG(info) << " Spline Data: "; - for (int32_t is = 0; is < mGeo.getNumberOfSlices(); is++) { + for (int32_t is = 0; is < mGeo.getNumberOfSectors(); is++) { for (int32_t ir = 0; ir < mGeo.getNumberOfRows(); ir++) { - LOG(info) << "slice " << is << " row " << ir << ": "; + LOG(info) << "sector " << is << " row " << ir << ": "; const SplineType& spline = getSpline(is, ir); - const float* d = getSplineData(is, ir); + const float* d = getCorrectionData(is, ir); int32_t k = 0; for (int32_t i = 0; i < spline.getGridX1().getNumberOfKnots(); i++) { for (int32_t j = 0; j < spline.getGridX2().getNumberOfKnots(); j++, k++) { @@ -238,8 +468,8 @@ void TPCFastSpaceChargeCorrection::print() const LOG(info) << ""; } } - // LOG(info) << "inverse correction: slice " << slice - // << " dx " << maxDslice[0] << " du " << maxDslice[1] << " dv " << maxDslice[2] ; + // LOG(info) << "inverse correction: sector " << sector + // << " dx " << maxDsector[0] << " du " << maxDsector[1] << " dv " << maxDsector[2] ; } } } @@ -260,15 +490,27 @@ void TPCFastSpaceChargeCorrection::startConstruction(const TPCFastTransformGeo& releaseConstructionMemory(); #if !defined(GPUCA_GPUCODE) - mConstructionRowInfos = new RowInfo[mGeo.getNumberOfRows()]; mConstructionScenarios = new SplineType[mNumberOfScenarios]; #endif - assert(mConstructionRowInfos != nullptr); assert(mConstructionScenarios != nullptr); - for (int32_t i = 0; i < mGeo.getNumberOfRows(); i++) { - mConstructionRowInfos[i].splineScenarioID = -1; + for (int32_t i = 0; i < mGeo.getNumberOfSectors(); i++) { + for (int32_t j = 0; j < mGeo.getNumberOfRows(); j++) { + auto& row = mSectorRowInfos[mGeo.getMaxNumberOfRows() * i + j]; + row.splineScenarioID = -1; + row.gridReal = {}; + row.gridMeasured = {}; + row.dataOffsetBytes[0] = 0; + row.dataOffsetBytes[1] = 0; + row.dataOffsetBytes[2] = 0; + row.minCorr[0] = 0; + row.minCorr[1] = 0; + row.minCorr[2] = 0; + row.maxCorr[0] = 0; + row.maxCorr[1] = 0; + row.maxCorr[2] = 0; + } } for (int32_t i = 0; i < mNumberOfScenarios; i++) { @@ -277,22 +519,21 @@ void TPCFastSpaceChargeCorrection::startConstruction(const TPCFastTransformGeo& mTimeStamp = -1; - mRowInfoPtr = nullptr; - mSliceRowInfoPtr = nullptr; mScenarioPtr = nullptr; for (int32_t s = 0; s < 3; s++) { - mSplineData[s] = nullptr; - mSliceDataSizeBytes[s] = 0; + mCorrectionData[s] = nullptr; + mCorrectionDataSize[s] = 0; } + mClassVersion = 4; } -void TPCFastSpaceChargeCorrection::setRowScenarioID(int32_t iRow, int32_t iScenario) +void TPCFastSpaceChargeCorrection::setRowScenarioID(int32_t iSector, int32_t iRow, int32_t iScenario) { /// Initializes a TPC row assert(mConstructionMask & ConstructionState::InProgress); + assert(iSector >= 0 && iSector < mGeo.getNumberOfSectors()); assert(iRow >= 0 && iRow < mGeo.getNumberOfRows() && iScenario >= 0 && iScenario < mNumberOfScenarios); - - RowInfo& row = mConstructionRowInfos[iRow]; + auto& row = getSectorRowInfo(iSector, iRow); row.splineScenarioID = iScenario; for (int32_t s = 0; s < 3; s++) { row.dataOffsetBytes[s] = 0; @@ -315,22 +556,21 @@ void TPCFastSpaceChargeCorrection::finishConstruction() assert(mConstructionMask & ConstructionState::InProgress); - for (int32_t i = 0; i < mGeo.getNumberOfRows(); i++) { - assert(mConstructionRowInfos[i].splineScenarioID >= 0); + for (int32_t i = 0; i < mGeo.getNumberOfSectors(); i++) { + for (int32_t j = 0; j < mGeo.getNumberOfRows(); j++) { + SectorRowInfo& row = getSectorRowInfo(i, j); + assert(row.splineScenarioID >= 0); + assert(row.splineScenarioID < mNumberOfScenarios); + } } + for (int32_t i = 0; i < mNumberOfScenarios; i++) { assert(mConstructionScenarios[i].isConstructed()); } // organize memory for the flat buffer and caculate its size - size_t rowsOffset = 0; - size_t rowsSize = sizeof(RowInfo) * mGeo.getNumberOfRows(); - - size_t sliceRowsOffset = rowsSize; - size_t sliceRowsSize = sizeof(SliceRowInfo) * mGeo.getNumberOfRows() * mGeo.getNumberOfSlices(); - - size_t scOffset = alignSize(sliceRowsOffset + sliceRowsSize, SplineType::getClassAlignmentBytes()); + size_t scOffset = 0; size_t scSize = sizeof(SplineType) * mNumberOfScenarios; size_t scBufferOffsets[mNumberOfScenarios]; @@ -343,36 +583,24 @@ void TPCFastSpaceChargeCorrection::finishConstruction() scBufferSize = alignSize(scBufferSize + sp.getFlatBufferSize(), sp.getBufferAlignmentBytes()); } size_t bufferSize = scBufferOffsets[0] + scBufferSize; - size_t sliceDataOffset[3]; + size_t correctionDataOffset[3]; for (int32_t is = 0; is < 3; is++) { - sliceDataOffset[is] = alignSize(bufferSize, SplineType::getParameterAlignmentBytes()); - mSliceDataSizeBytes[is] = 0; - for (int32_t i = 0; i < mGeo.getNumberOfRows(); i++) { - RowInfo& row = mConstructionRowInfos[i]; - SplineType& spline = mConstructionScenarios[row.splineScenarioID]; - row.dataOffsetBytes[is] = alignSize(mSliceDataSizeBytes[is], SplineType::getParameterAlignmentBytes()); - mSliceDataSizeBytes[is] = row.dataOffsetBytes[is] + spline.getSizeOfParameters(); + correctionDataOffset[is] = alignSize(bufferSize, SplineType::getParameterAlignmentBytes()); + mCorrectionDataSize[is] = 0; + for (int32_t i = 0; i < mGeo.getNumberOfSectors(); i++) { + for (int32_t j = 0; j < mGeo.getNumberOfRows(); j++) { + SectorRowInfo& row = getSectorRowInfo(i, j); + SplineType& spline = mConstructionScenarios[row.splineScenarioID]; + row.dataOffsetBytes[is] = alignSize(mCorrectionDataSize[is], SplineType::getParameterAlignmentBytes()); + mCorrectionDataSize[is] = row.dataOffsetBytes[is] + spline.getSizeOfParameters(); + } } - mSliceDataSizeBytes[is] = alignSize(mSliceDataSizeBytes[is], SplineType::getParameterAlignmentBytes()); - bufferSize = sliceDataOffset[is] + mSliceDataSizeBytes[is] * mGeo.getNumberOfSlices(); + mCorrectionDataSize[is] = alignSize(mCorrectionDataSize[is], SplineType::getParameterAlignmentBytes()); + bufferSize = correctionDataOffset[is] + mCorrectionDataSize[is]; } FlatObject::finishConstruction(bufferSize); - mRowInfoPtr = reinterpret_cast(mFlatBufferPtr + rowsOffset); - for (int32_t i = 0; i < mGeo.getNumberOfRows(); i++) { - mRowInfoPtr[i] = mConstructionRowInfos[i]; - } - - mSliceRowInfoPtr = reinterpret_cast(mFlatBufferPtr + sliceRowsOffset); - for (int32_t s = 0; s < mGeo.getNumberOfSlices(); s++) { - for (int32_t r = 0; r < mGeo.getNumberOfRows(); r++) { - mSliceRowInfoPtr[s * mGeo.getNumberOfRows() + r].gridCorrU0 = 0.; - mSliceRowInfoPtr[s * mGeo.getNumberOfRows() + r].scaleCorrUtoGrid = 0.; - mSliceRowInfoPtr[s * mGeo.getNumberOfRows() + r].scaleCorrVtoGrid = 0.; - } - } - mScenarioPtr = reinterpret_cast(mFlatBufferPtr + scOffset); for (int32_t i = 0; i < mNumberOfScenarios; i++) { @@ -383,7 +611,7 @@ void TPCFastSpaceChargeCorrection::finishConstruction() } for (int32_t is = 0; is < 3; is++) { - mSplineData[is] = reinterpret_cast(mFlatBufferPtr + sliceDataOffset[is]); + mCorrectionData[is] = reinterpret_cast(mFlatBufferPtr + correctionDataOffset[is]); } releaseConstructionMemory(); @@ -395,15 +623,13 @@ void TPCFastSpaceChargeCorrection::finishConstruction() GPUd() void TPCFastSpaceChargeCorrection::setNoCorrection() { // initialise all corrections to 0. - for (int32_t slice = 0; slice < mGeo.getNumberOfSlices(); slice++) { - double vLength = (slice < mGeo.getNumberOfSlicesA()) ? mGeo.getTPCzLengthA() : mGeo.getTPCzLengthC(); - SliceInfo& sliceInfo = getSliceInfo(slice); - sliceInfo.vMax = vLength; + for (int32_t sector = 0; sector < mGeo.getNumberOfSectors(); sector++) { + for (int32_t row = 0; row < mGeo.getNumberOfRows(); row++) { - const SplineType& spline = getSpline(slice, row); + const SplineType& spline = getSpline(sector, row); for (int32_t is = 0; is < 3; is++) { - float* data = getSplineData(slice, row, is); + float* data = getCorrectionData(sector, row, is); int32_t nPar = spline.getNumberOfParameters(); if (is == 1) { nPar = nPar / 3; @@ -416,31 +642,28 @@ GPUd() void TPCFastSpaceChargeCorrection::setNoCorrection() } } - SliceRowInfo& info = getSliceRowInfo(slice, row); - RowActiveArea& area = info.activeArea; - for (int32_t i = 1; i < 5; i++) { - area.maxDriftLengthCheb[i] = 0; - } - area.maxDriftLengthCheb[0] = vLength; - area.cuMin = mGeo.convPadToU(row, 0.f); - area.cuMax = -area.cuMin; - area.vMax = vLength; - area.cvMax = vLength; - info.gridV0 = 0.f; - info.gridCorrU0 = area.cuMin; - info.gridCorrV0 = info.gridV0; - info.scaleCorrUtoGrid = spline.getGridX1().getUmax() / (area.cuMax - area.cuMin); - info.scaleCorrVtoGrid = spline.getGridX2().getUmax() / area.cvMax; + SectorRowInfo& info = getSectorRowInfo(sector, row); + + float y0 = mGeo.getRowInfo(row).getYmin(); + float yScale = spline.getGridX1().getUmax() / mGeo.getRowInfo(row).getYwidth(); + float z0 = mGeo.getZmin(sector); + float zScale = spline.getGridX2().getUmax() / mGeo.getTPCzLength(); + float zReadout = mGeo.getZreadout(sector); + info.gridMeasured.set(y0, yScale, z0, zScale, zReadout, zReadout); + + info.gridReal = info.gridMeasured; } // row - } // slice + } // sector } void TPCFastSpaceChargeCorrection::constructWithNoCorrection(const TPCFastTransformGeo& geo) { const int32_t nCorrectionScenarios = 1; startConstruction(geo, nCorrectionScenarios); - for (int32_t row = 0; row < geo.getNumberOfRows(); row++) { - setRowScenarioID(row, 0); + for (int32_t sector = 0; sector < geo.getNumberOfSectors(); sector++) { + for (int32_t row = 0; row < geo.getNumberOfRows(); row++) { + setRowScenarioID(sector, row, 0); + } } { TPCFastSpaceChargeCorrection::SplineType spline; @@ -460,81 +683,102 @@ double TPCFastSpaceChargeCorrection::testInverse(bool prn) double tpcR2min = mGeo.getRowInfo(0).x - 1.; tpcR2min = tpcR2min * tpcR2min; double tpcR2max = mGeo.getRowInfo(mGeo.getNumberOfRows() - 1).x; - tpcR2max = tpcR2max / cos(2 * M_PI / mGeo.getNumberOfSlicesA() / 2) + 1.; + tpcR2max = tpcR2max / cos(2 * M_PI / mGeo.getNumberOfSectorsA() / 2) + 1.; tpcR2max = tpcR2max * tpcR2max; - double maxDtpc[3] = {0, 0, 0}; - double maxD = 0; + struct MaxValue { + double V{0.}; + int Sector{-1}; + int Row{-1}; + + void update(double v, int sector, int row) + { + if (fabs(v) > fabs(V)) { + V = v; + Sector = sector; + Row = row; + } + } + void update(const MaxValue& other) + { + update(other.V, other.Sector, other.Row); + } + + std::string toString() + { + std::stringstream ss; + ss << V << "(" << Sector << "," << Row << ")"; + return ss.str(); + } + }; + + MaxValue maxDtpc[3]; + MaxValue maxD; - for (int32_t slice = 0; slice < mGeo.getNumberOfSlices(); slice++) { + for (int32_t sector = 0; sector < mGeo.getNumberOfSectors(); sector++) { if (prn) { - LOG(info) << "check inverse transform for slice " << slice; + LOG(info) << "check inverse transform for sector " << sector; } - double vLength = (slice < mGeo.getNumberOfSlicesA()) ? mGeo.getTPCzLengthA() : mGeo.getTPCzLengthC(); - double maxDslice[3] = {0, 0, 0}; + + MaxValue maxDsector[3]; for (int32_t row = 0; row < mGeo.getNumberOfRows(); row++) { - float u0, u1, v0, v1; - mGeo.convScaledUVtoUV(slice, row, 0., 0., u0, v0); - mGeo.convScaledUVtoUV(slice, row, 1., 1., u1, v1); double x = mGeo.getRowInfo(row).x; - double stepU = (u1 - u0) / 100.; - double stepV = (v1 - v0) / 100.; - double maxDrow[3] = {0, 0, 0}; - for (double u = u0; u < u1; u += stepU) { - for (double v = v0; v < v1; v += stepV) { - float dx, du, dv; - getCorrection(slice, row, u, v, dx, du, dv); - double cx = x + dx; - double cu = u + du; - double cv = v + dv; - double r2 = cx * cx + cu * cu; - if (cv < 0 || cv > vLength || r2 < tpcR2min || r2 > tpcR2max) { + auto [y0, y1] = mGeo.getRowInfo(row).getYrange(); + auto [z0, z1] = mGeo.getZrange(sector); + + double stepY = (y1 - y0) / 100.; + double stepZ = (z1 - z0) / 100.; + MaxValue maxDrow[3]; + for (double y = y0; y < y1; y += stepY) { + for (double z = z0; z < z1; z += stepZ) { + auto [dx, dy, dz] = getCorrectionLocal(sector, row, y, z); + double realX = x + dx; + double realY = y + dy; + double realZ = z + dz; + if (!isLocalInsideGrid(sector, row, y, z) || !isRealLocalInsideGrid(sector, row, realY, realZ)) { + continue; + } + double r2 = realX * realX + realY * realY; + if (realY < y0 || realY > y1 || + realZ < z0 || realZ > z1 || + r2 < tpcR2min || r2 > tpcR2max) { continue; } - float nx, nu, nv; - getCorrectionInvCorrectedX(slice, row, cu, cv, nx); - getCorrectionInvUV(slice, row, cu, cv, nu, nv); - double d[3] = {nx - cx, nu - u, nv - v}; + float dxr = getCorrectionXatRealYZ(sector, row, realY, realZ); + auto [dyr, dzr] = getCorrectionYZatRealYZ(sector, row, realY, realZ); + double d[3] = {dxr - dx, dyr - dy, dzr - dz}; for (int32_t i = 0; i < 3; i++) { - if (fabs(d[i]) > fabs(maxDrow[i])) { - maxDrow[i] = d[i]; - } + maxDrow[i].update(d[i], sector, row); } if (0 && prn && fabs(d[0]) + fabs(d[1]) + fabs(d[2]) > 0.1) { - LOG(info) << nx - cx << " " << nu - u << " " << nv - v - << " x,u,v " << x << ", " << u << ", " << v - << " dx,du,dv " << cx - x << ", " << cu - u << ", " << cv - v - << " nx,nu,nv " << nx - x << ", " << cu - nu << ", " << cv - nv; + LOG(info) << dxr - dx << " " << dyr - dy << " " << dzr - dz + << " measured xyz " << x << ", " << y << ", " << z + << " dx,dy,dz from measured point " << dx << ", " << dy << ", " << dz + << " dx,dy,dz from real point " << dxr << ", " << dyr << ", " << dzr; } } } if (0 && prn) { - LOG(info) << "slice " << slice << " row " << row - << " dx " << maxDrow[0] << " du " << maxDrow[1] << " dv " << maxDrow[2]; + LOG(info) << "sector " << sector << " row " << row + << " dx " << maxDrow[0].V << " dy " << maxDrow[1].V << " dz " << maxDrow[2].V; } for (int32_t i = 0; i < 3; i++) { - if (fabs(maxDslice[i]) < fabs(maxDrow[i])) { - maxDslice[i] = maxDrow[i]; - } - if (fabs(maxDtpc[i]) < fabs(maxDrow[i])) { - maxDtpc[i] = maxDrow[i]; - } - if (fabs(maxD) < fabs(maxDrow[i])) { - maxD = maxDrow[i]; - } + maxDsector[i].update(maxDrow[i]); + maxDtpc[i].update(maxDrow[i]); + maxD.update(maxDrow[i]); } } if (prn) { - LOG(info) << "inverse correction: slice " << slice - << " dx " << maxDslice[0] << " du " << maxDslice[1] << " dv " << maxDslice[2]; + LOG(info) << "inverse correction: sector " << sector << ". Max deviations: " + << " dx " << maxDsector[0].toString() << " dy " << maxDsector[1].toString() << " dz " << maxDsector[2].toString(); } - } // slice + } // sector LOG(info) << "Test inverse TPC correction. max deviations: " - << " dx " << maxDtpc[0] << " du " << maxDtpc[1] << " dv " << maxDtpc[2] << " cm"; + << " dx " << maxDtpc[0].toString() << " dy " << maxDtpc[1].toString() << " dz " << maxDtpc[2].toString() << " cm"; - return maxD; + return maxD.V; } #endif // GPUCA_GPUCODE diff --git a/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrection.h b/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrection.h index 9589ecbfc1fc4..b4fab68b91542 100644 --- a/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrection.h +++ b/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrection.h @@ -39,40 +39,114 @@ namespace gpu class TPCFastSpaceChargeCorrection : public FlatObject { public: - /// - /// \brief The struct contains necessary info for TPC padrow - /// - struct RowInfo { - int32_t splineScenarioID{0}; ///< scenario index (which of Spline2D splines to use) - size_t dataOffsetBytes[3]{0}; ///< offset for the spline data withing a TPC slice - ClassDefNV(RowInfo, 1); + // obsolete structure, declared here only for backward compatibility + struct SliceInfo { + ClassDefNV(SliceInfo, 2); }; - struct RowActiveArea { - float maxDriftLengthCheb[5]{0.f}; - float vMax{0.f}; - float cuMin{0.f}; - float cuMax{0.f}; - float cvMax{0.f}; - ClassDefNV(RowActiveArea, 1); + struct GridInfo { + private: + float y0{0.f}; ///< Y coordinate of the U-grid start + float yScale{0.f}; //< scale Y to U-grid coordinate + float z0{0.f}; ///< Z coordinate of the V-grid start + float zScale{0.f}; //< scale Z to V-grid coordinate + float zOut{0.f}; // outer z of the grid; + float splineScalingWithZ{0.f}; ///< spline scaling factor in the Z region between the zOut and the readout plane + + public: + void set(float y0_, float yScale_, float z0_, float zScale_, float zOut_, float zReadout_) + { + this->y0 = y0_; + this->yScale = yScale_; + this->z0 = z0_; + this->zScale = zScale_; + this->zOut = zOut_; + // no scaling when the distance to the readout is too small + this->splineScalingWithZ = fabs(zReadout_ - zOut_) > 1. ? 1. / (zReadout_ - zOut_) : 0.; + } + + float getY0() const { return y0; } + float getYscale() const { return yScale; } + float getZ0() const { return z0; } + float getZscale() const { return zScale; } + + GPUd() float getSpineScaleForZ(float z) const + { + return 1.f - GPUCommonMath::Clamp((z - zOut) * splineScalingWithZ, 0.f, 1.f); + } + + /// convert local y, z to internal grid coordinates u,v, and spline scale + GPUd() std::array convLocalToGridUntruncated(float y, float z) const + { + return {(y - y0) * yScale, (z - z0) * zScale, getSpineScaleForZ(z)}; + } + + /// convert internal grid coordinates u,v to local y, z + std::array convGridToLocal(float gridU, float gridV) const + { + return {y0 + gridU / yScale, z0 + gridV / zScale}; + } + ClassDefNV(GridInfo, 1); }; - struct SliceRowInfo { - float gridV0{0.f}; ///< V coordinate of the V-grid start - float gridCorrU0{0.f}; ///< U coordinate of the U-grid start for corrected U - float gridCorrV0{0.f}; ///< V coordinate of the V-grid start for corrected V - float scaleCorrUtoGrid{0.f}; ///< scale corrected U to U-grid coordinate - float scaleCorrVtoGrid{0.f}; ///< scale corrected V to V-grid coordinate - RowActiveArea activeArea; - ClassDefNV(SliceRowInfo, 1); + struct SectorRowInfo { + int32_t splineScenarioID{0}; ///< scenario index (which of Spline2D splines to use) + size_t dataOffsetBytes[3]{0}; ///< offset for the spline data withing a TPC sector + + GridInfo gridMeasured; ///< grid info for measured coordinates + GridInfo gridReal; ///< grid info for real coordinates + + float minCorr[3]{-10.f, -10.f, -10.f}; ///< min correction for dX, dY, dZ + float maxCorr[3]{10.f, 10.f, 10.f}; ///< max correction for dX, dY, dZ + + void resetMaxValues() + { + minCorr[0] = -1.f; + maxCorr[0] = 1.f; + minCorr[1] = -1.f; + maxCorr[1] = 1.f; + minCorr[2] = -1.f; + maxCorr[2] = 1.f; + } + + void updateMaxValues(float dx, float du, float dv) + { + minCorr[0] = GPUCommonMath::Min(minCorr[0], dx); + maxCorr[0] = GPUCommonMath::Max(maxCorr[0], dx); + + minCorr[1] = GPUCommonMath::Min(minCorr[1], du); + maxCorr[1] = GPUCommonMath::Max(maxCorr[1], du); + + minCorr[2] = GPUCommonMath::Min(minCorr[2], dv); + maxCorr[2] = GPUCommonMath::Max(maxCorr[2], dv); + } + + void updateMaxValues(std::array dxdudv, float scale) + { + float dx = dxdudv[0] * scale; + float du = dxdudv[1] * scale; + float dv = dxdudv[2] * scale; + updateMaxValues(dx, du, dv); + } + + std::array getMaxValues() const + { + return {maxCorr[0], maxCorr[1], maxCorr[2]}; + } + + std::array getMinValues() const + { + return {minCorr[0], minCorr[1], minCorr[2]}; + } + + ClassDefNV(SectorRowInfo, 2); }; - struct SliceInfo { - float vMax{0.f}; ///< Max value of V coordinate - ClassDefNV(SliceInfo, 1); - }; + typedef Spline2D SplineTypeXYZ; + typedef Spline2D SplineTypeInvX; + typedef Spline2D SplineTypeInvYZ; - typedef Spline2D SplineType; + typedef SplineTypeXYZ SplineType; /// _____________ Constructors / destructors __________________________ @@ -107,6 +181,7 @@ class TPCFastSpaceChargeCorrection : public FlatObject /// Moving the class with its external buffer to another location + void setActualBufferAddressOld(char* actualFlatBufferPtr); void setActualBufferAddress(char* actualFlatBufferPtr); void setFutureBufferAddress(char* futureFlatBufferPtr); @@ -116,7 +191,7 @@ class TPCFastSpaceChargeCorrection : public FlatObject void startConstruction(const TPCFastTransformGeo& geo, int32_t numberOfSplineScenarios); /// Initializes a TPC row - void setRowScenarioID(int32_t iRow, int32_t iScenario); + void setRowScenarioID(int32_t iSector, int32_t iRow, int32_t iScenario); /// Sets approximation scenario void setSplineScenario(int32_t scenarioIndex, const SplineType& spline); @@ -134,57 +209,74 @@ class TPCFastSpaceChargeCorrection : public FlatObject /// Sets the time stamp of the current calibaration GPUd() void setTimeStamp(int64_t v) { mTimeStamp = v; } - /// Set safety marging for the interpolation around the TPC row. - /// Outside of this area the interpolation returns the boundary values. - GPUd() void setInterpolationSafetyMargin(float val) { fInterpolationSafetyMargin = val; } - /// Gives const pointer to a spline - GPUd() const SplineType& getSpline(int32_t slice, int32_t row) const; + GPUd() const SplineType& getSpline(int32_t sector, int32_t row) const; /// Gives pointer to a spline - GPUd() SplineType& getSpline(int32_t slice, int32_t row); + GPUd() SplineType& getSpline(int32_t sector, int32_t row); /// Gives pointer to spline data - GPUd() float* getSplineData(int32_t slice, int32_t row, int32_t iSpline = 0); + GPUd() float* getCorrectionData(int32_t sector, int32_t row, int32_t iSpline = 0); /// Gives pointer to spline data - GPUd() const float* getSplineData(int32_t slice, int32_t row, int32_t iSpline = 0) const; + GPUd() const float* getCorrectionData(int32_t sector, int32_t row, int32_t iSpline = 0) const; - /// _______________ The main method: cluster correction _______________________ - /// - GPUd() int32_t getCorrection(int32_t slice, int32_t row, float u, float v, float& dx, float& du, float& dv) const; + /// Gives const pointer to a spline for the inverse X correction + GPUd() const SplineTypeInvX& getSplineInvX(int32_t sector, int32_t row) const; + + /// Gives pointer to a spline for the inverse X correction + GPUd() SplineTypeInvX& getSplineInvX(int32_t sector, int32_t row); + + /// Gives pointer to spline data for the inverse X correction + GPUd() float* getCorrectionDataInvX(int32_t sector, int32_t row); + + /// Gives pointer to spline data for the inverse X correction + GPUd() const float* getCorrectionDataInvX(int32_t sector, int32_t row) const; - /// inverse correction: Corrected U and V -> coorrected X - GPUd() void getCorrectionInvCorrectedX(int32_t slice, int32_t row, float corrU, float corrV, float& corrX) const; + /// Gives const pointer to a spline for the inverse YZ correction + GPUd() const SplineTypeInvYZ& getSplineInvYZ(int32_t sector, int32_t row) const; - /// inverse correction: Corrected U and V -> uncorrected U and V - GPUd() void getCorrectionInvUV(int32_t slice, int32_t row, float corrU, float corrV, float& nomU, float& nomV) const; + /// Gives pointer to a spline for the inverse YZ correction + GPUd() SplineTypeInvYZ& getSplineInvYZ(int32_t sector, int32_t row); + + /// Gives pointer to spline data for the inverse YZ correction + GPUd() float* getCorrectionDataInvYZ(int32_t sector, int32_t row); + + /// Gives pointer to spline data for the inverse YZ correction + GPUd() const float* getCorrectionDataInvYZ(int32_t sector, int32_t row) const; + + /// _______________ The main method: cluster correction _______________________ + /// + // GPUd() int32_t getCorrectionInternal(int32_t sector, int32_t row, float u, float v, float& dx, float& du, float& dv) const; - /// maximal possible drift length of the active area - GPUd() float getMaxDriftLength(int32_t slice, int32_t row, float pad) const; + GPUdi() std::array getCorrectionLocal(int32_t sector, int32_t row, float y, float z) const; - /// maximal possible drift length of the active area - GPUd() float getMaxDriftLength(int32_t slice, int32_t row) const; + /// inverse correction: Real Y and Z -> Real X + GPUd() float getCorrectionXatRealYZ(int32_t sector, int32_t row, float realY, float realZ) const; - /// maximal possible drift length of the active area - GPUd() float getMaxDriftLength(int32_t slice) const; + /// inverse correction: Real Y and Z -> measred Y and Z + GPUd() std::array getCorrectionYZatRealYZ(int32_t sector, int32_t row, float realY, float realZ) const; /// _______________ Utilities _______________________________________________ - /// shrink u,v coordinats to the TPC row area +/- fkInterpolationSafetyMargin - GPUd() void schrinkUV(int32_t slice, int32_t row, float& u, float& v) const; + /// convert local y, z to internal grid coordinates u,v + /// return values: u, v, scaling factor + GPUd() std::array convLocalToGrid(int32_t sector, int32_t row, float y, float z) const; - /// shrink corrected u,v coordinats to the TPC row area +/- fkInterpolationSafetyMargin - GPUd() void schrinkCorrectedUV(int32_t slice, int32_t row, float& corrU, float& corrV) const; + /// convert internal grid coordinates u,v to local y, z + /// return values: y, z, scaling factor + GPUd() std::array convGridToLocal(int32_t sector, int32_t row, float u, float v) const; - /// convert u,v to internal grid coordinates - GPUd() void convUVtoGrid(int32_t slice, int32_t row, float u, float v, float& gridU, float& gridV) const; + /// convert real Y, Z to the internal grid coordinates + /// return values: u, v, scaling factor + GPUd() std::array convRealLocalToGrid(int32_t sector, int32_t row, float y, float z) const; - /// convert u,v to internal grid coordinates - GPUd() void convGridToUV(int32_t slice, int32_t row, float gridU, float gridV, float& u, float& v) const; + /// convert internal grid coordinates to the real Y, Z + /// return values: y, z + GPUd() std::array convGridToRealLocal(int32_t sector, int32_t row, float u, float v) const; - /// convert corrected u,v to internal grid coordinates - GPUd() void convCorrectedUVtoGrid(int32_t slice, int32_t row, float cu, float cv, float& gridU, float& gridV) const; + GPUd() bool isLocalInsideGrid(int32_t sector, int32_t row, float y, float z) const; + GPUd() bool isRealLocalInsideGrid(int32_t sector, int32_t row, float y, float z) const; /// TPC geometry information GPUd() const TPCFastTransformGeo& getGeometry() const @@ -195,34 +287,16 @@ class TPCFastSpaceChargeCorrection : public FlatObject /// Gives the time stamp of the current calibaration parameters int64_t getTimeStamp() const { return mTimeStamp; } - /// Gives the interpolation safety marging around the TPC row. - GPUd() float getInterpolationSafetyMargin() const { return fInterpolationSafetyMargin; } - - /// Gives TPC row info - GPUd() const RowInfo& getRowInfo(int32_t row) const { return mRowInfoPtr[row]; } - - /// Gives TPC slice info - GPUd() const SliceInfo& getSliceInfo(int32_t slice) const - { - return mSliceInfo[slice]; - } - - /// Gives TPC slice info - GPUd() SliceInfo& getSliceInfo(int32_t slice) - { - return mSliceInfo[slice]; - } - - /// Gives TPC slice & row info - GPUd() const SliceRowInfo& getSliceRowInfo(int32_t slice, int32_t row) const + /// Gives TPC sector & row info + GPUd() const SectorRowInfo& getSectorRowInfo(int32_t sector, int32_t row) const { - return mSliceRowInfoPtr[mGeo.getNumberOfRows() * slice + row]; + return mSectorRowInfos[mGeo.getMaxNumberOfRows() * sector + row]; } - /// Gives TPC slice & row info - GPUd() SliceRowInfo& getSliceRowInfo(int32_t slice, int32_t row) + /// Gives TPC sector & row info + GPUd() SectorRowInfo& getSectorRowInfo(int32_t sector, int32_t row) { - return mSliceRowInfoPtr[mGeo.getNumberOfRows() * slice + row]; + return mSectorRowInfos[mGeo.getMaxNumberOfRows() * sector + row]; } #if !defined(GPUCA_GPUCODE) @@ -237,14 +311,10 @@ class TPCFastSpaceChargeCorrection : public FlatObject /// release temporary memory used during construction void releaseConstructionMemory(); - /// temporary method with the an way of calculating 2D spline - GPUd() int32_t getCorrectionOld(int32_t slice, int32_t row, float u, float v, float& dx, float& du, float& dv) const; - /// _______________ Data members _______________________________________________ /// _______________ Construction control _______________________________________________ - RowInfo* mConstructionRowInfos = nullptr; //! (transient!!) Temporary container of the row infos during construction SplineType* mConstructionScenarios = nullptr; //! (transient!!) Temporary container for spline scenarios /// _______________ Geometry _______________________________________________ @@ -253,244 +323,199 @@ class TPCFastSpaceChargeCorrection : public FlatObject int32_t mNumberOfScenarios; ///< Number of approximation spline scenarios - SliceInfo mSliceInfo[TPCFastTransformGeo::getNumberOfSlices()]; ///< SliceInfo array - - SplineType* mScenarioPtr; //! (transient!!) pointer to spline scenarios - RowInfo* mRowInfoPtr; //! (transient!!) pointer to RowInfo array inside the mFlatBufferPtr buffer - SliceRowInfo* mSliceRowInfoPtr; //! (transient!!) pointer to SliceRowInfo array inside the mFlatBufferPtr + SplineType* mScenarioPtr; //! (transient!!) pointer to spline scenarios /// _______________ Calibration data _______________________________________________ int64_t mTimeStamp; ///< time stamp of the current calibration - char* mSplineData[3]; //! (transient!!) pointer to the spline data in the flat buffer + char* mCorrectionData[3]; //! (transient!!) pointer to the spline data in the flat buffer - size_t mSliceDataSizeBytes[3]; ///< size of the data for one slice in the flat buffer + size_t mCorrectionDataSize[3]; ///< size of the data per transformation (direct, inverseX, inverse YZ) in the flat buffer - float fInterpolationSafetyMargin{0.1f}; // 10% area around the TPC row. Outside of this area the interpolation returns the boundary values. + /// Class version. It is used to read older versions from disc. + /// The default version 3 is the one before this field was introduced. + /// The actual version must be set in startConstruction(). + int32_t mClassVersion{3}; - ClassDefNV(TPCFastSpaceChargeCorrection, 3); + SectorRowInfo mSectorRowInfos[TPCFastTransformGeo::getNumberOfSectors() * TPCFastTransformGeo::getMaxNumberOfRows()]; ///< SectorRowInfo array + + ClassDefNV(TPCFastSpaceChargeCorrection, 4); }; /// ==================================================== /// Inline implementations of some methods /// ==================================================== -GPUdi() const TPCFastSpaceChargeCorrection::SplineType& TPCFastSpaceChargeCorrection::getSpline(int32_t slice, int32_t row) const +GPUdi() const TPCFastSpaceChargeCorrection::SplineType& TPCFastSpaceChargeCorrection::getSpline(int32_t sector, int32_t row) const { /// Gives const pointer to spline - const RowInfo& rowInfo = mRowInfoPtr[row]; - return mScenarioPtr[rowInfo.splineScenarioID]; + return mScenarioPtr[getSectorRowInfo(sector, row).splineScenarioID]; } -GPUdi() TPCFastSpaceChargeCorrection::SplineType& TPCFastSpaceChargeCorrection::getSpline(int32_t slice, int32_t row) +GPUdi() TPCFastSpaceChargeCorrection::SplineType& TPCFastSpaceChargeCorrection::getSpline(int32_t sector, int32_t row) { /// Gives pointer to spline - const RowInfo& rowInfo = mRowInfoPtr[row]; - return mScenarioPtr[rowInfo.splineScenarioID]; + return mScenarioPtr[getSectorRowInfo(sector, row).splineScenarioID]; } -GPUdi() float* TPCFastSpaceChargeCorrection::getSplineData(int32_t slice, int32_t row, int32_t iSpline) +GPUdi() float* TPCFastSpaceChargeCorrection::getCorrectionData(int32_t sector, int32_t row, int32_t iSpline) { /// Gives pointer to spline data - const RowInfo& rowInfo = mRowInfoPtr[row]; - return reinterpret_cast(mSplineData[iSpline] + mSliceDataSizeBytes[iSpline] * slice + rowInfo.dataOffsetBytes[iSpline]); + return reinterpret_cast(mCorrectionData[iSpline] + getSectorRowInfo(sector, row).dataOffsetBytes[iSpline]); } -GPUdi() const float* TPCFastSpaceChargeCorrection::getSplineData(int32_t slice, int32_t row, int32_t iSpline) const +GPUdi() const float* TPCFastSpaceChargeCorrection::getCorrectionData(int32_t sector, int32_t row, int32_t iSpline) const { /// Gives pointer to spline data - const RowInfo& rowInfo = mRowInfoPtr[row]; - return reinterpret_cast(mSplineData[iSpline] + mSliceDataSizeBytes[iSpline] * slice + rowInfo.dataOffsetBytes[iSpline]); + return reinterpret_cast(mCorrectionData[iSpline] + getSectorRowInfo(sector, row).dataOffsetBytes[iSpline]); } -GPUdi() void TPCFastSpaceChargeCorrection::schrinkUV(int32_t slice, int32_t row, float& u, float& v) const +GPUdi() TPCFastSpaceChargeCorrection::SplineTypeInvX& TPCFastSpaceChargeCorrection::getSplineInvX(int32_t sector, int32_t row) { - /// shrink u,v coordinats to the TPC row area +/- fInterpolationSafetyMargin - - const TPCFastTransformGeo::RowInfo& rowInfo = mGeo.getRowInfo(row); - - float uWidth05 = rowInfo.getUwidth() * (0.5f + fInterpolationSafetyMargin); - float vWidth = mGeo.getTPCzLength(slice); - - if (u < -uWidth05) { - u = -uWidth05; - } - if (u > uWidth05) { - u = uWidth05; - } - if (v < -0.1f * vWidth) { - v = -0.1f * vWidth; - } - if (v > 1.1f * vWidth) { - v = 1.1f * vWidth; - } + /// Gives pointer to spline for the inverse X correction + return reinterpret_cast(getSpline(sector, row)); } -GPUdi() void TPCFastSpaceChargeCorrection::schrinkCorrectedUV(int32_t slice, int32_t row, float& corrU, float& corrV) const +GPUdi() const TPCFastSpaceChargeCorrection::SplineTypeInvX& TPCFastSpaceChargeCorrection::getSplineInvX(int32_t sector, int32_t row) const { - /// shrink corrected u,v coordinats to the TPC row area +/- fInterpolationSafetyMargin - - const TPCFastTransformGeo::RowInfo& rowInfo = mGeo.getRowInfo(row); - const SliceRowInfo& sliceRowInfo = getSliceRowInfo(slice, row); - - float uMargin = fInterpolationSafetyMargin * rowInfo.getUwidth(); - float vMargin = fInterpolationSafetyMargin * mGeo.getTPCzLength(slice); - - if (corrU < sliceRowInfo.activeArea.cuMin - uMargin) { - corrU = sliceRowInfo.activeArea.cuMin - uMargin; - } - - if (corrU > sliceRowInfo.activeArea.cuMax + uMargin) { - corrU = sliceRowInfo.activeArea.cuMax + uMargin; - } - - if (corrV < 0.f - vMargin) { - corrV = 0.f - vMargin; - } - - if (corrV > sliceRowInfo.activeArea.cvMax + vMargin) { - corrV = sliceRowInfo.activeArea.cvMax + vMargin; - } + /// Gives const pointer to spline for the inverse X correction + return reinterpret_cast(getSpline(sector, row)); } -GPUdi() void TPCFastSpaceChargeCorrection::convUVtoGrid(int32_t slice, int32_t row, float u, float v, float& gu, float& gv) const +GPUdi() float* TPCFastSpaceChargeCorrection::getCorrectionDataInvX(int32_t sector, int32_t row) { - // TODO optimise !!! - gu = 0.f; - gv = 0.f; - - schrinkUV(slice, row, u, v); - - const SliceRowInfo& info = getSliceRowInfo(slice, row); - const SplineType& spline = getSpline(slice, row); - - float su0 = 0.f, sv0 = 0.f; - mGeo.convUVtoScaledUV(slice, row, u, info.gridV0, su0, sv0); - mGeo.convUVtoScaledUV(slice, row, u, v, gu, gv); + /// Gives pointer to spline data for the inverse X correction + return getCorrectionData(sector, row, 1); +} - gv = (gv - sv0) / (1.f - sv0); - gu *= spline.getGridX1().getUmax(); - gv *= spline.getGridX2().getUmax(); +GPUdi() const float* TPCFastSpaceChargeCorrection::getCorrectionDataInvX(int32_t sector, int32_t row) const +{ + /// Gives pointer to spline data for the inverse X correction + return getCorrectionData(sector, row, 1); } -GPUdi() void TPCFastSpaceChargeCorrection::convGridToUV(int32_t slice, int32_t row, float gridU, float gridV, float& u, float& v) const +GPUdi() TPCFastSpaceChargeCorrection::SplineTypeInvYZ& TPCFastSpaceChargeCorrection::getSplineInvYZ(int32_t sector, int32_t row) { - // TODO optimise - /// convert u,v to internal grid coordinates - float su0 = 0.f, sv0 = 0.f; - const SliceRowInfo& info = getSliceRowInfo(slice, row); - const SplineType& spline = getSpline(slice, row); - mGeo.convUVtoScaledUV(slice, row, 0.f, info.gridV0, su0, sv0); - float su = gridU / spline.getGridX1().getUmax(); - float sv = sv0 + gridV / spline.getGridX2().getUmax() * (1.f - sv0); - mGeo.convScaledUVtoUV(slice, row, su, sv, u, v); + /// Gives pointer to spline for the inverse YZ correction + return reinterpret_cast(getSpline(sector, row)); } -GPUdi() void TPCFastSpaceChargeCorrection::convCorrectedUVtoGrid(int32_t slice, int32_t row, float corrU, float corrV, float& gridU, float& gridV) const +GPUdi() const TPCFastSpaceChargeCorrection::SplineTypeInvYZ& TPCFastSpaceChargeCorrection::getSplineInvYZ(int32_t sector, int32_t row) const { - schrinkCorrectedUV(slice, row, corrU, corrV); + /// Gives const pointer to spline for the inverse YZ correction + return reinterpret_cast(getSpline(sector, row)); +} - const SliceRowInfo& sliceRowInfo = getSliceRowInfo(slice, row); +GPUdi() float* TPCFastSpaceChargeCorrection::getCorrectionDataInvYZ(int32_t sector, int32_t row) +{ + /// Gives pointer to spline data for the inverse YZ correction + return getCorrectionData(sector, row, 2); +} - gridU = (corrU - sliceRowInfo.gridCorrU0) * sliceRowInfo.scaleCorrUtoGrid; - gridV = (corrV - sliceRowInfo.gridCorrV0) * sliceRowInfo.scaleCorrVtoGrid; +GPUdi() const float* TPCFastSpaceChargeCorrection::getCorrectionDataInvYZ(int32_t sector, int32_t row) const +{ + /// Gives pointer to spline data for the inverse YZ correction + return getCorrectionData(sector, row, 2); } -GPUdi() int32_t TPCFastSpaceChargeCorrection::getCorrection(int32_t slice, int32_t row, float u, float v, float& dx, float& du, float& dv) const +GPUdi() std::array TPCFastSpaceChargeCorrection::convLocalToGrid(int32_t sector, int32_t row, float y, float z) const { - const SplineType& spline = getSpline(slice, row); - const float* splineData = getSplineData(slice, row); - float gridU = 0, gridV = 0; - convUVtoGrid(slice, row, u, v, gridU, gridV); - float dxuv[3]; - spline.interpolateU(splineData, gridU, gridV, dxuv); - if (CAMath::Abs(dxuv[0]) > 100 || CAMath::Abs(dxuv[1]) > 100 || CAMath::Abs(dxuv[2]) > 100) { - dxuv[0] = dxuv[1] = dxuv[2] = 0; - } - dx = dxuv[0]; - du = dxuv[1]; - dv = dxuv[2]; - return 0; + /// convert local y, z to internal grid coordinates u,v + /// return values: u, v, scaling factor + const SplineType& spline = getSpline(sector, row); + auto val = getSectorRowInfo(sector, row).gridMeasured.convLocalToGridUntruncated(y, z); + // shrink to the grid + val[0] = GPUCommonMath::Clamp(val[0], 0.f, (float)spline.getGridX1().getUmax()); + val[1] = GPUCommonMath::Clamp(val[1], 0.f, (float)spline.getGridX2().getUmax()); + return val; } -GPUdi() int32_t TPCFastSpaceChargeCorrection::getCorrectionOld(int32_t slice, int32_t row, float u, float v, float& dx, float& du, float& dv) const +GPUdi() bool TPCFastSpaceChargeCorrection::isLocalInsideGrid(int32_t sector, int32_t row, float y, float z) const { - const SplineType& spline = getSpline(slice, row); - const float* splineData = getSplineData(slice, row); - float gridU = 0, gridV = 0; - convUVtoGrid(slice, row, u, v, gridU, gridV); - float dxuv[3]; - spline.interpolateUold(splineData, gridU, gridV, dxuv); - if (CAMath::Abs(dxuv[0]) > 100 || CAMath::Abs(dxuv[1]) > 100 || CAMath::Abs(dxuv[2]) > 100) { - dxuv[0] = dxuv[1] = dxuv[2] = 0; + /// check if local y, z are inside the grid + auto val = getSectorRowInfo(sector, row).gridMeasured.convLocalToGridUntruncated(y, z); + const auto& spline = getSpline(sector, row); + // shrink to the grid + if (val[0] < 0.f || val[0] > (float)spline.getGridX1().getUmax() || // + val[1] < 0.f || val[1] > (float)spline.getGridX2().getUmax()) { + return false; } - dx = dxuv[0]; - du = dxuv[1]; - dv = dxuv[2]; - return 0; + return true; } -GPUdi() void TPCFastSpaceChargeCorrection::getCorrectionInvCorrectedX( - int32_t slice, int32_t row, float corrU, float corrV, float& x) const +GPUdi() bool TPCFastSpaceChargeCorrection::isRealLocalInsideGrid(int32_t sector, int32_t row, float y, float z) const { - float gridU, gridV; - convCorrectedUVtoGrid(slice, row, corrU, corrV, gridU, gridV); - - const Spline2D& spline = reinterpret_cast&>(getSpline(slice, row)); - const float* splineData = getSplineData(slice, row, 1); - float dx = 0; - spline.interpolateU(splineData, gridU, gridV, &dx); - if (CAMath::Abs(dx) > 100) { - dx = 0; + /// check if local y, z are inside the grid + auto val = getSectorRowInfo(sector, row).gridReal.convLocalToGridUntruncated(y, z); + const auto& spline = getSpline(sector, row); + // shrink to the grid + if (val[0] < 0.f || val[0] > (float)spline.getGridX1().getUmax() || // + val[1] < 0.f || val[1] > (float)spline.getGridX2().getUmax()) { + return false; } - x = mGeo.getRowInfo(row).x + dx; + return true; } -GPUdi() void TPCFastSpaceChargeCorrection::getCorrectionInvUV( - int32_t slice, int32_t row, float corrU, float corrV, float& nomU, float& nomV) const +GPUdi() std::array TPCFastSpaceChargeCorrection::convGridToLocal(int32_t sector, int32_t row, float gridU, float gridV) const { - float gridU, gridV; - convCorrectedUVtoGrid(slice, row, corrU, corrV, gridU, gridV); + /// convert internal grid coordinates u,v to local y, z + return getSectorRowInfo(sector, row).gridMeasured.convGridToLocal(gridU, gridV); +} - const Spline2D& spline = reinterpret_cast&>(getSpline(slice, row)); - const float* splineData = getSplineData(slice, row, 2); +GPUdi() std::array TPCFastSpaceChargeCorrection::convRealLocalToGrid(int32_t sector, int32_t row, float y, float z) const +{ + /// convert real y, z to the internal grid coordinates + scale + const SplineType& spline = getSpline(sector, row); + auto val = getSectorRowInfo(sector, row).gridReal.convLocalToGridUntruncated(y, z); + // shrink to the grid + val[0] = GPUCommonMath::Clamp(val[0], 0.f, (float)spline.getGridX1().getUmax()); + val[1] = GPUCommonMath::Clamp(val[1], 0.f, (float)spline.getGridX2().getUmax()); + return val; +} - float duv[2]; - spline.interpolateU(splineData, gridU, gridV, duv); - if (CAMath::Abs(duv[0]) > 100 || CAMath::Abs(duv[1]) > 100) { - duv[0] = duv[1] = 0; - } - nomU = corrU - duv[0]; - nomV = corrV - duv[1]; +GPUdi() std::array TPCFastSpaceChargeCorrection::convGridToRealLocal(int32_t sector, int32_t row, float gridU, float gridV) const +{ + /// convert internal grid coordinates u,v to the real y, z + return getSectorRowInfo(sector, row).gridReal.convGridToLocal(gridU, gridV); } -GPUdi() float TPCFastSpaceChargeCorrection::getMaxDriftLength(int32_t slice, int32_t row, float pad) const +GPUdi() std::array TPCFastSpaceChargeCorrection::getCorrectionLocal(int32_t sector, int32_t row, float y, float z) const { - const RowActiveArea& area = getSliceRowInfo(slice, row).activeArea; - const float* c = area.maxDriftLengthCheb; - float x = -1.f + 2.f * pad / mGeo.getRowInfo(row).maxPad; - float y = c[0] + c[1] * x; - float f0 = 1.f; - float f1 = x; - x *= 2.f; - for (int32_t i = 2; i < 5; i++) { - double f = x * f1 - f0; - y += c[i] * f; - f0 = f1; - f1 = f; - } - return y; + const auto& info = getSectorRowInfo(sector, row); + const SplineType& spline = getSpline(sector, row); + const float* splineData = getCorrectionData(sector, row); + + auto val = convLocalToGrid(sector, row, y, z); + + float dxyz[3]; + spline.interpolateAtU(splineData, val[0], val[1], dxyz); + + float dx = val[2] * GPUCommonMath::Clamp(dxyz[0], info.minCorr[0], info.maxCorr[0]); + float dy = val[2] * GPUCommonMath::Clamp(dxyz[1], info.minCorr[1], info.maxCorr[1]); + float dz = val[2] * GPUCommonMath::Clamp(dxyz[2], info.minCorr[2], info.maxCorr[2]); + return {dx, dy, dz}; } -GPUdi() float TPCFastSpaceChargeCorrection::getMaxDriftLength(int32_t slice, int32_t row) const +GPUdi() float TPCFastSpaceChargeCorrection::getCorrectionXatRealYZ(int32_t sector, int32_t row, float realY, float realZ) const { - return getSliceRowInfo(slice, row).activeArea.vMax; + const auto& info = getSectorRowInfo(sector, row); + auto val = convRealLocalToGrid(sector, row, realY, realZ); + float dx = 0; + getSplineInvX(sector, row).interpolateAtU(getCorrectionDataInvX(sector, row), val[0], val[1], &dx); + dx = val[2] * GPUCommonMath::Clamp(dx, info.minCorr[0], info.maxCorr[0]); + return dx; } -GPUdi() float TPCFastSpaceChargeCorrection::getMaxDriftLength(int32_t slice) const +GPUdi() std::array TPCFastSpaceChargeCorrection::getCorrectionYZatRealYZ(int32_t sector, int32_t row, float realY, float realZ) const { - return getSliceInfo(slice).vMax; + auto val = convRealLocalToGrid(sector, row, realY, realZ); + const auto& info = getSectorRowInfo(sector, row); + float dyz[2]; + getSplineInvYZ(sector, row).interpolateAtU(getCorrectionDataInvYZ(sector, row), val[0], val[1], dyz); + dyz[0] = val[2] * GPUCommonMath::Clamp(dyz[0], info.minCorr[1], info.maxCorr[1]); + dyz[1] = val[2] * GPUCommonMath::Clamp(dyz[1], info.minCorr[2], info.maxCorr[2]); + return {dyz[0], dyz[1]}; } } // namespace gpu diff --git a/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrectionMap.h b/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrectionMap.h index 97b824aa6da32..e54cf878ee2ff 100644 --- a/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrectionMap.h +++ b/GPU/TPCFastTransformation/TPCFastSpaceChargeCorrectionMap.h @@ -42,27 +42,28 @@ class TPCFastSpaceChargeCorrectionMap /// \brief The struct contains necessary info for TPC padrow /// struct CorrectionPoint { - double mY, mZ; // not-distorted local coordinates - double mDx, mDy, mDz; // corrections to the local coordinates + double mY{0.}, mZ{0.}; // not-distorted local coordinates + double mDx{0.}, mDy{0.}, mDz{0.}; // corrections to the local coordinates + double mWeight{0.}; // weight of the point }; /// _____________ Constructors / destructors __________________________ /// Default constructor: creates an empty uninitialized object - TPCFastSpaceChargeCorrectionMap(int32_t nRocs, int32_t nRows) + TPCFastSpaceChargeCorrectionMap(int32_t nSectors, int32_t nRows) { - init(nRocs, nRows); + init(nSectors, nRows); } /// Destructor ~TPCFastSpaceChargeCorrectionMap() = default; /// (re-)init the map - void init(int32_t nRocs, int32_t nRows) + void init(int32_t nSectors, int32_t nRows) { - mNrocs = nRocs; + mNsectors = nSectors; mNrows = nRows; - int32_t n = mNrocs * mNrows; + int32_t n = mNsectors * mNrows; fDataPoints.resize(n); for (uint32_t i = 0; i < fDataPoints.size(); ++i) { fDataPoints[i].clear(); @@ -70,30 +71,30 @@ class TPCFastSpaceChargeCorrectionMap } /// Starts the construction procedure, reserves temporary memory - void addCorrectionPoint(int32_t iRoc, int32_t iRow, + void addCorrectionPoint(int32_t iSector, int32_t iRow, double y, double z, - double dx, double dy, double dz) + double dx, double dy, double dz, double weight) { - int32_t ind = mNrows * iRoc + iRow; + int32_t ind = mNrows * iSector + iRow; fDataPoints.at(ind).push_back(CorrectionPoint{y, z, - dx, dy, dz}); + dx, dy, dz, weight}); } - const std::vector& getPoints(int32_t iRoc, int32_t iRow) const + const std::vector& getPoints(int32_t iSector, int32_t iRow) const { - int32_t ind = mNrows * iRoc + iRow; + int32_t ind = mNrows * iSector + iRow; return fDataPoints.at(ind); } - int32_t getNrocs() const { return mNrocs; } + int32_t getNsectors() const { return mNsectors; } int32_t getNrows() const { return mNrows; } - bool isInitialized() const { return mNrocs > 0 && mNrows > 0; } + bool isInitialized() const { return mNsectors > 0 && mNrows > 0; } private: /// _______________ Data members _______________________________________________ - int32_t mNrocs{0}; + int32_t mNsectors{0}; int32_t mNrows{0}; std::vector> fDataPoints; //! (transient!!) points with space charge correction diff --git a/GPU/TPCFastTransformation/TPCFastTransform.cxx b/GPU/TPCFastTransformation/TPCFastTransform.cxx index bd29a760615ad..42c4c57ffa086 100644 --- a/GPU/TPCFastTransformation/TPCFastTransform.cxx +++ b/GPU/TPCFastTransformation/TPCFastTransform.cxx @@ -37,7 +37,7 @@ using namespace o2::gpu; TPCFastTransform::TPCFastTransform() - : FlatObject(), mTimeStamp(0), mCorrection(), mApplyCorrection(1), mT0(0.f), mVdrift(0.f), mVdriftCorrY(0.f), mLdriftCorr(0.f), mTOFcorr(0.f), mPrimVtxZ(0.f), mLumi(TPCFastTransform::DEFLUMI), mLumiError(0.f), mLumiScaleFactor(1.0f), mIDC(TPCFastTransform::DEFIDC), mIDCError(0.f), mCTP2IDCFallBackThreshold(30.f) + : FlatObject(), mTimeStamp(0), mCorrection(), mApplyCorrection(1), mT0(0.f), mVdrift(0.f), mLumi(TPCFastTransform::DEFLUMI), mLumiError(0.f), mLumiScaleFactor(1.0f), mIDC(TPCFastTransform::DEFIDC), mIDCError(0.f), mCTP2IDCFallBackThreshold(30.f) { // Default Constructor: creates an empty uninitialized object } @@ -54,10 +54,6 @@ void TPCFastTransform::cloneFromObject(const TPCFastTransform& obj, char* newFla mApplyCorrection = obj.mApplyCorrection; mT0 = obj.mT0; mVdrift = obj.mVdrift; - mVdriftCorrY = obj.mVdriftCorrY; - mLdriftCorr = obj.mLdriftCorr; - mTOFcorr = obj.mTOFcorr; - mPrimVtxZ = obj.mPrimVtxZ; mLumi = obj.mLumi; mLumiError = obj.mLumiError; mIDC = obj.mIDC; @@ -107,10 +103,6 @@ void TPCFastTransform::startConstruction(const TPCFastSpaceChargeCorrection& cor mApplyCorrection = 1; mT0 = 0.f; mVdrift = 0.f; - mVdriftCorrY = 0.f; - mLdriftCorr = 0.f; - mTOFcorr = 0.f; - mPrimVtxZ = 0.f; mLumi = DEFLUMI; mLumiError = 0.f; mIDC = DEFIDC; @@ -123,7 +115,7 @@ void TPCFastTransform::startConstruction(const TPCFastSpaceChargeCorrection& cor mCorrection.cloneFromObject(correction, nullptr); } -void TPCFastTransform::setCalibration(int64_t timeStamp, float t0, float vDrift, float vDriftCorrY, float lDriftCorr, float tofCorr, float primVtxZ) +void TPCFastTransform::setCalibration1(int64_t timeStamp, float t0, float vDrift) { /// Sets all drift calibration parameters and the time stamp /// @@ -133,10 +125,6 @@ void TPCFastTransform::setCalibration(int64_t timeStamp, float t0, float vDrift, mTimeStamp = timeStamp; mT0 = t0; mVdrift = vDrift; - mVdriftCorrY = vDriftCorrY; - mLdriftCorr = lDriftCorr; - mTOFcorr = tofCorr; - mPrimVtxZ = primVtxZ; mConstructionMask |= ConstructionExtraState::CalibrationIsSet; } @@ -160,10 +148,6 @@ void TPCFastTransform::print() const LOG(info) << "mApplyCorrection = " << mApplyCorrection; LOG(info) << "mT0 = " << mT0; LOG(info) << "mVdrift = " << mVdrift; - LOG(info) << "mVdriftCorrY = " << mVdriftCorrY; - LOG(info) << "mLdriftCorr = " << mLdriftCorr; - LOG(info) << "mTOFcorr = " << mTOFcorr; - LOG(info) << "mPrimVtxZ = " << mPrimVtxZ; LOG(info) << "mLumi = " << mLumi; LOG(info) << "mLumiError = " << mLumiError; LOG(info) << "mIDC = " << mIDC; diff --git a/GPU/TPCFastTransformation/TPCFastTransform.h b/GPU/TPCFastTransformation/TPCFastTransform.h index d9e35ba8bf405..d7b286eb74941 100644 --- a/GPU/TPCFastTransformation/TPCFastTransform.h +++ b/GPU/TPCFastTransformation/TPCFastTransform.h @@ -46,14 +46,14 @@ struct TPCSlowSpaceChargeCorrection { ~TPCSlowSpaceChargeCorrection(); /// getting the corrections for global coordinates - void getCorrections(const float gx, const float gy, const float gz, const int32_t slice, float& gdxC, float& gdyC, float& gdzC) const; + void getCorrections(const float gx, const float gy, const float gz, const int32_t sector, float& gdxC, float& gdyC, float& gdzC) const; o2::tpc::SpaceCharge* mCorr{nullptr}; ///< reference space charge corrections #else ~TPCSlowSpaceChargeCorrection() = default; /// setting dummy corrections for GPU - GPUd() void getCorrections(const float gx, const float gy, const float gz, const int32_t slice, float& gdxC, float& gdyC, float& gdzC) const + GPUd() void getCorrections(const float gx, const float gy, const float gz, const int32_t sector, float& gdxC, float& gdyC, float& gdzC) const { gdxC = 0; gdyC = 0; @@ -159,7 +159,7 @@ class TPCFastTransform : public FlatObject /// /// It must be called once during construction, /// but also may be called afterwards to reset these parameters. - void setCalibration(int64_t timeStamp, float t0, float vDrift, float vDriftCorrY, float lDriftCorr, float tofCorr, float primVtxZ); + void setCalibration1(int64_t timeStamp, float t0, float vDrift); /// Set Lumi info void setLumi(float l) { mLumi = l; } @@ -182,50 +182,46 @@ class TPCFastTransform : public FlatObject /// _______________ The main method: cluster transformation _______________________ /// - /// Transforms raw TPC coordinates to local XYZ withing a slice - /// taking calibration + alignment into account. + /// Transforms raw TPC coordinates to local XYZ withing a sector + /// taking calibration into account. /// - GPUd() void Transform(int32_t slice, int32_t row, float pad, float time, float& x, float& y, float& z, float vertexTime = 0, const TPCFastTransform* ref = nullptr, const TPCFastTransform* ref2 = nullptr, float scale = 0.f, float scale2 = 0.f, int32_t scaleMode = 0) const; - GPUd() void TransformXYZ(int32_t slice, int32_t row, float& x, float& y, float& z, const TPCFastTransform* ref = nullptr, const TPCFastTransform* ref2 = nullptr, float scale = 0.f, float scale2 = 0.f, int32_t scaleMode = 0) const; + GPUd() void Transform(int32_t sector, int32_t row, float pad, float time, float& x, float& y, float& z, float vertexTime = 0, const TPCFastTransform* ref = nullptr, const TPCFastTransform* ref2 = nullptr, float scale = 0.f, float scale2 = 0.f, int32_t scaleMode = 0) const; + GPUd() void TransformXYZ(int32_t sector, int32_t row, float& x, float& y, float& z, const TPCFastTransform* ref = nullptr, const TPCFastTransform* ref2 = nullptr, float scale = 0.f, float scale2 = 0.f, int32_t scaleMode = 0) const; /// Transformation in the time frame - GPUd() void TransformInTimeFrame(int32_t slice, int32_t row, float pad, float time, float& x, float& y, float& z, float maxTimeBin) const; - GPUd() void TransformInTimeFrame(int32_t slice, float time, float& z, float maxTimeBin) const; + GPUd() void TransformInTimeFrame(int32_t sector, int32_t row, float pad, float time, float& x, float& y, float& z, float maxTimeBin) const; + GPUd() void TransformInTimeFrame(int32_t sector, float time, float& z, float maxTimeBin) const; /// Inverse transformation - GPUd() void InverseTransformInTimeFrame(int32_t slice, int32_t row, float /*x*/, float y, float z, float& pad, float& time, float maxTimeBin) const; - GPUd() float InverseTransformInTimeFrame(int32_t slice, float z, float maxTimeBin) const; + GPUd() void InverseTransformInTimeFrame(int32_t sector, int32_t row, float /*x*/, float y, float z, float& pad, float& time, float maxTimeBin) const; + GPUd() float InverseTransformInTimeFrame(int32_t roc, float z, float maxTimeBin) const; /// Inverse transformation: Transformed Y and Z -> transformed X - GPUd() void InverseTransformYZtoX(int32_t slice, int32_t row, float y, float z, float& x, const TPCFastTransform* ref = nullptr, const TPCFastTransform* ref2 = nullptr, float scale = 0.f, float scale2 = 0.f, int32_t scaleMode = 0) const; + GPUd() void InverseTransformYZtoX(int32_t sector, int32_t row, float y, float z, float& x, const TPCFastTransform* ref = nullptr, const TPCFastTransform* ref2 = nullptr, float scale = 0.f, float scale2 = 0.f, int32_t scaleMode = 0) const; /// Inverse transformation: Transformed Y and Z -> Y and Z, transformed w/o space charge correction - GPUd() void InverseTransformYZtoNominalYZ(int32_t slice, int32_t row, float y, float z, float& ny, float& nz, const TPCFastTransform* ref = nullptr, const TPCFastTransform* ref2 = nullptr, float scale = 0.f, float scale2 = 0.f, int32_t scaleMode = 0) const; + GPUd() void InverseTransformYZtoNominalYZ(int32_t sector, int32_t row, float y, float z, float& ny, float& nz, const TPCFastTransform* ref = nullptr, const TPCFastTransform* ref2 = nullptr, float scale = 0.f, float scale2 = 0.f, int32_t scaleMode = 0) const; /// Inverse transformation: Transformed X, Y and Z -> X, Y and Z, transformed w/o space charge correction - GPUd() void InverseTransformXYZtoNominalXYZ(int32_t slice, int32_t row, float x, float y, float z, float& nx, float& ny, float& nz, const TPCFastTransform* ref = nullptr, const TPCFastTransform* ref2 = nullptr, float scale = 0.f, float scale2 = 0.f, int32_t scaleMode = 0) const; + GPUd() void InverseTransformXYZtoNominalXYZ(int32_t sector, int32_t row, float x, float y, float z, float& nx, float& ny, float& nz, const TPCFastTransform* ref = nullptr, const TPCFastTransform* ref2 = nullptr, float scale = 0.f, float scale2 = 0.f, int32_t scaleMode = 0) const; /// Ideal transformation with Vdrift only - without calibration - GPUd() void TransformIdeal(int32_t slice, int32_t row, float pad, float time, float& x, float& y, float& z, float vertexTime) const; - GPUd() void TransformIdealZ(int32_t slice, float time, float& z, float vertexTime) const; + GPUd() void TransformIdeal(int32_t sector, int32_t row, float pad, float time, float& x, float& y, float& z, float vertexTime) const; + GPUd() void TransformIdealZ(int32_t sector, float time, float& z, float vertexTime) const; - GPUd() void convPadTimeToUV(int32_t slice, int32_t row, float pad, float time, float& u, float& v, float vertexTime) const; - GPUd() void convPadTimeToUVinTimeFrame(int32_t slice, int32_t row, float pad, float time, float& u, float& v, float maxTimeBin) const; - GPUd() void convTimeToVinTimeFrame(int32_t slice, float time, float& v, float maxTimeBin) const; + GPUd() void convPadTimeToLocal(int32_t sector, int32_t row, float pad, float time, float& y, float& z, float vertexTime) const; + GPUd() void convPadTimeToLocalInTimeFrame(int32_t sector, int32_t row, float pad, float time, float& y, float& z, float maxTimeBin) const; - GPUd() void convUVtoPadTime(int32_t slice, int32_t row, float u, float v, float& pad, float& time, float vertexTime) const; - GPUd() void convUVtoPadTimeInTimeFrame(int32_t slice, int32_t row, float u, float v, float& pad, float& time, float maxTimeBin) const; - GPUd() void convVtoTime(float v, float& time, float vertexTime) const; + GPUd() void convLocalToPadTime(int32_t sector, int32_t row, float y, float z, float& pad, float& time, float vertexTime) const; + GPUd() void convLocalToPadTimeInTimeFrame(int32_t sector, int32_t row, float y, float z, float& pad, float& time, float maxTimeBin) const; - GPUd() float convTimeToZinTimeFrame(int32_t slice, float time, float maxTimeBin) const; - GPUd() float convZtoTimeInTimeFrame(int32_t slice, float z, float maxTimeBin) const; - GPUd() float convDeltaTimeToDeltaZinTimeFrame(int32_t slice, float deltaTime) const; - GPUd() float convDeltaZtoDeltaTimeInTimeFrame(int32_t slice, float deltaZ) const; + GPUd() float convTimeToZinTimeFrame(int32_t sector, float time, float maxTimeBin) const; + GPUd() float convZtoTimeInTimeFrame(int32_t sector, float z, float maxTimeBin) const; + GPUd() float convDeltaTimeToDeltaZinTimeFrame(int32_t sector, float deltaTime) const; + GPUd() float convDeltaZtoDeltaTimeInTimeFrame(int32_t sector, float deltaZ) const; GPUd() float convDeltaZtoDeltaTimeInTimeFrameAbs(float deltaZ) const; - GPUd() float convZOffsetToVertexTime(int32_t slice, float zOffset, float maxTimeBin) const; - GPUd() float convVertexTimeToZOffset(int32_t slice, float vertexTime, float maxTimeBin) const; - - GPUd() void getTOFcorrection(int32_t slice, int32_t row, float x, float y, float z, float& dz) const; + GPUd() float convZOffsetToVertexTime(float zOffset, float maxTimeBin) const; + GPUd() float convVertexTimeToZOffset(float vertexTime, float maxTimeBin) const; void setApplyCorrectionOn() { mApplyCorrection = 1; } void setApplyCorrectionOff() { mApplyCorrection = 0; } @@ -245,15 +241,6 @@ class TPCFastTransform : public FlatObject /// Return T0 in time bin units GPUd() float getT0() const { return mT0; } - /// Return VdriftCorrY in time_bin / cn - GPUd() float getVdriftCorrY() const { return mVdriftCorrY; } - - /// Return LdriftCorr offset in cm - GPUd() float getLdriftCorr() const { return mLdriftCorr; } - - /// Return TOF correction (vdrift / C) - GPUd() float getTOFCorr() const { return mLdriftCorr; } - /// Return map lumi GPUd() float getLumi() const { return mLumi; } @@ -276,13 +263,13 @@ class TPCFastTransform : public FlatObject GPUd() float getLumiScaleFactor() const { return mLumiScaleFactor; } /// maximal possible drift time of the active area - GPUd() float getMaxDriftTime(int32_t slice, int32_t row, float pad) const; + GPUd() float getMaxDriftTime(int32_t sector, int32_t row, float pad) const; /// maximal possible drift time of the active area - GPUd() float getMaxDriftTime(int32_t slice, int32_t row) const; + GPUd() float getMaxDriftTime(int32_t sector, int32_t row) const; /// maximal possible drift time of the active area - GPUd() float getMaxDriftTime(int32_t slice) const; + GPUd() float getMaxDriftTime(int32_t sector) const; #if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE) @@ -303,6 +290,8 @@ class TPCFastTransform : public FlatObject /// Print method void print() const; + GPUd() float convDriftLengthToTime(float driftLength, float vertexTime) const; + private: /// Enumeration of possible initialization states enum ConstructionExtraState : uint32_t { @@ -330,23 +319,10 @@ class TPCFastTransform : public FlatObject /// /// t = (float) time bin, y = global y /// - /// L(t,y) = (t-mT0)*(mVdrift + mVdriftCorrY*y ) + mLdriftCorr ____ + /// L(t,y) = (t-mT0)*mVdrift ____ /// - float mT0; ///< T0 in [time bin] - float mVdrift; ///< VDrift in [cm/time bin] - float mVdriftCorrY; ///< VDrift correction for global Y[cm] in [1/time bin] - float mLdriftCorr; ///< drift length correction in [cm] - - /// A coefficient for Time-Of-Flight correction: drift length -= EstimatedDistanceToVtx[cm]*mTOFcorr - /// - /// Since this correction requires a knowledge of the spatial position, it is appied after mCorrection, - /// not on the drift length but directly on V coordinate. - /// - /// mTOFcorr == mVdrift/(speed of light) - /// - float mTOFcorr; - - float mPrimVtxZ; ///< Z of the primary vertex, needed for the Time-Of-Flight correction + float mT0; ///< T0 in [time bin] + float mVdrift; ///< VDrift in [cm/time bin] float mLumi; ///< luminosity estimator float mLumiError; ///< error on luminosity @@ -359,293 +335,231 @@ class TPCFastTransform : public FlatObject /// Correction of (x,u,v) with tricubic interpolator on a regular grid TPCSlowSpaceChargeCorrection* mCorrectionSlow{nullptr}; ///< reference space charge corrections - GPUd() void TransformInternal(int32_t slice, int32_t row, float& u, float& v, float& x, const TPCFastTransform* ref, const TPCFastTransform* ref2, float scale, float scale2, int32_t scaleMode) const; + GPUd() void TransformLocal(int32_t sector, int32_t row, float& x, float& y, float& z, const TPCFastTransform* ref, const TPCFastTransform* ref2, float scale, float scale2, int32_t scaleMode) const; - ClassDefNV(TPCFastTransform, 4); + ClassDefNV(TPCFastTransform, 5); }; // ======================================================================= // Inline implementations of some methods // ======================================================================= -GPUdi() void TPCFastTransform::convPadTimeToUV(int32_t slice, int32_t row, float pad, float time, float& u, float& v, float vertexTime) const -{ - bool sideC = (slice >= getGeometry().getNumberOfSlicesA()); - - const TPCFastTransformGeo::RowInfo& rowInfo = getGeometry().getRowInfo(row); - const TPCFastTransformGeo::SliceInfo& sliceInfo = getGeometry().getSliceInfo(slice); - - float x = rowInfo.x; - u = (pad - 0.5f * rowInfo.maxPad) * rowInfo.padWidth; - - float y = sideC ? -u : u; // pads are mirrorred on C-side - float yLab = y * sliceInfo.cosAlpha + x * sliceInfo.sinAlpha; - - v = (time - mT0 - vertexTime) * (mVdrift + mVdriftCorrY * yLab) + mLdriftCorr; // drift length cm -} +// ---------------------------------------------------------------------- -GPUdi() void TPCFastTransform::convTimeToVinTimeFrame(int32_t slice, float time, float& v, float maxTimeBin) const +GPUdi() void TPCFastTransform::convPadTimeToLocal(int32_t sector, int32_t row, float pad, float time, float& y, float& z, float vertexTime) const { - v = (time - mT0 - maxTimeBin) * mVdrift + mLdriftCorr; // drift length cm - if (slice < getGeometry().getNumberOfSlicesA()) { - v += getGeometry().getTPCzLengthA(); - } else { - v += getGeometry().getTPCzLengthC(); - } + float l = (time - mT0 - vertexTime) * mVdrift; // drift length [cm] + const auto localval = getGeometry().convPadDriftLengthToLocal(sector, row, pad, l); + y = localval[0]; + z = localval[1]; } -GPUdi() void TPCFastTransform::convPadTimeToUVinTimeFrame(int32_t slice, int32_t row, float pad, float time, float& u, float& v, float maxTimeBin) const +GPUdi() void TPCFastTransform::convPadTimeToLocalInTimeFrame(int32_t sector, int32_t row, float pad, float time, float& y, float& z, float maxTimeBin) const { - const TPCFastTransformGeo::RowInfo& rowInfo = getGeometry().getRowInfo(row); - u = (pad - 0.5f * rowInfo.maxPad) * rowInfo.padWidth; - convTimeToVinTimeFrame(slice, time, v, maxTimeBin); + float l = (time - mT0 - maxTimeBin) * mVdrift; // drift length [cm] + const auto localval = getGeometry().convPadDriftLengthToLocal(sector, row, pad, l); + y = localval[0]; + z = localval[1]; } -GPUdi() float TPCFastTransform::convZOffsetToVertexTime(int32_t slice, float zOffset, float maxTimeBin) const -{ - if (slice < getGeometry().getNumberOfSlicesA()) { - return maxTimeBin - (getGeometry().getTPCzLengthA() + zOffset) / mVdrift; - } else { - return maxTimeBin - (getGeometry().getTPCzLengthC() - zOffset) / mVdrift; - } -} +// ---------------------------------------------------------------------- -GPUdi() float TPCFastTransform::convVertexTimeToZOffset(int32_t slice, float vertexTime, float maxTimeBin) const +GPUdi() float TPCFastTransform::convZOffsetToVertexTime(float zOffset, float maxTimeBin) const { - if (slice < getGeometry().getNumberOfSlicesA()) { - return (maxTimeBin - vertexTime) * mVdrift - getGeometry().getTPCzLengthA(); - } else { - return -((maxTimeBin - vertexTime) * mVdrift - getGeometry().getTPCzLengthC()); - } + return maxTimeBin - (getGeometry().getTPCzLength() + zOffset) / mVdrift; } -GPUdi() void TPCFastTransform::convUVtoPadTime(int32_t slice, int32_t row, float u, float v, float& pad, float& time, float vertexTime) const +GPUdi() float TPCFastTransform::convVertexTimeToZOffset(float vertexTime, float maxTimeBin) const { - bool sideC = (slice >= getGeometry().getNumberOfSlicesA()); - - const TPCFastTransformGeo::RowInfo& rowInfo = getGeometry().getRowInfo(row); - const TPCFastTransformGeo::SliceInfo& sliceInfo = getGeometry().getSliceInfo(slice); - - pad = u / rowInfo.padWidth + 0.5f * rowInfo.maxPad; - - float x = rowInfo.x; - float y = sideC ? -u : u; // pads are mirrorred on C-side - float yLab = y * sliceInfo.cosAlpha + x * sliceInfo.sinAlpha; - time = mT0 + vertexTime + (v - mLdriftCorr) / (mVdrift + mVdriftCorrY * yLab); + return (maxTimeBin - vertexTime) * mVdrift - getGeometry().getTPCzLength(); } -GPUdi() void TPCFastTransform::convVtoTime(float v, float& time, float vertexTime) const +GPUdi() float TPCFastTransform::convDriftLengthToTime(float driftLength, float vertexTime) const { - float yLab = 0.f; - time = mT0 + vertexTime + (v - mLdriftCorr) / (mVdrift + mVdriftCorrY * yLab); + return (mT0 + vertexTime + driftLength / mVdrift); } -GPUdi() void TPCFastTransform::convUVtoPadTimeInTimeFrame(int32_t slice, int32_t row, float u, float v, float& pad, float& time, float maxTimeBin) const +// ---------------------------------------------------------------------- + +GPUdi() void TPCFastTransform::convLocalToPadTime(int32_t sector, int32_t row, float y, float z, float& pad, float& time, float vertexTime) const { - if (slice < getGeometry().getNumberOfSlicesA()) { - v -= getGeometry().getTPCzLengthA(); - } else { - v -= getGeometry().getTPCzLengthC(); - } - const TPCFastTransformGeo::RowInfo& rowInfo = getGeometry().getRowInfo(row); - pad = u / rowInfo.padWidth + 0.5f * rowInfo.maxPad; - time = mT0 + maxTimeBin + (v - mLdriftCorr) / mVdrift; + const auto padLength = getGeometry().convLocalToPadDriftLength(sector, row, y, z); + pad = padLength[0]; + time = convDriftLengthToTime(padLength[1], vertexTime); } -GPUdi() void TPCFastTransform::getTOFcorrection(int32_t slice, int32_t /*row*/, float x, float y, float z, float& dz) const +GPUdi() void TPCFastTransform::convLocalToPadTimeInTimeFrame(int32_t sector, int32_t row, float y, float z, float& pad, float& time, float maxTimeBin) const { - // calculate time of flight correction for z coordinate - - bool sideC = (slice >= getGeometry().getNumberOfSlicesA()); - float distZ = z - mPrimVtxZ; - float dv = -GPUCommonMath::Sqrt(x * x + y * y + distZ * distZ) * mTOFcorr; - dz = sideC ? dv : -dv; + const auto padLength = getGeometry().convLocalToPadDriftLength(sector, row, y, z); + pad = padLength[0]; + time = convDriftLengthToTime(padLength[1], maxTimeBin); } -GPUdi() void TPCFastTransform::TransformInternal(int32_t slice, int32_t row, float& u, float& v, float& x, const TPCFastTransform* ref, const TPCFastTransform* ref2, float scale, float scale2, int32_t scaleMode) const +// ---------------------------------------------------------------------- + +GPUdi() void TPCFastTransform::TransformLocal(int32_t sector, int32_t row, float& x, float& y, float& z, const TPCFastTransform* ref, const TPCFastTransform* ref2, float scale, float scale2, int32_t scaleMode) const { GPUCA_RTC_SPECIAL_CODE(ref2 = nullptr; scale2 = 0.f;); - if (mApplyCorrection) { - float dx = 0.f, du = 0.f, dv = 0.f; - if ((scale >= 0.f) || (scaleMode == 1) || (scaleMode == 2)) { + + if (!mApplyCorrection) { + return; + } + + float dx = 0.f, dy = 0.f, dz = 0.f; + + if ((scale >= 0.f) || (scaleMode == 1) || (scaleMode == 2)) { #ifndef GPUCA_GPUCODE - if (mCorrectionSlow) { - float ly, lz; - getGeometry().convUVtoLocal(slice, u, v, ly, lz); - float gx, gy, gz; - getGeometry().convLocalToGlobal(slice, x, ly, lz, gx, gy, gz); - - float gdxC, gdyC, gdzC; - mCorrectionSlow->getCorrections(gx, gy, gz, slice, gdxC, gdyC, gdzC); - getGeometry().convGlobalToLocal(slice, gdxC, gdyC, gdzC, dx, du, dv); - - if (slice >= 18) { - du = -du; // mirror for c-Side - } else { - dv = -dv; // mirror z for A-Side - } - } else + if (mCorrectionSlow) { + float gx, gy, gz; + getGeometry().convLocalToGlobal(sector, x, y, z, gx, gy, gz); + float gdxC, gdyC, gdzC; + mCorrectionSlow->getCorrections(gx, gy, gz, sector, gdxC, gdyC, gdzC); + getGeometry().convGlobalToLocal(sector, gdxC, gdyC, gdzC, dx, dy, dz); + } else #endif // GPUCA_GPUCODE - { - mCorrection.getCorrection(slice, row, u, v, dx, du, dv); - if (ref) { - if ((scale > 0.f) && (scaleMode == 0)) { // scaling was requested - float dxRef, duRef, dvRef; - ref->mCorrection.getCorrection(slice, row, u, v, dxRef, duRef, dvRef); - dx = (dx - dxRef) * scale + dxRef; - du = (du - duRef) * scale + duRef; - dv = (dv - dvRef) * scale + dvRef; - } else if ((scale != 0.f) && ((scaleMode == 1) || (scaleMode == 2))) { - float dxRef, duRef, dvRef; - ref->mCorrection.getCorrection(slice, row, u, v, dxRef, duRef, dvRef); - dx = dxRef * scale + dx; - du = duRef * scale + du; - dv = dvRef * scale + dv; - } - } - if (ref2 && (scale2 != 0)) { - float dxRef, duRef, dvRef; - ref2->mCorrection.getCorrection(slice, row, u, v, dxRef, duRef, dvRef); - dx = dxRef * scale2 + dx; - du = duRef * scale2 + du; - dv = dvRef * scale2 + dv; + { + const auto corrLocal = mCorrection.getCorrectionLocal(sector, row, y, z); + dx = corrLocal[0]; + dy = corrLocal[1]; + dz = corrLocal[2]; + if (ref) { + if ((scale > 0.f) && (scaleMode == 0)) { // scaling was requested + auto val = ref->mCorrection.getCorrectionLocal(sector, row, y, z); + dx = (dx - val[0]) * scale + val[0]; + dy = (dy - val[1]) * scale + val[1]; + dz = (dz - val[2]) * scale + val[2]; + } else if ((scale != 0.f) && ((scaleMode == 1) || (scaleMode == 2))) { + auto val = ref->mCorrection.getCorrectionLocal(sector, row, y, z); + dx = val[0] * scale + dx; + dy = val[1] * scale + dy; + dz = val[2] * scale + dz; } } + if (ref2 && (scale2 != 0)) { + auto val = ref2->mCorrection.getCorrectionLocal(sector, row, y, z); + dx = val[0] * scale2 + dx; + dy = val[1] * scale2 + dy; + dz = val[2] * scale2 + dz; + } } - GPUCA_DEBUG_STREAMER_CHECK(if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamFastTransform)) { - float ly, lz; - getGeometry().convUVtoLocal(slice, u, v, ly, lz); + } - float gx, gy, gz; - getGeometry().convLocalToGlobal(slice, x, ly, lz, gx, gy, gz); + GPUCA_DEBUG_STREAMER_CHECK(if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamFastTransform)) { + float lx = x, ly = y, lz = z; - float lyT, lzT; - float uCorr = u + du; - float vCorr = v + dv; - float lxT = x + dx; - getGeometry().convUVtoLocal(slice, uCorr, vCorr, lyT, lzT); + float gx, gy, gz; + getGeometry().convLocalToGlobal(sector, lx, ly, lz, gx, gy, gz); - float invYZtoXScaled; - InverseTransformYZtoX(slice, row, lyT, lzT, invYZtoXScaled, ref, ref2, scale, scale2, scaleMode); + float lxT = lx + dx; + float lyT = ly + dy; + float lzT = lz + dz; - float invYZtoX; - InverseTransformYZtoX(slice, row, lyT, lzT, invYZtoX); + float invYZtoXScaled; + InverseTransformYZtoX(sector, row, lyT, lzT, invYZtoXScaled, ref, ref2, scale, scale2, scaleMode); - float YZtoNominalY; - float YZtoNominalZ; - InverseTransformYZtoNominalYZ(slice, row, lyT, lzT, YZtoNominalY, YZtoNominalZ); + float invYZtoX; + InverseTransformYZtoX(sector, row, lyT, lzT, invYZtoX); - float YZtoNominalYScaled; - float YZtoNominalZScaled; - InverseTransformYZtoNominalYZ(slice, row, lyT, lzT, YZtoNominalYScaled, YZtoNominalZScaled, ref, ref2, scale, scale2, scaleMode); + float YZtoNominalY; + float YZtoNominalZ; + InverseTransformYZtoNominalYZ(sector, row, lyT, lzT, YZtoNominalY, YZtoNominalZ); - float dxRef, duRef, dvRef; - if (ref) { - ref->mCorrection.getCorrection(slice, row, u, v, dxRef, duRef, dvRef); - } + float YZtoNominalYScaled; + float YZtoNominalZScaled; + InverseTransformYZtoNominalYZ(sector, row, lyT, lzT, YZtoNominalYScaled, YZtoNominalZScaled, ref, ref2, scale, scale2, scaleMode); - float dxRef2, duRef2, dvRef2; - if (ref2) { - ref2->mCorrection.getCorrection(slice, row, u, v, dxRef2, duRef2, dvRef2); - } + float dxRef = 0.f, dyRef = 0.f, dzRef = 0.f; + if (ref) { + const auto corr = ref->mCorrection.getCorrectionLocal(sector, row, y, z); + dxRef = corr[0]; + dyRef = corr[1]; + dzRef = corr[2]; + } - float dxOrig, duOrig, dvOrig; - mCorrection.getCorrection(slice, row, u, v, dxOrig, duOrig, dvOrig); - - o2::utils::DebugStreamer::instance()->getStreamer("debug_fasttransform", "UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName("tree_Transform").data() - // corrections in x, u, v - << "dxOrig=" << dxOrig - << "duOrig=" << duOrig - << "dvOrig=" << dvOrig - << "dxRef=" << dxRef - << "duRef=" << duRef - << "dvRef=" << dvRef - << "dxRef2=" << dxRef2 - << "duRef2=" << duRef2 - << "dvRef2=" << dvRef2 - << "dx=" << dx - << "du=" << du - << "dv=" << dv - << "v=" << v - << "u=" << u - << "row=" << row - << "slice=" << slice - << "scale=" << scale - << "scale2=" << scale2 - // original local coordinates - << "ly=" << ly - << "lz=" << lz - << "lx=" << x - // corrected local coordinated - << "lxT=" << lxT - << "lyT=" << lyT - << "lzT=" << lzT - // global uncorrected coordinates - << "gx=" << gx - << "gy=" << gy - << "gz=" << gz - // some transformations which are applied - << "invYZtoX=" << invYZtoX - << "invYZtoXScaled=" << invYZtoXScaled - << "YZtoNominalY=" << YZtoNominalY - << "YZtoNominalYScaled=" << YZtoNominalYScaled - << "YZtoNominalZ=" << YZtoNominalZ - << "YZtoNominalZScaled=" << YZtoNominalZScaled - << "scaleMode=" << scaleMode - << "\n"; - }) - - x += dx; - u += du; - v += dv; - } + float dxRef2 = 0.f, dyRef2 = 0.f, dzRef2 = 0.f; + if (ref2) { + const auto corr = ref2->mCorrection.getCorrectionLocal(sector, row, y, z); + dxRef2 = corr[0]; + dyRef2 = corr[1]; + dzRef2 = corr[2]; + } + + auto [dxOrig, dyOrig, dzOrig] = mCorrection.getCorrectionLocal(sector, row, y, z); + + o2::utils::DebugStreamer::instance()->getStreamer("debug_fasttransform", "UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName("tree_Transform").data() + // corrections in x, u, v + << "dxOrig=" << dxOrig + << "dyOrig=" << dyOrig + << "dzOrig=" << dzOrig + << "dxRef=" << dxRef + << "dyRef=" << dyRef + << "dzRef=" << dzRef + << "dxRef2=" << dxRef2 + << "dyRef2=" << dyRef2 + << "dzRef2=" << dzRef2 + << "dx=" << dx + << "dy=" << dy + << "dz=" << dz + << "row=" << row + << "sector=" << sector + << "scale=" << scale + << "scale2=" << scale2 + // original local coordinates + << "ly=" << ly + << "lz=" << lz + << "lx=" << lx + // corrected local coordinated + << "lxT=" << lxT + << "lyT=" << lyT + << "lzT=" << lzT + // global uncorrected coordinates + << "gx=" << gx + << "gy=" << gy + << "gz=" << gz + // some transformations which are applied + << "invYZtoX=" << invYZtoX + << "invYZtoXScaled=" << invYZtoXScaled + << "YZtoNominalY=" << YZtoNominalY + << "YZtoNominalYScaled=" << YZtoNominalYScaled + << "YZtoNominalZ=" << YZtoNominalZ + << "YZtoNominalZScaled=" << YZtoNominalZScaled + << "scaleMode=" << scaleMode + << "\n"; + }) + + x += dx; + y += dy; + z += dz; } -GPUdi() void TPCFastTransform::TransformXYZ(int32_t slice, int32_t row, float& x, float& y, float& z, const TPCFastTransform* ref, const TPCFastTransform* ref2, float scale, float scale2, int32_t scaleMode) const +GPUdi() void TPCFastTransform::TransformXYZ(int32_t sector, int32_t row, float& x, float& y, float& z, const TPCFastTransform* ref, const TPCFastTransform* ref2, float scale, float scale2, int32_t scaleMode) const { - float u, v; - getGeometry().convLocalToUV(slice, y, z, u, v); - TransformInternal(slice, row, u, v, x, ref, ref2, scale, scale2, scaleMode); - getGeometry().convUVtoLocal(slice, u, v, y, z); - float dzTOF = 0; - getTOFcorrection(slice, row, x, y, z, dzTOF); - z += dzTOF; + + TransformLocal(sector, row, x, y, z, ref, ref2, scale, scale2, scaleMode); } -GPUdi() void TPCFastTransform::Transform(int32_t slice, int32_t row, float pad, float time, float& x, float& y, float& z, float vertexTime, const TPCFastTransform* ref, const TPCFastTransform* ref2, float scale, float scale2, int32_t scaleMode) const +GPUdi() void TPCFastTransform::Transform(int32_t sector, int32_t row, float pad, float time, float& x, float& y, float& z, float vertexTime, const TPCFastTransform* ref, const TPCFastTransform* ref2, float scale, float scale2, int32_t scaleMode) const { /// _______________ The main method: cluster transformation _______________________ /// - /// Transforms raw TPC coordinates to local XYZ withing a slice - /// taking calibration + alignment into account. + /// Transforms raw TPC coordinates to local XYZ withing a sector + /// taking calibration into account. /// const TPCFastTransformGeo::RowInfo& rowInfo = getGeometry().getRowInfo(row); - // const SliceInfo &sliceInfo = getSliceInfo( slice ); - // bool sideC = ( slice >= NumberOfSlices / 2 ); - x = rowInfo.x; - float u = 0, v = 0; - convPadTimeToUV(slice, row, pad, time, u, v, vertexTime); - - TransformInternal(slice, row, u, v, x, ref, ref2, scale, scale2, scaleMode); - - getGeometry().convUVtoLocal(slice, u, v, y, z); - - float dzTOF = 0; - getTOFcorrection(slice, row, x, y, z, dzTOF); - z += dzTOF; + convPadTimeToLocal(sector, row, pad, time, y, z, vertexTime); + TransformLocal(sector, row, x, y, z, ref, ref2, scale, scale2, scaleMode); } -GPUdi() void TPCFastTransform::TransformInTimeFrame(int32_t slice, float time, float& z, float maxTimeBin) const +GPUdi() void TPCFastTransform::TransformInTimeFrame(int32_t sector, float time, float& z, float maxTimeBin) const { - float v = 0; - convTimeToVinTimeFrame(slice, time, v, maxTimeBin); - getGeometry().convVtoLocal(slice, v, z); + float l = (time - mT0 - maxTimeBin) * mVdrift; // drift length cm + z = getGeometry().convDriftLengthToZ1(sector, l); } -GPUdi() void TPCFastTransform::TransformInTimeFrame(int32_t slice, int32_t row, float pad, float time, float& x, float& y, float& z, float maxTimeBin) const +GPUdi() void TPCFastTransform::TransformInTimeFrame(int32_t sector, int32_t row, float pad, float time, float& x, float& y, float& z, float maxTimeBin) const { /// _______________ Special cluster transformation for a time frame _______________________ /// @@ -655,58 +569,52 @@ GPUdi() void TPCFastTransform::TransformInTimeFrame(int32_t slice, int32_t row, const TPCFastTransformGeo::RowInfo& rowInfo = getGeometry().getRowInfo(row); x = rowInfo.x; - float u = 0, v = 0; - convPadTimeToUVinTimeFrame(slice, row, pad, time, u, v, maxTimeBin); - getGeometry().convUVtoLocal(slice, u, v, y, z); + convPadTimeToLocalInTimeFrame(sector, row, pad, time, y, z, maxTimeBin); } -GPUdi() void TPCFastTransform::InverseTransformInTimeFrame(int32_t slice, int32_t row, float /*x*/, float y, float z, float& pad, float& time, float maxTimeBin) const +GPUdi() void TPCFastTransform::InverseTransformInTimeFrame(int32_t sector, int32_t row, float /*x*/, float y, float z, float& pad, float& time, float maxTimeBin) const { /// Inverse transformation to TransformInTimeFrame - float u = 0, v = 0; - getGeometry().convLocalToUV(slice, y, z, u, v); - convUVtoPadTimeInTimeFrame(slice, row, u, v, pad, time, maxTimeBin); + convLocalToPadTimeInTimeFrame(sector, row, y, z, pad, time, maxTimeBin); } -GPUdi() float TPCFastTransform::InverseTransformInTimeFrame(int32_t slice, float z, float maxTimeBin) const +GPUdi() float TPCFastTransform::InverseTransformInTimeFrame(int32_t sector, float z, float maxTimeBin) const { float pad, time; - InverseTransformInTimeFrame(slice, 0, 0, 0, z, pad, time, maxTimeBin); + InverseTransformInTimeFrame(sector, 0, 0, 0, z, pad, time, maxTimeBin); return time; } -GPUdi() void TPCFastTransform::TransformIdealZ(int32_t slice, float time, float& z, float vertexTime) const +GPUdi() void TPCFastTransform::TransformIdealZ(int32_t sector, float time, float& z, float vertexTime) const { /// _______________ The main method: cluster transformation _______________________ /// - /// Transforms time TPC coordinates to local Z withing a slice + /// Transforms time TPC coordinates to local Z withing a sector /// Ideal transformation: only Vdrift from DCS. /// No space charge corrections, no time of flight correction /// - float v = (time - mT0 - vertexTime) * mVdrift; // drift length cm - getGeometry().convVtoLocal(slice, v, z); + float l = (time - mT0 - vertexTime) * mVdrift; // drift length cm + z = getGeometry().convDriftLengthToZ1(sector, l); } -GPUdi() void TPCFastTransform::TransformIdeal(int32_t slice, int32_t row, float pad, float time, float& x, float& y, float& z, float vertexTime) const +GPUdi() void TPCFastTransform::TransformIdeal(int32_t sector, int32_t row, float pad, float time, float& x, float& y, float& z, float vertexTime) const { /// _______________ The main method: cluster transformation _______________________ /// - /// Transforms raw TPC coordinates to local XYZ withing a slice + /// Transforms raw TPC coordinates to local XYZ withing a sector /// Ideal transformation: only Vdrift from DCS. /// No space charge corrections, no time of flight correction /// - const TPCFastTransformGeo::RowInfo& rowInfo = getGeometry().getRowInfo(row); - - x = rowInfo.x; - float u = (pad - 0.5f * rowInfo.maxPad) * rowInfo.padWidth; - float v = (time - mT0 - vertexTime) * mVdrift; // drift length cm - - getGeometry().convUVtoLocal(slice, u, v, y, z); + x = getGeometry().getRowInfo(row).x; + float driftLength = (time - mT0 - vertexTime) * mVdrift; // drift length cm + const auto localval = getGeometry().convPadDriftLengthToLocal(sector, row, pad, driftLength); + y = localval[0]; + z = localval[1]; } -GPUdi() float TPCFastTransform::convTimeToZinTimeFrame(int32_t slice, float time, float maxTimeBin) const +GPUdi() float TPCFastTransform::convTimeToZinTimeFrame(int32_t sector, float time, float maxTimeBin) const { /// _______________ Special cluster transformation for a time frame _______________________ /// @@ -715,32 +623,22 @@ GPUdi() float TPCFastTransform::convTimeToZinTimeFrame(int32_t slice, float time /// Only Z coordinate. /// - float v = (time - mT0 - maxTimeBin) * mVdrift + mLdriftCorr; // drift length cm - float z = getGeometry().getTPCalignmentZ(); // global TPC alignment - if (slice < getGeometry().getNumberOfSlicesA()) { - z -= v; - } else { - z += v; - } + float v = (time - mT0 - maxTimeBin) * mVdrift; // drift length cm + float z = (sector < getGeometry().getNumberOfSectorsA()) ? -v : v; return z; } -GPUdi() float TPCFastTransform::convZtoTimeInTimeFrame(int32_t slice, float z, float maxTimeBin) const +GPUdi() float TPCFastTransform::convZtoTimeInTimeFrame(int32_t sector, float z, float maxTimeBin) const { /// Inverse transformation of convTimeToZinTimeFrame() - float v; - if (slice < getGeometry().getNumberOfSlicesA()) { - v = getGeometry().getTPCalignmentZ() - z; - } else { - v = z - getGeometry().getTPCalignmentZ(); - } - return mT0 + maxTimeBin + (v - mLdriftCorr) / mVdrift; + float v = (sector < getGeometry().getNumberOfSectorsA()) ? -z : z; + return mT0 + maxTimeBin + v / mVdrift; } -GPUdi() float TPCFastTransform::convDeltaTimeToDeltaZinTimeFrame(int32_t slice, float deltaTime) const +GPUdi() float TPCFastTransform::convDeltaTimeToDeltaZinTimeFrame(int32_t sector, float deltaTime) const { float deltaZ = deltaTime * mVdrift; - return slice < getGeometry().getNumberOfSlicesA() ? -deltaZ : deltaZ; + return sector < getGeometry().getNumberOfSectorsA() ? -deltaZ : deltaZ; } GPUdi() float TPCFastTransform::convDeltaZtoDeltaTimeInTimeFrameAbs(float deltaZ) const @@ -748,150 +646,117 @@ GPUdi() float TPCFastTransform::convDeltaZtoDeltaTimeInTimeFrameAbs(float deltaZ return deltaZ / mVdrift; } -GPUdi() float TPCFastTransform::convDeltaZtoDeltaTimeInTimeFrame(int32_t slice, float deltaZ) const +GPUdi() float TPCFastTransform::convDeltaZtoDeltaTimeInTimeFrame(int32_t sector, float deltaZ) const { float deltaT = deltaZ / mVdrift; - return slice < getGeometry().getNumberOfSlicesA() ? -deltaT : deltaT; + return sector < getGeometry().getNumberOfSectorsA() ? -deltaT : deltaT; } -/* -GPUdi() float TPCFastTransform::getLastCalibratedTimeBin(int32_t slice) const -{ - /// Return a value of the last timebin where correction map is valid - float u, v, pad, time; - getGeometry().convScaledUVtoUV(slice, 0, 0.f, 1.f, u, v); - convUVtoPadTime(slice, 0, u, v, pad, time, 0); - return time; -} -*/ - -GPUdi() float TPCFastTransform::getMaxDriftTime(int32_t slice, int32_t row, float pad) const +GPUdi() float TPCFastTransform::getMaxDriftTime(int32_t sector, int32_t row, float pad) const { /// maximal possible drift time of the active area - float maxL = mCorrection.getMaxDriftLength(slice, row, pad); - - bool sideC = (slice >= getGeometry().getNumberOfSlicesA()); - const TPCFastTransformGeo::RowInfo& rowInfo = getGeometry().getRowInfo(row); - const TPCFastTransformGeo::SliceInfo& sliceInfo = getGeometry().getSliceInfo(slice); - - float x = rowInfo.x; - float u = (pad - 0.5f * rowInfo.maxPad) * rowInfo.padWidth; - - float y = sideC ? -u : u; // pads are mirrorred on C-side - float yLab = y * sliceInfo.cosAlpha + x * sliceInfo.sinAlpha; - return mT0 + (maxL - mLdriftCorr) / (mVdrift + mVdriftCorrY * yLab); + return convDriftLengthToTime(getGeometry().getTPCzLength(), 0.f); } -GPUdi() float TPCFastTransform::getMaxDriftTime(int32_t slice, int32_t row) const +GPUdi() float TPCFastTransform::getMaxDriftTime(int32_t sector, int32_t row) const { /// maximal possible drift time of the active area - float maxL = mCorrection.getMaxDriftLength(slice, row); - float maxTime = 0.f; - convVtoTime(maxL, maxTime, 0.f); - return maxTime; + return convDriftLengthToTime(getGeometry().getTPCzLength(), 0.f); } -GPUdi() float TPCFastTransform::getMaxDriftTime(int32_t slice) const +GPUdi() float TPCFastTransform::getMaxDriftTime(int32_t sector) const { /// maximal possible drift time of the active area - float maxL = mCorrection.getMaxDriftLength(slice); - float maxTime = 0.f; - convVtoTime(maxL, maxTime, 0.f); - return maxTime; + return convDriftLengthToTime(getGeometry().getTPCzLength(), 0.f); } -GPUdi() void TPCFastTransform::InverseTransformYZtoX(int32_t slice, int32_t row, float y, float z, float& x, const TPCFastTransform* ref, const TPCFastTransform* ref2, float scale, float scale2, int32_t scaleMode) const +GPUdi() void TPCFastTransform::InverseTransformYZtoX(int32_t sector, int32_t row, float realY, float realZ, float& realX, const TPCFastTransform* ref, const TPCFastTransform* ref2, float scale, float scale2, int32_t scaleMode) const { GPUCA_RTC_SPECIAL_CODE(ref2 = nullptr; scale2 = 0.f;); /// Transformation y,z -> x - float u = 0, v = 0; - getGeometry().convLocalToUV(slice, y, z, u, v); + + float dx = 0.f; + if ((scale >= 0.f) || (scaleMode == 1) || (scaleMode == 2)) { - mCorrection.getCorrectionInvCorrectedX(slice, row, u, v, x); + dx = mCorrection.getCorrectionXatRealYZ(sector, row, realY, realZ); if (ref) { // scaling was requested if (scaleMode == 0 && scale > 0.f) { - float xr; - ref->mCorrection.getCorrectionInvCorrectedX(slice, row, u, v, xr); - x = (x - xr) * scale + xr; + float dxref = ref->mCorrection.getCorrectionXatRealYZ(sector, row, realY, realZ); + dx = (dx - dxref) * scale + dxref; } else if ((scale != 0) && ((scaleMode == 1) || (scaleMode == 2))) { - float xr; - ref->mCorrection.getCorrectionInvCorrectedX(slice, row, u, v, xr); - x = (xr - getGeometry().getRowInfo(row).x) * scale + x; // xr=mGeo.getRowInfo(row).x + dx; + float dxref = ref->mCorrection.getCorrectionXatRealYZ(sector, row, realY, realZ); + dx = dxref * scale + dx; } } if (ref2 && (scale2 != 0)) { - float xr; - ref2->mCorrection.getCorrectionInvCorrectedX(slice, row, u, v, xr); - x = (xr - getGeometry().getRowInfo(row).x) * scale2 + x; // xr=mGeo.getRowInfo(row).x + dx; + float dxref = ref2->mCorrection.getCorrectionXatRealYZ(sector, row, realY, realZ); + dx = dxref * scale2 + dx; } - } else { - x = mCorrection.getGeometry().getRowInfo(row).x; // corrections are disabled } + + realX = mCorrection.getGeometry().getRowInfo(row).x + dx; + GPUCA_DEBUG_STREAMER_CHECK(if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamFastTransform)) { o2::utils::DebugStreamer::instance()->getStreamer("debug_fasttransform", "UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName("tree_InverseTransformYZtoX").data() - << "slice=" << slice + << "sector=" << sector << "row=" << row << "scale=" << scale - << "y=" << y - << "z=" << z - << "x=" << x - << "v=" << v - << "u=" << u + << "y=" << realY + << "z=" << realZ + << "x=" << realX << "\n"; }) } -GPUdi() void TPCFastTransform::InverseTransformYZtoNominalYZ(int32_t slice, int32_t row, float y, float z, float& ny, float& nz, const TPCFastTransform* ref, const TPCFastTransform* ref2, float scale, float scale2, int32_t scaleMode) const +GPUdi() void TPCFastTransform::InverseTransformYZtoNominalYZ(int32_t sector, int32_t row, float realY, float realZ, float& measuredY, float& measuredZ, const TPCFastTransform* ref, const TPCFastTransform* ref2, float scale, float scale2, int32_t scaleMode) const { + /// Transformation real y,z -> measured y,z + GPUCA_RTC_SPECIAL_CODE(ref2 = nullptr; scale2 = 0.f;); - /// Transformation y,z -> x - float u = 0, v = 0, un = 0, vn = 0; - getGeometry().convLocalToUV(slice, y, z, u, v); + + float dy = 0; + float dz = 0; + if ((scale >= 0.f) || (scaleMode == 1) || (scaleMode == 2)) { - mCorrection.getCorrectionInvUV(slice, row, u, v, un, vn); + const auto corrYZ = mCorrection.getCorrectionYZatRealYZ(sector, row, realY, realZ); + dy = corrYZ[0]; + dz = corrYZ[1]; + if (ref) { // scaling was requested if (scaleMode == 0 && scale > 0.f) { - float unr = 0, vnr = 0; - ref->mCorrection.getCorrectionInvUV(slice, row, u, v, unr, vnr); - un = (un - unr) * scale + unr; - vn = (vn - vnr) * scale + vnr; + const auto val = ref->mCorrection.getCorrectionYZatRealYZ(sector, row, realY, realZ); + dy = (dy - val[0]) * scale + val[0]; + dz = (dz - val[1]) * scale + val[1]; } else if ((scale != 0) && ((scaleMode == 1) || (scaleMode == 2))) { - float unr = 0, vnr = 0; - ref->mCorrection.getCorrectionInvUV(slice, row, u, v, unr, vnr); - un = (unr - u) * scale + un; // unr = u - duv[0]; - vn = (vnr - v) * scale + vn; + const auto val = ref->mCorrection.getCorrectionYZatRealYZ(sector, row, realY, realZ); + dy = val[0] * scale + dy; + dz = val[1] * scale + dz; } if (ref2 && (scale2 != 0)) { - float unr = 0, vnr = 0; - ref2->mCorrection.getCorrectionInvUV(slice, row, u, v, unr, vnr); - un = (unr - u) * scale2 + un; // unr = u - duv[0]; - vn = (vnr - v) * scale2 + vn; + const auto val = ref2->mCorrection.getCorrectionYZatRealYZ(sector, row, realY, realZ); + dy = val[0] * scale2 + dy; + dz = val[1] * scale2 + dz; } } - } else { - un = u; - vn = v; } - getGeometry().convUVtoLocal(slice, un, vn, ny, nz); + + measuredY = realY - dy; + measuredZ = realZ - dz; GPUCA_DEBUG_STREAMER_CHECK(if (o2::utils::DebugStreamer::checkStream(o2::utils::StreamFlags::streamFastTransform)) { o2::utils::DebugStreamer::instance()->getStreamer("debug_fasttransform", "UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName("tree_InverseTransformYZtoNominalYZ").data() - << "slice=" << slice + << "sector=" << sector << "row=" << row << "scale=" << scale - << "y=" << y - << "z=" << z - << "ny=" << ny - << "nz=" << nz - << "u=" << u - << "v=" << v - << "un=" << un - << "vn=" << vn + << "real y=" << realY + << "real z=" << realZ + << "measured y=" << measuredY + << "measured z=" << measuredZ << "\n"; }) } -GPUdi() void TPCFastTransform::InverseTransformXYZtoNominalXYZ(int32_t slice, int32_t row, float x, float y, float z, float& nx, float& ny, float& nz, const TPCFastTransform* ref, const TPCFastTransform* ref2, float scale, float scale2, int32_t scaleMode) const +GPUdi() void TPCFastTransform::InverseTransformXYZtoNominalXYZ(int32_t sector, int32_t row, float x, float y, float z, float& nx, float& ny, float& nz, const TPCFastTransform* ref, const TPCFastTransform* ref2, float scale, float scale2, int32_t scaleMode) const { /// Inverse transformation: Transformed X, Y and Z -> X, Y and Z, transformed w/o space charge correction int32_t row2 = row + 1; @@ -902,8 +767,8 @@ GPUdi() void TPCFastTransform::InverseTransformXYZtoNominalXYZ(int32_t slice, in float nx2, ny2, nz2; // nominal coordinates for row2 nx1 = getGeometry().getRowInfo(row).x; nx2 = getGeometry().getRowInfo(row2).x; - InverseTransformYZtoNominalYZ(slice, row, y, z, ny1, nz1, ref, ref2, scale, scale2, scaleMode); - InverseTransformYZtoNominalYZ(slice, row2, y, z, ny2, nz2, ref, ref2, scale, scale2, scaleMode); + InverseTransformYZtoNominalYZ(sector, row, y, z, ny1, nz1, ref, ref2, scale, scale2, scaleMode); + InverseTransformYZtoNominalYZ(sector, row2, y, z, ny2, nz2, ref, ref2, scale, scale2, scaleMode); float c1 = (nx2 - nx) / (nx2 - nx1); float c2 = (nx - nx1) / (nx2 - nx1); nx = x; diff --git a/GPU/TPCFastTransformation/TPCFastTransformGeo.cxx b/GPU/TPCFastTransformation/TPCFastTransformGeo.cxx index 3c624b3222d77..2fe773a76e4d3 100644 --- a/GPU/TPCFastTransformation/TPCFastTransformGeo.cxx +++ b/GPU/TPCFastTransformation/TPCFastTransformGeo.cxx @@ -28,17 +28,15 @@ using namespace o2::gpu; TPCFastTransformGeo::TPCFastTransformGeo() { // Default Constructor: creates an empty uninitialized object - double dAlpha = 2. * M_PI / (NumberOfSlicesA); - for (int32_t i = 0; i < NumberOfSlices; i++) { - SliceInfo& s = mSliceInfos[i]; - double alpha = dAlpha * (i + 0.5); - s.sinAlpha = sin(alpha); - s.cosAlpha = cos(alpha); + for (int32_t i = 0; i < NumberOfSectors; i++) { + double angle = (i + 0.5) * 2. * M_PI / NumberOfSectorsA; + mSectorInfos[i].sinAlpha = sin(angle); + mSectorInfos[i].cosAlpha = cos(angle); } - mSliceInfos[NumberOfSlices] = SliceInfo{0.f, 0.f}; + mSectorInfos[NumberOfSectors] = SectorInfo{}; for (int32_t i = 0; i < MaxNumberOfRows + 1; i++) { - mRowInfos[i] = RowInfo{0.f, -1, 0.f, 0.f, 0.f, 0.f}; + mRowInfos[i] = RowInfo{}; } } @@ -51,45 +49,25 @@ void TPCFastTransformGeo::startConstruction(int32_t numberOfRows) mConstructionMask = ConstructionState::InProgress; mNumberOfRows = numberOfRows; - mTPCzLengthA = 0.f; - mTPCzLengthC = 0.f; - mTPCalignmentZ = 0.f; - mScaleVtoSVsideA = 0.f; - mScaleVtoSVsideC = 0.f; - mScaleSVtoVsideA = 0.f; - mScaleSVtoVsideC = 0.f; + mTPCzLength = 0.f; for (int32_t i = 0; i < MaxNumberOfRows; i++) { - mRowInfos[i] = RowInfo{0.f, -1, 0.f, 0.f, 0.f, 0.f}; + mRowInfos[i] = RowInfo{}; } } -void TPCFastTransformGeo::setTPCzLength(float tpcZlengthSideA, float tpcZlengthSideC) +void TPCFastTransformGeo::setTPCzLength(float tpcZlength) { /// Sets TPC z length for both sides assert(mConstructionMask & ConstructionState::InProgress); - assert((tpcZlengthSideA > 0.f) && (tpcZlengthSideC > 0.f)); + assert(tpcZlength > 0.f); - mTPCzLengthA = tpcZlengthSideA; - mTPCzLengthC = tpcZlengthSideC; - mScaleSVtoVsideA = tpcZlengthSideA + 3.; // add some extra possible drift length due to the space charge distortions - mScaleSVtoVsideC = tpcZlengthSideC + 3.; - mScaleVtoSVsideA = 1. / mScaleSVtoVsideA; - mScaleVtoSVsideC = 1. / mScaleSVtoVsideC; + mTPCzLength = tpcZlength; mConstructionMask |= ConstructionState::GeometryIsSet; } -void TPCFastTransformGeo::setTPCalignmentZ(float tpcAlignmentZ) -{ - /// Sets the TPC alignment - assert(mConstructionMask & ConstructionState::InProgress); - - mTPCalignmentZ = tpcAlignmentZ; - mConstructionMask |= ConstructionState::AlignmentIsSet; -} - void TPCFastTransformGeo::setTPCrow(int32_t iRow, float x, int32_t nPads, float padWidth) { /// Initializes a TPC row @@ -104,7 +82,7 @@ void TPCFastTransformGeo::setTPCrow(int32_t iRow, float x, int32_t nPads, float // Make scaled U = area between the geometrical sector borders - const double sectorAngle = 2. * M_PI / NumberOfSlicesA; + const double sectorAngle = 2. * M_PI / NumberOfSectorsA; const double scaleXtoRowWidth = 2. * tan(0.5 * sectorAngle); double uWidth = x * scaleXtoRowWidth; // distance to the sector border @@ -112,18 +90,15 @@ void TPCFastTransformGeo::setTPCrow(int32_t iRow, float x, int32_t nPads, float row.x = x; row.maxPad = nPads - 1; row.padWidth = padWidth; - row.u0 = -uWidth / 2.; - row.scaleUtoSU = 1. / uWidth; - row.scaleSUtoU = uWidth; + row.yMin = -uWidth / 2.; } void TPCFastTransformGeo::finishConstruction() { /// Finishes initialization: puts everything to the flat buffer, releases temporary memory - assert(mConstructionMask & ConstructionState::InProgress); // construction in process - assert(mConstructionMask & ConstructionState::GeometryIsSet); // geometry is set - assert(mConstructionMask & ConstructionState::AlignmentIsSet); // alignment is set + assert(mConstructionMask & ConstructionState::InProgress); // construction in process + assert(mConstructionMask & ConstructionState::GeometryIsSet); // geometry is set for (int32_t i = 0; i < mNumberOfRows; i++) { // all TPC rows are initialized assert(getRowInfo(i).maxPad > 0); @@ -138,9 +113,7 @@ void TPCFastTransformGeo::print() const #if !defined(GPUCA_GPUCODE) LOG(info) << "TPC Fast Transformation Geometry: "; LOG(info) << "mNumberOfRows = " << mNumberOfRows; - LOG(info) << "mTPCzLengthA = " << mTPCzLengthA; - LOG(info) << "mTPCzLengthC = " << mTPCzLengthC; - LOG(info) << "mTPCalignmentZ = " << mTPCalignmentZ; + LOG(info) << "mTPCzLength = " << mTPCzLength; LOG(info) << "TPC Rows : "; for (int32_t i = 0; i < mNumberOfRows; i++) { LOG(info) << " tpc row " << i << ": x = " << mRowInfos[i].x << " maxPad = " << mRowInfos[i].maxPad << " padWidth = " << mRowInfos[i].padWidth; @@ -148,7 +121,7 @@ void TPCFastTransformGeo::print() const #endif } -int32_t TPCFastTransformGeo::test(int32_t slice, int32_t row, float ly, float lz) const +int32_t TPCFastTransformGeo::test(int32_t sector, int32_t row, float ly, float lz) const { /// Check consistency of the class @@ -164,45 +137,20 @@ int32_t TPCFastTransformGeo::test(int32_t slice, int32_t row, float ly, float lz float lx1 = 0.f, ly1 = 0.f, lz1 = 0.f; float gx = 0.f, gy = 0.f, gz = 0.f; - convLocalToGlobal(slice, lx, ly, lz, gx, gy, gz); - convGlobalToLocal(slice, gx, gy, gz, lx1, ly1, lz1); + convLocalToGlobal(sector, lx, ly, lz, gx, gy, gz); + convGlobalToLocal(sector, gx, gy, gz, lx1, ly1, lz1); if (fabs(lx1 - lx) > 1.e-4 || fabs(ly1 - ly) > 1.e-4 || fabs(lz1 - lz) > 1.e-7) { LOG(info) << "Error local <-> global: x " << lx << " dx " << lx1 - lx << " y " << ly << " dy " << ly1 - ly << " z " << lz << " dz " << lz1 - lz; error = -3; } - float u = 0.f, v = 0.f; - convLocalToUV(slice, ly, lz, u, v); - convUVtoLocal(slice, u, v, ly1, lz1); - - if (fabs(ly1 - ly) + fabs(lz1 - lz) > 1.e-6) { - LOG(info) << "Error local <-> UV: y " << ly << " dy " << ly1 - ly << " z " << lz << " dz " << lz1 - lz; - error = -4; - } - float su = 0.f, sv = 0.f; + auto [pad, length] = convLocalToPadDriftLength(sector, 10, ly, lz); + auto [ly2, lz2] = convPadDriftLengthToLocal(sector, 10, pad, length); - convUVtoScaledUV(slice, row, u, v, su, sv); - - if (su < 0.f || su > 1.f) { - LOG(info) << "Error scaled U range: u " << u << " su " << su; - error = -5; - } - - float u1 = 0.f, v1 = 0.f; - convScaledUVtoUV(slice, row, su, sv, u1, v1); - - if (fabs(u1 - u) > 1.e-4 || fabs(v1 - v) > 1.e-4) { - LOG(info) << "Error UV<->scaled UV: u " << u << " du " << u1 - u << " v " << v << " dv " << v1 - v; - error = -6; - } - - float pad = convUtoPad(row, u); - u1 = convPadToU(row, pad); - - if (fabs(u1 - u) > 1.e-5) { - LOG(info) << "Error U<->Pad: u " << u << " pad " << pad << " du " << u1 - u; - error = -7; + if (fabs(ly2 - ly) + fabs(lz2 - lz) > 1.e-6) { + LOG(info) << "Error local <-> UV: y " << ly << " dy " << ly2 - ly << " z " << lz << " dz " << lz2 - lz; + error = -4; } #if !defined(GPUCA_GPUCODE) diff --git a/GPU/TPCFastTransformation/TPCFastTransformGeo.h b/GPU/TPCFastTransformation/TPCFastTransformGeo.h index 5eddada1e9acc..09793b6677d83 100644 --- a/GPU/TPCFastTransformation/TPCFastTransformGeo.h +++ b/GPU/TPCFastTransformation/TPCFastTransformGeo.h @@ -18,6 +18,9 @@ #define ALICEO2_GPUCOMMON_TPCFASTTRANSFORMATION_TPCFASTTRANSFORMGEO_H #include "GPUCommonDef.h" +#include "GPUCommonArray.h" +#include "GPUCommonMath.h" + #ifndef GPUCA_GPUCODE_DEVICE #include #include "GPUCommonRtypes.h" @@ -33,26 +36,35 @@ namespace gpu /// class TPCFastTransformGeo { + public: - /// The struct contains necessary info for TPC slice - struct SliceInfo { - float sinAlpha; - float cosAlpha; - ClassDefNV(SliceInfo, 1); + /// The struct contains necessary info for TPC sector + struct SectorInfo { + float sinAlpha{0.f}; ///< sin of the angle between the local x and the global x + float cosAlpha{0.f}; ///< cos of the angle between the local x and the global x + ClassDefNV(SectorInfo, 1); }; /// The struct contains necessary info about TPC padrow struct RowInfo { - float x; ///< nominal X coordinate of the row [cm] - int32_t maxPad; ///< maximal pad number = n pads - 1 - float padWidth; ///< width of pads [cm] - float u0; ///< min. u coordinate - float scaleUtoSU; ///< scale for su (scaled u ) coordinate - float scaleSUtoU; ///< scale for u coordinate - - /// get width in U - GPUd() float getUwidth() const { return -2.f * u0; } - ClassDefNV(RowInfo, 1); + float x{0.f}; ///< nominal X coordinate of the padrow [cm] + int32_t maxPad{0}; ///< maximal pad number = n pads - 1 + float padWidth{0.f}; ///< width of pads [cm] + float yMin{0.f}; ///< min. y coordinate + + /// get Y min + GPUd() float getYmin() const { return yMin; } + + /// get Y max + GPUd() float getYmax() const { return -yMin; } + + /// get Y range + GPUd() std::array getYrange() const { return {getYmin(), getYmax()}; } + + /// get width in Y + GPUd() float getYwidth() const { return -2.f * yMin; } + + ClassDefNV(RowInfo, 2); }; /// _____________ Constructors / destructors __________________________ @@ -76,7 +88,7 @@ class TPCFastTransformGeo /// _______________ Construction interface ________________________ - /// Starts the initialization procedure, reserves temporary memory + /// Starts the initialization psectoredure, reserves temporary memory void startConstruction(int32_t numberOfRows); /// Initializes a TPC row @@ -85,13 +97,7 @@ class TPCFastTransformGeo /// Sets TPC geometry /// /// It must be called once during initialization - void setTPCzLength(float tpcZlengthSideA, float tpcZlengthSideC); - - /// Sets all drift calibration parameters and the time stamp - /// - /// It must be called once during construction, - /// but also may be called afterwards to reset these parameters. - void setTPCalignmentZ(float tpcAlignmentZ); + void setTPCzLength(float tpcZlength); /// Finishes initialization: puts everything to the flat buffer, releases temporary memory void finishConstruction(); @@ -101,72 +107,58 @@ class TPCFastTransformGeo /// _______________ Getters _________________________________ - /// Gives number of TPC slices - GPUd() static constexpr int32_t getNumberOfSlices() { return NumberOfSlices; } + /// Gives number of TPC sectors + GPUd() static constexpr int32_t getNumberOfSectors() { return NumberOfSectors; } - /// Gives number of TPC slices in A side - GPUd() static constexpr int32_t getNumberOfSlicesA() { return NumberOfSlicesA; } + /// Gives number of TPC sectors on the A side + GPUd() static constexpr int32_t getNumberOfSectorsA() { return NumberOfSectorsA; } /// Gives number of TPC rows GPUd() int32_t getNumberOfRows() const { return mNumberOfRows; } - /// Gives slice info - GPUd() const SliceInfo& getSliceInfo(int32_t slice) const; + /// Gives number of TPC rows + GPUd() static constexpr int getMaxNumberOfRows() { return MaxNumberOfRows; } + + /// Gives sector info + GPUd() const SectorInfo& getSectorInfo(int32_t sector) const; /// Gives TPC row info GPUd() const RowInfo& getRowInfo(int32_t row) const; - /// Gives Z length of the TPC, side A - GPUd() float getTPCzLengthA() const { return mTPCzLengthA; } + /// Gives Z length of the TPC, one Z side + GPUd() float getTPCzLength() const { return mTPCzLength; } - /// Gives Z length of the TPC, side C - GPUd() float getTPCzLengthC() const { return mTPCzLengthC; } - - /// Gives Z length of the TPC, depending on the slice - GPUd() float getTPCzLength(int32_t slice) const - { - return (slice < NumberOfSlicesA) ? mTPCzLengthA - : mTPCzLengthC; - } - - /// Gives TPC alignment in Z - GPUd() float getTPCalignmentZ() const { return mTPCalignmentZ; } + /// Gives Z range for the corresponding TPC side + GPUd() std::array getZrange(int32_t sector) const; + GPUd() float getZmin(int32_t sector) const; + GPUd() float getZmax(int32_t sector) const; + GPUd() float getZreadout(int32_t sector) const; /// _______________ Conversion of coordinate systems __________ /// convert Local -> Global c.s. - GPUd() void convLocalToGlobal(int32_t slice, float lx, float ly, float lz, float& gx, float& gy, float& gz) const; + GPUd() void convLocalToGlobal(int32_t sector, float lx, float ly, float lz, float& gx, float& gy, float& gz) const; /// convert Global->Local c.s. - GPUd() void convGlobalToLocal(int32_t slice, float gx, float gy, float gz, float& lx, float& ly, float& lz) const; - - /// convert UV -> Local c.s. - GPUd() void convUVtoLocal(int32_t slice, float u, float v, float& y, float& z) const; - GPUd() void convVtoLocal(int32_t slice, float v, float& z) const; + GPUd() void convGlobalToLocal(int32_t sector, float gx, float gy, float gz, float& lx, float& ly, float& lz) const; - /// convert Local-> UV c.s. - GPUd() void convLocalToUV(int32_t slice, float y, float z, float& u, float& v) const; + /// convert Pad, DriftLength -> Local c.s. + GPUd() std::array convPadDriftLengthToLocal(int32_t sector, int32_t row, float pad, float driftLength) const; - /// convert UV -> Scaled UV - GPUd() void convUVtoScaledUV(int32_t slice, int32_t row, float u, float v, float& su, float& sv) const; + /// convert DriftLength -> Local c.s. + GPUd() float convDriftLengthToZ1(int32_t sector, float driftLength) const; - /// convert Scaled UV -> UV - GPUd() void convScaledUVtoUV(int32_t slice, int32_t row, float su, float sv, float& u, float& v) const; + /// convert Z to DriftLength + GPUd() float convZtoDriftLength1(int32_t sector, float z) const; - /// convert Scaled UV -> Local c.s. - GPUd() void convScaledUVtoLocal(int32_t slice, int32_t row, float su, float sv, float& ly, float& lz) const; - - /// convert Pad coordinate -> U - GPUd() float convPadToU(int32_t row, float pad) const; - - /// convert U -> Pad coordinate - GPUd() float convUtoPad(int32_t row, float u) const; + /// convert Local c.s. -> Pad, DriftLength + GPUd() std::array convLocalToPadDriftLength(int32_t sector, int32_t row, float y, float z) const; /// Print method void print() const; /// Method for testing consistency - int32_t test(int32_t slice, int32_t row, float ly, float lz) const; + int32_t test(int32_t sector, int32_t row, float ly, float lz) const; /// Method for testing consistency int32_t test() const; @@ -174,9 +166,9 @@ class TPCFastTransformGeo private: /// _______________ Data members _______________________________________________ - static constexpr int32_t NumberOfSlices = 36; ///< Number of TPC slices ( slice = inner + outer sector ) - static constexpr int32_t NumberOfSlicesA = NumberOfSlices / 2; ///< Number of TPC slices side A - static constexpr int32_t MaxNumberOfRows = 160; ///< Max Number of TPC rows in a slice + static constexpr int32_t NumberOfSectors = 36; ///< Number of TPC sectors ( sector = inner + outer sector ) + static constexpr int32_t NumberOfSectorsA = NumberOfSectors / 2; ///< Number of TPC sectors side A + static constexpr int32_t MaxNumberOfRows = 160; ///< Max Number of TPC rows in a sector /// _______________ Construction control _______________________________________________ @@ -186,39 +178,37 @@ class TPCFastTransformGeo Constructed = 0x1, ///< the object is constructed, temporary memory is released InProgress = 0x2, ///< construction started: temporary memory is reserved GeometryIsSet = 0x4, ///< the TPC geometry is set - AlignmentIsSet = 0x8 ///< the TPC alignment is set }; uint32_t mConstructionMask = ConstructionState::NotConstructed; ///< mask for constructed object members, first two bytes are used by this class /// _______________ Geometry _______________________________________________ - int32_t mNumberOfRows = 0; ///< Number of TPC rows. It is different for the Run2 and the Run3 setups - float mTPCzLengthA = 0.f; ///< Z length of the TPC, side A - float mTPCzLengthC = 0.f; ///< Z length of the TPC, side C - float mTPCalignmentZ = 0.f; ///< Global Z shift of the TPC detector. It is applied at the end of the transformation. - float mScaleVtoSVsideA = 0.f; ///< scale for v->sv for TPC side A - float mScaleVtoSVsideC = 0.f; ///< scale for v->sv for TPC side C - float mScaleSVtoVsideA = 0.f; ///< scale for sv->v for TPC side A - float mScaleSVtoVsideC = 0.f; ///< scale for sv->v for TPC side C + int32_t mNumberOfRows = 0; ///< Number of TPC rows. It is different for the Run2 and the Run3 setups + float mTPCzLength = 0.f; ///< Z length of one TPC side (A or C) - SliceInfo mSliceInfos[NumberOfSlices + 1]; ///< array of slice information [fixed size] - RowInfo mRowInfos[MaxNumberOfRows + 1]; ///< array of row information [fixed size] + SectorInfo mSectorInfos[NumberOfSectors + 1]; ///< array of sector information [fixed size] + RowInfo mRowInfos[MaxNumberOfRows + 1]; ///< array of row information [fixed size] + + public: + struct SliceInfo { // legacy, needed only for schema evolution + ClassDefNV(SliceInfo, 2); + }; - ClassDefNV(TPCFastTransformGeo, 1); + ClassDefNV(TPCFastTransformGeo, 3); }; // ======================================================================= // Inline implementations of some methods // ======================================================================= -GPUdi() const TPCFastTransformGeo::SliceInfo& TPCFastTransformGeo::getSliceInfo(int32_t slice) const +GPUdi() const TPCFastTransformGeo::SectorInfo& TPCFastTransformGeo::getSectorInfo(int32_t sector) const { - /// Gives slice info - if (slice < 0 || slice >= NumberOfSlices) { // return zero object - slice = NumberOfSlices; + /// Gives sector info + if (sector < 0 || sector >= NumberOfSectors) { // return zero object + sector = NumberOfSectors; } - return mSliceInfos[slice]; + return mSectorInfos[sector]; } GPUdi() const TPCFastTransformGeo::RowInfo& TPCFastTransformGeo::getRowInfo(int32_t row) const @@ -230,105 +220,106 @@ GPUdi() const TPCFastTransformGeo::RowInfo& TPCFastTransformGeo::getRowInfo(int3 return mRowInfos[row]; } -GPUdi() void TPCFastTransformGeo::convLocalToGlobal(int32_t slice, float lx, float ly, float lz, float& gx, float& gy, float& gz) const +GPUdi() void TPCFastTransformGeo::convLocalToGlobal(int32_t sector, float lx, float ly, float lz, float& gx, float& gy, float& gz) const { /// convert Local -> Global c.s. - const SliceInfo& sliceInfo = getSliceInfo(slice); - gx = lx * sliceInfo.cosAlpha - ly * sliceInfo.sinAlpha; - gy = lx * sliceInfo.sinAlpha + ly * sliceInfo.cosAlpha; + const SectorInfo& sectorInfo = getSectorInfo(sector); + gx = lx * sectorInfo.cosAlpha - ly * sectorInfo.sinAlpha; + gy = lx * sectorInfo.sinAlpha + ly * sectorInfo.cosAlpha; gz = lz; } -GPUdi() void TPCFastTransformGeo::convGlobalToLocal(int32_t slice, float gx, float gy, float gz, float& lx, float& ly, float& lz) const +GPUdi() void TPCFastTransformGeo::convGlobalToLocal(int32_t sector, float gx, float gy, float gz, float& lx, float& ly, float& lz) const { /// convert Global -> Local c.s. - const SliceInfo& sliceInfo = getSliceInfo(slice); - lx = gx * sliceInfo.cosAlpha + gy * sliceInfo.sinAlpha; - ly = -gx * sliceInfo.sinAlpha + gy * sliceInfo.cosAlpha; + const SectorInfo& sectorInfo = getSectorInfo(sector); + lx = gx * sectorInfo.cosAlpha + gy * sectorInfo.sinAlpha; + ly = -gx * sectorInfo.sinAlpha + gy * sectorInfo.cosAlpha; lz = gz; } -GPUdi() void TPCFastTransformGeo::convVtoLocal(int32_t slice, float v, float& lz) const +GPUdi() std::array TPCFastTransformGeo::convPadDriftLengthToLocal(int32_t sector, int32_t row, float pad, float driftLength) const { - /// convert UV -> Local c.s. - if (slice < NumberOfSlicesA) { // TPC side A - lz = mTPCzLengthA - v; - } else { // TPC side C - lz = v - mTPCzLengthC; // drift direction is mirrored on C-side + /// convert Pad, DriftLength -> Local c.s. + const RowInfo& rowInfo = getRowInfo(row); + float u = (pad - 0.5f * rowInfo.maxPad) * rowInfo.padWidth; + float y, z; + if (sector < NumberOfSectorsA) { // TPC side A + y = u; + z = mTPCzLength - driftLength; + } else { // TPC side C + y = -u; // pads are mirrorred on C-side + z = driftLength - mTPCzLength; // drift direction is mirrored on C-side } - lz += mTPCalignmentZ; // global TPC alignment + return {y, z}; } -GPUdi() void TPCFastTransformGeo::convUVtoLocal(int32_t slice, float u, float v, float& ly, float& lz) const +GPUdi() float TPCFastTransformGeo::convDriftLengthToZ1(int32_t sector, float driftLength) const { - /// convert UV -> Local c.s. - if (slice < NumberOfSlicesA) { // TPC side A - ly = u; - lz = mTPCzLengthA - v; - } else { // TPC side C - ly = -u; // pads are mirrorred on C-side - lz = v - mTPCzLengthC; // drift direction is mirrored on C-side - } - lz += mTPCalignmentZ; // global TPC alignment + /// convert DriftLength -> Local c.s. + return (sector < NumberOfSectorsA) ? (mTPCzLength - driftLength) : (driftLength - mTPCzLength); } -GPUdi() void TPCFastTransformGeo::convLocalToUV(int32_t slice, float ly, float lz, float& u, float& v) const +GPUdi() float TPCFastTransformGeo::convZtoDriftLength1(int32_t sector, float z) const { - /// convert Local-> UV c.s. - lz = lz - mTPCalignmentZ; // global TPC alignment - if (slice < NumberOfSlicesA) { // TPC side A - u = ly; - v = mTPCzLengthA - lz; - } else { // TPC side C - u = -ly; // pads are mirrorred on C-side - v = lz + mTPCzLengthC; // drift direction is mirrored on C-side - } + /// convert Z to DriftLength + return (sector < NumberOfSectorsA) ? (mTPCzLength - z) : (z + mTPCzLength); } -GPUdi() void TPCFastTransformGeo::convUVtoScaledUV(int32_t slice, int32_t row, float u, float v, float& su, float& sv) const +GPUdi() std::array TPCFastTransformGeo::getZrange(int32_t sector) const { - /// convert UV -> Scaled UV - const RowInfo& rowInfo = getRowInfo(row); - su = (u - rowInfo.u0) * rowInfo.scaleUtoSU; - if (slice < NumberOfSlicesA) { - sv = v * mScaleVtoSVsideA; - } else { - sv = v * mScaleVtoSVsideC; + /// z range for the sector + if (sector < NumberOfSectorsA) { // TPC side A + return {0.f, mTPCzLength}; + } else { // TPC side C + return {-mTPCzLength, 0.f}; } } -GPUdi() void TPCFastTransformGeo::convScaledUVtoUV(int32_t slice, int32_t row, float su, float sv, float& u, float& v) const +GPUdi() float TPCFastTransformGeo::getZmin(int32_t sector) const { - /// convert Scaled UV -> UV - const RowInfo& rowInfo = getRowInfo(row); - u = rowInfo.u0 + su * rowInfo.scaleSUtoU; - if (slice < NumberOfSlicesA) { - v = sv * mScaleSVtoVsideA; - } else { - v = sv * mScaleSVtoVsideC; + /// z min for the sector + if (sector < NumberOfSectorsA) { // TPC side A + return 0.f; + } else { // TPC side C + return -mTPCzLength; } } -GPUdi() void TPCFastTransformGeo::convScaledUVtoLocal(int32_t slice, int32_t row, float su, float sv, float& ly, float& lz) const +GPUdi() float TPCFastTransformGeo::getZmax(int32_t sector) const { - /// convert Scaled UV -> Local c.s. - float u, v; - convScaledUVtoUV(slice, row, su, sv, u, v); - convUVtoLocal(slice, u, v, ly, lz); + /// z max for the sector + if (sector < NumberOfSectorsA) { // TPC side A + return mTPCzLength; + } else { // TPC side C + return 0.f; + } } -GPUdi() float TPCFastTransformGeo::convPadToU(int32_t row, float pad) const +GPUdi() float TPCFastTransformGeo::getZreadout(int32_t sector) const { - /// convert Pad coordinate -> U - const RowInfo& rowInfo = getRowInfo(row); - return (pad - 0.5f * rowInfo.maxPad) * rowInfo.padWidth; + /// z readout for the sector + if (sector < NumberOfSectorsA) { // TPC side A + return mTPCzLength; + } else { // TPC side C + return -mTPCzLength; + } } -GPUdi() float TPCFastTransformGeo::convUtoPad(int32_t row, float u) const +GPUdi() std::array TPCFastTransformGeo::convLocalToPadDriftLength(int32_t sector, int32_t row, float y, float z) const { - /// convert U -> Pad coordinate - const RowInfo& rowInfo = getRowInfo(row); - return u / rowInfo.padWidth + 0.5f * rowInfo.maxPad; + /// convert Local c.s. -> Pad, DriftLength + float u, l; + if (sector < NumberOfSectorsA) { // TPC side A + u = y; + l = mTPCzLength - z; + } else { // TPC side C + u = -y; // pads are mirrorred on C-side + l = z + mTPCzLength; // drift direction is mirrored on C-side + } + const TPCFastTransformGeo::RowInfo& rowInfo = getRowInfo(row); + float pad = u / rowInfo.padWidth + 0.5f * rowInfo.maxPad; + return {pad, l}; } } // namespace gpu diff --git a/GPU/TPCFastTransformation/TPCFastTransformManager.cxx b/GPU/TPCFastTransformation/TPCFastTransformManager.cxx deleted file mode 100644 index 7d0aa29545578..0000000000000 --- a/GPU/TPCFastTransformation/TPCFastTransformManager.cxx +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file TPCFastTransformManager.cxx -/// \brief Implementation of TPCFastTransformManager class -/// -/// \author Sergey Gorbunov - -#include "TPCFastTransformManager.h" -#include "AliHLTTPCGeometry.h" -#include "AliTPCParam.h" -#include "AliTPCRecoParam.h" -#include "AliTPCTransform.h" -#include "AliTPCcalibDB.h" -#include "TPCFastTransform.h" -#include "Spline2DHelper.h" - -using namespace o2::gpu; - -TPCFastTransformManager::TPCFastTransformManager() - : mError(), mOrigTransform(nullptr), fLastTimeBin(0) {} - -int32_t TPCFastTransformManager::create(TPCFastTransform& fastTransform, - AliTPCTransform* transform, - long TimeStamp) -{ - /// Initializes TPCFastTransform object - - AliTPCcalibDB* pCalib = AliTPCcalibDB::Instance(); - if (!pCalib) { - return storeError( - -1, "TPCFastTransformManager::Init: No TPC calibration instance found"); - } - - AliTPCParam* tpcParam = pCalib->GetParameters(); - if (!tpcParam) { - return storeError( - -2, "TPCFastTransformManager::Init: No TPCParam object found"); - } - - if (!transform) { - transform = pCalib->GetTransform(); - } - if (!transform) { - return storeError( - -3, "TPCFastTransformManager::Init: No TPC transformation found"); - } - - mOrigTransform = transform; - - tpcParam->Update(); - tpcParam->ReadGeoMatrices(); - - const AliTPCRecoParam* rec = transform->GetCurrentRecoParam(); - if (!rec) { - return storeError(-5, - "TPCFastTransformManager::Init: No TPC Reco Param " - "set in transformation"); - } - - bool useCorrectionMap = rec->GetUseCorrectionMap(); - - if (useCorrectionMap) { - transform->SetCorrectionMapMode(kTRUE); // If the simulation set this to - // false to simulate corrections, we - // need to reverse it for the - // transformation - } - // find last calibrated time bin - - fLastTimeBin = rec->GetLastBin(); - - const int32_t nRows = tpcParam->GetNRowLow() + tpcParam->GetNRowUp(); - - TPCFastTransformGeo geo; - - { // construct the geometry - geo.startConstruction(nRows); - - float tpcZlengthSideA = tpcParam->GetZLength(0); - float tpcZlengthSideC = - tpcParam->GetZLength(TPCFastTransformGeo::getNumberOfSlices() / 2); - - geo.setTPCzLength(tpcZlengthSideA, tpcZlengthSideC); - geo.setTPCalignmentZ(-mOrigTransform->GetDeltaZCorrTime()); - - for (int32_t row = 0; row < geo.getNumberOfRows(); row++) { - int32_t slice = 0, sector = 0, secrow = 0; - AliHLTTPCGeometry::Slice2Sector(slice, row, sector, secrow); - Int_t nPads = tpcParam->GetNPads(sector, secrow); - float xRow = tpcParam->GetPadRowRadii(sector, secrow); - float padWidth = tpcParam->GetInnerPadPitchWidth(); - if (row >= tpcParam->GetNRowLow()) { - padWidth = tpcParam->GetOuterPadPitchWidth(); - } - geo.setTPCrow(row, xRow, nPads, padWidth); - } - geo.finishConstruction(); - } - - TPCFastSpaceChargeCorrection correction; - - { // create the correction map - - const int32_t nDistortionScenarios = 1; - - correction.startConstruction(geo, nDistortionScenarios); - - TPCFastSpaceChargeCorrection::SplineType spline; - spline.recreate(8, 20); - - int32_t scenario = 0; - correction.setSplineScenario(scenario, spline); - - for (int32_t row = 0; row < geo.getNumberOfRows(); row++) { - correction.setRowScenarioID(row, scenario); - } - - correction.finishConstruction(); - } // .. create the correction map - - { // create the fast transform object - - fastTransform.startConstruction(correction); - - // tell the transformation to apply the space charge corrections - fastTransform.setApplyCorrectionOn(); - - // set some initial calibration values, will be reinitialised later int32_t - // updateCalibration() - const float t0 = 0.; - const float vDrift = 0.f; - const float vdCorrY = 0.; - const float ldCorr = 0.; - const float tofCorr = 0.; - const float primVtxZ = 0.; - const int64_t initTimeStamp = -1; - fastTransform.setCalibration(initTimeStamp, t0, vDrift, vdCorrY, ldCorr, - tofCorr, primVtxZ); - - fastTransform.finishConstruction(); - } - - return updateCalibration(fastTransform, TimeStamp); -} - -int32_t TPCFastTransformManager::updateCalibration(TPCFastTransform& fastTransform, - long TimeStamp) -{ - // Update the calibration with the new time stamp - - long lastTS = fastTransform.getTimeStamp(); - - // deinitialize - - fastTransform.setTimeStamp(-1); - - if (TimeStamp < 0) { - return 0; - } - - // search for the calibration database - - if (!mOrigTransform) { - return storeError(-1, - "TPCFastTransformManager::SetCurrentTimeStamp: TPC " - "transformation has not been set properly"); - } - - AliTPCcalibDB* pCalib = AliTPCcalibDB::Instance(); - if (!pCalib) { - return storeError(-2, - "TPCFastTransformManager::SetCurrentTimeStamp: No " - "TPC calibration found"); - } - - AliTPCParam* tpcParam = pCalib->GetParameters(); - if (!tpcParam) { - return storeError(-3, - "TPCFastTransformManager::SetCurrentTimeStamp: No " - "TPCParam object found"); - } - - AliTPCRecoParam* recoParam = mOrigTransform->GetCurrentRecoParamNonConst(); - if (!recoParam) { - return storeError(-5, - "TPCFastTransformManager::Init: No TPC Reco Param " - "set in transformation"); - } - - // calibration found, set the initialized status back - - fastTransform.setTimeStamp(lastTS); - - // less than 60 seconds from the previois time stamp, don't do anything - - if (lastTS >= 0 && TMath::Abs(lastTS - TimeStamp) < 60) { - return 0; - } - - // start the initialization - - bool useCorrectionMap = recoParam->GetUseCorrectionMap(); - - if (useCorrectionMap) { - // If the simulation set this to false to simulate corrections, we need to - // reverse it for the transformation This is a design feature. Historically - // HLT code runs as a part of simulation, not reconstruction. - mOrigTransform->SetCorrectionMapMode(kTRUE); - } - - // set the current time stamp - - mOrigTransform->SetCurrentTimeStamp(static_cast(TimeStamp)); - fastTransform.setTimeStamp(TimeStamp); - - // find last calibrated time bin - - fLastTimeBin = recoParam->GetLastBin(); - - double t0 = mOrigTransform->GetTBinOffset(); - double driftCorrPT = mOrigTransform->GetDriftCorrPT(); - double vdCorrectionTime = mOrigTransform->GetVDCorrectionTime(); - double vdCorrectionTimeGY = mOrigTransform->GetVDCorrectionTimeGY(); - double time0CorrTime = mOrigTransform->GetTime0CorrTime(); - - // original formula: - // L = (t-t0)*ZWidth*driftCorrPT*vdCorrectionTime*( 1 + - // yLab*vdCorrectionTimeGY ) - time0CorrTime + 3.*tpcParam->GetZSigma(); Z = - // Z(L) - fDeltaZCorrTime chebyshev corrections for xyz Time-of-flight - // correction: ldrift += dist-to-vtx*tofCorr - - // fast transform formula: - // L = (t-t0)*(mVdrift + mVdriftCorrY*yLab ) + mLdriftCorr - // Z = Z(L) + tpcAlignmentZ - // spline corrections for xyz - // Time-of-flight correction: ldrift += dist-to-vtx*tofCorr - - double vDrift = tpcParam->GetZWidth() * driftCorrPT * vdCorrectionTime; - double vdCorrY = vDrift * vdCorrectionTimeGY; - double ldCorr = -time0CorrTime + 3 * tpcParam->GetZSigma(); - - double tofCorr = (0.01 * tpcParam->GetDriftV()) / TMath::C(); - double primVtxZ = mOrigTransform->GetPrimVertex()[2]; - - bool useTOFcorrection = recoParam->GetUseTOFCorrection(); - - if (!useTOFcorrection) { - tofCorr = 0; - } - - fastTransform.setCalibration(TimeStamp, t0, vDrift, vdCorrY, ldCorr, tofCorr, - primVtxZ); - - // now calculate the correction map: dx,du,dv = ( origTransform() -> x,u,v) - - // fastTransformNominal:x,u,v - - const TPCFastTransformGeo& geo = fastTransform.getGeometry(); - - TPCFastSpaceChargeCorrection& correction = - fastTransform.getCorrection(); - - // switch TOF correction off for a while - - recoParam->SetUseTOFCorrection(kFALSE); - - for (int32_t slice = 0; slice < geo.getNumberOfSlices(); slice++) { - - for (int32_t row = 0; row < geo.getNumberOfRows(); row++) { - - const TPCFastTransformGeo::RowInfo& rowInfo = geo.getRowInfo(row); - - const TPCFastSpaceChargeCorrection::SplineType& spline = correction.getSpline(slice, row); - float* data = correction.getSplineData(slice, row); - - Spline2DHelper helper; - helper.setSpline(spline, 4, 4); - auto F = [&](double su, double sv, double dxuv[3]) { - float x = rowInfo.x; - // x, u, v cordinates of the knot (local cartesian coord. of slice - // towards central electrode ) - float u = 0, v = 0; - geo.convScaledUVtoUV(slice, row, su, sv, u, v); - - // row, pad, time coordinates of the knot - float vertexTime = 0.f; - float pad = 0.f, time = 0.f; - fastTransform.convUVtoPadTime(slice, row, u, v, pad, time, vertexTime); - - // nominal x,y,z coordinates of the knot (without corrections and - // time-of-flight correction) - float y = 0, z = 0; - geo.convUVtoLocal(slice, u, v, y, z); - - // original TPC transformation (row,pad,time) -> (x,y,z) without - // time-of-flight correction - float ox = 0, oy = 0, oz = 0; - { - int32_t sector = 0, secrow = 0; - AliHLTTPCGeometry::Slice2Sector(slice, row, sector, secrow); - int32_t is[] = {sector}; - double xx[] = {static_cast(secrow), pad, time}; - mOrigTransform->Transform(xx, is, 0, 1); - ox = xx[0]; - oy = xx[1]; - oz = xx[2]; - } - // convert to u,v - float ou = 0, ov = 0; - geo.convLocalToUV(slice, oy, oz, ou, ov); - - // corrections in x,u,v: - dxuv[0] = ox - x; - dxuv[1] = ou - u; - dxuv[2] = ov - v; - }; - - helper.approximateFunction(data, 0., 1., 0., 1., F); - } // row - } // slice - - // set back the time-of-flight correction; - - recoParam->SetUseTOFCorrection(useTOFcorrection); - - return 0; -} diff --git a/GPU/TPCFastTransformation/TPCFastTransformManager.h b/GPU/TPCFastTransformation/TPCFastTransformManager.h deleted file mode 100644 index f981b05bec241..0000000000000 --- a/GPU/TPCFastTransformation/TPCFastTransformManager.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file TPCFastTransformManager.h -/// \brief Definition of TPCFastTransformManager class -/// -/// \author Sergey Gorbunov - -#ifndef ALICEO2_GPUCOMMON_TPCFASTTRANSFORMATION_TPCFASTTRANSFORMMANAGER_H -#define ALICEO2_GPUCOMMON_TPCFASTTRANSFORMATION_TPCFASTTRANSFORMMANAGER_H - -#include - -#include "GPUCommonDef.h" -#include "Rtypes.h" -#include "TString.h" -#include "AliTPCTransform.h" - -namespace o2 -{ -namespace gpu -{ -class TPCFastTransform; - -/// -/// The TPCFastTransformManager class is to initialize TPCFastTransformation object -/// - -class TPCFastTransformManager -{ - public: - /// _____________ Constructors / destructors __________________________ - - /// Default constructor - TPCFastTransformManager(); - - /// Copy constructor: disabled - TPCFastTransformManager(const TPCFastTransformManager&) = delete; - - /// Assignment operator: disabled - TPCFastTransformManager& operator=(const TPCFastTransformManager&) = delete; - - /// Destructor - ~TPCFastTransformManager() = default; - - /// _______________ Main functionality ________________________ - - /// Initializes TPCFastTransform object - int32_t create(TPCFastTransform& spline, AliTPCTransform* transform, long TimeStamp); - - /// Updates the transformation with the new time stamp - Int_t updateCalibration(TPCFastTransform& spline, long TimeStamp); - - /// _______________ Utilities ________________________ - - AliTPCTransform* getOriginalTransform() { return mOrigTransform; } - - /// Gives error string - const char* getLastError() const { return mError.Data(); } - - private: - /// Stores an error message - int32_t storeError(Int_t code, const char* msg); - - TString mError; ///< error string - AliTPCTransform* mOrigTransform; ///< transient - int32_t fLastTimeBin; ///< last calibrated time bin -}; - -inline int32_t TPCFastTransformManager::storeError(int32_t code, const char* msg) -{ - mError = msg; - return code; -} -} // namespace gpu -} // namespace o2 - -#endif diff --git a/GPU/TPCFastTransformation/TPCFastTransformationLinkDef_O2.h b/GPU/TPCFastTransformation/TPCFastTransformationLinkDef_O2.h index 4421d44aab0c8..f1872549a46aa 100644 --- a/GPU/TPCFastTransformation/TPCFastTransformationLinkDef_O2.h +++ b/GPU/TPCFastTransformation/TPCFastTransformationLinkDef_O2.h @@ -58,19 +58,36 @@ #pragma link C++ class o2::gpu::SemiregularSpline2D3D + ; #pragma link C++ class o2::gpu::IrregularSpline2D3DCalibrator + ; -#pragma link C++ class o2::gpu::TPCFastTransformGeo + ; #pragma link C++ class o2::gpu::TPCFastTransformGeo::SliceInfo + ; +#pragma link C++ class o2::gpu::TPCFastTransformGeo::SectorInfo + ; + +#pragma link C++ class o2::gpu::TPCFastTransformGeo + ; +#pragma read \ + sourceClass = "o2::gpu::TPCFastTransformGeo" targetClass = "o2::gpu::TPCFastTransformGeo" source = "float mTPCzLengthA; float mTPCzLengthC; float mTPCalignmentZ; float mScaleVtoSVsideA; float mScaleVtoSVsideC; float mScaleSVtoVsideA; float mScaleSVtoVsideC;" version = "[-1]" target = "mTPCzLength" code = "{ mTPCzLength = onfile.mTPCzLengthA; }"; + +#pragma read \ + sourceClass = "o2::gpu::TPCFastTransformGeo" targetClass = "o2::gpu::TPCFastTransformGeo" source = "o2::gpu::TPCFastTransformGeo::SliceInfo mSliceInfos[37]" version = "[-2]" target = "" code = "{}"; + #pragma link C++ class o2::gpu::TPCFastTransformGeo::RowInfo + ; +#pragma read \ + sourceClass = "o2::gpu::TPCFastTransformGeo::RowInfo" targetClass = "o2::gpu::TPCFastTransformGeo::RowInfo" source = "float u0; float scaleUtoSU; float scaleSUtoU" version = "[-1]" target = "yMin" code = "{ yMin = onfile.u0; }" #pragma link C++ class o2::gpu::TPCFastTransform + ; #pragma link C++ class o2::gpu::TPCFastSpaceChargeCorrectionMap + ; -#pragma link C++ class o2::gpu::TPCFastSpaceChargeCorrection::RowInfo + ; #pragma link C++ class o2::gpu::TPCFastSpaceChargeCorrection + ; #pragma link C++ class o2::gpu::TPCFastSpaceChargeCorrection::SliceInfo + ; -#pragma link C++ class o2::gpu::TPCFastSpaceChargeCorrection::RowActiveArea + ; -#pragma link C++ class o2::gpu::TPCFastSpaceChargeCorrection::SliceRowInfo + ; +#pragma link C++ class o2::gpu::TPCFastSpaceChargeCorrection::SectorRowInfo + ; +#pragma link C++ class o2::gpu::TPCFastSpaceChargeCorrection::GridInfo + ; +#pragma read \ + sourceClass = "o2::gpu::TPCFastSpaceChargeCorrection" targetClass = "o2::gpu::TPCFastSpaceChargeCorrection" source = "o2::gpu::TPCFastSpaceChargeCorrection::SliceInfo mSliceInfo[36]" version = "[-3]" target = "" code = "{}"; + +#pragma read \ + sourceClass = "o2::gpu::TPCFastSpaceChargeCorrection" targetClass = "o2::gpu::TPCFastSpaceChargeCorrection" source = "size_t mSliceDataSizeBytes[3]" version = "[-3]" target = "mCorrectionDataSize" code = "{ for (int i=0; i<3; i++) mCorrectionDataSize[i] = onfile.mSliceDataSizeBytes[i] * 36; }"; + +#pragma read \ + sourceClass = "o2::gpu::TPCFastSpaceChargeCorrection" targetClass = "o2::gpu::TPCFastSpaceChargeCorrection" source = "float fInterpolationSafetyMargin" version = "[-3]" target = "" code = "{}"; #pragma link C++ class o2::gpu::CorrectionMapsHelper + ; #pragma link C++ struct o2::gpu::MultivariatePolynomialContainer + ; diff --git a/GPU/TPCFastTransformation/macro/TPCFastTransformInit.C b/GPU/TPCFastTransformation/macro/TPCFastTransformInit.C index 6b3756aca3b73..baaeca90202d5 100644 --- a/GPU/TPCFastTransformation/macro/TPCFastTransformInit.C +++ b/GPU/TPCFastTransformation/macro/TPCFastTransformInit.C @@ -18,29 +18,34 @@ /// how to run the macro: /// -/// root -l TPCFastTransformInit.C'("debugVoxRes.root")' +/// root -l TPCFastTransformInit.C'("VoxRes.root", "VoxResInv.root")' /// #if !defined(__CLING__) || defined(__ROOTCLING__) +#include +#include #include "TFile.h" #include "TSystem.h" #include "TTree.h" #include "TNtuple.h" #include "Riostream.h" +#include "Algorithm/RangeTokenizer.h" +#include "Framework/Logger.h" #include "GPU/TPCFastTransform.h" #include "SpacePoints/TrackResiduals.h" #include "TPCReconstruction/TPCFastTransformHelperO2.h" #include "TPCCalibration/TPCFastSpaceChargeCorrectionHelper.h" - #endif +#include "Algorithm/RangeTokenizer.h" + using namespace o2::tpc; using namespace o2::gpu; -void TPCFastTransformInit(const char* fileName = "debugVoxRes.root", - const char* outFileName = "TPCFastTransform_VoxRes.root", bool useSmoothed = false, bool invertSigns = false) +void TPCFastTransformInit(const char* fileName = "debugVoxRes.root", const char* fileNameInv = "debugVoxResInv.root", + const char* outFileName = "TPCFastTransform_VoxRes.root", bool useSmoothed = false, bool invertSigns = false, bool doDebug = true) { // Initialise TPCFastTransform object from "voxRes" tree of @@ -51,11 +56,14 @@ void TPCFastTransformInit(const char* fileName = "debugVoxRes.root", To visiualise the results: root -l transformDebug.root - corr->Draw("cx:y:z","iRoc==0&&iRow==10","") - grid->Draw("cx:y:z","iRoc==0&&iRow==10","same") - vox->Draw("vx:y:z","iRoc==0&&iRow==10","same") + all->Draw("cx:y:z","sec==0&&row==10","") + grid->Draw("cx:y:z","sec==0&&row==10","same") + vox->Draw("vx:y:z","sec==0&&row==10","same") + points->Draw("px:y:z","sec==0&&row==10","same") */ + const bool debugMirrorAdata2C = 0; + if (gSystem->AccessPathName(fileName)) { std::cout << " input file " << fileName << " does not exist!" << std::endl; return; @@ -75,8 +83,34 @@ void TPCFastTransformInit(const char* fileName = "debugVoxRes.root", return; } + TTree* voxResTreeInverse = nullptr; + std::unique_ptr fileInv; + if (fileNameInv && !std::string(fileNameInv).empty()) { + fileInv = std::unique_ptr(TFile::Open(fileNameInv, "READ")); + if (!fileInv || !fileInv->IsOpen()) { + std::cout << " input file " << fileNameInv << " does not exist!" << std::endl; + return; + } + fileInv->cd(); + gDirectory->GetObject("voxResTree", voxResTreeInverse); + } + + auto userInfo = voxResTree->GetUserInfo(); + + if (!userInfo->FindObject("y2xBinning") || !userInfo->FindObject("z2xBinning")) { + std::cout << "'y2xBinning' or 'z2xBinning' not found in UserInfo, but required to get the correct binning" << std::endl; + return; + } + + userInfo->Print(); + + // required for the binning that was used o2::tpc::TrackResiduals trackResiduals; - trackResiduals.init(); // also initializes the default binning which was used + auto y2xBins = o2::RangeTokenizer::tokenize(userInfo->FindObject("y2xBinning")->GetTitle()); + auto z2xBins = o2::RangeTokenizer::tokenize(userInfo->FindObject("z2xBinning")->GetTitle()); + trackResiduals.setY2XBinning(y2xBins); + trackResiduals.setZ2XBinning(z2xBins); + trackResiduals.init(); std::cout << "create fast transformation ... " << std::endl; @@ -84,29 +118,99 @@ void TPCFastTransformInit(const char* fileName = "debugVoxRes.root", o2::tpc::TPCFastSpaceChargeCorrectionHelper* corrHelper = o2::tpc::TPCFastSpaceChargeCorrectionHelper::instance(); - auto corrPtr = corrHelper->createFromTrackResiduals(trackResiduals, voxResTree, useSmoothed, invertSigns); + corrHelper->setNthreadsToMaximum(); + // corrHelper->setNthreads(1); + + if (debugMirrorAdata2C) { + corrHelper->setDebugMirrorAdata2C(); + } + // corrHelper->setDebugUseVoxelCenters(); + + o2::gpu::TPCFastSpaceChargeCorrectionMap mapDirect(0, 0), mapInverse(0, 0); + + auto corrPtr = corrHelper->createFromTrackResiduals(trackResiduals, voxResTree, voxResTreeInverse, useSmoothed, invertSigns, + &mapDirect, &mapInverse); std::unique_ptr fastTransform( helper->create(0, *corrPtr)); - o2::gpu::TPCFastSpaceChargeCorrection& corr = fastTransform->getCorrection(); - std::cout << "... create fast transformation completed " << std::endl; if (*outFileName) { fastTransform->writeToFile(outFileName, "ccdb_object"); } - std::cout << "verify the results ..." << std::endl; + if (!doDebug) { + return; + } + + { // debug output + + std::cout << " ===== input track residuals ==== " << std::endl; + std::cout << "voxel tree y2xBins: " << y2xBins.size() << std::endl; + + for (auto y2x : y2xBins) { + std::cout << " y2x: " << y2x << std::endl; + } + std::cout << std::endl; - // the difference + int32_t nY2Xbins = trackResiduals.getNY2XBins(); - double maxDiff[3] = {0., 0., 0.}; - int32_t maxDiffRoc[3] = {0, 0, 0}; - int32_t maxDiffRow[3] = {0, 0, 0}; + std::cout << " TrackResiduals y2x bins: " << nY2Xbins << std::endl; + for (int32_t i = 0; i < nY2Xbins; i++) { + std::cout << "scaled getY2X(bin) : " << trackResiduals.getY2X(0, i) / trackResiduals.getMaxY2X(0) << std::endl; + } + + std::cout << "voxel tree z2xBins: " << z2xBins.size() << std::endl; + + for (auto z2x : z2xBins) { + std::cout << "z2x: " << z2x << std::endl; + } + std::cout << std::endl; + + int32_t nZ2Xbins = trackResiduals.getNZ2XBins(); + std::cout << " TrackResiduals z2x bins: " << nZ2Xbins << std::endl; + for (int32_t i = 0; i < nZ2Xbins; i++) { + std::cout << "getZ2X(bin) : " << trackResiduals.getZ2X(i) << std::endl; + } + std::cout << " ==================================== " << std::endl; + } + + if (1) { // read transformation from the output file to verify the io + + const char* fileName = outFileName; + + // fileName = "~/test/master/TPCFastTransform_VoxRes.root"; + + std::cout << "load corrections from file " << fileName << std::endl; + + fastTransform->cloneFromObject(*TPCFastTransform::loadFromFile(fileName, "ccdb_object"), nullptr); - double sumDiff[3] = {0., 0., 0.}; - int64_t nDiff = 0; + o2::gpu::TPCFastSpaceChargeCorrection& corr = fastTransform->getCorrection(); + + if (0) { + std::cout << "check the loaded correction ..." << std::endl; + + const o2::gpu::TPCFastTransformGeo& geo = helper->getGeometry(); + + // for (int32_t iSector = 0; iSector < geo.getNumberOfSectors(); iSector++) { + for (int32_t iSector = 0; iSector < 1; iSector++) { + for (int32_t iRow = 0; iRow < geo.getNumberOfRows(); iRow++) { + auto& info = corr.getSectorRowInfo(iSector, iRow); + std::cout << "sector " << iSector << " row " << iRow + << " gridY0 " << info.gridMeasured.getY0() << " gridZ0 " << info.gridMeasured.getZ0() + << " scaleYtoGrid " << info.gridMeasured.getYscale() << " scaleLtoGrid " << info.gridMeasured.getZscale() + << " gridRealY0 " << info.gridReal.getY0() << " gridRealZ0 " << info.gridReal.getZ0() + << " scaleRealYtoGrid " << info.gridReal.getYscale() << " scaleRealLtoGrid " << info.gridReal.getZscale() + << std::endl; + } + } + } + } + + std::cout << "verify the results ..." << std::endl; + + o2::gpu::TPCFastSpaceChargeCorrection& corr = fastTransform->getCorrection(); // a debug file with some NTuples @@ -115,39 +219,82 @@ void TPCFastTransformInit(const char* fileName = "debugVoxRes.root", TFile* debugFile = new TFile("transformDebug.root", "RECREATE"); debugFile->cd(); - // ntuple with created TPC corrections - TNtuple* debugCorr = new TNtuple("corr", "corr", "iRoc:iRow:x:y:z:cx:cy:cz"); + // debug ntuple with created TPC corrections + // + // measured x,y,z; corrections cx,cy,cz from the measured to the real x,y,z; + // inverse corrections ix,iy,iz at the real position (x+cx,y+cy,z+cz) + // ideally, ix = cx, iy = cy, iz = cz + TNtuple* ntAll = new TNtuple("all", "all", + debugMirrorAdata2C ? "sec:row:x:y:z:cx:cy:cz:ix:iy:iz:cxC:cyC:czC:ixC:iyC:izC" + : "sec:row:x:y:z:cx:cy:cz:ix:iy:iz"); - debugCorr->SetMarkerStyle(8); - debugCorr->SetMarkerSize(0.1); - debugCorr->SetMarkerColor(kBlack); + ntAll->SetMarkerStyle(8); + ntAll->SetMarkerSize(0.1); + ntAll->SetMarkerColor(kBlack); - // ntuple with the input data: voxel corrections debugFile->cd(); - TNtuple* debugVox = - new TNtuple("vox", "vox", "iRoc:iRow:x:y:z:vx:vy:vz:cx:cy:cz"); + TNtuple* ntInvAll = new TNtuple("invall", "invall", + debugMirrorAdata2C ? "sec:row:x:y:z:cx:cy:cz:cxC:cyC:czC" + : "sec:row:x:y:z:cx:cy:cz"); - debugVox->SetMarkerStyle(8); - debugVox->SetMarkerSize(0.8); - debugVox->SetMarkerColor(kBlue); + ntInvAll->SetMarkerStyle(8); + ntInvAll->SetMarkerSize(0.1); + ntInvAll->SetMarkerColor(kBlack); - // ntuple with spline grid points + // duplicate of debugVox + the spline data at voxels in a different color debugFile->cd(); - TNtuple* debugGrid = new TNtuple("grid", "grid", "iRoc:iRow:x:y:z:cx:cy:cz"); + TNtuple* ntVox = + new TNtuple("vox", "vox", + debugMirrorAdata2C ? "sec:row:n:x:y:z:vx:vy:vz:cx:cy:cz:ix:iy:iz:cxC:cyC:czC:ixC:iyC:izC" + : "sec:row:n:x:y:z:vx:vy:vz:cx:cy:cz:ix:iy:iz"); - debugGrid->SetMarkerStyle(8); - debugGrid->SetMarkerSize(1.2); - debugGrid->SetMarkerColor(kBlack); + ntVox->SetMarkerStyle(8); + ntVox->SetMarkerSize(0.8); + ntVox->SetMarkerColor(kMagenta); - // ntuple with data points created from voxels (with data smearing and - // extension to the edges) + // duplicate of debugVox + the spline data at voxels in a different color debugFile->cd(); - TNtuple* debugPoints = - new TNtuple("points", "points", "iRoc:iRow:x:y:z:px:py:pz:cx:cy:cz"); + TNtuple* ntInvVox = + new TNtuple("invvox", "invvox", + debugMirrorAdata2C ? "sec:row:n:x:y:z:vx:vy:vz:cx:cy:cz:cxC:cyC:czC" + : "sec:row:n:x:y:z:vx:vy:vz:cx:cy:cz"); - debugPoints->SetMarkerStyle(8); - debugPoints->SetMarkerSize(0.4); - debugPoints->SetMarkerColor(kRed); + ntInvVox->SetMarkerStyle(8); + ntInvVox->SetMarkerSize(0.8); + ntInvVox->SetMarkerColor(kMagenta); + + // corrections at the spline grid points + debugFile->cd(); + TNtuple* ntGrid = new TNtuple("grid", "grid", "sec:row:x:y:z:cx:cy:cz:ix:iy:iz"); + + ntGrid->SetMarkerStyle(8); + ntGrid->SetMarkerSize(1.2); + ntGrid->SetMarkerColor(kBlack); + + // corrections at the spline grid points + debugFile->cd(); + TNtuple* ntInvGrid = new TNtuple("invgrid", "invgrid", "sec:row:x:y:z:cx:cy:cz"); + + ntInvGrid->SetMarkerStyle(8); + ntInvGrid->SetMarkerSize(1.2); + ntGrid->SetMarkerColor(kBlack); + + // ntuple with data points created from voxels (with the data smearing, extension to the edges etc.) + debugFile->cd(); + TNtuple* ntFitPoints = + new TNtuple("fitpoints", "fit points", "sec:row:x:y:z:px:py:pz:cx:cy:cz"); + + ntFitPoints->SetMarkerStyle(8); + ntFitPoints->SetMarkerSize(0.4); + ntFitPoints->SetMarkerColor(kRed); + + debugFile->cd(); + TNtuple* ntInvFitPoints = + new TNtuple("invfitpoints", "fit points", "sec:row:x:y:z:px:py:pz:cx:cy:cz"); + + ntInvFitPoints->SetMarkerStyle(8); + ntInvFitPoints->SetMarkerSize(0.4); + ntInvFitPoints->SetMarkerColor(kRed); currDir->cd(); @@ -157,183 +304,326 @@ void TPCFastTransformInit(const char* fileName = "debugVoxRes.root", const o2::gpu::TPCFastTransformGeo& geo = helper->getGeometry(); - o2::tpc::TrackResiduals::VoxRes* v = nullptr; - TBranch* branch = voxResTree->GetBranch("voxRes"); - branch->SetAddress(&v); - branch->SetAutoDelete(kTRUE); + auto getInvCorrections = [&](int iSector, int iRow, float realY, float realZ, float& ix, float& iy, float& iz) { + // get the inverse corrections ix, iy, iz at x,y,z + ix = corr.getCorrectionXatRealYZ(iSector, iRow, realY, realZ); + const auto c = corr.getCorrectionYZatRealYZ(iSector, iRow, realY, realZ); + iy = c[0]; + iz = c[1]; + }; + + auto getAllCorrections = [&](int iSector, int iRow, float y, float z, float& cx, float& cy, float& cz, float& ix, float& iy, float& iz) { + // get the corrections cx,cy,cz at x,y,z + const auto c = corr.getCorrectionLocal(iSector, iRow, y, z); + cx = c[0]; + cy = c[1]; + cz = c[2]; + getInvCorrections(iSector, iRow, y + cy, z + cz, ix, iy, iz); + }; + + for (int direction = 0; direction < 2; direction++) { // 0 - normal, 1 - inverse + + std::string directionName = (direction == 0) ? "direct" : "inverse"; + + TTree* currentTree = (direction == 0) ? voxResTree : voxResTreeInverse; + if (!currentTree) { + std::cout << "tree voxResTree does not exist!" << std::endl; + return; + } - for (int32_t iVox = 0; iVox < voxResTree->GetEntriesFast(); iVox++) { + o2::tpc::TrackResiduals::VoxRes* v = nullptr; + TBranch* branch = currentTree->GetBranch("voxRes"); + branch->SetAddress(&v); + branch->SetAutoDelete(kTRUE); - voxResTree->GetEntry(iVox); + int32_t iSectorLast = -1; + int32_t iRowLast = -1; - float voxEntries = v->stat[o2::tpc::TrackResiduals::VoxV]; + // the difference - int32_t xBin = - v->bvox[o2::tpc::TrackResiduals::VoxX]; // bin number in x (= pad row) + double maxDiff[3] = {0., 0., 0.}; + int32_t maxDiffSector[3] = {0, 0, 0}; + int32_t maxDiffRow[3] = {0, 0, 0}; - int32_t y2xBin = - v->bvox[o2::tpc::TrackResiduals::VoxF]; // bin number in y/x 0..14 + double sumDiff[3] = {0., 0., 0.}; + int64_t nDiff = 0; - int32_t z2xBin = - v->bvox[o2::tpc::TrackResiduals::VoxZ]; // bin number in z/x 0..4 + LOG(info) << directionName << " correction: fill debug ntuples at voxels ..."; - int32_t iRoc = (int32_t)v->bsec; - int32_t iRow = (int32_t)xBin; + for (int32_t iVox = 0; iVox < currentTree->GetEntriesFast(); iVox++) { - double x = trackResiduals.getX(xBin); // radius of the pad row + currentTree->GetEntry(iVox); - double y2x = trackResiduals.getY2X( - xBin, y2xBin); // y/x coordinate of the bin ~-0.15 ... 0.15 + float voxEntries = v->stat[o2::tpc::TrackResiduals::VoxV]; - double z2x = - trackResiduals.getZ2X(z2xBin); // z/x coordinate of the bin 0.1 .. 0.9 + int32_t xBin = + v->bvox[o2::tpc::TrackResiduals::VoxX]; // bin number in x (= pad row) - double y = x * y2x; - double z = x * z2x; + int32_t y2xBin = + v->bvox[o2::tpc::TrackResiduals::VoxF]; // bin number in y/x 0..14 - if (iRoc >= geo.getNumberOfSlicesA()) { - z = -z; - } + int32_t z2xBin = + v->bvox[o2::tpc::TrackResiduals::VoxZ]; // bin number in z/x 0..4 - double correctionX = useSmoothed ? v->DS[o2::tpc::TrackResiduals::ResX] : v->D[o2::tpc::TrackResiduals::ResX]; - double correctionY = useSmoothed ? v->DS[o2::tpc::TrackResiduals::ResY] : v->D[o2::tpc::TrackResiduals::ResY]; - double correctionZ = useSmoothed ? v->DS[o2::tpc::TrackResiduals::ResZ] : v->D[o2::tpc::TrackResiduals::ResZ]; + int32_t iSector = (int32_t)v->bsec; + int32_t iRow = (int32_t)xBin; - if (invertSigns) { - correctionX *= -1.; - correctionY *= -1.; - correctionZ *= -1.; - } + iSectorLast = iSector; + iRowLast = iRow; - // TODO: skip empty voxels? - if (voxEntries < 1.) { // no statistics - // std::cout << "Empty Voxel!!! corrections: " << correctionX << " " - // << correctionY << " " << correctionZ << std::endl; - // continue; - } + double x = trackResiduals.getX(xBin); // radius of the pad row - float u, v, cx, cu, cv, cy, cz; - geo.convLocalToUV(iRoc, y, z, u, v); - corr.getCorrection(iRoc, iRow, u, v, cx, cu, cv); - geo.convUVtoLocal(iRoc, u + cu, v + cv, cy, cz); - cy -= y; - cz -= z; - double d[3] = {cx - correctionX, cy - correctionY, cz - correctionZ}; - for (int32_t i = 0; i < 3; i++) { - if (fabs(maxDiff[i]) < fabs(d[i])) { - maxDiff[i] = d[i]; - maxDiffRoc[i] = iRoc; - maxDiffRow[i] = iRow; - std::cout << " roc " << iRoc << " row " << iRow << " xyz " << i - << " diff " << d[i] << std::endl; + double y2x = trackResiduals.getY2X( + xBin, y2xBin); // y/x coordinate of the bin ~-0.15 ... 0.15 + + double z2x = + trackResiduals.getZ2X(z2xBin); // z/x coordinate of the bin 0.1 .. 0.9 + + double y = x * y2x; + double z = x * z2x; + + double correctionX = useSmoothed ? v->DS[o2::tpc::TrackResiduals::ResX] : v->D[o2::tpc::TrackResiduals::ResX]; + double correctionY = useSmoothed ? v->DS[o2::tpc::TrackResiduals::ResY] : v->D[o2::tpc::TrackResiduals::ResY]; + double correctionZ = useSmoothed ? v->DS[o2::tpc::TrackResiduals::ResZ] : v->D[o2::tpc::TrackResiduals::ResZ]; + + double voxelSizeY = x / trackResiduals.getDY2XI(xBin, y2xBin); + double voxelSizeZ = x * trackResiduals.getDZ2X(z2xBin); + + if (invertSigns) { + correctionX *= -1.; + correctionY *= -1.; + correctionZ *= -1.; } - sumDiff[i] += d[i] * d[i]; - } - nDiff++; - debugVox->Fill(iRoc, iRow, x, y, z, correctionX, correctionY, correctionZ, - cx, cy, cz); - } - std::cout << "create debug ntuples ..." << std::endl; - - for (int32_t iRoc = 0; iRoc < geo.getNumberOfSlices(); iRoc++) { - // for (int32_t iRoc = 0; iRoc < 1; iRoc++) { - std::cout << "debug ntules for roc " << iRoc << std::endl; - for (int32_t iRow = 0; iRow < geo.getNumberOfRows(); iRow++) { - - double x = geo.getRowInfo(iRow).x; - - // the correction - - for (double su = 0.; su <= 1.0001; su += 0.01) { - for (double sv = 0.; sv <= 1.0001; sv += 0.1) { - float u, v; - geo.convScaledUVtoUV(iRoc, iRow, su, sv, u, v); - float y, z; - geo.convUVtoLocal(iRoc, u, v, y, z); - float cx, cu, cv; - corr.getCorrection(iRoc, iRow, u, v, cx, cu, cv); - float cy, cz; - geo.convUVtoLocal(iRoc, u + cu, v + cv, cy, cz); - cy -= y; - cz -= z; - debugCorr->Fill(iRoc, iRow, x, y, z, cx, cy, cz); + if (!corrHelper->isDebugUseVoxelCenters()) { + if (voxEntries > 0.) { + // use mean statistical positions instead of the bin centers, unless they are wrong + double yFit = x * v->stat[o2::tpc::TrackResiduals::VoxF]; + if (fabs(yFit - y) <= corrHelper->getVoxelMeanValidityRange() * voxelSizeY / 2.) { + y = yFit; + } + double zFit = x * v->stat[o2::tpc::TrackResiduals::VoxZ]; + if (fabs(zFit - z) <= corrHelper->getVoxelMeanValidityRange() * voxelSizeZ / 2.) { + z = zFit; + } } } - // the spline grid - - const auto& gridU = corr.getSpline(iRoc, iRow).getGridX1(); - const auto& gridV = corr.getSpline(iRoc, iRow).getGridX2(); - for (int32_t iu = 0; iu < gridU.getNumberOfKnots(); iu++) { - double su = gridU.convUtoX(gridU.getKnot(iu).getU()); - for (int32_t iv = 0; iv < gridV.getNumberOfKnots(); iv++) { - double sv = gridV.convUtoX(gridV.getKnot(iv).getU()); - float u, v; - corr.convGridToUV(iRoc, iRow, iu, iv, u, v); - float y, z; - geo.convUVtoLocal(iRoc, u, v, y, z); - float cx, cu, cv; - corr.getCorrection(iRoc, iRow, u, v, cx, cu, cv); - float cy, cz; - geo.convUVtoLocal(iRoc, u + cu, v + cv, cy, cz); - cy -= y; - cz -= z; - debugGrid->Fill(iRoc, iRow, x, y, z, cx, cy, cz); + int mirrorSector = iSector + geo.getNumberOfSectorsA(); + + if (iSector >= geo.getNumberOfSectorsA()) { + z = -z; + mirrorSector = iSector - geo.getNumberOfSectorsA(); + } + + float cx{0.f}, cy{0.f}, cz{0.f}, ix{0.f}, iy{0.f}, iz{0.f}; + float cxC{0.f}, cyC{0.f}, czC{0.f}, ixC{0.f}, iyC{0.f}, izC{0.f}; + if (direction == 0) { + getAllCorrections(iSector, iRow, y, z, cx, cy, cz, ix, iy, iz); + if (debugMirrorAdata2C) { + getAllCorrections(mirrorSector, iRow, y, -z, cxC, cyC, czC, ixC, iyC, izC); } + float ntEntry[] = {(float)iSector, (float)iRow, voxEntries, + (float)x, (float)y, (float)z, + (float)correctionX, (float)correctionY, (float)correctionZ, + (float)cx, (float)cy, (float)cz, + (float)ix, (float)iy, (float)iz, + (float)cxC, (float)cyC, (float)czC, (float)ixC, (float)iyC, (float)izC}; + + // fill the ntuple with the correction at the voxel + ntVox->Fill(ntEntry); + } else { + getInvCorrections(iSector, iRow, y, z, cx, cy, cz); + if (debugMirrorAdata2C) { + getInvCorrections(mirrorSector, iRow, y, -z, cxC, cyC, czC); + } + float ntEntry[] = {(float)iSector, (float)iRow, voxEntries, + (float)x, (float)y, (float)z, + (float)correctionX, (float)correctionY, (float)correctionZ, + (float)cx, (float)cy, (float)cz, + (float)cxC, (float)cyC, (float)czC}; + // fill the ntuple with the correction at the voxel + ntInvVox->Fill(ntEntry); } - // the data points used in spline fit - // (they are kept in - // TPCFastTransformHelperO2::instance()->getCorrectionMap() ) - - o2::gpu::TPCFastSpaceChargeCorrectionMap& map = - corrHelper->getCorrectionMap(); - auto& points = map.getPoints(iRoc, iRow); - - for (uint32_t ip = 0; ip < points.size(); ip++) { - auto point = points[ip]; - float y = point.mY; - float z = point.mZ; - float correctionX = point.mDx; - float correctionY = point.mDy; - float correctionZ = point.mDz; - - float u, v, cx, cu, cv, cy, cz; - geo.convLocalToUV(iRoc, y, z, u, v); - corr.getCorrection(iRoc, iRow, u, v, cx, cu, cv); - geo.convUVtoLocal(iRoc, u + cu, v + cv, cy, cz); - cy -= y; - cz -= z; - - debugPoints->Fill(iRoc, iRow, x, y, z, correctionX, correctionY, - correctionZ, cx, cy, cz); + if (voxEntries >= 1.) { + double d[3] = {cx - correctionX, cy - correctionY, cz - correctionZ}; + + for (int32_t i = 0; i < 3; i++) { + if (fabs(maxDiff[i]) < fabs(d[i])) { + maxDiff[i] = d[i]; + maxDiffSector[i] = iSector; + maxDiffRow[i] = iRow; + // std::cout << " sector " << iSector << " row " << iRow << " xyz " << i + // << " diff " << d[i] << " entries " << voxEntries << " y " << y2xBin << " z " << z2xBin << std::endl; + } + sumDiff[i] += d[i] * d[i]; + } + nDiff++; } } - } - for (int32_t i = 0; i < 3; i++) { - sumDiff[i] = sqrt(sumDiff[i]) / nDiff; - } + LOG(info) << directionName << " correction: fill debug ntuples everywhere .."; + + for (int32_t iSector = 0; iSector < geo.getNumberOfSectors(); iSector++) { + // for (int32_t iSector = 0; iSector < 1; iSector++) { + LOG(info) << directionName << " correction: fill debug ntuples everywhere in sector " << iSector; + + int mirrorSector = (iSector >= geo.getNumberOfSectorsA()) ? iSector - geo.getNumberOfSectorsA() : iSector + geo.getNumberOfSectorsA(); - std::cout << "Max difference in x : " << maxDiff[0] << " at ROC " - << maxDiffRoc[0] << " row " << maxDiffRow[0] << std::endl; + for (int32_t iRow = 0; iRow < geo.getNumberOfRows(); iRow++) { - std::cout << "Max difference in y : " << maxDiff[1] << " at ROC " - << maxDiffRoc[1] << " row " << maxDiffRow[1] << std::endl; + double x = geo.getRowInfo(iRow).x; - std::cout << "Max difference in z : " << maxDiff[2] << " at ROC " - << maxDiffRoc[2] << " row " << maxDiffRow[2] << std::endl; + // the spline grid - std::cout << "Mean difference in x,y,z : " << sumDiff[0] << " " << sumDiff[1] - << " " << sumDiff[2] << std::endl; + const auto& gridY = corr.getSpline(iSector, iRow).getGridX1(); + const auto& gridZ = corr.getSpline(iSector, iRow).getGridX2(); + if (iSector == 0 && iRow == 0) { + std::cout << "spline scenario " << corr.getSectorRowInfo(iSector, iRow).splineScenarioID << std::endl; + std::cout << "spline grid Y: u = " << 0 << ".." << gridY.getUmax() << ", x = " << gridY.getXmin() << ".." << gridY.getXmax() << std::endl; + std::cout << "spline grid Z: u = " << 0 << ".." << gridZ.getUmax() << ", x = " << gridZ.getXmin() << ".." << gridZ.getXmax() << std::endl; + } - corr.testInverse(0); + // the correction + { + std::vector points[2], knots[2]; + + auto [yMin, yMax] = geo.getRowInfo(iRow).getYrange(); + auto [zMin, zMax] = geo.getZrange(iSector); + + for (int32_t iu = 0; iu < gridY.getNumberOfKnots(); iu++) { + auto [y, z] = corr.convGridToLocal(iSector, iRow, gridY.getKnot(iu).getU(), 0.); + knots[0].push_back(y); + points[0].push_back(y); + } + for (int32_t iv = 0; iv < gridZ.getNumberOfKnots(); iv++) { + auto [y, z] = corr.convGridToLocal(iSector, iRow, 0., gridZ.getKnot(iv).getU()); + knots[1].push_back(z); + points[1].push_back(z); + } + + for (int32_t iyz = 0; iyz <= 1; iyz++) { + std::sort(knots[iyz].begin(), knots[iyz].end()); + std::sort(points[iyz].begin(), points[iyz].end()); + int32_t n = points[iyz].size(); + int nsteps = (iyz == 0) ? 10 : 5; + for (int32_t i = 0; i < n - 1; i++) { + double d = (points[iyz][i + 1] - points[iyz][i]) / nsteps; + for (int32_t ii = 1; ii < nsteps; ii++) { + points[iyz].push_back(points[iyz][i] + d * ii); + } + } + } + points[0].push_back(yMin); + points[0].push_back(yMax); + points[1].push_back(zMin); + points[1].push_back(zMax); + for (int32_t iyz = 0; iyz <= 1; iyz++) { + std::sort(points[iyz].begin(), points[iyz].end()); + } + + for (int32_t iter = 0; iter < 2; iter++) { + std::vector& py = ((iter == 0) ? knots[0] : points[0]); + std::vector& pz = ((iter == 0) ? knots[1] : points[1]); + for (uint32_t iu = 0; iu < py.size(); iu++) { + for (uint32_t iv = 0; iv < pz.size(); iv++) { + float y = py[iu]; + float z = pz[iv]; + float cx{0}, cy{0}, cz{0}, ix{0}, iy{0}, iz{0}; + float cxC{0}, cyC{0}, czC{0}, ixC{0}, iyC{0}, izC{0}; + if (direction == 0) { + getAllCorrections(iSector, iRow, y, z, cx, cy, cz, ix, iy, iz); + if (debugMirrorAdata2C) { + getAllCorrections(mirrorSector, iRow, y, -z, cxC, cyC, czC, ixC, iyC, izC); + } + if (iter == 0) { + ntGrid->Fill(iSector, iRow, x, y, z, cx, cy, cz, ix, iy, iz); + } else { + float ntEntry[] = {(float)iSector, (float)iRow, (float)x, y, z, + cx, cy, cz, ix, iy, iz, + cxC, cyC, czC, ixC, iyC, izC}; + ntAll->Fill(ntEntry); + } + } else { + getInvCorrections(iSector, iRow, y, z, cx, cy, cz); + if (debugMirrorAdata2C) { + getInvCorrections(mirrorSector, iRow, y, -z, cxC, cyC, czC); + } + if (iter == 0) { + ntInvGrid->Fill(iSector, iRow, x, y, z, cx, cy, cz); + } else { + float ntEntry[] = {(float)iSector, (float)iRow, (float)x, y, z, + cx, cy, cz, + cxC, cyC, czC}; + ntInvAll->Fill(ntEntry); + } + } + } + } + } + } + + // the data points used in spline fit + // (they are kept in + // TPCFastTransformHelperO2::instance()->getCorrectionMap() ) + + o2::gpu::TPCFastSpaceChargeCorrectionMap& map = (direction == 0 ? mapDirect : mapInverse); + + auto& points = map.getPoints(iSector, iRow); + + for (uint32_t ip = 0; ip < points.size(); ip++) { + auto point = points[ip]; + float y = point.mY; + float z = point.mZ; + float correctionX = point.mDx; + float correctionY = point.mDy; + float correctionZ = point.mDz; + if (direction == 0) { + auto [cx, cy, cz] = + corr.getCorrectionLocal(iSector, iRow, y, z); + ntFitPoints->Fill(iSector, iRow, x, y, z, correctionX, correctionY, + correctionZ, cx, cy, cz); + } else { + float cx = + corr.getCorrectionXatRealYZ(iSector, iRow, y, z); + auto [cy, cz] = + corr.getCorrectionYZatRealYZ(iSector, iRow, y, z); + ntInvFitPoints->Fill(iSector, iRow, x, y, z, correctionX, correctionY, + correctionZ, cx, cy, cz); + } + } + } + } + + for (int32_t i = 0; i < 3; i++) { + sumDiff[i] = sqrt(sumDiff[i]) / nDiff; + } + LOG(info) << directionName << " correction: max and mean differences between spline and voxel corrections:"; + LOG(info) << "Max difference in x : " << maxDiff[0] << " at Sector " + << maxDiffSector[0] << " row " << maxDiffRow[0]; + + LOG(info) << "Max difference in y : " << maxDiff[1] << " at Sector " + << maxDiffSector[1] << " row " << maxDiffRow[1]; + + LOG(info) << "Max difference in z : " << maxDiff[2] << " at Sector " + << maxDiffSector[2] << " row " << maxDiffRow[2]; + + LOG(info) << "Mean difference in x,y,z : " << sumDiff[0] << " " << sumDiff[1] + << " " << sumDiff[2] << std::endl; + } // direction + + corr.testInverse(true); debugFile->cd(); - debugCorr->Write(); - debugVox->Write(); - debugGrid->Write(); - debugPoints->Write(); + ntAll->Write(); + ntVox->Write(); + ntGrid->Write(); + ntFitPoints->Write(); + ntInvAll->Write(); + ntInvVox->Write(); + ntInvGrid->Write(); + ntInvFitPoints->Write(); + debugFile->Close(); } diff --git a/GPU/TPCFastTransformation/macro/generateTPCCorrectionNTuple.C b/GPU/TPCFastTransformation/macro/generateTPCCorrectionNTuple.C index 67a0f09522f60..2c8f22e4a3f3b 100644 --- a/GPU/TPCFastTransformation/macro/generateTPCCorrectionNTuple.C +++ b/GPU/TPCFastTransformation/macro/generateTPCCorrectionNTuple.C @@ -82,26 +82,24 @@ void generateTPCCorrectionNTuple(const char* path = "InputSCDensityHistograms.ro const o2::gpu::TPCFastTransformGeo& geo = fastTransform->getGeometry(); TFile* f = new TFile("tpcCorrection.root", "RECREATE"); - TNtuple* nt = new TNtuple("dist", "dist", "slice:row:su:sv:dx:du:dv"); + TNtuple* nt = new TNtuple("dist", "dist", "sector:row:x:y:z:dx:dy:dz"); - int32_t nSlices = 1; // fastTransform->getNumberOfSlices(); - // for( int32_t slice=0; slicegetNumberOfSectors(); + // for( int32_t sector=0; sectorcorrectElectron(positionCorrected); @@ -111,15 +109,12 @@ void generateTPCCorrectionNTuple(const char* path = "InputSCDensityHistograms.ro // global to local float x1, y1, z1; - geo.convGlobalToLocal(slice, gx, gy, gz, x1, y1, z1); - float u1 = 0, v1 = 0; - geo.convLocalToUV(slice, y1, z1, u1, v1); + geo.convGlobalToLocal(sector, gx, gy, gz, x1, y1, z1); float dx = x1 - x; - float du = u1 - u; - float dv = v1 - v; - std::cout << slice << " " << row << " " << su << " " << sv << " " << dx << " " << du << " " << dv << std::endl; - nt->Fill(slice, row, su, sv, dx, du, dv); + float dy = y1 - y; + float dz = z1 - z; + nt->Fill(sector, row, x, y, z, dx, dy, dz); } } }