Skip to content

Commit b66cc62

Browse files
committed
Added a function to calculate multiple dEdx settings for the same track without repeating track propagation and introduced minor improvements
1 parent bc2f134 commit b66cc62

3 files changed

Lines changed: 791 additions & 96 deletions

File tree

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

Lines changed: 92 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,21 @@ inline ClusterFlags operator&(ClusterFlags a, ClusterFlags b) { return static_ca
9595
inline ClusterFlags operator~(ClusterFlags a) { return static_cast<ClusterFlags>(~static_cast<unsigned short>(a)); }
9696
inline ClusterFlags operator|(ClusterFlags a, ClusterFlags b) { return static_cast<ClusterFlags>(static_cast<unsigned short>(a) | static_cast<unsigned short>(b)); }
9797

98+
/// \brief bundles the settings of one calculatedEdx() call (everything except the track/output/averageOcc)
99+
/// used by calculatedEdxMultipleSettings() to evaluate several settings for the same track without repeating
100+
/// the track refit/propagation for every setting
101+
struct dEdxSettings {
102+
float low = 0.015f; ///< lower cluster cut
103+
float high = 0.6f; ///< higher cluster cut
104+
CorrectionFlags correctionMask = CorrectionFlags::TopologyPol | CorrectionFlags::dEdxResidual; ///< corrections to apply
105+
ClusterFlags clusterMask = ClusterFlags::None; ///< clusters to exclude
106+
int subthresholdMethod = 0; ///< subthreshold cluster charge filling method
107+
int stackBoundaryMethod = 0; ///< stack boundary cluster exclusion method
108+
std::string debugRootFile = "dEdxDebug.root"; ///< debug streamer output file used if mDebug is set
109+
float maxSubthresholdChargeTot = 100000.f; ///< upper limit for the per-region minimum qTot used as the virtual charge of a subthreshold cluster (default effectively disables the cap)
110+
float maxSubthresholdChargeMax = 100000.f; ///< upper limit for the per-region minimum qMax used as the virtual charge of a subthreshold cluster (default effectively disables the cap)
111+
};
112+
98113
class CalculatedEdx
99114
{
100115
public:
@@ -126,12 +141,6 @@ class CalculatedEdx
126141
/// \param maxMissingCl maximum number of missing clusters for subthreshold check
127142
void setMaxMissingCl(int maxMissingCl) { mMaxMissingCl = maxMissingCl; }
128143

129-
/// \param minChargeTotThreshold upper limit for the possible minimum charge tot in subthreshold treatment
130-
void setMinChargeTotThreshold(float minChargeTotThreshold) { mMinChargeTotThreshold = minChargeTotThreshold; }
131-
132-
/// \param minChargeMaxThreshold upper limit for the possible minimum charge max in subthreshold treatment
133-
void setMinChargeMaxThreshold(float minChargeMaxThreshold) { mMinChargeMaxThreshold = minChargeMaxThreshold; }
134-
135144
/// set the debug streamer for a given output file; a new streamer is only created the first time a given debugRootFile is seen,
136145
/// so different calculatedEdx() calls using different debugRootFile names each get their own independent debug file
137146
void setStreamer(const char* debugRootFile)
@@ -154,14 +163,28 @@ class CalculatedEdx
154163
/// \return returns maxMissingCl for subthreshold cluster treatment
155164
int getMaxMissingCl() { return mMaxMissingCl; }
156165

157-
/// \return returns the upper limit for the possible minimum charge tot in subthreshold treatment
158-
float getMinChargeTotThreshold() { return mMinChargeTotThreshold; }
166+
/// \return returns the number of rows where refit/propagation failed (row.propagationFailed) since the last resetDebugCounters()
167+
long getNPropagationFailed() const { return mNPropagationFailed; }
159168

160-
/// \return returns the upper limit for the possible minimum charge max in subthreshold treatment
161-
float getMinChargeMaxThreshold() { return mMinChargeMaxThreshold; }
169+
/// \return returns the number of rows gathered by gatherRowClusterData() (processed for refit/propagation) since the last resetDebugCounters()
170+
long getNRowsProcessed() const { return mNRowsProcessed; }
171+
172+
/// \return returns the number of row gaps filled as subthreshold clusters by calculatedEdxFromRowData() since the last resetDebugCounters() per setting
173+
const std::vector<long>& getNSubThresholdFilledPerSettings() const { return mNSubThresholdFilledPerSettings; }
174+
175+
/// reset the running counters returned by getNPropagationFailed()/getNRowsProcessed()/getNSubThresholdFilledPerSettings()
176+
void resetDebugCounters()
177+
{
178+
mNPropagationFailed = 0;
179+
mNRowsProcessed = 0;
180+
mNSubThresholdFilledPerSettings.clear();
181+
}
162182

163-
/// fill missing clusters with minimum charge (method=0) or minimum charge/2 (method=1)
164-
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);
183+
/// fill missing clusters per region with that region's running minimum charge (method=0) or half of it (method=1),
184+
/// \param missingClusters number of row gaps to fill, per region (IROC, OROC1, OROC2, OROC3)
185+
/// \param minChargeTot per-region running minimum qTot among the accepted clusters of that region
186+
/// \param minChargeMax per-region running minimum qMax among the accepted clusters of that region
187+
void fillMissingClusters(int missingClusters[4], const float minChargeTot[4], const float minChargeMax[4], int method, std::array<std::vector<float>, 5>& chargeTotROC, std::array<std::vector<float>, 5>& chargeMaxROC);
165188

166189
/// \param rowOrder (sector, row) keys in the order they are first encountered while scanning the track's native cluster references (0..nClusterReferences-1), i.e. the track's true physical row-traversal order
167190
void handleSameRowClusters(o2::tpc::TrackTPC& track, std::vector<std::pair<unsigned char, unsigned char>>& rowOrder, 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);
@@ -175,7 +198,16 @@ class CalculatedEdx
175198
/// \param high higher cluster cut
176199
/// \param correctionMask to apply different corrections: TopologySimple = simple analytical topology correction, TopologyPol = topology correction from polynomials, GainFull = full gain map from calibration container,
177200
/// GainResidual = residuals gain map from calibration container, dEdxResidual = residual dEdx correction
178-
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");
201+
/// \param maxSubthresholdChargeTot upper limit for the per-region minimum qTot used as the virtual charge of a subthreshold cluster
202+
/// \param maxSubthresholdChargeMax upper limit for the per-region minimum qMax used as the virtual charge of a subthreshold cluster
203+
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", float maxSubthresholdChargeTot = 100000.f, float maxSubthresholdChargeMax = 100000.f);
204+
205+
/// evaluate several dEdx settings for the same track while performing the track refit/propagation to each cluster row only once
206+
/// \param track input track
207+
/// \param outputs output dEdxInfo, filled with one entry per entry in settingsList, in the same order
208+
/// \param averageOcc output average cluster occupancy of the track, per TPC region; a single value, since occupancy does not depend on the dEdx settings and is therefore the same for every entry in settingsList
209+
/// \param settingsList list of dEdx settings to evaluate for this track
210+
void calculatedEdxMultipleSettings(TrackTPC& track, std::vector<dEdxInfo>& outputs, AverageOccupancy& averageOcc, const std::vector<dEdxSettings>& settingsList);
179211

180212
/// get the truncated mean for the input charge vector and the truncation range low*nCl<nCl<high*nCl
181213
/// \param charge input vector
@@ -262,6 +294,50 @@ class CalculatedEdx
262294
void setPropagatorFromFile(const char* folder, const char* file, const char* object);
263295

264296
private:
297+
/// \brief per (sector,row) cluster/track data gathered once per track by gatherRowClusterData(), independent of the dEdx settings reused by calculatedEdxFromRowData() for each entry in a settingsList so the track refit/propagation done in gatherRowClusterData() is not repeated per setting
298+
struct RowClusterData {
299+
o2::tpc::ClusterNative cl; ///< cluster (combined if isCombined)
300+
o2::tpc::TrackTPC trackSnapshot; ///< track state after refit/propagation to this row's cluster
301+
unsigned char sectorIndex;
302+
unsigned char rowIndex;
303+
unsigned int region;
304+
unsigned char pad;
305+
GEMstack stack;
306+
int stackNumber;
307+
StackID stackID;
308+
float chargeTot;
309+
float chargeMax;
310+
float clPad;
311+
float clTime;
312+
float threshold;
313+
float gain;
314+
float gainResidual;
315+
unsigned int occupancy;
316+
bool isShared;
317+
bool isCombined;
318+
bool isDeadRegion;
319+
bool propagationFailed; ///< true if refit/propagation to this row failed, or the resulting track param is NaN
320+
int missingClusters; ///< number of skipped rows since the previous entry in rowData (i.e. rowIndex - previous rowIndex - 1); same for every settings entry since rowOrder does not depend on the settings
321+
bool sameSectorAsPrevRow; ///< true if this row's sector equals the previous entry in rowData's sector
322+
bool missingClusterGapDeadOrEdge; ///< true if any of the missingClusters skipped row(s) would land on a dead channel or off the padrow edge
323+
};
324+
325+
/// gather, for every (sector, row) of the track's row-traversal order, performing the refit/propagation to each cluster row exactly once
326+
/// \param track input track, mutated in place by refit/propagation
327+
/// \param rowData output per-row data
328+
/// \param averageOcc output average cluster occupancy of the track, per TPC region
329+
void gatherRowClusterData(o2::tpc::TrackTPC& track, std::vector<RowClusterData>& rowData, AverageOccupancy& averageOcc);
330+
331+
/// compute the dEdx output for one dEdx settings entry from the row data previously gathered by gatherRowClusterData()
332+
/// \param rowData per row data gathered by gatherRowClusterData() for the track being processed
333+
/// \param settings dEdx settings to apply
334+
/// \param settingsIndex index of settings within its settingsList
335+
/// \param trackTime0 track.getTime0() of the track being processed, captured before refit/propagation (unaffected by it)
336+
/// \param trackOrig pristine track (before refit/propagation mutated it), used for the debug "dEdxDebugTrack" row; ignored if mDebug is false
337+
/// \param averageOcc average cluster occupancy of the track as computed by gatherRowClusterData(), only used for the debug "dEdxDebugTrack" row; ignored if mDebug is false
338+
/// \param output output dEdxInfo
339+
void calculatedEdxFromRowData(const std::vector<RowClusterData>& rowData, const dEdxSettings& settings, size_t settingsIndex, float trackTime0, const o2::tpc::TrackTPC& trackOrig, const AverageOccupancy& averageOcc, dEdxInfo& output);
340+
265341
std::vector<TrackTPC>* mTracks{nullptr}; ///< vector containing the tpc tracks which will be processed
266342
std::vector<TPCClRefElem>* mTPCTrackClIdxVecInput{nullptr}; ///< input vector with TPC tracks cluster indicies
267343
const o2::tpc::ClusterNativeAccess* mClusterIndex{nullptr}; ///< needed to access clusternative with tpctracks
@@ -272,15 +348,16 @@ class CalculatedEdx
272348
std::unique_ptr<o2::gpu::GPUO2InterfaceRefit> mRefit{nullptr}; ///< TPC refitter used for TPC tracks refit during the reconstruction
273349

274350
int mMaxMissingCl{1}; ///< maximum number of missing clusters for subthreshold check
275-
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
276-
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
277351
float mFieldNominalGPUBz{5}; ///< magnetic field in kG, used for track propagation
278352
bool mPropagateTrack{false}; ///< propagating the track instead of performing a refit (faster than refit)
279353
bool mPropagateParams{false}; ///< propagating the parameters instead of full propagation (faster than track propagation)
280354
bool mDebug{false}; ///< use the debug streamer
281355
CalibdEdxContainer mCalibCont; ///< calibration container
282356
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
283357
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
358+
long mNPropagationFailed{0}; ///< number of rows where refit/propagation failed since the last resetDebugCounters()
359+
long mNRowsProcessed{0}; ///< number of rows gathered by gatherRowClusterData() since the last resetDebugCounters()
360+
std::vector<long> mNSubThresholdFilledPerSettings; ///< number of row gaps filled as subthreshold clusters, per dEdxSettings list index, since the last resetDebugCounters()
284361

285362
CorrectdEdxDistortions mSCdEdxCorrection; ///< for space-charge correction of dE/dx
286363

0 commit comments

Comments
 (0)