Skip to content

Commit 8957bd6

Browse files
TPC: adding dEdx space-charge correction (#13557)
* TPC: adding dEdx space-charge correction - adding check for shared clusters - adding cluster occupancy * Adding missing include
1 parent 0a1fe0e commit 8957bd6

File tree

5 files changed

+358
-4
lines changed

5 files changed

+358
-4
lines changed

Detectors/TPC/calibration/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ o2_add_library(TPCCalibration
5656
src/CorrMapParam.cxx
5757
src/TPCMShapeCorrection.cxx
5858
src/DigitAdd.cxx
59+
src/CorrectdEdxDistortions.cxx
5960
PUBLIC_LINK_LIBRARIES O2::DataFormatsTPC O2::TPCBase
6061
O2::TPCReconstruction ROOT::Minuit
6162
Microsoft.GSL::GSL
@@ -111,7 +112,8 @@ o2_target_root_dictionary(TPCCalibration
111112
include/TPCCalibration/TPCScaler.h
112113
include/TPCCalibration/CorrMapParam.h
113114
include/TPCCalibration/TPCMShapeCorrection.h
114-
include/TPCCalibration/DigitAdd.h)
115+
include/TPCCalibration/DigitAdd.h
116+
include/TPCCalibration/CorrectdEdxDistortions.h)
115117

116118
o2_add_test_root_macro(macro/comparePedestalsAndNoise.C
117119
PUBLIC_LINK_LIBRARIES O2::TPCBase

Detectors/TPC/calibration/include/TPCCalibration/CalculatedEdx.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "CalibdEdxContainer.h"
2525
#include "CorrectionMapsHelper.h"
2626
#include "CommonUtils/TreeStreamRedirector.h"
27+
#include "TPCCalibration/CorrectdEdxDistortions.h"
2728

2829
#include <vector>
2930

@@ -55,6 +56,7 @@ enum class CorrectionFlags : unsigned short {
5556
GainFull = 1 << 2, ///< flag for full gain map from calibration container
5657
GainResidual = 1 << 3, ///< flag for residuals gain map from calibration container
5758
dEdxResidual = 1 << 4, ///< flag for residual dEdx correction
59+
dEdxSC = 1 << 5, ///< flag for space-charge dEdx correction
5860
};
5961

6062
enum class ClusterFlags : unsigned short {
@@ -64,6 +66,7 @@ enum class ClusterFlags : unsigned short {
6466
ExcludeEdgeCl = 1 << 2, ///< flag to exclude sector edge clusters in dEdx calculation
6567
ExcludeSubthresholdCl = 1 << 3, ///< flag to exclude subthreshold clusters in dEdx calculation
6668
ExcludeSectorBoundaries = 1 << 4, ///< flag to exclude sector boundary clusters in subthreshold cluster treatment
69+
ExcludeSharedCl = 1 << 5, ///< flag to exclude clusters shared between tracks
6770
};
6871

6972
inline CorrectionFlags operator&(CorrectionFlags a, CorrectionFlags b) { return static_cast<CorrectionFlags>(static_cast<unsigned short>(a) & static_cast<unsigned short>(b)); }
@@ -111,6 +114,9 @@ class CalculatedEdx
111114
/// set the debug streamer
112115
void setStreamer(const char* debugRootFile) { mStreamer = std::make_unique<o2::utils::TreeStreamRedirector>(debugRootFile, "recreate"); };
113116

117+
/// set the debug streamer of the space-charge dedx correction
118+
void setSCStreamer(const char* debugRootFile = "debug_sc_corrections.root") { mSCdEdxCorrection.setStreamer(debugRootFile); }
119+
114120
/// \return returns magnetic field in kG
115121
float getFieldNominalGPUBz() { return mFieldNominalGPUBz; }
116122

@@ -160,7 +166,8 @@ class CalculatedEdx
160166

161167
/// load calibration objects from CCDB
162168
/// \param runNumberOrTimeStamp run number or time stamp
163-
void loadCalibsFromCCDB(long runNumberOrTimeStamp);
169+
/// \param isMC set if dEdx space-charge corrections will be loaded for MC or real data
170+
void loadCalibsFromCCDB(long runNumberOrTimeStamp, const bool isMC = false);
164171

165172
/// load calibration objects from local CCDB folder
166173
/// \param localCCDBFolder local CCDB folder
@@ -208,6 +215,15 @@ class CalculatedEdx
208215
/// \param object name of the object to load
209216
void setPropagatorFromFile(const char* folder, const char* file, const char* object);
210217

218+
/// \param lumi set luminosity for space-charge correction map scaling
219+
void setLumi(const float lumi) { mSCdEdxCorrection.setLumi(lumi); }
220+
221+
/// \return returns space-charge dedx correctin
222+
auto& getSCCorrection() { return mSCdEdxCorrection; }
223+
224+
/// \return returns cluster occupancy for given cluster
225+
unsigned int getOccupancy(const o2::tpc::ClusterNative& cl) const;
226+
211227
private:
212228
std::vector<TrackTPC>* mTracks{nullptr}; ///< vector containing the tpc tracks which will be processed
213229
std::vector<TPCClRefElem>* mTPCTrackClIdxVecInput{nullptr}; ///< input vector with TPC tracks cluster indicies
@@ -228,6 +244,8 @@ class CalculatedEdx
228244

229245
std::array<std::vector<float>, 5> mChargeTotROC;
230246
std::array<std::vector<float>, 5> mChargeMaxROC;
247+
248+
CorrectdEdxDistortions mSCdEdxCorrection; ///< for space-charge correction of dE/dx
231249
};
232250

233251
} // namespace o2::tpc
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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+
12+
///
13+
/// @file CorrectdEdxDistortions.h
14+
/// @author Matthias Kleiner, mkleiner@ikf.uni-frankfurt.de
15+
///
16+
17+
#ifndef ALICEO2_TPC_CORRECTDEDXDISTORTIONS_H
18+
#define ALICEO2_TPC_CORRECTDEDXDISTORTIONS_H
19+
20+
#include "GPUTPCGeometry.h"
21+
#include <memory>
22+
23+
// forward declare classes
24+
namespace o2::gpu
25+
{
26+
class TPCFastTransform;
27+
}
28+
29+
namespace o2::utils
30+
{
31+
class TreeStreamRedirector;
32+
}
33+
34+
namespace o2::tpc
35+
{
36+
37+
class CorrectdEdxDistortions
38+
{
39+
public:
40+
/// Default constructor
41+
CorrectdEdxDistortions();
42+
43+
/// Default destructor
44+
~CorrectdEdxDistortions();
45+
46+
/// setting the space-charge corrections from local file
47+
/// \param scAvgFile average space-charge correction map
48+
/// \param scDerFile derivative space-charge correction map
49+
/// \param lumi luminosity which is used for scaling the correction map
50+
void setSCCorrFromFile(const char* scAvgFile, const char* scDerFile, const float lumi = -1);
51+
52+
/// setting the space-charge corrections
53+
/// \param avg average space-charge correction map
54+
/// \param der derivative space-charge correction map
55+
/// \param lumi luminosity which is used for scaling the correction map
56+
void setCorrectionMaps(o2::gpu::TPCFastTransform* avg, o2::gpu::TPCFastTransform* der, const float lumi);
57+
58+
/// setting the space-charge corrections
59+
/// \param avg average space-charge correction map
60+
/// \param der derivative space-charge correction map
61+
void setCorrectionMaps(o2::gpu::TPCFastTransform* avg, o2::gpu::TPCFastTransform* der);
62+
63+
/// \param lumi luminosity which is used for scaling the correction map
64+
void setLumi(float lumi);
65+
66+
/// enable the debug streamer
67+
void setStreamer(const char* debugRootFile = "debug_sc_corrections.root");
68+
69+
/// \return getting the correction value for the cluster charge
70+
/// \param time true time information of the cluster
71+
/// \param sector TPC sector of the cluster
72+
/// \param padrow global padrow
73+
/// \param pad pad number in the padrow
74+
float getCorrection(const float time, unsigned char sector, unsigned char padrow, int pad) const;
75+
76+
/// set minimum allowed lx correction at lower pad
77+
void setMinLX0(const float minLX) { mLX0Min = minLX; }
78+
79+
/// set minimum allowed lx correction upper lower pad
80+
void setMinLX1(const float minLX) { mLX1Min = minLX; }
81+
82+
/// set minimum allowed correction value
83+
void setMinCorr(const float minCorr) { mScCorrMin = minCorr; }
84+
85+
/// set maximum allowed correction value
86+
void setMaxCorr(const float maxCorr) { mScCorrMax = maxCorr; }
87+
88+
private:
89+
float mScaleDer = 0;
90+
std::unique_ptr<o2::gpu::TPCFastTransform> mCorrAvg{nullptr}; ///< correction map for average distortions
91+
std::unique_ptr<o2::gpu::TPCFastTransform> mCorrDer{nullptr}; ///< correction map for distortions
92+
o2::gpu::GPUTPCGeometry mTPCGeometry; ///< geometry information of TPC
93+
std::unique_ptr<o2::utils::TreeStreamRedirector> mStreamer{nullptr}; ///< debug streamer
94+
float mLX0Min{82}; ///< minimum allowed lx position after correction at position of the bottom pad
95+
float mLX1Min{82}; ///< minimum allowed lx position after correction at position of the top pad
96+
float mScCorrMin{0.7}; ///< minimum allowed correction values
97+
float mScCorrMax{1.6}; ///< maximum allowed correction values
98+
};
99+
} // namespace o2::tpc
100+
101+
#endif

Detectors/TPC/calibration/src/CalculatedEdx.cxx

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "CalibdEdxTrackTopologyPol.h"
2727
#include "DataFormatsParameters/GRPMagField.h"
2828
#include "GPUO2InterfaceUtils.h"
29+
#include "GPUTPCGMMergedTrackHit.h"
2930

3031
using namespace o2::tpc;
3132

@@ -111,9 +112,12 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, fl
111112
std::vector<float> gainResidualVector;
112113
std::vector<float> residualCorrTotVector;
113114
std::vector<float> residualCorrMaxVector;
115+
std::vector<float> scCorrVector;
114116

115117
std::vector<o2::tpc::TrackTPC> trackVector;
116118
std::vector<o2::tpc::ClusterNative> clVector;
119+
std::vector<unsigned int> occupancyVector;
120+
std::vector<bool> isClusterShared;
117121

118122
if (mDebug) {
119123
excludeClVector.reserve(nClusters);
@@ -134,6 +138,9 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, fl
134138
residualCorrMaxVector.reserve(nClusters);
135139
trackVector.reserve(nClusters);
136140
clVector.reserve(nClusters);
141+
scCorrVector.reserve(nClusters);
142+
occupancyVector.reserve(nClusters);
143+
isClusterShared.reserve(nClusters);
137144
}
138145

139146
// for missing clusters
@@ -154,6 +161,10 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, fl
154161
// set sectorIndex, rowIndex, clusterIndexNumb
155162
track.getClusterReference(*mTPCTrackClIdxVecInput, iCl, sectorIndex, rowIndex, clusterIndexNumb);
156163

164+
// check if the cluster is shared
165+
const unsigned int absoluteIndex = mClusterIndex->clusterOffset[sectorIndex][rowIndex] + clusterIndexNumb;
166+
const bool isShared = mRefit ? (mTPCRefitterShMap[absoluteIndex] & GPUCA_NAMESPACE::gpu::GPUTPCGMMergedTrackHit::flagShared) : 0;
167+
157168
// get region, pad, stack and stack ID
158169
const int region = Mapper::REGION[rowIndex];
159170
const unsigned char pad = std::clamp(static_cast<unsigned int>(cl.getPad() + 0.5f), static_cast<unsigned int>(0), Mapper::PADSPERROW[region][Mapper::getLocalRowFromGlobalRow(rowIndex)] - 1); // the left side of the pad is defined at e.g. 3.5 and the right side at 4.5
@@ -179,6 +190,9 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, fl
179190
if (((clusterMask & ClusterFlags::ExcludeEdgeCl) == ClusterFlags::ExcludeEdgeCl) && ((flagsCl & ClusterNative::flagEdge) == ClusterNative::flagEdge)) {
180191
excludeCl += 0b100; // 4 for edge cluster
181192
}
193+
if (((clusterMask & ClusterFlags::ExcludeSharedCl) == ClusterFlags::ExcludeSharedCl) && isShared) {
194+
excludeCl += 0b10000; // for shared cluster
195+
}
182196

183197
// get the x position of the track
184198
const float xPosition = Mapper::instance().getPadCentre(PadPos(rowIndex, 0)).X();
@@ -214,6 +228,8 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, fl
214228
offsPadVector.emplace_back(offsPad);
215229
trackVector.emplace_back(track);
216230
clVector.emplace_back(cl);
231+
occupancyVector.emplace_back(getOccupancy(cl));
232+
isClusterShared.emplace_back(isShared);
217233

218234
topologyCorrVector.emplace_back(-999.f);
219235
topologyCorrTotVector.emplace_back(-999.f);
@@ -222,6 +238,7 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, fl
222238
gainResidualVector.emplace_back(-999.f);
223239
residualCorrTotVector.emplace_back(-999.f);
224240
residualCorrMaxVector.emplace_back(-999.f);
241+
scCorrVector.emplace_back(-999.f);
225242
}
226243
// to avoid counting the skipped cluster as a subthreshold cluster
227244
rowIndexOld = rowIndex;
@@ -325,6 +342,19 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, fl
325342
minChargeMax = chargeMax;
326343
};
327344

