Skip to content

Commit a50c7d4

Browse files
TPC: createFromLocalCorrection with irregular spline knots
New overload of TPCFastSpaceChargeCorrectionHelper::createFromLocalCorrection taking the knot positions in y and z as vectors, so a correction from a continuous function can have dense knots where it changes fast (e.g. at the sector edges). The knots are rounded to an integer grid with 1/10 of the smallest knot distance as step, as in createFromTrackResiduals; the first and the last knot are put at the ends of the grid (row y edges; central electrode and readout in z). The function is sampled at 6 points per knot interval over the whole grid. The existing uniform version is unchanged. It samples y only between the outermost pad centres, so the outer half pad of each row is extrapolated by the spline. Test with a B = 0 cosmics correction map (spline - map, rms in dx / dy / dz): - 10 x 10 uniform knots: new overload 61 / 42 / 43 um, existing function 60 / 49 / 42 um; within 6 % of the row width of the sector edges dy 41 um (1.7 mm max) vs 218 um (3.9 mm max). - 20 x 10 uniform knots: new overload 59 / 38 / 39 um; existing function 0.5 / 2.1 / 1.0 mm, up to 16 cm on the pad range and 36 cm at the sector edges. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 1bd4969 commit a50c7d4

2 files changed

Lines changed: 120 additions & 0 deletions

File tree

‎Detectors/TPC/calibration/include/TPCCalibration/TPCFastSpaceChargeCorrectionHelper.h‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,17 @@ class TPCFastSpaceChargeCorrectionHelper
8080
std::function<void(int roc, int irow, double y, double z, double& dx, double& dy, double& dz)> correctionLocal,
8181
const int nKnotsY = 10, const int nKnotsZ = 20);
8282

