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#include "TTreeReader.h"
33#include "TTreeReaderValue.h"
34#include "ROOT/TTreeProcessorMT.hxx"
35#include <algorithm>
36#include <sstream>
37
38using namespace o2::gpu;
39
40namespace o2
41{
42namespace tpc
43{
44
45TPCFastSpaceChargeCorrectionHelper* TPCFastSpaceChargeCorrectionHelper::sInstance = nullptr;
46
48{
49 // returns TPCFastSpaceChargeCorrectionHelper instance (singleton)
50 if (!sInstance) {
51 sInstance = new TPCFastSpaceChargeCorrectionHelper();
52 sInstance->initGeometry();
53 }
54 return sInstance;
55}
56
57void TPCFastSpaceChargeCorrectionHelper::initGeometry()
58{
59 // initialize geometry
60
61 const Mapper& mapper = Mapper::instance();
62
63 const int nRows = mapper.getNumberOfRows();
64
65 mGeo.startConstruction(nRows);
66
67 auto& detParam = ParameterDetector::Instance();
68
69 mGeo.setTPCzLength(detParam.TPClength);
70
71 for (int iRow = 0; iRow < mGeo.getNumberOfRows(); iRow++) {
72 Sector sector = 0;
73 int regionNumber = 0;
74 while (iRow >= mapper.getGlobalRowOffsetRegion(regionNumber) + mapper.getNumberOfRowsRegion(regionNumber)) {
75 regionNumber++;
76 }
77
78 const PadRegionInfo& region = mapper.getPadRegionInfo(regionNumber);
79
80 int nPads = mapper.getNumberOfPadsInRowSector(iRow);
81 float padWidth = region.getPadWidth();
82
83 const GlobalPadNumber pad = mapper.globalPadNumber(PadPos(iRow, nPads / 2));
84 const PadCentre& padCentre = mapper.padCentre(pad);
85 float xRow = padCentre.X();
86
87 mGeo.setTPCrow(iRow, xRow, nPads, padWidth);
88 }
89
90 mGeo.finishConstruction();
91
92 // check if calculated pad geometry is consistent with the map
93 testGeometry(mGeo);
94
95 mIsInitialized = 1;
96}
97
99{
100 LOG(info) << "fast space charge correction helper: use " << n << ((n > 1) ? " cpu threads" : " cpu thread");
101 mNthreads = (n > 0) ? n : 1;
102}
103
105{
107
108 mNthreads = std::thread::hardware_concurrency();
109
110 LOG(info) << "fast space charge correction helper: use " << mNthreads << ((mNthreads > 1) ? " cpu threads" : " cpu thread");
111
112 if (mNthreads < 1) {
113 mNthreads = 1;
114 }
115}
116
117void TPCFastSpaceChargeCorrectionHelper::fillSpaceChargeCorrectionFromMap(TPCFastSpaceChargeCorrection& correction, bool processingInverseCorrection)
118{
119 // calculate correction map: dx,du,dv = ( origTransform() -> x,u,v) - fastTransformNominal:x,u,v
120 // for the future: switch TOF correction off for a while
121
122 TStopwatch watch;
123
124 if (!mIsInitialized) {
125 initGeometry();
126 }
127
128 if (!mCorrectionMap.isInitialized()) {
129 correction.setNoCorrection();
130 return;
131 }
132
133 LOG(info) << "fast space charge correction helper: init from data points";
134
135 for (int sector = 0; sector < correction.getGeometry().getNumberOfSectors(); sector++) {
136
137 auto myThread = [&](int iThread) {
138 for (int row = iThread; row < correction.getGeometry().getNumberOfRows(); row += mNthreads) {
139
140 TPCFastSpaceChargeCorrection::SplineType& spline = correction.getSplineForRow(row);
142 std::vector<float> splineParameters;
143 splineParameters.resize(spline.getNumberOfParameters());
144
145 const std::vector<o2::gpu::TPCFastSpaceChargeCorrectionMap::CorrectionPoint>& data = mCorrectionMap.getPoints(sector, row);
146 int nDataPoints = data.size();
147
148 if (nDataPoints >= 4) {
149 std::vector<double> pointGU(nDataPoints);
150 std::vector<double> pointGV(nDataPoints);
151 std::vector<double> pointWeight(nDataPoints);
152 std::vector<double> pointCorr(3 * nDataPoints); // 3 dimensions
153 for (int i = 0; i < nDataPoints; ++i) {
155 // not corrected grid coordinates
156 float gu, gv, scale;
157 correction.convLocalToGrid(sector, row, p.mY, p.mZ, gu, gv, scale);
158 if (scale - 1.f > 1.e-6) { // point is outside the grid
159 continue;
160 }
161 pointGU[i] = gu;
162 pointGV[i] = gv;
163 pointWeight[i] = p.mWeight;
164 pointCorr[3 * i + 0] = p.mDx;
165 pointCorr[3 * i + 1] = p.mDy;
166 pointCorr[3 * i + 2] = p.mDz;
167 }
168 helper.approximateDataPoints(spline, splineParameters.data(), 0., spline.getGridX1().getUmax(), 0., spline.getGridX2().getUmax(), pointGU.data(),
169 pointGV.data(), pointCorr.data(), pointWeight.data(), nDataPoints);
170 } else {
171 for (int i = 0; i < spline.getNumberOfParameters(); i++) {
172 splineParameters[i] = 0.f;
173 }
174 }
175
176 if (processingInverseCorrection) {
177 float* splineX = correction.getCorrectionDataInvX(sector, row);
178 float* splineYZ = correction.getCorrectionDataInvYZ(sector, row);
179 for (int i = 0; i < spline.getNumberOfParameters() / 3; i++) {
180 splineX[i] = splineParameters[3 * i + 0];
181 splineYZ[2 * i + 0] = splineParameters[3 * i + 1];
182 splineYZ[2 * i + 1] = splineParameters[3 * i + 2];
183 }
184 } else {
185 float* splineXYZ = correction.getCorrectionData(sector, row);
186 for (int i = 0; i < spline.getNumberOfParameters(); i++) {
187 splineXYZ[i] = splineParameters[i];
188 }
189 }
190 } // row
191 }; // thread
192
193 std::vector<std::thread> threads(mNthreads);
194
195 // run n threads
196 for (int i = 0; i < mNthreads; i++) {
197 threads[i] = std::thread(myThread, i);
198 }
199
200 // wait for the threads to finish
201 for (auto& th : threads) {
202 th.join();
203 }
204
205 } // sector
206
207 watch.Stop();
208
209 LOGP(info, "Space charge correction tooks: {}s", watch.RealTime());
210} // fillSpaceChargeCorrectionFromMap
211
212std::unique_ptr<TPCFastSpaceChargeCorrection> TPCFastSpaceChargeCorrectionHelper::createFromGlobalCorrection(
213 std::function<void(int sector, double gx, double gy, double gz,
214 double& dgx, double& dgy, double& dgz)>
215 correctionGlobal,
216 const int nKnotsY, const int nKnotsZ)
217{
219
220 auto correctionLocal = [&](int sector, int irow, double ly, double lz,
221 double& dlx, double& dly, double& dlz) {
222 double lx = mGeo.getRowInfo(irow).x;
223 float gx, gy, gz;
224 mGeo.convLocalToGlobal(sector, lx, ly, lz, gx, gy, gz);
225 double dgx, dgy, dgz;
226 correctionGlobal(sector, gx, gy, gz, dgx, dgy, dgz);
227 float lx1, ly1, lz1;
228 mGeo.convGlobalToLocal(sector, gx + dgx, gy + dgy, gz + dgz, lx1, ly1, lz1);
229 dlx = lx1 - lx;
230 dly = ly1 - ly;
231 dlz = lz1 - lz;
232 };
233 return std::move(createFromLocalCorrection(correctionLocal, nKnotsY, nKnotsZ));
234}
235
236std::unique_ptr<TPCFastSpaceChargeCorrection> TPCFastSpaceChargeCorrectionHelper::createFromLocalCorrection(
237 std::function<void(int sector, int irow, double y, double z, double& dx, double& dy, double& dz)> correctionLocal,
238 const int nKnotsY, const int nKnotsZ)
239{
241
242 LOG(info) << "fast space charge correction helper: create correction using " << mNthreads << " threads";
243
244 std::unique_ptr<TPCFastSpaceChargeCorrection> correctionPtr(new TPCFastSpaceChargeCorrection);
245 TPCFastSpaceChargeCorrection& correction = *correctionPtr;
246
247 { // create a correction map
248
249 if (!mIsInitialized) {
250 initGeometry();
251 }
252
253 const int nRows = mGeo.getNumberOfRows();
254 const int nCorrectionScenarios = nRows / 10 + 1;
255
256 correction.startConstruction(mGeo, nCorrectionScenarios);
257
258 // assign spline type for TPC rows
259 for (int row = 0; row < mGeo.getNumberOfRows(); row++) {
260 int scenario = row / 10;
261 if (scenario >= nCorrectionScenarios) {
262 scenario = nCorrectionScenarios - 1;
263 }
264 correction.setRowScenarioID(row, scenario);
265 }
266
267 for (int scenario = 0; scenario < nCorrectionScenarios; scenario++) {
268 int row = scenario * 10;
270 spline.recreate(nKnotsY, nKnotsZ);
271 correction.setSplineScenario(scenario, spline);
272 }
273 correction.finishConstruction();
274 }
275
276 LOG(info) << "fast space charge correction helper: fill data points from an input SP correction function";
277
278 {
281
282 int nSectors = mGeo.getNumberOfSectors();
283 int nRows = mGeo.getNumberOfRows();
284 mCorrectionMap.init(nSectors, nRows);
285
286 for (int iSector = 0; iSector < nSectors; iSector++) {
287
288 auto myThread = [&](int iThread) {
289 for (int iRow = iThread; iRow < nRows; iRow += mNthreads) {
290 const auto& info = mGeo.getRowInfo(iRow);
291 double dl = mGeo.getTPCzLength() / (6. * (nKnotsZ - 1));
292 double dpad = info.maxPad / (6. * (nKnotsY - 1));
293 for (double pad = 0; pad < info.maxPad + .5 * dpad; pad += dpad) {
294 for (double l = 0.; l < mGeo.getTPCzLength() + .5 * dl; l += dl) {
295 float y, z;
296 mGeo.convPadDriftLengthToLocal(iSector, iRow, pad, l, y, z);
297 double dx, dy, dz;
298 correctionLocal(iSector, iRow, y, z, dx, dy, dz);
299 mCorrectionMap.addCorrectionPoint(iSector, iRow,
300 y, z, dx, dy, dz, 1.);
301 }
302 }
303 } // row
304 }; // thread
305
306 std::vector<std::thread> threads(mNthreads);
307
308 // run n threads
309 for (int i = 0; i < mNthreads; i++) {
310 threads[i] = std::thread(myThread, i);
311 }
312
313 // wait for the threads to finish
314 for (auto& th : threads) {
315 th.join();
316 }
317
318 } // sector
319
320 fillSpaceChargeCorrectionFromMap(correction, false);
321 initInverse(correction, false);
322 }
323
324 return std::move(correctionPtr);
325} // createFromLocalCorrection
326
328{
329 const Mapper& mapper = Mapper::instance();
330
332 LOG(fatal) << "Wrong number of sectors :" << geo.getNumberOfSectors() << " instead of " << Sector::MAXSECTOR << std::endl;
333 }
334
335 if (geo.getNumberOfRows() != mapper.getNumberOfRows()) {
336 LOG(fatal) << "Wrong number of rows :" << geo.getNumberOfRows() << " instead of " << mapper.getNumberOfRows() << std::endl;
337 }
338
339 double maxDx = 0, maxDy = 0;
340
341 for (int row = 0; row < geo.getNumberOfRows(); row++) {
342
343 const int nPads = geo.getRowInfo(row).maxPad + 1;
344
345 if (nPads != mapper.getNumberOfPadsInRowSector(row)) {
346 LOG(fatal) << "Wrong number of pads :" << nPads << " instead of " << mapper.getNumberOfPadsInRowSector(row) << std::endl;
347 }
348
349 const double x = geo.getRowInfo(row).x;
350
351 // check if calculated pad positions are equal to the real ones
352
353 for (int pad = 0; pad < nPads; pad++) {
354 const GlobalPadNumber p = mapper.globalPadNumber(PadPos(row, pad));
355 const PadCentre& c = mapper.padCentre(p);
356 float y, z;
357 geo.convPadDriftLengthToLocal(0, row, pad, 0., y, z);
358 const double dx = x - c.X();
359 const double dy = y - (-c.Y()); // diferent sign convention for Y coordinate in the map
360
361 if (fabs(dx) >= 1.e-6 || fabs(dy) >= 1.e-5) {
362 LOG(warning) << "wrong calculated pad position:"
363 << " row " << row << " pad " << pad << " x calc " << x << " x in map " << c.X() << " dx " << (x - c.X())
364 << " y calc " << y << " y in map " << -c.Y() << " dy " << dy << std::endl;
365 }
366 if (fabs(maxDx) < fabs(dx)) {
367 maxDx = dx;
368 }
369 if (fabs(maxDy) < fabs(dy)) {
370 maxDy = dy;
371 }
372 }
373 }
374
375 if (fabs(maxDx) >= 1.e-4 || fabs(maxDy) >= 1.e-4) {
376 LOG(fatal) << "wrong calculated pad position:"
377 << " max Dx " << maxDx << " max Dy " << maxDy << std::endl;
378 }
379}
380
381std::unique_ptr<o2::gpu::TPCFastSpaceChargeCorrection> TPCFastSpaceChargeCorrectionHelper::createFromTrackResiduals(
382 const o2::tpc::TrackResiduals& trackResiduals, TTree* voxResTree, TTree* voxResTreeInverse, bool useSmoothed, bool invertSigns,
383 TPCFastSpaceChargeCorrectionMap* fitPointsDirect,
384 TPCFastSpaceChargeCorrectionMap* fitPointsInverse)
385{
386 // create o2::gpu::TPCFastSpaceChargeCorrection from o2::tpc::TrackResiduals::VoxRes voxel tree
387
388 LOG(info) << "fast space charge correction helper: create correction from track residuals using " << mNthreads << " threads";
389
390 TStopwatch watch, watch1;
391
392 std::unique_ptr<o2::gpu::TPCFastSpaceChargeCorrection> correctionPtr(new o2::gpu::TPCFastSpaceChargeCorrection);
393
394 o2::gpu::TPCFastSpaceChargeCorrection& correction = *correctionPtr;
395
397 const o2::gpu::TPCFastTransformGeo& geo = helper->getGeometry();
398
399 int nY2Xbins = trackResiduals.getNY2XBins();
400 int nZ2Xbins = trackResiduals.getNZ2XBins();
401
402 std::vector<double> knotsDouble[2];
403
404 knotsDouble[0].reserve(nY2Xbins);
405 knotsDouble[1].reserve(nZ2Xbins);
406
407 // to get enouth measurements, make a spline knot at every second bin. Boundary bins are always included.
408
409 for (int i = 0, j = nY2Xbins - 1; i <= j; i += 2, j -= 2) {
410 knotsDouble[0].push_back(trackResiduals.getY2X(0, i));
411 if (j >= i + 1) {
412 knotsDouble[0].push_back(trackResiduals.getY2X(0, j));
413 }
414 }
415
416 for (int i = 0, j = nZ2Xbins - 1; i <= j; i += 2, j -= 2) {
417 knotsDouble[1].push_back(trackResiduals.getZ2X(i));
418 if (j >= i + 1) {
419 knotsDouble[1].push_back(trackResiduals.getZ2X(j));
420 }
421 }
422
423 std::vector<int> knotsInt[2];
424
425 for (int dim = 0; dim < 2; dim++) {
426 auto& knotsD = knotsDouble[dim];
427 std::sort(knotsD.begin(), knotsD.end());
428
429 double pitch = knotsD[1] - knotsD[0]; // min distance between the knots
430 for (int i = 2; i < knotsD.size(); i++) {
431 double d = knotsD[i] - knotsD[i - 1];
432 if (d < pitch) {
433 pitch = d;
434 }
435 }
436 // spline knots must be positioned on the grid with an integer internal coordinate
437 // we set the knot positioning accuracy to 0.1*pitch
438 pitch = 0.1 * pitch;
439 auto& knotsI = knotsInt[dim];
440 knotsI.reserve(knotsD.size());
441 double u0 = knotsD[0];
442 double u1 = knotsD[knotsD.size() - 1];
443 for (auto& u : knotsD) {
444 u -= u0;
445 int iu = int(u / pitch + 0.5);
446 knotsI.push_back(iu);
447 // debug printout: corrected vs original knot positions, scaled to [-1,1] interval
448 double uorig = u / (u1 - u0) * 2 - 1.;
449 u = (iu * pitch) / (u1 - u0) * 2 - 1.;
450 LOG(info) << "TPC SC splines: convert " << (dim == 0 ? "y" : (dim == 1 ? "z" : "-z")) << " bin to the knot: " << uorig << " -> " << u << " -> " << iu;
451 }
452
453 if (knotsI.size() < 2) { // minimum 2 knots
454 knotsI.clear();
455 knotsI.push_back(0);
456 knotsI.push_back(1);
457 }
458 }
459
460 auto& yKnotsInt = knotsInt[0];
461 auto& zKnotsInt = knotsInt[1];
462
463 int nKnotsY = yKnotsInt.size();
464 int nKnotsZ = zKnotsInt.size();
465
466 // std::cout << "n knots Y: " << nKnotsY << std::endl;
467 // std::cout << "n knots Z: " << nKnotsZA << ", " << nKnotsZC << std::endl;
468
469 const int nRows = geo.getNumberOfRows();
470 const int nSectors = geo.getNumberOfSectors();
471
472 { // create the correction object
473
474 const int nCorrectionScenarios = 1;
475
476 correction.startConstruction(geo, nCorrectionScenarios);
477
478 // init rows
479 for (int row = 0; row < geo.getNumberOfRows(); row++) {
480 correction.setRowScenarioID(row, 0);
481 }
482
483 { // init spline scenario
485 spline.recreate(nKnotsY, &yKnotsInt[0], nKnotsZ, &zKnotsInt[0]);
486 correction.setSplineScenario(0, spline);
487 }
488 correction.finishConstruction();
489 } // .. create the correction object
490
491 // set the grid borders
492 for (int iRow = 0; iRow < geo.getNumberOfRows(); iRow++) {
493 auto& info = correction.getRowInfo(iRow);
494 const auto& spline = correction.getSplineForRow(iRow);
495 double rowX = geo.getRowInfo(iRow).x;
496 double yMin = rowX * trackResiduals.getY2X(iRow, 0);
497 double yMax = rowX * trackResiduals.getY2X(iRow, trackResiduals.getNY2XBins() - 1);
498 double zMin = rowX * trackResiduals.getZ2X(0);
499 double zMax = rowX * trackResiduals.getZ2X(trackResiduals.getNZ2XBins() - 1);
500 double zOut = zMax;
501 info.gridMeasured.set(yMin, spline.getGridX1().getUmax() / (yMax - yMin), // y
502 zMin, spline.getGridX2().getUmax() / (zMax - zMin), // z
503 zOut, geo.getTPCzLength()); // correction scaling region
504
505 info.gridReal = info.gridMeasured;
506
507 // std::cout << " iSector " << iSector << " iRow " << iRow << " uMin: " << uMin << " uMax: " << uMax << " vMin: " << vMin << " vMax: " << vMax
508 //<< " grid scale u "<< info.scaleUtoGrid << " grid scale v "<< info.scaleVtoGrid<< std::endl;
509 }
510
511 LOG(info) << "fast space charge correction helper: preparation took " << watch1.RealTime() << "s";
512
513 for (int processingInverseCorrection = 0; processingInverseCorrection <= 1; processingInverseCorrection++) {
514
515 TTree* currentTree = (processingInverseCorrection) ? voxResTreeInverse : voxResTree;
516
517 if (!currentTree) {
518 continue;
519 }
520 const char* directionName = (processingInverseCorrection) ? "inverse" : "direct";
521 LOG(info) << "\n fast space charge correction helper: Process " << directionName
522 << " correction: fill data points from track residuals.. ";
523
524 TStopwatch watch3;
525 o2::gpu::TPCFastSpaceChargeCorrectionMap& map = helper->getCorrectionMap();
526 map.init(geo.getNumberOfSectors(), geo.getNumberOfRows());
527
528 // read the data Sector by Sector
529
530 // data in the tree is not sorted by row
531 // first find which data belong to which row
532
533 struct VoxelData {
534 int mNentries{0}; // number of entries
535 float mX, mY, mZ; // mean position in the local coordinates
536 float mCx, mCy, mCz; // corrections to the local coordinates
537 };
538
539 std::vector<VoxelData> vSectorData[nRows * nSectors];
540 for (int ir = 0; ir < nRows * nSectors; ir++) {
541 vSectorData[ir].resize(nY2Xbins * nZ2Xbins);
542 }
543
544 { // read data from the tree to vSectorData
545
546 ROOT::TTreeProcessorMT processor(*currentTree, mNthreads);
547 std::string errMsg = std::string("Error reading ") + directionName + " track residuals: ";
548 auto myThread = [&](TTreeReader& readerSubRange) {
549 TTreeReaderValue<o2::tpc::TrackResiduals::VoxRes> v(readerSubRange, "voxRes");
550 while (readerSubRange.Next()) {
551 int iSector = (int)v->bsec;
552 if (iSector < 0 || iSector >= nSectors) {
553 LOG(fatal) << errMsg << "Sector number " << iSector << " is out of range";
554 continue;
555 }
556 int iRow = (int)v->bvox[o2::tpc::TrackResiduals::VoxX]; // bin number in x (= pad row)
557 if (iRow < 0 || iRow >= nRows) {
558 LOG(fatal) << errMsg << "Row number " << iRow << " is out of range";
559 }
560 double rowX = trackResiduals.getX(iRow); // X of the pad row
561 int iy = v->bvox[o2::tpc::TrackResiduals::VoxF]; // bin number in y/x 0..14
562 int iz = v->bvox[o2::tpc::TrackResiduals::VoxZ]; // bin number in z/x 0..4
563 auto& data = vSectorData[iSector * nRows + iRow][iy * nZ2Xbins + iz];
564 data.mNentries = (int)v->stat[o2::tpc::TrackResiduals::VoxV];
566 data.mY = v->stat[o2::tpc::TrackResiduals::VoxF] * rowX;
567 data.mZ = v->stat[o2::tpc::TrackResiduals::VoxZ] * rowX;
571 if (invertSigns) {
572 data.mCx *= -1.;
573 data.mCy *= -1.;
574 data.mCz *= -1.;
575 }
576 }
577 };
578 processor.Process(myThread);
579 }
580
581 // debug: mirror the data for TPC C side
582
583 if (mDebugMirrorAdata2C) {
584 for (int iSector = 0; iSector < geo.getNumberOfSectorsA(); iSector++) {
585 for (int iRow = 0; iRow < nRows; iRow++) {
586 for (int iy = 0; iy < nY2Xbins; iy++) {
587 for (int iz = 0; iz < nZ2Xbins; iz++) {
588 auto& dataA = vSectorData[iSector * nRows + iRow][iy * nZ2Xbins + iz];
589 auto& dataC = vSectorData[(iSector + geo.getNumberOfSectorsA()) * nRows + iRow][iy * nZ2Xbins + iz];
590 dataC = dataA; // copy the data
591 dataC.mZ = -dataC.mZ; // mirror the Z coordinate
592 dataC.mCz = -dataC.mCz; // mirror the Z correction
593 }
594 }
595 }
596 }
597 }
598
599 double maxError[3] = {0., 0., 0.};
600 int nErrors = 0;
601
602 for (int iSector = 0; iSector < nSectors; iSector++) {
603
604 // now process the data row-by-row
605
606 auto myThread = [&](int iThread, int nTreads) {
607 struct Voxel {
608 float mY, mZ; // non-distorted local coordinates
609 float mDy, mDz; // voxel size
610 int mSmoothingStep{100}; // is the voxel data original or smoothed at this step
611 };
612
613 std::vector<Voxel> vRowVoxels(nY2Xbins * nZ2Xbins);
614
615 for (int iRow = iThread; iRow < nRows; iRow += nTreads) {
616 // LOG(info) << "Processing Sector " << iSector << " row " << iRow;
617
618 // complete the voxel data
619 {
620 int xBin = iRow;
621 double x = trackResiduals.getX(xBin); // radius of the pad row
622 double dx = 1. / trackResiduals.getDXI(xBin);
623 bool isDataFound = false;
624 for (int iy = 0; iy < nY2Xbins; iy++) {
625 for (int iz = 0; iz < nZ2Xbins; iz++) {
626 auto& data = vSectorData[iSector * nRows + iRow][iy * nZ2Xbins + iz];
627 auto& vox = vRowVoxels[iy * nZ2Xbins + iz];
628 // y/x coordinate of the bin ~-0.15 ... 0.15
629 double y2x = trackResiduals.getY2X(xBin, iy);
630 // z/x coordinate of the bin 0.1 .. 0.9
631 double z2x = trackResiduals.getZ2X(iz);
632 vox.mY = x * y2x;
633 vox.mZ = x * z2x;
634 vox.mDy = x / trackResiduals.getDY2XI(xBin, iy);
635 vox.mDz = x * trackResiduals.getDZ2X(iz);
636 if (iSector >= geo.getNumberOfSectorsA()) {
637 vox.mZ = -vox.mZ;
638 }
639 if (data.mNentries > 0) { // voxel contains data
640 vox.mSmoothingStep = 0; // take original data
641 isDataFound = true;
642
643 // correct the mean position if it is outside the voxel
644 std::stringstream msg;
645 if (fabs(x - data.mX) > mVoxelMeanValidityRange * dx / 2.) {
646 msg << "\n x: center " << x << " dx " << data.mX - x << " half bin size " << dx / 2;
647 }
648
649 if (fabs(vox.mY - data.mY) > mVoxelMeanValidityRange * vox.mDy / 2.) {
650 msg << "\n y: center " << vox.mY << " dy " << data.mY - vox.mY << " half bin size " << vox.mDy / 2;
651 data.mY = vox.mY;
652 }
653
654 if (fabs(vox.mZ - data.mZ) > mVoxelMeanValidityRange * vox.mDz / 2.) {
655 msg << "\n z: center " << vox.mZ << " dz " << data.mZ - vox.mZ << " half bin size " << vox.mDz / 2;
656 data.mZ = vox.mZ;
657 }
658
659 if (!msg.str().empty()) {
660 bool isMaxErrorExceeded = (fabs(data.mX - x) / dx > maxError[0]) ||
661 (fabs(data.mY - vox.mY) / vox.mDy > maxError[1]) ||
662 (fabs(data.mZ - vox.mZ) / vox.mDz > maxError[2]);
663 static std::mutex mutex;
664 mutex.lock();
665 nErrors++;
666 if (nErrors < 20 || isMaxErrorExceeded) {
667 LOG(warning) << directionName << " correction: error N " << nErrors << "fitted voxel position is outside the voxel: "
668 << " sector " << iSector << " row " << iRow << " bin y " << iy << " bin z " << iz
669 << msg.str();
670 maxError[0] = GPUCommonMath::Max<double>(maxError[0], fabs(data.mX - x) / dx);
671 maxError[1] = GPUCommonMath::Max<double>(maxError[1], fabs(data.mY - vox.mY) / vox.mDy);
672 maxError[2] = GPUCommonMath::Max<double>(maxError[2], fabs(data.mZ - vox.mZ) / vox.mDz);
673 }
674 mutex.unlock();
675 }
676
677 } else { // no data, take voxel center position
678 data.mCx = 0.;
679 data.mCy = 0.;
680 data.mCz = 0.;
681 data.mX = x;
682 data.mY = vox.mY;
683 data.mZ = vox.mZ;
684 vox.mSmoothingStep = 100; // fill this data point with smoothed values from the neighbours
685 }
686 if (mDebugUseVoxelCenters) { // debug: always use voxel center instead of the mean position
687 data.mY = vox.mY;
688 data.mZ = vox.mZ;
689 }
690 }
691 }
692
693 if (!isDataFound) { // fill everything with 0
694 for (int iy = 0; iy < nY2Xbins; iy++) {
695 for (int iz = 0; iz < nZ2Xbins; iz++) {
696 vRowVoxels[iy * nZ2Xbins + iz].mSmoothingStep = 0;
697 }
698 }
699 }
700 } // complete the voxel data
701
702 // repare the voxel data: fill empty voxels
703
704 int nRepairs = 0;
705
706 for (int ismooth = 1; ismooth <= 2; ismooth++) {
707 for (int iy = 0; iy < nY2Xbins; iy++) {
708 for (int iz = 0; iz < nZ2Xbins; iz++) {
709 auto& data = vSectorData[iSector * nRows + iRow][iy * nZ2Xbins + iz];
710 auto& vox = vRowVoxels[iy * nZ2Xbins + iz];
711 if (vox.mSmoothingStep <= ismooth) { // already filled
712 continue;
713 }
714 nRepairs++;
715 data.mCx = 0.;
716 data.mCy = 0.;
717 data.mCz = 0.;
718 double w = 0.;
719 bool filled = false;
720 auto update = [&](int iy1, int iz1) {
721 auto& data1 = vSectorData[iSector * nRows + iRow][iy1 * nZ2Xbins + iz1];
722 auto& vox1 = vRowVoxels[iy1 * nZ2Xbins + iz1];
723 if (vox1.mSmoothingStep >= ismooth) {
724 return false;
725 }
726 double w1 = 1. / (abs(iy - iy1) + abs(iz - iz1) + 1);
727 data.mCx += w1 * data1.mCx;
728 data.mCy += w1 * data1.mCy;
729 data.mCz += w1 * data1.mCz;
730 w += w1;
731 filled = true;
732 return true;
733 };
734
735 for (int iy1 = iy - 1; iy1 >= 0 && !update(iy1, iz); iy1--) {
736 }
737 for (int iy1 = iy + 1; iy1 < nY2Xbins && !update(iy1, iz); iy1++) {
738 }
739 for (int iz1 = iz - 1; iz1 >= 0 && !update(iy, iz1); iz1--) {
740 }
741 for (int iz1 = iz + 1; iz1 < nZ2Xbins && !update(iy, iz1); iz1++) {
742 }
743
744 if (filled) {
745 data.mCx /= w;
746 data.mCy /= w;
747 data.mCz /= w;
748 vox.mSmoothingStep = ismooth;
749 }
750 } // iz
751 } // iy
752 } // ismooth
753
754 if (nRepairs > 0) {
755 LOG(debug) << "Sector " << iSector << " row " << iRow << ": " << nRepairs << " voxel repairs for " << nY2Xbins * nZ2Xbins << " voxels";
756 }
757
758 // feed the row data to the helper
759
760 auto& info = correction.getRowInfo(iRow);
761 const auto& spline = correction.getSplineForRow(iRow);
762
763 auto addVoxel = [&](int iy, int iz, double weight) {
764 auto& vox = vRowVoxels[iy * nZ2Xbins + iz];
765 if (vox.mSmoothingStep > 2) {
766 LOG(fatal) << "empty voxel is not repared: y " << iy << " z " << iz;
767 }
768 auto& data = vSectorData[iSector * nRows + iRow][iy * nZ2Xbins + iz];
769 map.addCorrectionPoint(iSector, iRow, data.mY, data.mZ, data.mCx, data.mCy, data.mCz, weight);
770 };
771
772 auto addEdge = [&](int iy1, int iz1, int iy2, int iz2, int nPoints) {
773 // add n points on the edge between two voxels excluding the voxel points
774 if (nPoints < 1) {
775 return;
776 }
777 if (iy1 < 0 || iy1 >= nY2Xbins || iz1 < 0 || iz1 >= nZ2Xbins) {
778 return;
779 }
780 if (iy2 < 0 || iy2 >= nY2Xbins || iz2 < 0 || iz2 >= nZ2Xbins) {
781 return;
782 }
783 auto& data1 = vSectorData[iSector * nRows + iRow][iy1 * nZ2Xbins + iz1];
784 auto& vox1 = vRowVoxels[iy1 * nZ2Xbins + iz1];
785 auto& data2 = vSectorData[iSector * nRows + iRow][iy2 * nZ2Xbins + iz2];
786 auto& vox2 = vRowVoxels[iy2 * nZ2Xbins + iz2];
787 double y1 = data1.mY;
788 double z1 = data1.mZ;
789 double cx1 = data1.mCx;
790 double cy1 = data1.mCy;
791 double cz1 = data1.mCz;
792 double y2 = data2.mY;
793 double z2 = data2.mZ;
794 double cx2 = data2.mCx;
795 double cy2 = data2.mCy;
796 double cz2 = data2.mCz;
797
798 for (int is = 1; is <= nPoints; is++) {
799 double s2 = is / (double)(nPoints + 1);
800 double s1 = 1. - s2;
801 double y = s1 * y1 + s2 * y2;
802 double z = s1 * z1 + s2 * z2;
803 double cx = s1 * cx1 + s2 * cx2;
804 double cy = s1 * cy1 + s2 * cy2;
805 double cz = s1 * cz1 + s2 * cz2;
806 map.addCorrectionPoint(iSector, iRow, y, z, cx, cy, cz, 1.);
807 }
808 };
809
810 // original measurements weighted by 8 at each voxel and 8 additional artificial measurements around each voxel
811 //
812 // (y+1, z) 8 1 1 8 (y+1, z+1)
813 // 1 1 1 1 1
814 // 1 1 1 1 1
815 // (y,z) 8 1 1 8 1
816 // 1 1 1 1 1
817
818 for (int iy = 0; iy < nY2Xbins; iy++) {
819 for (int iz = 0; iz < nZ2Xbins; iz++) {
820 addVoxel(iy, iz, 8);
821 addEdge(iy, iz, iy, iz + 1, 2);
822 addEdge(iy, iz, iy + 1, iz, 2);
823 addEdge(iy, iz, iy + 1, iz + 1, 2);
824 addEdge(iy + 1, iz, iy, iz + 1, 2);
825 }
826 }
827
828 } // iRow
829 }; // myThread
830
831 // run n threads
832
833 int nThreads = mNthreads;
834 // nThreads = 1;
835
836 std::vector<std::thread> threads(nThreads);
837
838 for (int i = 0; i < nThreads; i++) {
839 threads[i] = std::thread(myThread, i, nThreads);
840 }
841
842 // wait for the threads to finish
843 for (auto& th : threads) {
844 th.join();
845 }
846 } // iSector
847
848 LOGP(info, "Reading & reparing of the track residuals tooks: {}s", watch3.RealTime());
849
850 LOG(info) << "fast space charge correction helper: create space charge from the map of data points..";
851
852 TStopwatch watch4;
853
854 if (!processingInverseCorrection && fitPointsDirect) {
855 *fitPointsDirect = helper->getCorrectionMap();
856 }
857 if (processingInverseCorrection && fitPointsInverse) {
858 *fitPointsInverse = helper->getCorrectionMap();
859 }
860
861 helper->fillSpaceChargeCorrectionFromMap(correction, processingInverseCorrection);
862
863 LOG(info) << "fast space charge correction helper: creation from the data map took " << watch4.RealTime() << "s";
864
865 } // processingInverseCorrection
866
867 if (voxResTree && !voxResTreeInverse) {
868 LOG(info) << "fast space charge correction helper: init inverse correction from direct correction..";
869 TStopwatch watch4;
870 helper->initInverse(correction, false);
871 LOG(info) << "fast space charge correction helper: init inverse correction took " << watch4.RealTime() << "s";
872 }
873
874 LOGP(info, "Creation from track residuals tooks in total: {}s", watch.RealTime());
875
876 return std::move(correctionPtr);
877
878} // createFromTrackResiduals
879
881{
882 std::vector<o2::gpu::TPCFastSpaceChargeCorrection*> corr{&correction};
883 initInverse(corr, std::vector<float>{1}, prn);
884}
885
886void TPCFastSpaceChargeCorrectionHelper::initInverse(std::vector<o2::gpu::TPCFastSpaceChargeCorrection*>& corrections, const std::vector<float>& scaling, bool prn)
887{
889 TStopwatch watch;
890 LOG(info) << "fast space charge correction helper: init inverse";
891
892 if (corrections.size() != scaling.size()) {
893 LOGP(error, "Input corrections and scaling values have different size");
894 return;
895 }
896
897 auto& correction = *(corrections.front());
898
899 double tpcR2min = mGeo.getRowInfo(0).x - 1.;
900 tpcR2min = tpcR2min * tpcR2min;
901 double tpcR2max = mGeo.getRowInfo(mGeo.getNumberOfRows() - 1).x;
902 tpcR2max = tpcR2max / cos(2 * M_PI / mGeo.getNumberOfSectorsA() / 2) + 1.;
903 tpcR2max = tpcR2max * tpcR2max;
904
905 for (int row = 0; row < mGeo.getNumberOfRows(); row++) {
906 auto& rowInfo = correction.getRowInfo(row);
907 rowInfo.gridReal = rowInfo.gridMeasured;
908 }
909
910 for (int sector = 0; sector < mGeo.getNumberOfSectors(); sector++) {
911 // LOG(info) << "inverse transform for sector " << sector ;
912
913 auto myThread = [&](int iThread) {
915 std::vector<float> splineParameters;
916
917 for (int row = iThread; row < mGeo.getNumberOfRows(); row += mNthreads) {
918 auto& rowInfo = correction.getRowInfo(row);
919
920 TPCFastSpaceChargeCorrection::SplineType spline = correction.getSplineForRow(row);
921 helper.setSpline(spline, 10, 10);
922
923 std::vector<double> gridU;
924 {
925 const auto& grid = spline.getGridX1();
926 for (int i = 0; i < grid.getNumberOfKnots(); i++) {
927 if (i == grid.getNumberOfKnots() - 1) {
928 gridU.push_back(grid.getKnot(i).u);
929 break;
930 }
931 for (double s = 1.; s > 0.; s -= 0.1) {
932 gridU.push_back(s * grid.getKnot(i).u + (1. - s) * grid.getKnot(i + 1).u);
933 }
934 }
935 }
936 std::vector<double> gridV;
937 {
938 const auto& grid = spline.getGridX2();
939 for (int i = 0; i < grid.getNumberOfKnots(); i++) {
940 if (i == grid.getNumberOfKnots() - 1) {
941 gridV.push_back(grid.getKnot(i).u);
942 break;
943 }
944 for (double s = 1.; s > 0.; s -= 0.1) {
945 gridV.push_back(s * grid.getKnot(i).u + (1. - s) * grid.getKnot(i + 1).u);
946 }
947 }
948 }
949
950 std::vector<double> dataPointGridU, dataPointGridV, dataPointF, dataPointWeight;
951 dataPointGridU.reserve(gridU.size() * gridV.size());
952 dataPointGridV.reserve(gridU.size() * gridV.size());
953 dataPointF.reserve(3 * gridU.size() * gridV.size());
954 dataPointWeight.reserve(gridU.size() * gridV.size());
955
956 for (int iu = 0; iu < gridU.size(); iu++) {
957 for (int iv = 0; iv < gridV.size(); iv++) {
958 float y, z;
959 correction.convGridToLocal(sector, row, gridU[iu], gridV[iv], y, z);
960 double dx = 0, dy = 0, dz = 0;
961
962 // add corrections
963 for (int i = 0; i < corrections.size(); ++i) {
964 float dxTmp, dyTmp, dzTmp;
965 corrections[i]->getCorrectionLocal(sector, row, y, z, dxTmp, dyTmp, dzTmp);
966 dx += dxTmp * scaling[i];
967 dy += dyTmp * scaling[i];
968 dz += dzTmp * scaling[i];
969 }
970 float gridU, gridV, scale;
971 correction.convRealLocalToGrid(sector, row, y + dy, z + dz, gridU, gridV, scale);
972 dataPointGridU.push_back(gridU);
973 dataPointGridV.push_back(gridV);
974 dataPointF.push_back(scale * dx);
975 dataPointF.push_back(scale * dy);
976 dataPointF.push_back(scale * dz);
977 dataPointWeight.push_back(1.);
978 }
979 }
980
981 int nDataPoints = dataPointGridU.size();
982 splineParameters.resize(spline.getNumberOfParameters());
983
984 helper.approximateDataPoints(spline, splineParameters.data(), 0., spline.getGridX1().getUmax(),
985 0., spline.getGridX2().getUmax(),
986 dataPointGridU.data(), dataPointGridV.data(),
987 dataPointF.data(), dataPointWeight.data(), nDataPoints);
988
989 float* splineX = correction.getCorrectionDataInvX(sector, row);
990 float* splineUV = correction.getCorrectionDataInvYZ(sector, row);
991 for (int i = 0; i < spline.getNumberOfParameters() / 3; i++) {
992 splineX[i] = splineParameters[3 * i + 0];
993 splineUV[2 * i + 0] = splineParameters[3 * i + 1];
994 splineUV[2 * i + 1] = splineParameters[3 * i + 2];
995 }
996 } // row
997 }; // thread
998
999 std::vector<std::thread> threads(mNthreads);
1000
1001 // run n threads
1002 for (int i = 0; i < mNthreads; i++) {
1003 threads[i] = std::thread(myThread, i);
1004 }
1005
1006 // wait for the threads to finish
1007 for (auto& th : threads) {
1008 th.join();
1009 }
1010
1011 } // sector
1012 float duration = watch.RealTime();
1013 LOGP(info, "Inverse tooks: {}s", duration);
1014}
1015
1017 o2::gpu::TPCFastSpaceChargeCorrection& mainCorrection, float mainScale,
1018 const std::vector<std::pair<const o2::gpu::TPCFastSpaceChargeCorrection*, float>>& additionalCorrections, bool /*prn*/)
1019{
1021
1022 TStopwatch watch;
1023 LOG(info) << "fast space charge correction helper: Merge corrections";
1024
1025 const auto& geo = mainCorrection.getGeometry();
1026
1027 for (int sector = 0; sector < geo.getNumberOfSectors(); sector++) {
1028
1029 auto myThread = [&](int iThread) {
1030 for (int row = iThread; row < geo.getNumberOfRows(); row += mNthreads) {
1031 auto& rowInfo = mainCorrection.getRowInfo(row);
1032 const auto& spline = mainCorrection.getSplineForRow(row);
1033
1034 float* splineParameters = mainCorrection.getCorrectionData(sector, row);
1035 float* splineParametersInvX = mainCorrection.getCorrectionDataInvX(sector, row);
1036 float* splineParametersInvYZ = mainCorrection.getCorrectionDataInvYZ(sector, row);
1037
1038 constexpr int nKnotPar1d = 4;
1039 constexpr int nKnotPar2d = nKnotPar1d * 2;
1040 constexpr int nKnotPar3d = nKnotPar1d * 3;
1041
1042 { // scale the main correction
1043
1044 double parscale[4] = {mainScale, mainScale, mainScale, mainScale * mainScale};
1045 for (int iknot = 0, ind = 0; iknot < spline.getNumberOfKnots(); iknot++) {
1046 for (int ipar = 0; ipar < nKnotPar1d; ++ipar) {
1047 for (int idim = 0; idim < 3; idim++, ind++) {
1048 splineParameters[ind] *= parscale[ipar];
1049 }
1050 }
1051 }
1052 for (int iknot = 0, ind = 0; iknot < spline.getNumberOfKnots(); iknot++) {
1053 for (int ipar = 0; ipar < nKnotPar1d; ++ipar) {
1054 for (int idim = 0; idim < 1; idim++, ind++) {
1055 splineParametersInvX[ind] *= parscale[ipar];
1056 }
1057 }
1058 }
1059 for (int iknot = 0, ind = 0; iknot < spline.getNumberOfKnots(); iknot++) {
1060 for (int ipar = 0; ipar < nKnotPar1d; ++ipar) {
1061 for (int idim = 0; idim < 2; idim++, ind++) {
1062 splineParametersInvYZ[ind] *= parscale[ipar];
1063 }
1064 }
1065 }
1066 }
1067
1068 // add the other corrections
1069
1070 const auto& gridU = spline.getGridX1();
1071 const auto& gridV = spline.getGridX2();
1072
1073 for (int icorr = 0; icorr < additionalCorrections.size(); ++icorr) {
1074 const auto& corr = *(additionalCorrections[icorr].first);
1075 double scale = additionalCorrections[icorr].second;
1076 auto& linfo = corr.getRowInfo(row);
1077
1078 double scaleU = rowInfo.gridMeasured.getYscale() / linfo.gridMeasured.getYscale();
1079 double scaleV = rowInfo.gridMeasured.getZscale() / linfo.gridMeasured.getZscale();
1080 double scaleRealU = rowInfo.gridReal.getYscale() / linfo.gridReal.getYscale();
1081 double scaleRealV = rowInfo.gridReal.getZscale() / linfo.gridReal.getZscale();
1082
1083 for (int iu = 0; iu < gridU.getNumberOfKnots(); iu++) {
1084 double u = gridU.getKnot(iu).u;
1085 for (int iv = 0; iv < gridV.getNumberOfKnots(); iv++) {
1086 double v = gridV.getKnot(iv).u;
1087 int knotIndex = spline.getKnotIndex(iu, iv);
1088 float P[nKnotPar3d];
1089
1090 { // direct correction
1091 float y, z;
1092 mainCorrection.convGridToLocal(sector, row, u, v, y, z);
1093 // return values: u, v, scaling factor
1094 float lu, lv, ls;
1095 corr.convLocalToGrid(sector, row, y, z, lu, lv, ls);
1096 ls *= scale;
1097 double parscale[4] = {ls, ls * scaleU, ls * scaleV, ls * ls * scaleU * scaleV};
1098 const auto& spl = corr.getSplineForRow(row);
1099 spl.interpolateParametersAtU(corr.getCorrectionData(sector, row), lu, lv, P);
1100 for (int ipar = 0, ind = 0; ipar < nKnotPar1d; ++ipar) {
1101 for (int idim = 0; idim < 3; idim++, ind++) {
1102 splineParameters[knotIndex * nKnotPar3d + ind] += parscale[ipar] * P[ind];
1103 }
1104 }
1105 }
1106
1107 float y, z;
1108 mainCorrection.convGridToRealLocal(sector, row, u, v, y, z);
1109 // return values: u, v, scaling factor
1110 float lu, lv, ls;
1111 corr.convRealLocalToGrid(sector, row, y, z, lu, lv, ls);
1112 ls *= scale;
1113 double parscale[4] = {ls, ls * scaleRealU, ls * scaleRealV, ls * ls * scaleRealU * scaleRealV};
1114
1115 { // inverse X correction
1116 corr.getSplineInvXforRow(row).interpolateParametersAtU(corr.getCorrectionDataInvX(sector, row), lu, lv, P);
1117 for (int ipar = 0, ind = 0; ipar < nKnotPar1d; ++ipar) {
1118 for (int idim = 0; idim < 1; idim++, ind++) {
1119 splineParametersInvX[knotIndex * nKnotPar1d + ind] += parscale[ipar] * P[ind];
1120 }
1121 }
1122 }
1123
1124 { // inverse YZ correction
1125 corr.getSplineInvYZforRow(row).interpolateParametersAtU(corr.getCorrectionDataInvYZ(sector, row), lu, lv, P);
1126 for (int ipar = 0, ind = 0; ipar < nKnotPar1d; ++ipar) {
1127 for (int idim = 0; idim < 2; idim++, ind++) {
1128 splineParametersInvYZ[knotIndex * nKnotPar2d + ind] += parscale[ipar] * P[ind];
1129 }
1130 }
1131 }
1132
1133 } // iv
1134 } // iu
1135 } // corrections
1136
1137 } // row
1138 }; // thread
1139
1140 std::vector<std::thread> threads(mNthreads);
1141
1142 // run n threads
1143 for (int i = 0; i < mNthreads; i++) {
1144 threads[i] = std::thread(myThread, i);
1145 }
1146
1147 // wait for the threads to finish
1148 for (auto& th : threads) {
1149 th.join();
1150 }
1151
1152 } // sector
1153 float duration = watch.RealTime();
1154 LOGP(info, "Merge of corrections tooks: {}s", duration);
1155}
1156
1158{
1159 LOG(info) << "fast space charge correction helper: use voxel centers for correction";
1160 mDebugUseVoxelCenters = true;
1161}
1162
1164{
1165 LOG(info) << "fast space charge correction helper: mirror A data to C data";
1166 mDebugMirrorAdata2C = true;
1167}
1168
1169} // namespace tpc
1170} // namespace o2
Definition of ChebyshevFit1D class.
std::ostringstream debug
int32_t i
uint32_t iSector
float float float & zMax
float & yMax
float zMin
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 j
Definition RawData.h:0
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.
int32_t setSpline(const Spline2DContainerBase< DataT, FlatObject > &spline, int32_t nAuxiliaryPointsU1, int32_t nAuxiliaryPointsU2)
_______________ Interface for a step-wise construction of the best-fit spline _______________________...
void approximateDataPoints(Spline2DContainerBase< DataT, FlatObject > &spline, DataT *splineParameters, double x1Min, double x1Max, double x2Min, double x2Max, const double dataPointX1[], const double dataPointX2[], const double dataPointF[], const double dataPointWeight[], int32_t nDataPoints)
Create best-fit spline parameters for a given set of data points.
Forward declaration — specializations below select ClassDefNV based on FlatBase.
Definition Spline2D.h:104
const std::vector< CorrectionPoint > & getPoints(int32_t iSector, int32_t iRow) const
void init(int32_t nSectors, int32_t nRows)
(re-)init the map
void addCorrectionPoint(int32_t iSector, int32_t iRow, double y, double z, double dx, double dy, double dz, double weight)
Starts the construction procedure, reserves temporary memory.
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 setTPCzLength(float tpcZlength)
void startConstruction(int32_t numberOfRows)
_______________ Construction interface ________________________
void setTPCrow(int32_t iRow, float x, int32_t nPads, float padWidth)
Initializes a TPC row.
static constexpr int32_t getNumberOfSectorsA()
Gives number of TPC sectors on the A side.
static constexpr int32_t getNumberOfSectors()
_______________ Getters _________________________________
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, TTree *voxResTreeInverse, bool useSmoothed, bool invertSigns, TPCFastSpaceChargeCorrectionMap *fitPointsDirect=nullptr, TPCFastSpaceChargeCorrectionMap *fitPointsInverse=nullptr)
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
void setDebugMirrorAdata2C()
debug: if true, mirror the data from the A side to the C side of the TPC
TPCFastSpaceChargeCorrectionHelper()=default
_____________ Constructors / destructors __________________________
void setNthreads(int n)
_______________ Settings ________________________
void setDebugUseVoxelCenters()
debug: if true, use voxel centers instead of the fitted positions for correction
void mergeCorrections(o2::gpu::TPCFastSpaceChargeCorrection &mainCorrection, float scale, const std::vector< std::pair< const o2::gpu::TPCFastSpaceChargeCorrection *, float > > &additionalCorrections, bool prn)
void setNthreadsToMaximum()
sets number of threads to N cpu cores
static TPCFastSpaceChargeCorrectionHelper * instance()
Singleton.
float getZ2X(int iz) const
float getX(int ix) const
float getY2X(int ix, int ip) const
@ VoxV
voxel dispersions
float getDY2XI(int ix, int iy=0) const
float getDXI(int ix) const
float getDZ2X(int iz=0) const
GLdouble n
Definition glcorearb.h:1982
GLint GLenum GLint x
Definition glcorearb.h:403
GLuint GLfloat GLfloat GLfloat GLfloat y1
Definition glcorearb.h:5034
const GLdouble * v
Definition glcorearb.h:832
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
Definition glcorearb.h:5034
GLuint GLuint GLfloat weight
Definition glcorearb.h:5477
GLint y
Definition glcorearb.h:270
GLboolean * data
Definition glcorearb.h:298
GLubyte GLubyte GLubyte GLubyte w
Definition glcorearb.h:852
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
math_utils::Point2D< float > PadCentre
Pad centres as 2D float.
Definition Defs.h:105
unsigned short GlobalPadNumber
global pad number
Definition Defs.h:112
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)
std::vector< int > row
uint64_t const void const *restrict const msg
Definition x9.h:153