345+
// space-charge dEdx corrections
346+
const float time = cl.getTime() - track.getTime0(); // ToDo: get correct time from ITS-TPC track if possible
347+
float scCorr = 1.0f;
348+
if ((correctionMask & CorrectionFlags::dEdxSC) == CorrectionFlags::dEdxSC) {
349+
scCorr = mSCdEdxCorrection.getCorrection(time, sectorIndex, rowIndex, pad);
350+
if (scCorr > 0) {
351+
chargeTot /= scCorr;
352+
};
353+
if (corrMax > 0) {
354+
chargeMax /= scCorr;
355+
};
356+
}
357+
328358
if (stack == GEMstack::IROCgem) {
329359
mChargeTotROC[0].emplace_back(chargeTot);
330360
mChargeMaxROC[0].emplace_back(chargeMax);
@@ -359,6 +389,8 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, fl
359389
offsPadVector.emplace_back(offsPad);
360390
trackVector.emplace_back(track);
361391
clVector.emplace_back(cl);
392+
occupancyVector.emplace_back(getOccupancy(cl));
393+
isClusterShared.emplace_back(isShared);
362394

363395
topologyCorrVector.emplace_back(effectiveLength);
364396
topologyCorrTotVector.emplace_back(effectiveLengthTot);
@@ -367,6 +399,7 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, fl
367399
gainResidualVector.emplace_back(gainResidual);
368400
residualCorrTotVector.emplace_back(corrTot);
369401
residualCorrMaxVector.emplace_back(corrMax);
402+
scCorrVector.emplace_back(scCorr);
370403
};
371404
}
372405

