Project
Loading...
Searching...
No Matches
TPCFastSpaceChargeCorrectionHelper.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
14
16
17#include "TPCBase/Mapper.h"
22#include "TPCBase/Sector.h"
24#include "DataFormatsTPC/Defs.h"
25#include "TPCFastTransform.h"
26#include "ChebyshevFit1D.h"
27#include "Spline2DHelper.h"
28#include "Riostream.h"
29#include <fairlogger/Logger.h>
30#include <thread>
31#include "TStopwatch.h"
32
33using namespace o2::gpu;
34
35namespace o2
36{
37namespace tpc
38{
39
40TPCFastSpaceChargeCorrectionHelper* TPCFastSpaceChargeCorrectionHelper::sInstance = nullptr;
41
43{
44 // returns TPCFastSpaceChargeCorrectionHelper instance (singleton)
45 if (!sInstance) {
46 sInstance = new TPCFastSpaceChargeCorrectionHelper();
47 sInstance->initGeometry();
48 }
49 return sInstance;
50}
51
52void TPCFastSpaceChargeCorrectionHelper::initGeometry()
53{
54 // initialize geometry
55
56 const Mapper& mapper = Mapper::instance();
57
58 const int nRows = mapper.getNumberOfRows();
59
60 mGeo.startConstruction(nRows);
61
62 auto& detParam = ParameterDetector::Instance();
63 float tpcZlengthSideA = detParam.TPClength;
64 float tpcZlengthSideC = detParam.TPClength;
65
66 mGeo.setTPCzLength(tpcZlengthSideA, tpcZlengthSideC);
67
68 mGeo.setTPCalignmentZ(0.);
69
70 for (int iRow = 0; iRow < mGeo.getNumberOfRows(); iRow++) {
71 Sector sector = 0;
72 int regionNumber = 0;
73 while (iRow >= mapper.getGlobalRowOffsetRegion(regionNumber) + mapper.getNumberOfRowsRegion(regionNumber)) {
74 regionNumber++;
75 }
76
77 const PadRegionInfo& region = mapper.getPadRegionInfo(regionNumber);
78
79 int nPads = mapper.getNumberOfPadsInRowSector(iRow);
80 float padWidth = region.getPadWidth();
81
82 const GlobalPadNumber pad = mapper.globalPadNumber(PadPos(iRow, nPads / 2));
83 const PadCentre& padCentre = mapper.padCentre(pad);
84 float xRow = padCentre.X();
85
86 mGeo.setTPCrow(iRow, xRow, nPads, padWidth);
87 }
88
89 mGeo.finishConstruction();
90
91 // check if calculated pad geometry is consistent with the map
92 testGeometry(mGeo);
93
94 mIsInitialized = 1;
95}
96
98{
99 LOG(info) << "fast space charge correction helper: use " << n << ((n > 1) ? " cpu threads" : " cpu thread");
100 mNthreads = (n > 0) ? n : 1;
101}
102
104{
106
107 mNthreads = std::thread::hardware_concurrency();
108
109 LOG(info) << "fast space charge correction helper: use " << mNthreads << ((mNthreads > 1) ? " cpu threads" : " cpu thread");
110
111 if (mNthreads < 1) {
112 mNthreads = 1;
113 }
114}
115
117{
118 // calculate correction map: dx,du,dv = ( origTransform() -> x,u,v) - fastTransformNominal:x,u,v
119 // for the future: switch TOF correction off for a while
120
121 if (!mIsInitialized) {
122 initGeometry();
123 }
124
125 if (!mCorrectionMap.isInitialized()) {
126 correction.setNoCorrection();
127 return;
128 }
129
130 LOG(info) << "fast space charge correction helper: init from data points";
131
132 for (int slice = 0; slice < correction.getGeometry().getNumberOfSlices(); slice++) {
133
134 auto myThread = [&](int iThread) {
135 for (int row = iThread; row < correction.getGeometry().getNumberOfRows(); row += mNthreads) {
136
137 TPCFastSpaceChargeCorrection::SplineType& spline = correction.getSpline(slice, row);
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); // 3 dimensions
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);
149 pointSU[i] = su;
150 pointSV[i] = sv;
151 pointCorr[3 * i + 0] = dx;
152 pointCorr[3 * i + 1] = du;
153 pointCorr[3 * i + 2] = dv;
154 }
155 helper.approximateDataPoints(spline, splineParameters, 0., spline.getGridX1().getNumberOfKnots() - 1, 0., spline.getGridX2().getNumberOfKnots() - 1, &pointSU[0],
156 &pointSV[0], &pointCorr[0], nDataPoints);
157 } else {
158 for (int i = 0; i < spline.getNumberOfParameters(); i++) {
159 splineParameters[i] = 0.f;
160 }
161 }
162 } // row
163 }; // thread
164
165 std::vector<std::thread> threads(mNthreads);
166
167 // run n threads
168 for (int i = 0; i < mNthreads; i++) {
169 threads[i] = std::thread(myThread, i);
170 }
171
172 // wait for the threads to finish
173 for (auto& th : threads) {
174 th.join();
175 }
176
177 } // slice
178
179 initInverse(correction, 0);
180}
181
182void TPCFastSpaceChargeCorrectionHelper::getSpaceChargeCorrection(const TPCFastSpaceChargeCorrection& correction, int slice, int row, o2::gpu::TPCFastSpaceChargeCorrectionMap::CorrectionPoint p,
183 double& su, double& sv, double& dx, double& du, double& dv)
184{
185 // get space charge correction in internal TPCFastTransform coordinates su,sv->dx,du,dv
186
187 if (!mIsInitialized) {
188 initGeometry();
189 }
190
191 // not corrected coordinates in u,v
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);
195 // mGeo.convUVtoScaledUV(slice, row, u, v, fsu, fsv);
196 su = fsu;
197 sv = fsv;
198 // corrected coordinates in u,v
199 float u1 = 0.f, v1 = 0.f;
200 mGeo.convLocalToUV(slice, p.mY + p.mDy, p.mZ + p.mDz, u1, v1);
201
202 dx = p.mDx;
203 du = u1 - u;
204 dv = v1 - v;
205}
206
207std::unique_ptr<TPCFastSpaceChargeCorrection> TPCFastSpaceChargeCorrectionHelper::createFromGlobalCorrection(
208 std::function<void(int roc, double gx, double gy, double gz,
209 double& dgx, double& dgy, double& dgz)>
210 correctionGlobal,
211 const int nKnotsY, const int nKnotsZ)
212{
214
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;
218 float gx, gy, gz;
219 mGeo.convLocalToGlobal(roc, lx, ly, lz, gx, gy, gz);
220 double dgx, dgy, dgz;
221 correctionGlobal(roc, gx, gy, gz, dgx, dgy, dgz);
222 float lx1, ly1, lz1;
223 mGeo.convGlobalToLocal(roc, gx + dgx, gy + dgy, gz + dgz, lx1, ly1, lz1);
224 dlx = lx1 - lx;
225 dly = ly1 - ly;
226 dlz = lz1 - lz;
227 };
228 return std::move(createFromLocalCorrection(correctionLocal, nKnotsY, nKnotsZ));
229}
230
231std::unique_ptr<TPCFastSpaceChargeCorrection> TPCFastSpaceChargeCorrectionHelper::createFromLocalCorrection(
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)
234{
236
237 LOG(info) << "fast space charge correction helper: create correction using " << mNthreads << " threads";
238
239 std::unique_ptr<TPCFastSpaceChargeCorrection> correctionPtr(new TPCFastSpaceChargeCorrection);
240 TPCFastSpaceChargeCorrection& correction = *correctionPtr;
241
242 { // create a correction map
243
244 if (!mIsInitialized) {
245 initGeometry();
246 }
247
248 const int nRows = mGeo.getNumberOfRows();
249 const int nCorrectionScenarios = nRows / 10 + 1;
250
251 correction.startConstruction(mGeo, nCorrectionScenarios);
252
253 // assign spline type for TPC rows
254 for (int row = 0; row < mGeo.getNumberOfRows(); row++) {
255 int scenario = row / 10;
256 if (scenario >= nCorrectionScenarios) {
257 scenario = nCorrectionScenarios - 1;
258 }
259 correction.setRowScenarioID(row, scenario);
260 }
261
262 for (int scenario = 0; scenario < nCorrectionScenarios; scenario++) {
263 int row = scenario * 10;
265 spline.recreate(nKnotsY, nKnotsZ);
266 correction.setSplineScenario(scenario, spline);
267 }
268 correction.finishConstruction();
269 }
270
271 LOG(info) << "fast space charge correction helper: fill data points from an input SP correction function";
272
273 {
276
277 int nRocs = mGeo.getNumberOfSlices();
278 int nRows = mGeo.getNumberOfRows();
279 mCorrectionMap.init(nRocs, nRows);
280
281 for (int iRoc = 0; iRoc < nRocs; iRoc++) {
282
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));
288
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) {
293 float ly, lz;
294 mGeo.convUVtoLocal(iRoc, u, v, ly, lz);
295 double dx, dy, dz;
296 correctionLocal(iRoc, iRow, ly, lz, dx, dy, dz);
297 mCorrectionMap.addCorrectionPoint(iRoc, iRow,
298 ly, lz, dx, dy, dz);
299 }
300 }
301 } // row
302 }; // thread
303
304 std::vector<std::thread> threads(mNthreads);
305
306 // run n threads
307 for (int i = 0; i < mNthreads; i++) {
308 threads[i] = std::thread(myThread, i);
309 }
310
311 // wait for the threads to finish
312 for (auto& th : threads) {
313 th.join();
314 }
315
316 } // roc
317
319 }
320
321 return std::move(correctionPtr);
322}
323
325{
326 const Mapper& mapper = Mapper::instance();
327
328 if (geo.getNumberOfSlices() != Sector::MAXSECTOR) {
329 LOG(fatal) << "Wrong number of sectors :" << geo.getNumberOfSlices() << " instead of " << Sector::MAXSECTOR << std::endl;
330 }
331
332 if (geo.getNumberOfRows() != mapper.getNumberOfRows()) {
333 LOG(fatal) << "Wrong number of rows :" << geo.getNumberOfRows() << " instead of " << mapper.getNumberOfRows() << std::endl;
334 }
335
336 double maxDx = 0, maxDy = 0;
337
338 for (int row = 0; row < geo.getNumberOfRows(); row++) {
339
340 const int nPads = geo.getRowInfo(row).maxPad + 1;
341
342 if (nPads != mapper.getNumberOfPadsInRowSector(row)) {
343 LOG(fatal) << "Wrong number of pads :" << nPads << " instead of " << mapper.getNumberOfPadsInRowSector(row) << std::endl;
344 }
345
346 const double x = geo.getRowInfo(row).x;
347
348 // check if calculated pad positions are equal to the real ones
349
350 for (int pad = 0; pad < nPads; pad++) {
351 const GlobalPadNumber p = mapper.globalPadNumber(PadPos(row, pad));
352 const PadCentre& c = mapper.padCentre(p);
353 double u = geo.convPadToU(row, pad);
354
355 const double dx = x - c.X();
356 const double dy = u - (-c.Y()); // diferent sign convention for Y coordinate in the map
357
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;
362 }
363 if (fabs(maxDx) < fabs(dx)) {
364 maxDx = dx;
365 }
366 if (fabs(maxDy) < fabs(dy)) {
367 maxDy = dy;
368 }
369 }
370 }
371
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;
375 }
376}
377
378std::unique_ptr<o2::gpu::TPCFastSpaceChargeCorrection> TPCFastSpaceChargeCorrectionHelper::createFromTrackResiduals(
379 const o2::tpc::TrackResiduals& trackResiduals, TTree* voxResTree, bool useSmoothed, bool invertSigns)
380{
381 // create o2::gpu::TPCFastSpaceChargeCorrection from o2::tpc::TrackResiduals::VoxRes voxel tree
382
383 LOG(info) << "fast space charge correction helper: create correction using " << mNthreads << " threads";
384
385 std::unique_ptr<o2::gpu::TPCFastSpaceChargeCorrection> correctionPtr(new o2::gpu::TPCFastSpaceChargeCorrection);
386
387 o2::gpu::TPCFastSpaceChargeCorrection& correction = *correctionPtr;
388
389 // o2::tpc::TrackResiduals::VoxRes* v = nullptr;
390 // voxResTree->SetBranchAddress("voxRes", &v);
391
393 TBranch* branch = voxResTree->GetBranch("voxRes");
394 branch->SetAddress(&v);
395 branch->SetAutoDelete(kTRUE);
396
398 const o2::gpu::TPCFastTransformGeo& geo = helper->getGeometry();
399
400 o2::gpu::TPCFastSpaceChargeCorrectionMap& map = helper->getCorrectionMap();
401 map.init(geo.getNumberOfSlices(), geo.getNumberOfRows());
402
403 int nY2Xbins = trackResiduals.getNY2XBins();
404 int nZ2Xbins = trackResiduals.getNZ2XBins();
405
406 int nKnotsY = nY2Xbins / 2;
407 int nKnotsZ = nZ2Xbins / 2;
408
409 if (nKnotsY < 2) {
410 nKnotsY = 2;
411 }
412
413 if (nKnotsZ < 2) {
414 nKnotsZ = 2;
415 }
416
417 // std::cout << "n knots Y: " << nKnotsY << std::endl;
418 // std::cout << "n knots Z: " << nKnotsZ << std::endl;
419
420 { // create the correction object
421
422 const int nRows = geo.getNumberOfRows();
423 const int nCorrectionScenarios = 1;
424
425 correction.startConstruction(geo, nCorrectionScenarios);
426
427 // init rows
428 for (int row = 0; row < geo.getNumberOfRows(); row++) {
429 correction.setRowScenarioID(row, 0);
430 }
431 { // init spline scenario
433 spline.recreate(nKnotsY, nKnotsZ);
434 correction.setSplineScenario(0, spline);
435 }
436 correction.finishConstruction();
437 } // .. create the correction object
438
439 // set the grid borders in Z to Z/X==1
440 for (int iRoc = 0; iRoc < geo.getNumberOfSlices(); iRoc++) {
441 for (int iRow = 0; iRow < geo.getNumberOfRows(); iRow++) {
442 auto rowInfo = geo.getRowInfo(iRow);
443 o2::gpu::TPCFastSpaceChargeCorrection::SliceRowInfo& info = correction.getSliceRowInfo(iRoc, iRow);
444 double len = geo.getTPCzLength(iRoc);
445 info.gridV0 = len - rowInfo.x;
446 if (info.gridV0 < 0.) {
447 info.gridV0 = 0.;
448 }
449 }
450 }
451
452 LOG(info) << "fast space charge correction helper: fill data points from track residuals";
453
454 for (int iVox = 0; iVox < voxResTree->GetEntriesFast(); iVox++) {
455
456 voxResTree->GetEntry(iVox);
457 auto xBin =
458 v->bvox[o2::tpc::TrackResiduals::VoxX]; // bin number in x (= pad row)
459 auto y2xBin =
460 v->bvox[o2::tpc::TrackResiduals::VoxF]; // bin number in y/x 0..14
461 auto z2xBin =
462 v->bvox[o2::tpc::TrackResiduals::VoxZ]; // bin number in z/x 0..4
463
464 int iRoc = (int)v->bsec;
465 int iRow = (int)xBin;
466
467 // x,y,z of the voxel in local TPC coordinates
468
469 double x = trackResiduals.getX(xBin); // radius of the pad row
470 double y2x = trackResiduals.getY2X(
471 xBin, y2xBin); // y/x coordinate of the bin ~-0.15 ... 0.15
472 double z2x =
473 trackResiduals.getZ2X(z2xBin); // z/x coordinate of the bin 0.1 .. 0.9
474 double y = x * y2x;
475 double z = x * z2x;
476
477 if (iRoc >= geo.getNumberOfSlicesA()) {
478 z = -z;
479 // y = -y;
480 }
481
482 {
483 float sx, sy, sz;
484 trackResiduals.getVoxelCoordinates(iRoc, xBin, y2xBin, z2xBin, sx, sy, sz);
485 sy *= x;
486 sz *= x;
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;
489 }
490 }
491
492 // skip empty voxels
493 float voxEntries = v->stat[o2::tpc::TrackResiduals::VoxV];
494 if (voxEntries < 1.) { // no statistics
495 continue;
496 }
497
498 // double statX = v->stat[o2::tpc::TrackResiduals::VoxX]; // weight
499 // double statY = v->stat[o2::tpc::TrackResiduals::VoxF]; // weight
500 // double statZ = v->stat[o2::tpc::TrackResiduals::VoxZ]; // weight
501
502 // double dx = 1. / trackResiduals.getDXI(xBin);
503 double dy = x / trackResiduals.getDY2XI(xBin, y2xBin);
504 double dz = x * trackResiduals.getDZ2X(z2xBin);
505
506 double correctionX = useSmoothed ? v->DS[o2::tpc::TrackResiduals::ResX] : v->D[o2::tpc::TrackResiduals::ResX];
507 double correctionY = useSmoothed ? v->DS[o2::tpc::TrackResiduals::ResY] : v->D[o2::tpc::TrackResiduals::ResY];
508 double correctionZ = useSmoothed ? v->DS[o2::tpc::TrackResiduals::ResZ] : v->D[o2::tpc::TrackResiduals::ResZ];
509 if (invertSigns) {
510 correctionX *= -1.;
511 correctionY *= -1.;
512 correctionZ *= -1.;
513 }
514 // add one point per voxel
515
516 // map.addCorrectionPoint(iRoc, iRow, y, z, correctionX, correctionY,
517 // correctionZ);
518
519 // add several points per voxel,
520 // extend values of the edge voxels to the edges of the TPC row
521 //
522
523 double yFirst = y - dy / 2.;
524 double yLast = y + dy / 2.;
525
526 if (y2xBin == 0) { // extend value of the first Y bin to the row edge
527 float u, v;
528 if (iRoc < geo.getNumberOfSlicesA()) {
529 geo.convScaledUVtoUV(iRoc, iRow, 0., 0., u, v);
530 } else {
531 geo.convScaledUVtoUV(iRoc, iRow, 1., 0., u, v);
532 }
533 float py, pz;
534 geo.convUVtoLocal(iRoc, u, v, py, pz);
535 yFirst = py;
536 }
537
538 if (y2xBin == trackResiduals.getNY2XBins() - 1) { // extend value of the last Y bin to the row edge
539 float u, v;
540 if (iRoc < geo.getNumberOfSlicesA()) {
541 geo.convScaledUVtoUV(iRoc, iRow, 1., 0., u, v);
542 } else {
543 geo.convScaledUVtoUV(iRoc, iRow, 0., 0., u, v);
544 }
545 float py, pz;
546 geo.convUVtoLocal(iRoc, u, v, py, pz);
547 yLast = py;
548 }
549
550 double z0 = 0.;
551 if (iRoc < geo.getNumberOfSlicesA()) {
552 z0 = geo.getTPCzLengthA();
553 } else {
554 z0 = -geo.getTPCzLengthC();
555 }
556
557 double yStep = (yLast - yFirst) / 2;
558
559 for (double py = yFirst; py <= yLast + yStep / 2.; py += yStep) {
560
561 for (double pz = z - dz / 2.; pz <= z + dz / 2. + 1.e-4; pz += dz / 2.) {
562 map.addCorrectionPoint(iRoc, iRow, py, pz, correctionX, correctionY,
563 correctionZ);
564 }
565
566 if (z2xBin == trackResiduals.getNZ2XBins() - 1) {
567 // extend value of the first Z bin to the readout, linear decrease of all values to 0.
568 int nZsteps = 3;
569 for (int is = 0; is < nZsteps; is++) {
570 double pz = z + (z0 - z) * (is + 1.) / nZsteps;
571 double s = (nZsteps - 1. - is) / nZsteps;
572 map.addCorrectionPoint(iRoc, iRow, py, pz, s * correctionX,
573 s * correctionY, s * correctionZ);
574 }
575 }
576 }
577 }
578 helper->fillSpaceChargeCorrectionFromMap(correction);
579 return std::move(correctionPtr);
580}
581
582void TPCFastSpaceChargeCorrectionHelper::initMaxDriftLength(o2::gpu::TPCFastSpaceChargeCorrection& correction, bool prn)
583{
585
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;
591
592 ChebyshevFit1D chebFitter;
593
594 for (int slice = 0; slice < mGeo.getNumberOfSlices(); slice++) {
595 if (prn) {
596 LOG(info) << "init MaxDriftLength for slice " << slice;
597 }
598 double vLength = (slice < mGeo.getNumberOfSlicesA()) ? mGeo.getTPCzLengthA() : mGeo.getTPCzLengthC();
599 TPCFastSpaceChargeCorrection::SliceInfo& sliceInfo = correction.getSliceInfo(slice);
600 sliceInfo.vMax = 0.f;
601
602 for (int row = 0; row < mGeo.getNumberOfRows(); row++) {
603 TPCFastSpaceChargeCorrection::RowActiveArea& area = correction.getSliceRowInfo(slice, row).activeArea;
604 area.cvMax = 0;
605 area.vMax = 0;
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);
612 float v0 = 0;
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);
618 float dx, du, dv;
619 correction.getCorrection(slice, row, u, v, dx, du, dv);
620 double cx = x + dx;
621 double cu = u + du;
622 double cv = v + dv;
623 double r2 = cx * cx + cu * cu;
624 if (cv < 0) {
625 v0 = v;
626 } else if (cv <= vLength && r2 >= tpcR2min && r2 <= tpcR2max) {
627 v0 = v;
628 vLastValid = v;
629 cvLastValid = cv;
630 } else {
631 v1 = v;
632 }
633 }
634 if (vLastValid > 0.) {
635 chebFitter.addMeasurement(pad, vLastValid);
636 }
637 if (area.vMax < vLastValid) {
638 area.vMax = vLastValid;
639 }
640 if (area.cvMax < cvLastValid) {
641 area.cvMax = cvLastValid;
642 }
643 }
644 chebFitter.fit();
645 for (int i = 0; i < 5; i++) {
646 area.maxDriftLengthCheb[i] = chebFitter.getCoefficients()[i];
647 }
648 if (sliceInfo.vMax < area.vMax) {
649 sliceInfo.vMax = area.vMax;
650 }
651 } // row
652 } // slice
653}
654
656{
657 std::vector<o2::gpu::TPCFastSpaceChargeCorrection*> corr{&correction};
658 initInverse(corr, std::vector<float>{1}, prn);
659}
660
661void TPCFastSpaceChargeCorrectionHelper::initInverse(std::vector<o2::gpu::TPCFastSpaceChargeCorrection*>& corrections, const std::vector<float>& scaling, bool prn)
662{
664 TStopwatch watch;
665 LOG(info) << "fast space charge correction helper: init inverse";
666
667 if (corrections.size() != scaling.size()) {
668 LOGP(error, "Input corrections and scaling values have different size");
669 return;
670 }
671
672 auto& correction = *(corrections.front());
673 initMaxDriftLength(correction, prn);
674
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;
680
681 for (int slice = 0; slice < mGeo.getNumberOfSlices(); slice++) {
682 // LOG(info) << "inverse transform for slice " << slice ;
683 double vLength = (slice < mGeo.getNumberOfSlicesA()) ? mGeo.getTPCzLengthA() : mGeo.getTPCzLengthC();
684
685 auto myThread = [&](int iThread) {
687 std::vector<float> splineParameters;
688 ChebyshevFit1D chebFitterX, chebFitterU, chebFitterV;
689
690 for (int row = iThread; row < mGeo.getNumberOfRows(); row += mNthreads) {
691 TPCFastSpaceChargeCorrection::SplineType spline = correction.getSpline(slice, row);
692 helper.setSpline(spline, 10, 10);
693 std::vector<double> dataPointCU, dataPointCV, dataPointF;
694
695 float u0, u1, v0, v1;
696 mGeo.convScaledUVtoUV(slice, row, 0., 0., u0, v0);
697 mGeo.convScaledUVtoUV(slice, row, 1., 1., u1, v1);
698
699 double x = mGeo.getRowInfo(row).x;
700 int nPointsU = (spline.getGridX1().getNumberOfKnots() - 1) * 10;
701 int nPointsV = (spline.getGridX2().getNumberOfKnots() - 1) * 10;
702
703 double stepU = (u1 - u0) / (nPointsU - 1);
704 double stepV = (v1 - v0) / (nPointsV - 1);
705
706 if (prn) {
707 LOG(info) << "u0 " << u0 << " u1 " << u1 << " v0 " << v0 << " v1 " << v1;
708 }
709 TPCFastSpaceChargeCorrection::RowActiveArea& area = correction.getSliceRowInfo(slice, row).activeArea;
710 area.cuMin = 1.e10;
711 area.cuMax = -1.e10;
712
713 /*
714 v1 = area.vMax;
715 stepV = (v1 - v0) / (nPointsU - 1);
716 if (stepV < 1.f) {
717 stepV = 1.f;
718 }
719 */
720
721 for (double u = u0; u < u1 + stepU; u += stepU) {
722 for (double v = v0; v < v1 + stepV; v += stepV) {
723 float dx, du, dv;
724 correction.getCorrection(slice, row, u, v, dx, du, dv);
725 dx *= scaling[0];
726 du *= scaling[0];
727 dv *= scaling[0];
728 // add remaining corrections
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];
735 }
736 double cx = x + dx;
737 double cu = u + du;
738 double cv = v + dv;
739 if (cu < area.cuMin) {
740 area.cuMin = cu;
741 }
742 if (cu > area.cuMax) {
743 area.cuMax = cu;
744 }
745
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);
751
752 if (prn) {
753 LOG(info) << "measurement cu " << cu << " cv " << cv << " dx " << dx << " du " << du << " dv " << dv;
754 }
755 } // v
756 } // u
757
758 if (area.cuMax - area.cuMin < 0.2) {
759 area.cuMax = .1;
760 area.cuMin = -.1;
761 }
762 if (area.cvMax < 0.1) {
763 area.cvMax = .1;
764 }
765 if (prn) {
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;
768 }
769
770 TPCFastSpaceChargeCorrection::SliceRowInfo& info = correction.getSliceRowInfo(slice, row);
771 info.gridCorrU0 = area.cuMin;
772 info.scaleCorrUtoGrid = spline.getGridX1().getUmax() / (area.cuMax - area.cuMin);
773 info.scaleCorrVtoGrid = spline.getGridX2().getUmax() / area.cvMax;
774
775 info.gridCorrU0 = u0;
776 info.gridCorrV0 = info.gridV0;
777 info.scaleCorrUtoGrid = spline.getGridX1().getUmax() / (u1 - info.gridCorrU0);
778 info.scaleCorrVtoGrid = spline.getGridX2().getUmax() / (v1 - info.gridCorrV0);
779
780 int nDataPoints = dataPointCU.size();
781 for (int i = 0; i < nDataPoints; i++) {
782 dataPointCU[i] = (dataPointCU[i] - info.gridCorrU0) * info.scaleCorrUtoGrid;
783 dataPointCV[i] = (dataPointCV[i] - info.gridCorrV0) * info.scaleCorrVtoGrid;
784 }
785
786 splineParameters.resize(spline.getNumberOfParameters());
787
788 helper.approximateDataPoints(spline, splineParameters.data(), 0., spline.getGridX1().getUmax(),
789 0., spline.getGridX2().getUmax(),
790 dataPointCU.data(), dataPointCV.data(),
791 dataPointF.data(), dataPointCU.size());
792
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];
799 }
800 } // row
801 }; // thread
802
803 std::vector<std::thread> threads(mNthreads);
804
805 // run n threads
806 for (int i = 0; i < mNthreads; i++) {
807 threads[i] = std::thread(myThread, i);
808 }
809
810 // wait for the threads to finish
811 for (auto& th : threads) {
812 th.join();
813 }
814
815 } // slice
816 float duration = watch.RealTime();
817 LOGP(info, "Inverse took: {}s", duration);
818}
819
820} // namespace tpc
821} // namespace o2
Definition of ChebyshevFit1D class.
int32_t i
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.
uint32_t roc
Definition RawData.h:3
uint32_t c
Definition RawData.h:2
Definition of Spline2DHelper class.
class to create TPC fast space charge correction
Definition of TPCFastTransform class.
Definition of the TrackResiduals class.
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.
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.
void finishConstruction()
Finishes initialization: puts everything to the flat buffer, releases temporary memory.
void startConstruction(int32_t numberOfRows)
_______________ Construction interface ________________________
void setTPCrow(int32_t iRow, float x, int32_t nPads, float padWidth)
Initializes a TPC row.
void setTPCalignmentZ(float tpcAlignmentZ)
void setTPCzLength(float tpcZlengthSideA, float tpcZlengthSideC)
int getNumberOfRows() const
Definition Mapper.h:297
int getNumberOfPadsInRowSector(int row) const
Definition Mapper.h:340
int getGlobalRowOffsetRegion(int region) const
Definition Mapper.h:313
GlobalPadNumber globalPadNumber(const PadPos &globalPadPosition) const
Definition Mapper.h:56
static Mapper & instance(const std::string mappingDir="")
Definition Mapper.h:44
const PadRegionInfo & getPadRegionInfo(const unsigned char region) const
Definition Mapper.h:385
int getNumberOfRowsRegion(int region) const
Definition Mapper.h:309
const PadCentre & padCentre(GlobalPadNumber padNumber) const
Definition Mapper.h:51
static constexpr int MAXSECTOR
Definition Sector.h:44
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
float getX(int i) const
void getVoxelCoordinates(int isec, int ix, int ip, int iz, float &x, float &p, float &z) const
@ VoxV
voxel dispersions
float getDZ2X(int iz=0) const
GLdouble n
Definition glcorearb.h:1982
GLint GLenum GLint x
Definition glcorearb.h:403
const GLdouble * v
Definition glcorearb.h:832
GLboolean * data
Definition glcorearb.h:298
GLfloat v0
Definition glcorearb.h:811
GLfloat GLfloat v1
Definition glcorearb.h:812
GLenum GLenum GLsizei len
Definition glcorearb.h:4232
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
math_utils::Point2D< float > PadCentre
Pad centres as 2D float.
Definition Defs.h:122
unsigned short GlobalPadNumber
global pad number
Definition Defs.h:129
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
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 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"
std::vector< int > row