83+
/// creates TPCFastSpaceChargeCorrection object from a continuous space charge correction in local coordinates,
84+
/// with irregular spline knots (e.g. denser where the correction changes fast)
85+
/// \param correctionLocal correction function in local coordinates
86+
/// \param knotsY knot positions along the row, increasing; the first and the last knot are put at the row's y edges, the others in proportion
87+
/// \param knotsZ knot positions along the drift, increasing; the first knot is put at the central electrode, the last one at the readout
88+
/// \note the knots are rounded to an integer grid with 1/10 of the smallest knot distance as step (as in createFromTrackResiduals).
89+
/// The correction is sampled at 6 points per knot interval over the whole grid, in y and in z.
90+
std::unique_ptr<TPCFastSpaceChargeCorrection> createFromLocalCorrection(
91+
std::function<void(int roc, int irow, double y, double z, double& dx, double& dy, double& dz)> correctionLocal,
92+
const std::vector<double>& knotsY, const std::vector<double>& knotsZ);
93+
8394
/// creates TPCFastSpaceChargeCorrection object from a continious space charge correction in global coordinates
8495
std::unique_ptr<TPCFastSpaceChargeCorrection> createFromGlobalCorrection(
8596
std::function<void(int roc, double gx, double gy, double gz,

‎Detectors/TPC/calibration/src/TPCFastSpaceChargeCorrectionHelper.cxx‎

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,115 @@ std::unique_ptr<TPCFastSpaceChargeCorrection> TPCFastSpaceChargeCorrectionHelper
324324
return std::move(correctionPtr);
325325
} // createFromLocalCorrection
326326

327+
std::unique_ptr<TPCFastSpaceChargeCorrection> TPCFastSpaceChargeCorrectionHelper::createFromLocalCorrection(
328+
std::function<void(int sector, int irow, double y, double z, double& dx, double& dy, double& dz)> correctionLocal,
329+
const std::vector<double>& knotsY, const std::vector<double>& knotsZ)
330+
{
331+
/// creates TPCFastSpaceChargeCorrection object from a continuous space charge correction in local coordinates,
332+
/// with irregular spline knots
333+
334+
LOG(info) << "fast space charge correction helper: create correction with irregular knots using " << mNthreads << " threads";
335+
336+
if (!mIsInitialized) {
337+
initGeometry();
338+
}
339+
340+
// spline knots must be positioned on the grid with an integer internal coordinate:
341+
// the knot positioning accuracy is set to 0.1 * the smallest knot distance
342+
std::vector<int> knotsInt[2];
343+
for (int dim = 0; dim < 2; dim++) {
344+
const std::vector<double>& knots = (dim == 0) ? knotsY : knotsZ;
345+
if (knots.size() < 2) {
346+
LOG(error) << "fast space charge correction helper: at least 2 knots needed in " << (dim == 0 ? "y" : "z");
347+
return nullptr;
348+
}
349+
double minDistance = knots[1] - knots[0];
350+
for (size_t i = 2; i < knots.size(); i++) {
351+
minDistance = std::min(minDistance, knots[i] - knots[i - 1]);
352+
}
353+
if (!(minDistance > 0.)) {
354+
LOG(error) << "fast space charge correction helper: the knots in " << (dim == 0 ? "y" : "z") << " must be strictly increasing";
355+
return nullptr;
356+
}
357+
const double pitch = 0.1 * minDistance;
358+
for (const double knot : knots) {
359+
knotsInt[dim].push_back(int((knot - knots[0]) / pitch + 0.5));
360+
}
361+
}
362+
363+
std::unique_ptr<TPCFastSpaceChargeCorrection> correctionPtr(new TPCFastSpaceChargeCorrection);
364+
TPCFastSpaceChargeCorrection& correction = *correctionPtr;
365+
366+
{ // create the correction object: one spline scenario for all rows
367+
correction.startConstruction(mGeo, 1);
368+
for (int row = 0; row < mGeo.getNumberOfRows(); row++) {
369+
correction.setRowScenarioID(row, 0);
370+
}
371+
TPCFastSpaceChargeCorrection::SplineType spline;
372+
spline.recreate(knotsInt[0].size(), knotsInt[0].data(), knotsInt[1].size(), knotsInt[1].data());
373+
correction.setSplineScenario(0, spline);
374+
correction.finishConstruction();
375+
}
376+
377+
// sampling points, relative to the grid (0: the first knot, 1: the last one): 6 per knot interval
378+
std::vector<double> samplingPoints[2];
379+
for (int dim = 0; dim < 2; dim++) {
380+
const std::vector<int>& knots = knotsInt[dim];
381+
const double uMax = knots.back();
382+
for (size_t i = 0; i + 1 < knots.size(); i++) {
383+
for (int j = 0; j < 6; j++) {
384+
samplingPoints[dim].push_back((knots[i] + (knots[i + 1] - knots[i]) * j / 6.) / uMax);
385+
}
386+
}
387+
samplingPoints[dim].push_back(1.);
388+
}
389+
390+
LOG(info) << "fast space charge correction helper: fill data points from an input SP correction function";
391+
392+
const int nSectors = mGeo.getNumberOfSectors();
393+
const int nRows = mGeo.getNumberOfRows();
394+
mCorrectionMap.init(nSectors, nRows);
395+
396+
for (int iSector = 0; iSector < nSectors; iSector++) {
397+
398+
auto myThread = [&](int iThread) {
399+
for (int iRow = iThread; iRow < nRows; iRow += mNthreads) {
400+
const auto& rowInfo = mGeo.getRowInfo(iRow);
401+
for (const double pointY : samplingPoints[0]) {
402+
const double y = rowInfo.getYmin() + pointY * rowInfo.getYwidth();
403+
for (const double pointZ : samplingPoints[1]) {
404+
// z of the grid: 0 at the central electrode, mirrored on the C side
405+
const double z = (iSector < mGeo.getNumberOfSectorsA() ? 1. : -1.) * pointZ * mGeo.getTPCzLength();
406+
double dx;
407+
double dy;
408+
double dz;
409+
correctionLocal(iSector, iRow, y, z, dx, dy, dz);
410+
mCorrectionMap.addCorrectionPoint(iSector, iRow, y, z, dx, dy, dz, 1.);
411+
}
412+
}
413+
} // row
414+
}; // thread
415+
416+
std::vector<std::thread> threads(mNthreads);
417+
418+
// run n threads
419+
for (int i = 0; i < mNthreads; i++) {
420+
threads[i] = std::thread(myThread, i);
421+
}
422+
423+
// wait for the threads to finish
424+
for (auto& th : threads) {
425+
th.join();
426+
}
427+
428+
} // sector
429+
430+
fillSpaceChargeCorrectionFromMap(correction, false);
431+
initInverse(correction, false);
432+
433+
return correctionPtr;
434+
} // createFromLocalCorrection with irregular knots
435+
327436
void TPCFastSpaceChargeCorrectionHelper::testGeometry(const TPCFastTransformGeo& geo) const
328437
{
329438
const Mapper& mapper = Mapper::instance();

0 commit comments

Comments
 (0)