@@ -394,6 +427,10 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, fl
394427
output.NHitsOROC3 = nClsROC[3];
395428
}
396429

430+
// copy corrected cluster charges
431+
auto chargeTotVector = mChargeTotROC[4];
432+
auto chargeMaxVector = mChargeMaxROC[4];
433+
397434
// calculate dEdx
398435
output.dEdxTotIROC = getTruncMean(mChargeTotROC[0], low, high);
399436
output.dEdxTotOROC1 = getTruncMean(mChargeTotROC[1], low, high);
@@ -428,6 +465,7 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, fl
428465
<< "gainResidualVector=" << gainResidualVector
429466
<< "residualCorrTotVector=" << residualCorrTotVector
430467
<< "residualCorrMaxVector=" << residualCorrMaxVector
468+
<< "scCorrVector=" << scCorrVector
431469
<< "localXVector=" << localXVector
432470
<< "localYVector=" << localYVector
433471
<< "offsPadVector=" << offsPadVector
@@ -436,6 +474,10 @@ void CalculatedEdx::calculatedEdx(o2::tpc::TrackTPC& track, dEdxInfo& output, fl
436474
<< "minChargeTot=" << minChargeTot
437475
<< "minChargeMax=" << minChargeMax
438476
<< "output=" << output
477+
<< "occupancy=" << occupancyVector
478+
<< "chargeTotVector=" << chargeTotVector
479+
<< "chargeMaxVector=" << chargeMaxVector
480+
<< "isClusterShared=" << isClusterShared
439481
<< "\n";
440482
}
441483
}
@@ -492,7 +534,7 @@ float CalculatedEdx::getTrackTopologyCorrectionPol(const o2::tpc::TrackTPC& trac
492534
return effectiveLength;
493535
}
494536

