Skip to content

Commit 66f8031

Browse files
committed
TPC: Improve standalone dEdx calculation class
1 parent 7e06656 commit 66f8031

5 files changed

Lines changed: 766 additions & 269 deletions

File tree

Detectors/TPC/calibration/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ o2_add_test_root_macro(macro/drawCMV.C
165165
COMPILE_ONLY
166166
PUBLIC_LINK_LIBRARIES O2::TPCCalibration O2::TPCBase
167167
LABELS tpc)
168+
o2_add_test_root_macro(macro/calculatedEdx.C
169+
COMPILE_ONLY
170+
PUBLIC_LINK_LIBRARIES O2::TPCCalibration O2::TPCBase
171+
LABELS tpc)
168172

169173
o2_add_test(IDCFourierTransform
170174
COMPONENT_NAME calibration

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

Lines changed: 70 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,32 @@
2020
// o2 includes
2121
#include "DataFormatsTPC/TrackTPC.h"
2222
#include "DataFormatsTPC/dEdxInfo.h"
23+
#include "TPCBase/Mapper.h"
2324
#include "GPUO2InterfaceRefit.h"
2425
#include "CalibdEdxContainer.h"
26+
#include "CorrectionMapsHelper.h"
2527
#include "CommonUtils/TreeStreamRedirector.h"
2628
#include "TPCCalibration/CorrectdEdxDistortions.h"
2729
#include "TPCFastTransformPOD.h"
30+
#include "GPUCommonRtypes.h"
2831
#include <vector>
32+
#include <map>
33+
#include <unordered_map>
34+
#include <string>
35+
#include <utility>
2936

3037
namespace o2::tpc
3138
{
3239

40+
/// \brief average cluster occupancy of a track, per TPC region
41+
struct AverageOccupancy {
42+
double IROC = 0.;
43+
double OROC1 = 0.;
44+
double OROC2 = 0.;
45+
double OROC3 = 0.;
46+
ClassDefNV(AverageOccupancy, 1);
47+
};
48+
3349
/// \brief dEdx calculation class
3450
///
3551
/// This class is used to calculate dEdx of reconstructed tracks.
@@ -46,7 +62,7 @@ namespace o2::tpc
4662
/// c.setMembers(tpcTrackClIdxVecInput, clusterIndex, tpcTracks); // set the member variables: TrackTPC, TPCClRefElem, o2::tpc::ClusterNativeAccess
4763
/// c.setRefit(); // set the refit pointer to perform refitting of tracks, otherwise setPropagateTrack to true
4864
/// start looping over the tracks
49-
/// c.calculatedEdx(track, output, 0.015, 0.60, CorrectionFlags::TopologyPol | CorrectionFlags::dEdxResidual, ClusterFlags::ExcludeEdgeCl) // this will fill the dEdxInfo output for given track
65+
/// c.calculatedEdx(track, output, averageOcc, 0.015, 0.60, CorrectionFlags::TopologyPol | CorrectionFlags::dEdxResidual, ClusterFlags::ExcludeEdgeCl) // this will fill the dEdxInfo output and per-region average track occupancy averageOcc for given track
5066

5167
enum class CorrectionFlags : unsigned short {
5268
None = 0,
@@ -61,11 +77,14 @@ enum class CorrectionFlags : unsigned short {
6177
enum class ClusterFlags : unsigned short {
6278
None = 0,
6379
ExcludeSingleCl = 1 << 0, ///< flag to exclude single clusters in dEdx calculation
64-
ExcludeSplitCl = 1 << 1, ///< flag to exclude split clusters in dEdx calculation
65-
ExcludeEdgeCl = 1 << 2, ///< flag to exclude sector edge clusters in dEdx calculation
66-
ExcludeSubthresholdCl = 1 << 3, ///< flag to exclude subthreshold clusters in dEdx calculation
67-
ExcludeSectorBoundaries = 1 << 4, ///< flag to exclude sector boundary clusters in subthreshold cluster treatment
68-
ExcludeSharedCl = 1 << 5, ///< flag to exclude clusters shared between tracks
80+
ExcludeSplitPadCl = 1 << 1, ///< flag to exclude split pad clusters in dEdx calculation
81+
ExcludeSplitTimeCl = 1 << 2, ///< flag to exclude split time clusters in dEdx calculation
82+
ExcludeSplitCl = 1 << 3, ///< flag to exclude split pad or time clusters in dEdx calculation
83+
ExcludeEdgeCl = 1 << 4, ///< flag to exclude sector edge clusters in dEdx calculation
84+
ExcludeSubthresholdCl = 1 << 5, ///< flag to exclude subthreshold clusters in dEdx calculation
85+
ExcludeSectorBoundaries = 1 << 6, ///< flag to exclude sector boundary clusters in subthreshold cluster treatment
86+
ExcludeSharedCl = 1 << 7, ///< flag to exclude clusters shared between tracks in dEdx calculation
87+
ExcludeSamePadRowCl = 1 << 8, ///< flag to exclude clusters in the same pad row in dEdx calculation
6988
};
7089

7190
inline CorrectionFlags operator&(CorrectionFlags a, CorrectionFlags b) { return static_cast<CorrectionFlags>(static_cast<unsigned short>(a) & static_cast<unsigned short>(b)); }
@@ -95,6 +114,9 @@ class CalculatedEdx
95114
/// \param propagate propagate the tracks to extract the track parameters instead of performing a refit
96115
void setPropagateTrack(const bool propagate) { mPropagateTrack = propagate; }
97116

117+
/// \param propagate propagate the tracks to extract the track parameters instead of performing a refit
118+
void setPropagateParams(const bool propagate) { mPropagateParams = propagate; }
119+
98120
/// \param debug use debug streamer and set debug vectors
99121
void setDebug(const bool debug) { mDebug = debug; }
100122

@@ -110,12 +132,22 @@ class CalculatedEdx
110132
/// \param minChargeMaxThreshold upper limit for the possible minimum charge max in subthreshold treatment
111133
void setMinChargeMaxThreshold(float minChargeMaxThreshold) { mMinChargeMaxThreshold = minChargeMaxThreshold; }
112134

113-
/// set the debug streamer
114-
void setStreamer(const char* debugRootFile) { mStreamer = std::make_unique<o2::utils::TreeStreamRedirector>(debugRootFile, "recreate"); };
135+
/// set the debug streamer for a given output file; a new streamer is only created the first time a given debugRootFile is seen,
136+
/// so different calculatedEdx() calls using different debugRootFile names each get their own independent debug file
137+
void setStreamer(const char* debugRootFile)
138+
{
139+
auto& streamer = mStreamers[debugRootFile];
140+
if (!streamer) {
141+
streamer = std::make_unique<o2::utils::TreeStreamRedirector>(debugRootFile, "recreate");
142+
}
143+
};
115144

116145
/// set the debug streamer of the space-charge dedx correction
117146
void setSCStreamer(const char* debugRootFile = "debug_sc_corrections.root") { mSCdEdxCorrection.setStreamer(debugRootFile); }
118147

148+
/// \param lumi set luminosity for space-charge correction map scaling
149+
void setLumi(const float lumi) { mSCdEdxCorrection.setLumi(lumi); }
150+
119151
/// \return returns magnetic field in kG
120152
float getFieldNominalGPUBz() { return mFieldNominalGPUBz; }
121153

@@ -128,18 +160,21 @@ class CalculatedEdx
128160
/// \return returns the upper limit for the possible minimum charge max in subthreshold treatment
129161
float getMinChargeMaxThreshold() { return mMinChargeMaxThreshold; }
130162

131-
/// fill missing clusters with minimum charge (method=0) or minimum charge/2 (method=1) or Landau (method=2)
163+
/// fill missing clusters with minimum charge (method=0) or minimum charge/2 (method=1)
132164
void fillMissingClusters(int missingClusters[4], float minChargeTot, float minChargeMax, int method, std::array<std::vector<float>, 5>& chargeTotROC, std::array<std::vector<float>, 5>& chargeMaxROC);
133165

166+
void handleSameRowClusters(o2::tpc::TrackTPC& track, std::map<std::pair<unsigned char, unsigned char>, std::vector<int>>& clustersByRow, std::map<std::pair<unsigned char, unsigned char>, o2::tpc::ClusterNative>& combinedClustersByRow, std::map<int, std::tuple<unsigned char, unsigned char, unsigned int>>& clusterReferencesByIndex);
167+
134168
/// get the truncated mean for the input track with the truncation range, charge type, region and corrections
135169
/// the cluster charge is normalized by effective length*gain, you can turn off the normalization by setting all corrections to false
136170
/// \param track input track
137171
/// \param output output dEdxInfo
172+
/// \param averageOcc output average cluster occupancy of the track, per TPC region
138173
/// \param low lower cluster cut
139174
/// \param high higher cluster cut
140-
/// \param mask to apply different corrections: TopologySimple = simple analytical topology correction, TopologyPol = topology correction from polynomials, GainFull = full gain map from calibration container,
175+
/// \param correctionMask to apply different corrections: TopologySimple = simple analytical topology correction, TopologyPol = topology correction from polynomials, GainFull = full gain map from calibration container,
141176
/// GainResidual = residuals gain map from calibration container, dEdxResidual = residual dEdx correction
142-
void calculatedEdx(TrackTPC& track, dEdxInfo& output, float low = 0.015f, float high = 0.6f, CorrectionFlags correctionMask = CorrectionFlags::TopologyPol | CorrectionFlags::dEdxResidual, ClusterFlags clusterMask = ClusterFlags::None, int subthresholdMethod = 0, const char* debugRootFile = "dEdxDebug.root");
177+
void calculatedEdx(TrackTPC& track, dEdxInfo& output, AverageOccupancy& averageOcc, float low = 0.015f, float high = 0.6f, CorrectionFlags correctionMask = CorrectionFlags::TopologyPol | CorrectionFlags::dEdxResidual, ClusterFlags clusterMask = ClusterFlags::None, int subthresholdMethod = 0, int stackBoundaryMethod = 0, const char* debugRootFile = "dEdxDebug.root");
143178

144179
/// get the truncated mean for the input charge vector and the truncation range low*nCl<nCl<high*nCl
145180
/// \param charge input vector
@@ -155,14 +190,24 @@ class CalculatedEdx
155190

156191
/// get effective track length using topology correction from polynomials
157192
/// \param track input track
158-
/// \param cl cluster
193+
/// \param clPad cluster pad
194+
/// \param clTime cluster time
159195
/// \param region pad region
160196
/// \param charge total or maximum charge of the cluster, cl
161197
/// \param chargeType total or maximum
162198
/// \param threshold zero supression threshold
163199
/// \return returns topology correction from polynomials
164200
float getTrackTopologyCorrectionPol(const o2::tpc::TrackTPC& track, const o2::tpc::ClusterNative& cl, const unsigned int region, const float charge, ChargeType chargeType, const float threshold) const;
165201

202+
/// \return returns space-charge dedx correctin
203+
auto& getSCCorrection() { return mSCdEdxCorrection; }
204+
205+
/// \return returns cluster occupancy for given cluster time; only valid (non-sentinel) when the refit method is used, since the occupancy map is only filled by setRefit()
206+
unsigned int getOccupancy(float clTime) const;
207+
208+
/// \return returns true if given row index is in a stack boundary
209+
bool isInStackBoundaries(int stackNumber, unsigned char rowIndex, int stackBoundaryMethod);
210+
166211
/// load calibration objects from CCDB
167212
/// \param runNumberOrTimeStamp run number or time stamp
168213
/// \param isMC set if dEdx space-charge corrections will be loaded for MC or real data
@@ -214,15 +259,6 @@ class CalculatedEdx
214259
/// \param object name of the object to load
215260
void setPropagatorFromFile(const char* folder, const char* file, const char* object);
216261

217-
/// \param lumi set luminosity for space-charge correction map scaling
218-
void setLumi(const float lumi) { mSCdEdxCorrection.setLumi(lumi); }
219-
220-
/// \return returns space-charge dedx correctin
221-
auto& getSCCorrection() { return mSCdEdxCorrection; }
222-
223-
/// \return returns cluster occupancy for given cluster
224-
unsigned int getOccupancy(const o2::tpc::ClusterNative& cl) const;
225-
226262
private:
227263
std::vector<TrackTPC>* mTracks{nullptr}; ///< vector containing the tpc tracks which will be processed
228264
std::vector<TPCClRefElem>* mTPCTrackClIdxVecInput{nullptr}; ///< input vector with TPC tracks cluster indicies
@@ -233,18 +269,22 @@ class CalculatedEdx
233269
std::vector<unsigned int> mTPCRefitterOccMap; ///< externally set TPC clusters occupancy map
234270
std::unique_ptr<o2::gpu::GPUO2InterfaceRefit> mRefit{nullptr}; ///< TPC refitter used for TPC tracks refit during the reconstruction
235271

236-
int mMaxMissingCl{1}; ///< maximum number of missing clusters for subthreshold check
237-
float mMinChargeTotThreshold{50}; ///< upper limit for minimum charge tot value in subthreshold treatment, i.e for a high dEdx track adding a minimum value of 500 to track as a virtual charge doesn't make sense
238-
float mMinChargeMaxThreshold{50}; ///< upper limit for minimum charge max value in subthreshold treatment, i.e for a high dEdx track adding a minimum value of 500 to track as a virtual charge doesn't make sense
239-
float mFieldNominalGPUBz{5}; ///< magnetic field in kG, used for track propagation
240-
bool mPropagateTrack{false}; ///< propagating the track instead of performing a refit
241-
bool mDebug{false}; ///< use the debug streamer
242-
CalibdEdxContainer mCalibCont; ///< calibration container
243-
std::unique_ptr<o2::utils::TreeStreamRedirector> mStreamer{nullptr}; ///< debug streamer
272+
int mMaxMissingCl{1}; ///< maximum number of missing clusters for subthreshold check
273+
float mMinChargeTotThreshold{50}; ///< upper limit for minimum charge tot value in subthreshold treatment, i.e for a high dEdx track adding a minimum value of 500 to track as a virtual charge doesn't make sense
274+
float mMinChargeMaxThreshold{50}; ///< upper limit for minimum charge max value in subthreshold treatment, i.e for a high dEdx track adding a minimum value of 500 to track as a virtual charge doesn't make sense
275+
float mFieldNominalGPUBz{5}; ///< magnetic field in kG, used for track propagation
276+
bool mPropagateTrack{false}; ///< propagating the track instead of performing a refit (faster than refit)
277+
bool mPropagateParams{false}; ///< propagating the parameters instead of full propagation (faster than track propagation)
278+
bool mDebug{false}; ///< use the debug streamer
279+
CalibdEdxContainer mCalibCont; ///< calibration container
280+
std::unordered_map<std::string, std::unique_ptr<o2::utils::TreeStreamRedirector>> mStreamers; ///< debug streamers, keyed by output file name so each debugRootFile gets its own tree
281+
long mDebugTrackIndex{-1}; ///< running index of the track being processed, written to the debug trees so per-cluster rows can be grouped back into tracks
244282

245283
CorrectdEdxDistortions mSCdEdxCorrection; ///< for space-charge correction of dE/dx
284+
285+
std::array<std::vector<unsigned char>, 4> mStackBoundaries = {{{0, 62}, {63, 96}, {97, 126}, {127, 151}}}; // for excluding stack boundaries in dEdx calculation
246286
};
247287

248288
} // namespace o2::tpc
249289

250-
#endif
290+
#endif

0 commit comments

Comments
 (0)