ATLAS Offline Software
Loading...
Searching...
No Matches
StripClusteringTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7
8#include <Acts/Clusterization/Clusterization.hpp>
9
13#include <TrkSurfaces/Surface.h>
14
15#include <algorithm>
16#include <stdexcept>
17
18
19namespace ActsTrk {
20constexpr double ONE_TWELFTH = 1./12.;
21constexpr float oneStripSF = 1.1025;
22constexpr float twoStripSF = 0.0729;
23
24 // Required by ACTS clusterization
25static
26int getCellColumn(const StripClusteringTool::Cell& cell)
27{
28 return cell.index;
29}
30
31// Required by ACTS clusterization
32static inline void clusterReserve(StripClusteringTool::Cluster& cl,
33 std::size_t n)
34{
35 cl.ids.reserve(n);
36}
37
38// Required by ACTS clusterization
39static
40void clusterAddCell(StripClusteringTool::Cluster& cl, const StripClusteringTool::Cell& cell)
41{
42 cl.ids.push_back(cell.id.get_compact());
43 if (cl.ids.size() < (sizeof(cl.hitsInThirdTimeBin) * 8)) {
44 cl.hitsInThirdTimeBin |= cell.timeBits.test(0) << cl.ids.size();
45 }
46}
47
49 const std::string& type, const std::string& name, const IInterface* parent)
50 : base_class(type,name,parent)
51{
52}
53
55{
56 ATH_MSG_DEBUG("Initializing " << name() << "...");
57
64
65
66 ATH_CHECK(m_conditionsTool.retrieve(DisableTool{!m_stripDetElStatus.empty()} ));
67 ATH_CHECK(m_lorentzAngleTool.retrieve());
69
70 ATH_CHECK(m_stripDetElStatus.initialize(not m_stripDetElStatus.empty()));
71 ATH_CHECK(m_stripDetEleCollKey.initialize());
72
73 ATH_CHECK( detStore()->retrieve(m_stripID, "SCT_ID") );
74
75 return StatusCode::SUCCESS;
76}
77
79{
80 for (size_t i = 0; i < m_timeBinStr.size(); i++) {
81 if (i >= 3) {
82 ATH_MSG_WARNING("Time bin string has excess characters");
83 break;
84 }
85 switch (std::toupper(m_timeBinStr[i])) {
86 case 'X': m_timeBinBits[i] = -1; break;
87 case '0': m_timeBinBits[i] = 0; break;
88 case '1': m_timeBinBits[i] = 1; break;
89 default:
90 ATH_MSG_FATAL("Invalid time bin string: " << m_timeBinStr);
91 return StatusCode::FAILURE;
92 }
93 }
94 return StatusCode::SUCCESS;
95}
96
97StatusCode
98StripClusteringTool::clusterize(const EventContext& ctx,
99 const RawDataCollection& RDOs,
100 const InDet::SiDetectorElementStatus& stripDetElStatus,
101 const InDetDD::SiDetectorElement& element,
102 Acts::Ccl::ClusteringData& data,
103 std::vector<typename IStripClusteringTool::ClusterCollection>& collection) const
104{
105 IdentifierHash idHash = RDOs.identifyHash();
106 // At least an empty cluster collection needs to be always added because the
107 // assumption is that there is one element per element RawDataCollection.
108 collection.emplace_back();
109 bool goodModule = true;
110 if (m_checkBadModules.value()) {
111 goodModule = stripDetElStatus.isGood(idHash);
112 }
113
115 m_checkBadModules.value() && !m_stripDetElStatus.empty(),
116 stripDetElStatus.isGood(idHash), m_conditionsTool->isGood(idHash));
117
118 if (!goodModule) {
119 ATH_MSG_DEBUG("Strip module failed status check");
120 return StatusCode::SUCCESS;
121 }
122
123 // If more than a certain number of RDOs set module to bad
124 // in this case we skip clusterization
125 if (m_maxFiredStrips != 0u) {
126 unsigned int nFiredStrips = 0u;
127 for (const SCT_RDORawData* rdo : RDOs) {
128 nFiredStrips += rdo->getGroupSize();
129 }
130 if (nFiredStrips > m_maxFiredStrips)
131 return StatusCode::SUCCESS;
132 }
133
134 std::optional<std::pair<typename IStripClusteringTool::CellCollection,bool>> unpckd
135 = unpackRDOs(ctx, RDOs, stripDetElStatus, element);
136
137 if (not unpckd.has_value()) {
138 ATH_MSG_FATAL("Error encountered while unpacking strip RDOs!");
139 return StatusCode::FAILURE;
140 }
141
142 auto& [cells, badStripOnModule] = *unpckd;
143 // Bad strips on a module invalidates the hitsInThirdTimeBin word.
144 // Therefore set it to 0 if that's the case.
145 // We are currently not using this, but keeping it here should we need it in the future
146
147 Acts::Ccl::createClusters<CellCollection, typename IStripClusteringTool::ClusterCollection, 1>(data, cells, collection.back());
148
149 return StatusCode::SUCCESS;
150}
151
152
153StatusCode
154StripClusteringTool::makeClusters(const EventContext& ctx,
156 const InDetDD::SiDetectorElement& element,
157 size_t /*icluster*/,
158 std::any& /*vars*/,
159 typename ClusterContainer::iterator itrContainer) const
160{
161 const IdentifierHash idHash = element.identifyHash();
162 double lorentzShift = m_lorentzAngleTool->getLorentzShift(idHash, ctx);
163
164 const InDetDD::SiDetectorDesign& design = element.design();
165 // get the pitch, this will be the local covariance for the cluster
166
167 assert((not m_isITk) || element.isBarrel() || dynamic_cast<const InDetDD::StripStereoAnnulusDesign*>(&element.design()) !=nullptr);
168 float pitch = (element.isBarrel() or (not m_isITk))
169 ? design.phiPitch()
170 : static_cast<const InDetDD::StripStereoAnnulusDesign&>(element.design()).phiPitchPhi();
171 Eigen::Matrix<float,1,1> localCov(pitch * pitch * ONE_TWELFTH);
172
173 for (typename IStripClusteringTool::Cluster& cl : clusters) {
174 try {
175 xAOD::StripCluster *xaodCluster = *itrContainer;
177 lorentzShift,
178 localCov,
179 *m_stripID,
180 element,
181 design,
182 *xaodCluster));
183 ++itrContainer;
184 } catch (const std::exception& e) {
185 ATH_MSG_FATAL("Exception thrown while creating xAOD::StripCluster:"
186 << e.what());
187 ATH_MSG_FATAL("Detector Element identifier: " << element.identify());
188 ATH_MSG_FATAL("Strip Identifiers in cluster:");
189 for (const auto& id : cl.ids)
190 ATH_MSG_FATAL(" " << id);
191 return StatusCode::FAILURE;
192 }
193 }
194
195 return StatusCode::SUCCESS;
196}
197
198static
199std::pair<
200 Eigen::Matrix<float,1,1>,
201 Eigen::Matrix<float,3,1>>
202computePosition(const StripClusteringTool::Cluster& cluster,
203 std::size_t size,
204 double lorentzShift,
205 const IStripClusteringTool::IDHelper& stripID,
206 const InDetDD::SiDetectorElement& element,
207 const InDetDD::SiDetectorDesign& design,
208 bool isITk )
209{
210
211 Identifier ids_front(cluster.ids.front());
212 Identifier ids_back(cluster.ids.back());
213 InDetDD::SiCellId frontId = stripID.strip(ids_front);
214 InDetDD::SiLocalPosition pos = design.localPositionOfCell(frontId);
215 if (size > 1) {
216 InDetDD::SiCellId backId = stripID.strip(ids_back);
218 design.localPositionOfCell(backId);
219 pos = 0.5 * (pos + backPos);
220 }
221
222 // update the xPhi position
223 pos.xPhi( pos.xPhi() + lorentzShift );
224 Eigen::Matrix<float,3,1> posG(element.surface().localToGlobal(pos).cast<float>());
225
226 if ((not element.isBarrel()) and isITk) {
227 assert(dynamic_cast<const InDetDD::StripStereoAnnulusDesign*>(&design) != nullptr);
228 const InDetDD::StripStereoAnnulusDesign& annulusDesign =
229 static_cast<const InDetDD::StripStereoAnnulusDesign&>
230 (design);
231 pos = annulusDesign.localPositionOfCellPC(element.cellIdOfPosition(pos));
232 }
233
234 return std::make_pair(Eigen::Matrix<float,1,1>(pos.xPhi()),
235 std::move(posG));
236}
237
238
239// N.B. the cluster is added to the container
240StatusCode
242 double lorentzShift,
243 Eigen::Matrix<float,1,1>& localCov,
244 const StripID& stripID,
245 const InDetDD::SiDetectorElement& element,
246 const InDetDD::SiDetectorDesign& design,
247 xAOD::StripCluster& cl) const
248{
249 std::size_t size = cluster.ids.size();
250
251 auto [localPos, globalPos]
252 = computePosition(cluster, size, lorentzShift, stripID, element, design, m_isITk);
253
254 // For Strip Clusters the identifier is taken from the front rod list object
255 // This is the same strategy used in Athena:
256 // Since clusterId is arbitary (it only needs to be unique) just use ID of first strip
257 // For strip Cluster it has been found that "identifierOfPosition" does not produces unique values
258
259
260 // If requiring broad errors, use the cluster size as error -
261 // TODO use SiWidth to get the right cluster size as I'm assuming equal strip pitch
262
263 if (m_errorStrategy == 1) {// use width
264
265 localCov *= size*size;
266
267 } else if (m_errorStrategy == 2) { //use tuned error as function of size
268
269 if (size == 1)
270 localCov *= oneStripSF;
271 else if (size == 2)
272 localCov *= twoStripSF*size*size;
273 else
274 localCov *= size*size;
275
276 }
277
278 cl.setMeasurement<1>(element.identifyHash(), localPos, localCov);
279 cl.setIdentifier( cluster.ids.front() );
280
281 // Do I really need the global position in fast tracking?
282 cl.globalPosition() = globalPos;
283
284 cl.setChannelsInPhi(size);
285 cl.setRDOlist(std::move(cluster.ids));
286
287 return StatusCode::SUCCESS;
288}
289
290
291bool StripClusteringTool::passTiming(const std::bitset<3>& timePattern) const {
292 // Convert the given timebin to a bit set and test each bit
293 // if bit is -1 (i.e. X) it always passes, other wise require exact match of 0/1
294 // N.B bitset has opposite order to the bit pattern we define
295 if (m_timeBinBits[0] != -1 and timePattern.test(2) != static_cast<bool>(m_timeBinBits[0])) return false;
296 if (m_timeBinBits[1] != -1 and timePattern.test(1) != static_cast<bool>(m_timeBinBits[1])) return false;
297 if (m_timeBinBits[2] != -1 and timePattern.test(0) != static_cast<bool>(m_timeBinBits[2])) return false;
298 return true;
299}
300
301
302bool StripClusteringTool::isBadStrip(const EventContext& ctx,
303 const InDet::SiDetectorElementStatus *stripDetElStatus,
304 const StripID& stripID,
305 IdentifierHash waferHash,
306 Identifier stripId) const
307{
308 if (stripDetElStatus) {
309 const int strip_i{stripID.strip(stripId)};
311 stripDetElStatus,
312 stripDetElStatus->isCellGood(waferHash.value(), strip_i),
314 return not stripDetElStatus->isCellGood(waferHash.value(), strip_i) ;
315 }
316 return not m_conditionsTool->isGood(stripId, InDetConditions::SCT_STRIP, ctx);
317}
318
319
320std::optional<std::pair<typename IStripClusteringTool::CellCollection, bool>>
321StripClusteringTool::unpackRDOs(const EventContext& ctx,
322 const RawDataCollection& RDOs,
323 const InDet::SiDetectorElementStatus& stripDetElStatus,
324 const InDetDD::SiDetectorElement& element) const
325{
326 const InDetDD::SiDetectorDesign& design = element.design();
327
328 CellCollection cells;
329 // reserve memory. number evaluated on ttbar pu200
330 cells.reserve(60);
331 bool badStripOnModule{false};
332 //Check type in debug build otherwise assume it is correct
333 assert(dynamic_cast<const InDetDD::SCT_ModuleSideDesign*>(&design)!=nullptr);
334 std::size_t ncells = static_cast<size_t>(static_cast<const InDetDD::SCT_ModuleSideDesign&>(design).cells());
335
336 // Simple single-entry cache
337 Identifier::value_type waferId_compact_cache = 0;
338 IdentifierHash waferHash_cache(0);
339 bool cache_valid = false;
340
341 for (const StripRDORawData * raw : RDOs) {
342
343 //Check type in debug build otherwise assume it is correct
344 assert(static_cast<const SCT3_RawData*>(raw)!=nullptr);
345 const SCT3_RawData* raw3 = static_cast<const SCT3_RawData*>(raw);
346
347 std::bitset<3> timePattern(raw3->getTimeBin());
348 if (!passTiming(timePattern)) {
349 ATH_MSG_DEBUG("Strip failed timing check");
350 continue;
351 }
352
353 Identifier firstStripId = raw->identify();
354 Identifier waferId = m_stripID->wafer_id(firstStripId);
355
356 Identifier::value_type waferId_compact = waferId.get_compact();
357
358
359 // Check cache - will be invalid when switching wafer groups
360 if (!cache_valid || waferId_compact != waferId_compact_cache) {
361 waferId_compact_cache = waferId_compact;
362 waferHash_cache = m_stripID->wafer_hash(waferId);
363 cache_valid = true;
364 }
365
366 std::size_t iFirstStrip = static_cast<size_t>(m_stripID->strip(firstStripId));
367
368 std::size_t iMaxStrip = std::min(
369 iFirstStrip + raw->getGroupSize(),
370 ncells
371 );
372
373 for (size_t i = iFirstStrip; i < iMaxStrip; i++) {
374 Identifier stripIdent = m_stripID->strip_id(waferId, i);
375 if (isBadStrip(ctx, &stripDetElStatus, *m_stripID, waferHash_cache, stripIdent)) {
376 // Bad strip, throw it out to minimize useless work.
377 ATH_MSG_DEBUG("Bad strip encountered:" << stripIdent
378 << ", wafer is: " << waferId);
379 badStripOnModule = true;
380 } else {
381 // Good strip!
382 cells.emplace_back(i, stripIdent, std::move(timePattern));
383 }
384 }
385 }
386
387 return std::make_pair(std::move(cells), badStripOnModule);
388}
389
390} // namespace ActsTrk
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_FATAL(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
#define VALIDATE_STATUS_ARRAY(use_info, info_val, summary_val)
std::vector< Cluster > ClusterCollection
Gaudi::Property< bool > m_isITk
ToolHandle< IInDetConditionsTool > m_conditionsTool
Gaudi::Property< unsigned int > m_maxFiredStrips
Gaudi::Property< bool > m_checkBadModules
bool passTiming(const std::bitset< 3 > &timePattern) const
virtual StatusCode initialize() override
bool isBadStrip(const EventContext &ctx, const InDet::SiDetectorElementStatus *sctDetElStatus, const StripID &idHelper, IdentifierHash waferHash, Identifier stripId) const
StripClusteringTool(const std::string &type, const std::string &name, const IInterface *parent)
ToolHandle< ISiLorentzAngleTool > m_lorentzAngleTool
virtual StatusCode makeClusters(const EventContext &ctx, typename IStripClusteringTool::ClusterCollection &cluster, const InDetDD::SiDetectorElement &element, size_t icluster, std::any &vars, typename ClusterContainer::iterator itrContainer) const override
StatusCode makeCluster(StripClusteringTool::Cluster &cluster, double LorentzShift, Eigen::Matrix< float, 1, 1 > &localCov, const StripID &stripID, const InDetDD::SiDetectorElement &element, const InDetDD::SiDetectorDesign &design, xAOD::StripCluster &container) const
virtual StatusCode clusterize(const EventContext &ctx, const InDetRawDataCollection< StripRDORawData > &RDOs, const InDet::SiDetectorElementStatus &stripDetElStatus, const InDetDD::SiDetectorElement &element, Acts::Ccl::ClusteringData &data, std::vector< typename IStripClusteringTool::ClusterCollection > &collection) const override
SG::ReadCondHandleKey< InDetDD::SiDetectorElementCollection > m_stripDetEleCollKey
Gaudi::Property< unsigned int > m_errorStrategy
SG::ReadHandleKey< InDet::SiDetectorElementStatus > m_stripDetElStatus
std::optional< std::pair< typename IStripClusteringTool::CellCollection, bool > > unpackRDOs(const EventContext &ctx, const RawDataCollection &RDOs, const InDet::SiDetectorElementStatus &stripDetElStatus, const InDetDD::SiDetectorElement &element) const
This is a "hash" representation of an Identifier.
constexpr value_type value() const
value_type get_compact() const
Get the compact id.
virtual SiLocalPosition localPositionOfCell(const SiCellId &cellId) const =0
readout or diode id -> position.
virtual double phiPitch() const =0
Pitch in phi direction.
Base class for the SCT module side design, extended by the Forward and Barrel module design.
int cells() const
number of readout stips within module side:
Identifier for the strip or pixel cell.
Definition SiCellId.h:29
Base class for the detector design classes for Pixel and SCT.
Class to hold geometrical description of a silicon detector element.
virtual const SiDetectorDesign & design() const override final
access to the local description (inline):
Class to represent a position in the natural frame of a silicon sensor, for Pixel and SCT For Pixel: ...
SiCellId cellIdOfPosition(const Amg::Vector2D &localPos) const
As in previous method but returns SiCellId.
virtual IdentifierHash identifyHash() const override final
identifier hash (inline)
virtual Identifier identify() const override final
identifier of this detector element (inline)
Trk::Surface & surface()
Element Surface.
double phiPitchPhi(const SiLocalPosition &localPosition) const
SiLocalPosition localPositionOfCellPC(const SiCellId &cellId) const
This is for debugging only.
bool isCellGood(IdentifierHash hash, unsigned short cell_i) const
bool isGood(IdentifierHash hash) const
int getTimeBin() const
int strip(const Identifier &id) const
Definition SCT_ID.h:717
virtual void localToGlobal(const Amg::Vector2D &locp, const Amg::Vector3D &mom, Amg::Vector3D &glob) const =0
Specified by each surface type: LocalToGlobal method without dynamic memory allocation.
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
constexpr float oneStripSF
static std::pair< Eigen::Matrix< float, 1, 1 >, Eigen::Matrix< float, 3, 1 > > computePosition(const StripClusteringTool::Cluster &cluster, std::size_t size, double lorentzShift, const IStripClusteringTool::IDHelper &stripID, const InDetDD::SiDetectorElement &element, const InDetDD::SiDetectorDesign &design, bool isITk)
static void clusterAddCell(PixelClusteringTool::Cluster &cl, const PixelClusteringTool::Cell &cell)
constexpr float twoStripSF
constexpr double ONE_TWELFTH
static int getCellColumn(const typename PixelClusteringTool::Cell &cell)
static void clusterReserve(PixelClusteringTool::Cluster &cl, std::size_t n)
StripCluster_v1 StripCluster
Define the version of the strip cluster class.