495-
void CalculatedEdx::loadCalibsFromCCDB(long runNumberOrTimeStamp)
537+
void CalculatedEdx::loadCalibsFromCCDB(long runNumberOrTimeStamp, const bool isMC)
496538
{
497539
// setup CCDB manager
498540
auto& cm = o2::ccdb::BasicCCDBManager::instance();
@@ -542,6 +584,15 @@ void CalculatedEdx::loadCalibsFromCCDB(long runNumberOrTimeStamp)
542584
auto propagator = o2::base::Propagator::Instance();
543585
const o2::base::MatLayerCylSet* matLut = o2::base::MatLayerCylSet::rectifyPtrFromFile(cm.get<o2::base::MatLayerCylSet>("GLO/Param/MatLUT"));
544586
propagator->setMatLUT(matLut);
587+
588+
// load sc correction maps
589+
auto avgMap = isMC ? cm.getForTimeStamp<o2::gpu::TPCFastTransform>(o2::tpc::CDBTypeMap.at(o2::tpc::CDBType::CalCorrMapMC), tRun) : cm.getForTimeStamp<o2::gpu::TPCFastTransform>(o2::tpc::CDBTypeMap.at(o2::tpc::CDBType::CalCorrMap), tRun);
590+
avgMap->rectifyAfterReadingFromFile();
591+
592+
auto derMap = isMC ? cm.getForTimeStamp<o2::gpu::TPCFastTransform>(o2::tpc::CDBTypeMap.at(o2::tpc::CDBType::CalCorrDerivMapMC), tRun) : cm.getForTimeStamp<o2::gpu::TPCFastTransform>(o2::tpc::CDBTypeMap.at(o2::tpc::CDBType::CalCorrDerivMap), tRun);
593+
derMap->rectifyAfterReadingFromFile();
594+
595+
mSCdEdxCorrection.setCorrectionMaps(avgMap, derMap);
545596
}
546597

547598
void CalculatedEdx::loadCalibsFromLocalCCDBFolder(const char* localCCDBFolder)
@@ -624,4 +675,12 @@ void CalculatedEdx::setPropagatorFromFile(const char* folder, const char* file,
624675
o2::base::MatLayerCylSet* matLut = o2::base::MatLayerCylSet::rectifyPtrFromFile((o2::base::MatLayerCylSet*)matLutFile->Get(object));
625676
propagator->setMatLUT(matLut);
626677
}
627-
}
678+
}
679+
680+
unsigned int CalculatedEdx::getOccupancy(const o2::tpc::ClusterNative& cl) const
681+
{
682+
const int nTimeBinsPerOccupBin = 16;
683+
const int iBinOcc = cl.getTime() / nTimeBinsPerOccupBin + 2;
684+
const unsigned int occupancy = mTPCRefitterOccMap.empty() ? -1 : mTPCRefitterOccMap[iBinOcc];
685+
return occupancy;
686+
}

0 commit comments

Comments
 (0)