29#include <fairlogger/Logger.h>
31#include "TStopwatch.h"
40TPCFastSpaceChargeCorrectionHelper* TPCFastSpaceChargeCorrectionHelper::sInstance =
nullptr;
47 sInstance->initGeometry();
52void TPCFastSpaceChargeCorrectionHelper::initGeometry()
63 float tpcZlengthSideA = detParam.TPClength;
64 float tpcZlengthSideC = detParam.TPClength;
70 for (
int iRow = 0; iRow < mGeo.getNumberOfRows(); iRow++) {
80 float padWidth = region.getPadWidth();
84 float xRow = padCentre.X();
86 mGeo.
setTPCrow(iRow, xRow, nPads, padWidth);
99 LOG(info) <<
"fast space charge correction helper: use " <<
n << ((
n > 1) ?
" cpu threads" :
" cpu thread");
100 mNthreads = (
n > 0) ?
n : 1;
107 mNthreads = std::thread::hardware_concurrency();
109 LOG(info) <<
"fast space charge correction helper: use " << mNthreads << ((mNthreads > 1) ?
" cpu threads" :
" cpu thread");
121 if (!mIsInitialized) {
126 correction.setNoCorrection();
130 LOG(info) <<
"fast space charge correction helper: init from data points";
132 for (
int slice = 0; slice < correction.getGeometry().getNumberOfSlices(); slice++) {
134 auto myThread = [&](
int iThread) {
135 for (
int row = iThread;
row < correction.getGeometry().getNumberOfRows();
row += mNthreads) {
139 float* splineParameters = correction.getSplineData(slice,
row);
140 const std::vector<o2::gpu::TPCFastSpaceChargeCorrectionMap::CorrectionPoint>&
data = mCorrectionMap.
getPoints(slice,
row);
141 int nDataPoints =
data.size();
142 if (nDataPoints >= 4) {
143 std::vector<double> pointSU(nDataPoints);
144 std::vector<double> pointSV(nDataPoints);
145 std::vector<double> pointCorr(3 * nDataPoints);
146 for (
int i = 0;
i < nDataPoints; ++
i) {
147 double su, sv, dx, du, dv;
148 getSpaceChargeCorrection(correction, slice,
row,
data[
i], su, sv, dx, du, dv);
151 pointCorr[3 *
i + 0] = dx;
152 pointCorr[3 *
i + 1] = du;
153 pointCorr[3 *
i + 2] = dv;
155 helper.
approximateDataPoints(spline, splineParameters, 0., spline.getGridX1().getNumberOfKnots() - 1, 0., spline.getGridX2().getNumberOfKnots() - 1, &pointSU[0],
156 &pointSV[0], &pointCorr[0], nDataPoints);
158 for (
int i = 0;
i < spline.getNumberOfParameters();
i++) {
159 splineParameters[
i] = 0.f;
165 std::vector<std::thread> threads(mNthreads);
168 for (
int i = 0;
i < mNthreads;
i++) {
169 threads[
i] = std::thread(myThread,
i);
173 for (
auto& th : threads) {
183 double& su,
double& sv,
double& dx,
double& du,
double& dv)
187 if (!mIsInitialized) {
192 float u = 0.f,
v = 0.f, fsu = 0.f, fsv = 0.f;
193 mGeo.convLocalToUV(slice, p.
mY, p.
mZ, u,
v);
194 correction.convUVtoGrid(slice,
row, u,
v, fsu, fsv);
199 float u1 = 0.f,
v1 = 0.f;
200 mGeo.convLocalToUV(slice, p.
mY + p.
mDy, p.
mZ + p.
mDz, u1,
v1);
208 std::function<
void(
int roc,
double gx,
double gy,
double gz,
209 double& dgx,
double& dgy,
double& dgz)>
211 const int nKnotsY,
const int nKnotsZ)
215 auto correctionLocal = [&](
int roc,
int irow,
double ly,
double lz,
216 double& dlx,
double& dly,
double& dlz) {
217 double lx = mGeo.getRowInfo(irow).x;
219 mGeo.convLocalToGlobal(
roc, lx, ly, lz, gx, gy, gz);
220 double dgx, dgy, dgz;
221 correctionGlobal(
roc, gx, gy, gz, dgx, dgy, dgz);
223 mGeo.convGlobalToLocal(
roc, gx + dgx, gy + dgy, gz + dgz, lx1, ly1, lz1);
232 std::function<
void(
int roc,
int irow,
double y,
double z,
double& dx,
double& dy,
double& dz)> correctionLocal,
233 const int nKnotsY,
const int nKnotsZ)
237 LOG(info) <<
"fast space charge correction helper: create correction using " << mNthreads <<
" threads";
244 if (!mIsInitialized) {
248 const int nRows = mGeo.getNumberOfRows();
249 const int nCorrectionScenarios = nRows / 10 + 1;
254 for (
int row = 0;
row < mGeo.getNumberOfRows();
row++) {
255 int scenario =
row / 10;
256 if (scenario >= nCorrectionScenarios) {
257 scenario = nCorrectionScenarios - 1;
262 for (
int scenario = 0; scenario < nCorrectionScenarios; scenario++) {
263 int row = scenario * 10;
265 spline.recreate(nKnotsY, nKnotsZ);
271 LOG(info) <<
"fast space charge correction helper: fill data points from an input SP correction function";
277 int nRocs = mGeo.getNumberOfSlices();
278 int nRows = mGeo.getNumberOfRows();
279 mCorrectionMap.
init(nRocs, nRows);
281 for (
int iRoc = 0; iRoc < nRocs; iRoc++) {
283 auto myThread = [&](
int iThread) {
284 for (
int iRow = iThread; iRow < nRows; iRow += mNthreads) {
285 const auto& info = mGeo.getRowInfo(iRow);
286 double vMax = mGeo.getTPCzLength(iRoc);
287 double dv = vMax / (6. * (nKnotsZ - 1));
289 double dpad = info.maxPad / (6. * (nKnotsY - 1));
290 for (
double pad = 0; pad < info.maxPad + .5 * dpad; pad += dpad) {
291 float u = mGeo.convPadToU(iRow, pad);
292 for (
double v = 0.;
v < vMax + .5 * dv;
v += dv) {
294 mGeo.convUVtoLocal(iRoc, u,
v, ly, lz);
296 correctionLocal(iRoc, iRow, ly, lz, dx, dy, dz);
304 std::vector<std::thread> threads(mNthreads);
307 for (
int i = 0;
i < mNthreads;
i++) {
308 threads[
i] = std::thread(myThread,
i);
312 for (
auto& th : threads) {
321 return std::move(correctionPtr);
329 LOG(fatal) <<
"Wrong number of sectors :" << geo.getNumberOfSlices() <<
" instead of " <<
Sector::MAXSECTOR << std::endl;
333 LOG(fatal) <<
"Wrong number of rows :" << geo.getNumberOfRows() <<
" instead of " << mapper.
getNumberOfRows() << std::endl;
336 double maxDx = 0, maxDy = 0;
338 for (
int row = 0;
row < geo.getNumberOfRows();
row++) {
340 const int nPads = geo.getRowInfo(
row).maxPad + 1;
346 const double x = geo.getRowInfo(
row).x;
350 for (
int pad = 0; pad < nPads; pad++) {
353 double u = geo.convPadToU(
row, pad);
355 const double dx =
x -
c.X();
356 const double dy = u - (-
c.Y());
358 if (fabs(dx) >= 1.e-6 || fabs(dy) >= 1.e-5) {
359 LOG(warning) <<
"wrong calculated pad position:"
360 <<
" row " <<
row <<
" pad " << pad <<
" x calc " <<
x <<
" x in map " <<
c.X() <<
" dx " << (
x -
c.X())
361 <<
" y calc " << u <<
" y in map " << -
c.Y() <<
" dy " << dy << std::endl;
363 if (fabs(maxDx) < fabs(dx)) {
366 if (fabs(maxDy) < fabs(dy)) {
372 if (fabs(maxDx) >= 1.e-4 || fabs(maxDy) >= 1.e-4) {
373 LOG(fatal) <<
"wrong calculated pad position:"
374 <<
" max Dx " << maxDx <<
" max Dy " << maxDy << std::endl;
383 LOG(info) <<
"fast space charge correction helper: create correction using " << mNthreads <<
" threads";
393 TBranch* branch = voxResTree->GetBranch(
"voxRes");
394 branch->SetAddress(&
v);
395 branch->SetAutoDelete(kTRUE);
401 map.
init(geo.getNumberOfSlices(), geo.getNumberOfRows());
406 int nKnotsY = nY2Xbins / 2;
407 int nKnotsZ = nZ2Xbins / 2;
422 const int nRows = geo.getNumberOfRows();
423 const int nCorrectionScenarios = 1;
428 for (
int row = 0;
row < geo.getNumberOfRows();
row++) {
433 spline.recreate(nKnotsY, nKnotsZ);
440 for (
int iRoc = 0; iRoc < geo.getNumberOfSlices(); iRoc++) {
441 for (
int iRow = 0; iRow < geo.getNumberOfRows(); iRow++) {
442 auto rowInfo = geo.getRowInfo(iRow);
444 double len = geo.getTPCzLength(iRoc);
452 LOG(info) <<
"fast space charge correction helper: fill data points from track residuals";
454 for (
int iVox = 0; iVox < voxResTree->GetEntriesFast(); iVox++) {
456 voxResTree->GetEntry(iVox);
464 int iRoc = (
int)
v->bsec;
465 int iRow = (
int)xBin;
469 double x = trackResiduals.
getX(xBin);
470 double y2x = trackResiduals.
getY2X(
473 trackResiduals.
getZ2X(z2xBin);
477 if (iRoc >= geo.getNumberOfSlicesA()) {
487 if (fabs(sx -
x) + fabs(sy -
y) + fabs(sz -
z) > 1.e-4) {
488 std::cout <<
"wrong coordinates: " <<
x <<
" " <<
y <<
" " <<
z <<
" / " << sx <<
" " << sy <<
" " << sz << std::endl;
494 if (voxEntries < 1.) {
503 double dy =
x / trackResiduals.
getDY2XI(xBin, y2xBin);
504 double dz =
x * trackResiduals.
getDZ2X(z2xBin);
523 double yFirst =
y - dy / 2.;
524 double yLast =
y + dy / 2.;
528 if (iRoc < geo.getNumberOfSlicesA()) {
529 geo.convScaledUVtoUV(iRoc, iRow, 0., 0., u,
v);
531 geo.convScaledUVtoUV(iRoc, iRow, 1., 0., u,
v);
534 geo.convUVtoLocal(iRoc, u,
v, py, pz);
540 if (iRoc < geo.getNumberOfSlicesA()) {
541 geo.convScaledUVtoUV(iRoc, iRow, 1., 0., u,
v);
543 geo.convScaledUVtoUV(iRoc, iRow, 0., 0., u,
v);
546 geo.convUVtoLocal(iRoc, u,
v, py, pz);
551 if (iRoc < geo.getNumberOfSlicesA()) {
552 z0 = geo.getTPCzLengthA();
554 z0 = -geo.getTPCzLengthC();
557 double yStep = (yLast - yFirst) / 2;
559 for (
double py = yFirst; py <= yLast + yStep / 2.; py += yStep) {
561 for (
double pz =
z - dz / 2.; pz <=
z + dz / 2. + 1.e-4; pz += dz / 2.) {
569 for (
int is = 0; is < nZsteps; is++) {
570 double pz =
z + (z0 -
z) * (is + 1.) / nZsteps;
571 double s = (nZsteps - 1. - is) / nZsteps;
573 s * correctionY, s * correctionZ);
578 helper->fillSpaceChargeCorrectionFromMap(correction);
579 return std::move(correctionPtr);
586 double tpcR2min = mGeo.getRowInfo(0).x - 1.;
587 tpcR2min = tpcR2min * tpcR2min;
588 double tpcR2max = mGeo.getRowInfo(mGeo.getNumberOfRows() - 1).x;
589 tpcR2max = tpcR2max / cos(2 * M_PI / mGeo.getNumberOfSlicesA() / 2) + 1.;
590 tpcR2max = tpcR2max * tpcR2max;
594 for (
int slice = 0; slice < mGeo.getNumberOfSlices(); slice++) {
596 LOG(info) <<
"init MaxDriftLength for slice " << slice;
598 double vLength = (slice < mGeo.getNumberOfSlicesA()) ? mGeo.getTPCzLengthA() : mGeo.getTPCzLengthC();
600 sliceInfo.
vMax = 0.f;
602 for (
int row = 0;
row < mGeo.getNumberOfRows();
row++) {
606 area.cuMin = mGeo.convPadToU(
row, 0.f);
607 area.cuMax = -area.cuMin;
608 chebFitter.
reset(4, 0., mGeo.getRowInfo(
row).maxPad);
609 double x = mGeo.getRowInfo(
row).x;
610 for (
int pad = 0; pad < mGeo.getRowInfo(
row).maxPad; pad++) {
611 float u = mGeo.convPadToU(
row, (
float)pad);
613 float v1 = 1.1 * vLength;
614 float vLastValid = -1;
615 float cvLastValid = -1;
616 while (
v1 -
v0 > 0.1) {
617 float v = 0.5 * (
v0 +
v1);
619 correction.getCorrection(slice,
row, u,
v, dx, du, dv);
623 double r2 = cx * cx + cu * cu;
626 }
else if (cv <= vLength && r2 >= tpcR2min && r2 <= tpcR2max) {
634 if (vLastValid > 0.) {
637 if (
area.vMax < vLastValid) {
638 area.vMax = vLastValid;
640 if (
area.cvMax < cvLastValid) {
641 area.cvMax = cvLastValid;
645 for (
int i = 0;
i < 5;
i++) {
657 std::vector<o2::gpu::TPCFastSpaceChargeCorrection*> corr{&correction};
665 LOG(info) <<
"fast space charge correction helper: init inverse";
667 if (corrections.size() != scaling.size()) {
668 LOGP(error,
"Input corrections and scaling values have different size");
672 auto& correction = *(corrections.front());
673 initMaxDriftLength(correction, prn);
675 double tpcR2min = mGeo.getRowInfo(0).x - 1.;
676 tpcR2min = tpcR2min * tpcR2min;
677 double tpcR2max = mGeo.getRowInfo(mGeo.getNumberOfRows() - 1).x;
678 tpcR2max = tpcR2max / cos(2 * M_PI / mGeo.getNumberOfSlicesA() / 2) + 1.;
679 tpcR2max = tpcR2max * tpcR2max;
681 for (
int slice = 0; slice < mGeo.getNumberOfSlices(); slice++) {
683 double vLength = (slice < mGeo.getNumberOfSlicesA()) ? mGeo.getTPCzLengthA() : mGeo.getTPCzLengthC();
685 auto myThread = [&](
int iThread) {
687 std::vector<float> splineParameters;
690 for (
int row = iThread;
row < mGeo.getNumberOfRows();
row += mNthreads) {
693 std::vector<double> dataPointCU, dataPointCV, dataPointF;
695 float u0, u1,
v0,
v1;
696 mGeo.convScaledUVtoUV(slice,
row, 0., 0., u0,
v0);
697 mGeo.convScaledUVtoUV(slice,
row, 1., 1., u1,
v1);
699 double x = mGeo.getRowInfo(
row).x;
700 int nPointsU = (spline.getGridX1().getNumberOfKnots() - 1) * 10;
701 int nPointsV = (spline.getGridX2().getNumberOfKnots() - 1) * 10;
703 double stepU = (u1 - u0) / (nPointsU - 1);
704 double stepV = (
v1 -
v0) / (nPointsV - 1);
707 LOG(info) <<
"u0 " << u0 <<
" u1 " << u1 <<
" v0 " <<
v0 <<
" v1 " <<
v1;
721 for (
double u = u0; u < u1 + stepU; u += stepU) {
722 for (
double v =
v0;
v <
v1 + stepV;
v += stepV) {
724 correction.getCorrection(slice,
row, u,
v, dx, du, dv);
729 for (
int i = 1;
i < corrections.size(); ++
i) {
730 float dxTmp, duTmp, dvTmp;
731 corrections[
i]->getCorrection(slice,
row, u,
v, dxTmp, duTmp, dvTmp);
732 dx += dxTmp * scaling[
i];
733 du += duTmp * scaling[
i];
734 dv += dvTmp * scaling[
i];
739 if (cu < area.cuMin) {
742 if (cu > area.cuMax) {
746 dataPointCU.push_back(cu);
747 dataPointCV.push_back(cv);
748 dataPointF.push_back(dx);
749 dataPointF.push_back(du);
750 dataPointF.push_back(dv);
753 LOG(info) <<
"measurement cu " << cu <<
" cv " << cv <<
" dx " << dx <<
" du " << du <<
" dv " << dv;
758 if (area.cuMax - area.cuMin < 0.2) {
762 if (area.cvMax < 0.1) {
766 LOG(info) <<
"slice " << slice <<
" row " <<
row <<
" max drift L = " << correction.getMaxDriftLength(slice,
row)
767 <<
" active area: cuMin " << area.cuMin <<
" cuMax " << area.cuMax <<
" vMax " << area.vMax <<
" cvMax " << area.cvMax;
772 info.
scaleCorrUtoGrid = spline.getGridX1().getUmax() / (area.cuMax - area.cuMin);
780 int nDataPoints = dataPointCU.size();
781 for (
int i = 0;
i < nDataPoints;
i++) {
786 splineParameters.resize(spline.getNumberOfParameters());
789 0., spline.getGridX2().getUmax(),
790 dataPointCU.data(), dataPointCV.data(),
791 dataPointF.data(), dataPointCU.size());
793 float* splineX = correction.getSplineData(slice,
row, 1);
794 float* splineUV = correction.getSplineData(slice,
row, 2);
795 for (
int i = 0;
i < spline.getNumberOfParameters() / 3;
i++) {
796 splineX[
i] = splineParameters[3 *
i + 0];
797 splineUV[2 *
i + 0] = splineParameters[3 *
i + 1];
798 splineUV[2 *
i + 1] = splineParameters[3 *
i + 2];
803 std::vector<std::thread> threads(mNthreads);
806 for (
int i = 0;
i < mNthreads;
i++) {
807 threads[
i] = std::thread(myThread,
i);
811 for (
auto& th : threads) {
816 float duration = watch.RealTime();
817 LOGP(info,
"Inverse took: {}s", duration);
Definition of ChebyshevFit1D class.
Definition of the parameter class for the detector.
Definition of the parameter class for the detector electronics.
Definition of the parameter class for the detector gas.
Definition of Spline2DHelper class.
class to create TPC fast space charge correction
Definition of the TrackResiduals class.
static const ParameterDetector & Instance()
void addMeasurement(double x, double m)
const std::vector< double > & getCoefficients() const
void reset(int32_t order, double xMin, double xMax)
int32_t setSpline(const Spline2DContainer< DataT > &spline, int32_t nAuxiliaryPointsU1, int32_t nAuxiliaryPointsU2)
_______________ Interface for a step-wise construction of the best-fit spline _______________________...
void approximateDataPoints(Spline2DContainer< DataT > &spline, DataT *splineParameters, double x1Min, double x1Max, double x2Min, double x2Max, const double dataPointX1[], const double dataPointX2[], const double dataPointF[], int32_t nDataPoints)
Create best-fit spline parameters for a given set of data points.
void addCorrectionPoint(int32_t iRoc, int32_t iRow, double y, double z, double dx, double dy, double dz)
Starts the construction procedure, reserves temporary memory.
bool isInitialized() const
const std::vector< CorrectionPoint > & getPoints(int32_t iRoc, int32_t iRow) const
void init(int32_t nRocs, int32_t nRows)
(re-)init the map
void setSplineScenario(int32_t scenarioIndex, const SplineType &spline)
Sets approximation scenario.
void setRowScenarioID(int32_t iRow, int32_t iScenario)
Initializes a TPC row.
void startConstruction(const TPCFastTransformGeo &geo, int32_t numberOfSplineScenarios)
_______________ Construction interface ________________________
void finishConstruction()
Finishes construction: puts everything to the flat buffer, releases temporary memory.
int getNumberOfRows() const
int getNumberOfPadsInRowSector(int row) const
int getGlobalRowOffsetRegion(int region) const
GlobalPadNumber globalPadNumber(const PadPos &globalPadPosition) const
static Mapper & instance(const std::string mappingDir="")
const PadRegionInfo & getPadRegionInfo(const unsigned char region) const
int getNumberOfRowsRegion(int region) const
const PadCentre & padCentre(GlobalPadNumber padNumber) const
static constexpr int MAXSECTOR
std::unique_ptr< TPCFastSpaceChargeCorrection > createFromLocalCorrection(std::function< void(int roc, int irow, double y, double z, double &dx, double &dy, double &dz)> correctionLocal, const int nKnotsY=10, const int nKnotsZ=20)
_______________ Main functionality ________________________
void initInverse(o2::gpu::TPCFastSpaceChargeCorrection &correction, bool prn)
initialise inverse transformation
std::unique_ptr< o2::gpu::TPCFastSpaceChargeCorrection > createFromTrackResiduals(const o2::tpc::TrackResiduals &trackResiduals, TTree *voxResTree, bool useSmoothed=false, bool invertSigns=false)
Create SpaceCharge correction out of the voxel tree.
std::unique_ptr< TPCFastSpaceChargeCorrection > createFromGlobalCorrection(std::function< void(int roc, double gx, double gy, double gz, double &dgx, double &dgy, double &dgz)> correctionGlobal, const int nKnotsY=10, const int nKnotsZ=20)
creates TPCFastSpaceChargeCorrection object from a continious space charge correction in global coord...
void testGeometry(const TPCFastTransformGeo &geo) const
TPCFastSpaceChargeCorrectionHelper()=default
_____________ Constructors / destructors __________________________
void setNthreads(int n)
_______________ Settings ________________________
void setNthreadsToMaximum()
sets number of threads to N cpu cores
void fillSpaceChargeCorrectionFromMap(TPCFastSpaceChargeCorrection &correction)
static TPCFastSpaceChargeCorrectionHelper * instance()
Singleton.
float getZ2X(int iz) const
float getY2X(int ix, int ip) const
float getDY2XI(int ix, int iy=0) const
void getVoxelCoordinates(int isec, int ix, int ip, int iz, float &x, float &p, float &z) const
float getDZ2X(int iz=0) const
GLenum GLenum GLsizei len
GLdouble GLdouble GLdouble z
math_utils::Point2D< float > PadCentre
Pad centres as 2D float.
unsigned short GlobalPadNumber
global pad number
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
The struct contains necessary info for TPC padrow.
float vMax
Max value of V coordinate.
float scaleCorrUtoGrid
scale corrected U to U-grid coordinate
float scaleCorrVtoGrid
scale corrected V to V-grid coordinate
float gridCorrU0
U coordinate of the U-grid start for corrected U.
float gridV0
V coordinate of the V-grid start.
float gridCorrV0
V coordinate of the V-grid start for corrected V.
Structure which gets filled with the results for each voxel.
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"