ATLAS Offline Software
Loading...
Searching...
No Matches
PixelClusteringTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
5
6#include <Acts/Clusterization/Clusterization.hpp>
7
12#include <TrkSurfaces/Surface.h>
13
14#include <unordered_set>
15#include <stdexcept>
16
17using CLHEP::micrometer;
18
19// Helper functions for use with ACTS clusterization
20// Put these in the InDet namespace so that ACTS can find them
21// via ADL.
22//
23namespace ActsTrk {
24 static inline int getCellRow(const typename PixelClusteringTool::Cell& cell) { return cell.ROW; }
25 static inline int getCellColumn(const typename PixelClusteringTool::Cell& cell) { return cell.COL; }
26 static inline void clusterReserve(PixelClusteringTool::Cluster& cl,
27 std::size_t n)
28 {
29 cl.ids.reserve(n);
30 cl.tots.reserve(n);
31 }
32 static inline void clusterAddCell(PixelClusteringTool::Cluster& cl,
33 const PixelClusteringTool::Cell& cell)
34 {
35 cl.ids.push_back(cell.ID);
36 cl.tots.push_back(cell.TOT);
37 if (cell.LVL1 < cl.lvl1min)
38 cl.lvl1min = cell.LVL1;
39 }
40
42{
43 ATH_MSG_DEBUG("Initializing " << name() << " ...");
44
49
51
52 ATH_CHECK(m_chargeDataKey.initialize(not m_chargeDataKey.empty()));
53
54 ATH_MSG_INFO(" Charge Data Key:" << m_chargeDataKey);
55
56 ATH_CHECK( detStore()->retrieve(m_pixelID, "PixelID") );
57
58 ATH_MSG_DEBUG(name() << " successfully initialized");
59 return StatusCode::SUCCESS;
60}
61
63 const std::string& type, const std::string& name, const IInterface* parent)
64 : base_class(type,name,parent)
65{}
66
67StatusCode
68PixelClusteringTool::makeCluster(PixelClusteringTool::Cluster &cluster,
69 const InDetDD::SiDetectorElement* element,
70 const InDetDD::PixelModuleDesign& design,
71 const PixelChargeCalibCondData *calibData,
73 const double lorentz_shift,
74 size_t icluster,
75 xAOD::PixelCluster::ClusterVars& clusterVars) const
76{
77
78 Amg::Vector2D pos_acc(0,0);
79 int tot_acc = 0;
80
81 std::vector<float> chargeList;
82 if (calibData) chargeList.reserve(cluster.ids.size());
83
84 InDetDD::PixelDiodeTree::CellIndexType rowmax = std::numeric_limits<InDetDD::PixelDiodeTree::CellIndexType>::min();
85 InDetDD::PixelDiodeTree::CellIndexType colmax = std::numeric_limits<InDetDD::PixelDiodeTree::CellIndexType>::min();
86 InDetDD::PixelDiodeTree::CellIndexType rowmin = std::numeric_limits<InDetDD::PixelDiodeTree::CellIndexType>::max();
87 InDetDD::PixelDiodeTree::CellIndexType colmin = std::numeric_limits<InDetDD::PixelDiodeTree::CellIndexType>::max();
92
93 // We temporary comment this since it is not used
94 // bool hasGanged = false;
95
96 IdentifierHash moduleHash = element->identifyHash();
97
98 for (size_t i = 0; i < cluster.ids.size(); i++) {
99
100 //Construct the identifier class
101 Identifier id = Identifier(cluster.ids[i]);
102
103 // We temporary comment this since it is not used
104 // TODO: Check how the ganged info is used in legacy
105 // if (multiChip) {
106 // hasGanged = hasGanged ||
107 // m_pixelRDOTool->isGanged(id, element).has_value();
108 // }
109
110 int tot = cluster.tots.at(i);
111 float charge = tot;
112
113 std::array<InDetDD::PixelDiodeTree::CellIndexType,2> diode_idx
115 m_pixelID->eta_index(id));
117
118 if (calibData) {
119 // Retrieving the calibration only depends on FE and not per cell (can be further optimized)
120 // Single FE modules could have an optimized getCharge function where the calib constants are cached
121 std::uint32_t feValue = design.getFE(si_param);
122 auto diode_type = design.getDiodeType(si_param);
123 if (m_isITk){
125 ATH_MSG_ERROR("Chip type is not recognized!");
126 return StatusCode::FAILURE;
127 }
128
129 charge = calibData->getCharge(diode_type,
130 calibStrategy,
131 moduleHash,
132 feValue,
133 tot);
134 chargeList.push_back(charge);
135 } else {
136 charge = calibData->getCharge(diode_type,
137 moduleHash,
138 feValue,
139 tot);
140
141 // These numbers are taken from the Cluster Maker Tool
142 if (design.getReadoutTechnology() != InDetDD::PixelReadoutTechnology::RD53 && (moduleHash < 12 or moduleHash > 2035)) {
143 charge = tot/8.0*(8000.0-1200.0)+1200.0;
144 }
145 chargeList.push_back(charge);
146 }
147 }
148
149 const InDetDD::PixelDiodeTree::CellIndexType &row = diode_idx[0];
150 const InDetDD::PixelDiodeTree::CellIndexType &col = diode_idx[1];
151 if (row>rowmax) {
152 rowmax=row;
153 rowmax_diode = si_param;
154 }
155 if (row<rowmin) {
156 rowmin=row;
157 rowmin_diode = si_param;
158 }
159 if (col>colmax) {
160 colmax=col;
161 colmax_diode = si_param;
162 }
163 if (col<colmin) {
164 colmin=col;
165 colmin_diode = si_param;
166 }
167
168 // We compute the digital position as a sum of all RDO positions
169 // all with the same weight of 1
170 // We do not compute a charge-weighted center of gravity here (by default) since
171 // we observe it to be worse than the digital position
172 // ToT-weighted center of gravity must not be used
173 if (m_useWeightedPos) {
174 pos_acc += charge * si_param.position();
175 tot_acc += charge;
176 } else {
177 pos_acc += si_param.position();
178 tot_acc += 1;
179 }
180
181 }
182
183 if (tot_acc > 0)
184 pos_acc /= tot_acc;
185
186
187 const int colWidth = colmax - colmin + 1;
188 const int rowWidth = rowmax - rowmin + 1;
189
190 double etaWidth = colmax_diode.xEtaMax() - colmin_diode.xEtaMin(); // design.widthFromColumnRange(colmin, colmax);
191 double phiWidth = rowmax_diode.xPhiMax() - rowmin_diode.xPhiMin(); // design.widthFromColumnRange(colmin, colmax);
192
193 // ask for Lorentz correction, get global position
194 const Amg::Vector2D localPos = pos_acc;
195 Amg::Vector2D locpos(localPos[Trk::locX]+lorentz_shift, localPos[Trk::locY]);
196 // find global position of element
197 const Amg::Transform3D& T = element->surface().transform();
198 double Ax[3] = {T(0,0),T(1,0),T(2,0)};
199 double Ay[3] = {T(0,1),T(1,1),T(2,1)};
200 double R [3] = {T(0,3),T(1,3),T(2,3)};
201
202 const Amg::Vector2D& M = locpos;
203 Amg::Vector3D globalPos(M[0]*Ax[0]+M[1]*Ay[0]+R[0],M[0]*Ax[1]+M[1]*Ay[1]+R[1],M[0]*Ax[2]+M[1]*Ay[2]+R[2]);
204
205 // Compute error matrix
206 float width0, width1;
207 if (m_broadErrors) {
208 // Use cluster width
209 width0 = phiWidth;
210 width1 = etaWidth;
211 } else {
212 // Use average pixel width
213 width0 = phiWidth / rowWidth;
214 width1 = etaWidth / colWidth;
215 }
216
217 // Actually create the cluster (i.e. fill the values)
218
219 Eigen::Matrix<float,2,1> localPosition(locpos.x(), locpos.y());
220 Eigen::Matrix<float,2,2> localCovariance = Eigen::Matrix<float,2,2>::Zero();
221 localCovariance(0, 0) = width0 * width0 / 12.0f;
222 localCovariance(1, 1) = width1 * width1 / 12.0f;
223
224 clusterVars.identifierHash[icluster] = moduleHash;
225 xAOD::VectorMap<2>(clusterVars.localPositionDim2[icluster].data()) = localPosition;
226 xAOD::MatrixMap<2>(clusterVars.localCovarianceDim2[icluster].data()) = localCovariance;
227 clusterVars.identifier[icluster] = cluster.ids.front();
228 clusterVars.rdoList[icluster] = std::move(cluster.ids);
229 xAOD::VectorMap<3>(clusterVars.globalPosition[icluster].data()) = globalPos.cast<float>();
230 clusterVars.totList[icluster] = std::move(cluster.tots);
231 clusterVars.lvl1a[icluster] = cluster.lvl1min;
232 clusterVars.channelsInPhi[icluster] = rowWidth;
233 clusterVars.channelsInEta[icluster] = colWidth;
234 clusterVars.widthInEta[icluster] = etaWidth;
235
236 return StatusCode::SUCCESS;
237}
238
239StatusCode
240PixelClusteringTool::clusterize(const EventContext& /*ctx*/,
241 const RawDataCollection& RDOs,
242 const InDet::SiDetectorElementStatus& pixelDetElStatus,
243 const InDetDD::SiDetectorElement& element,
244 Acts::Ccl::ClusteringData& data,
245 std::vector<ClusterCollection>& collection) const
246{
247 IdentifierHash idHash = RDOs.identifyHash();
248 collection.emplace_back();
249 if ( not pixelDetElStatus.isGood(idHash) ) {
250 // the module being flagged as bad is not a failure
251 // An empty cluster collection needs to be added because the assumption
252 // is that there is one element per element RawDataCollection.
253 return StatusCode::SUCCESS;
254 }
255
256 // Retrieve the cells from the detector element
257 CellCollection cells = unpackRDOs(RDOs, pixelDetElStatus, element);
258
259 Acts::Ccl::createClusters<CellCollection, ClusterCollection, 2>
260 (data, cells, collection.back(), Acts::Ccl::DefaultConnect<Cell, 2>(m_addCorners));
261
262 return StatusCode::SUCCESS;
263}
264
265
267{
268 return std::any (xAOD::PixelCluster::ClusterVars (cont));
269}
270
271
272StatusCode
273PixelClusteringTool::makeClusters(const EventContext& ctx,
275 const InDetDD::SiDetectorElement& element,
276 size_t icluster,
277 std::any& vars,
278 typename ClusterContainer::iterator /*itrContainer*/) const
279{
280 // Retrieve the calibration data
281 const PixelChargeCalibCondData *calibData = nullptr;
282 if (not m_chargeDataKey.empty()) {
284 calibData = calibDataHandle.cptr();
285
286 if (!calibData) {
287 ATH_MSG_ERROR("PixelChargeCalibCondData requested but couldn't be retrieved from " << m_chargeDataKey.key());
288 return StatusCode::FAILURE;
289 }
290 }
291
292 // Get the element design
293 const InDetDD::PixelModuleDesign& design =
294 static_cast<const InDetDD::PixelModuleDesign&>(element.design());
295
296 // Get the calibration strategy for this module.
297 // Default to RD53 if the calibData is not available. That is fine because it won't be used anyway
298 auto calibrationStrategy = calibData ? calibData->getCalibrationStrategy(element.identifyHash()) : PixelChargeCalibCondData::CalibrationStrategy::RD53;
299
300 double lorentz_shift = m_pixelLorentzAngleTool->getLorentzShift(element.identifyHash(), ctx);
301
302 auto* clusterVars = std::any_cast<xAOD::PixelCluster::ClusterVars> (&vars);
303 if (!clusterVars) throw std::bad_any_cast();
304
305 for (typename IPixelClusteringTool::Cluster& cl : clusters) {
307 &element,
308 design,
309 calibData,
310 calibrationStrategy,
311 lorentz_shift,
312 icluster++,
313 *clusterVars));
314 }
315
316 return StatusCode::SUCCESS;
317}
318
320PixelClusteringTool::unpackRDOs(const RawDataCollection& RDOs,
321 const InDet::SiDetectorElementStatus& pixelDetElStatus,
322 const InDetDD::SiDetectorElement& element) const
323{
324 // Get the element design
325 const InDetDD::PixelModuleDesign& design =
326 static_cast<const InDetDD::PixelModuleDesign&>(element.design());
327 CellCollection cells;
328 cells.reserve(300);
329
330 const IdentifierHash& idHash = RDOs.identifyHash();
331 for (const auto *const rdo : RDOs) {
332 const Identifier& rdoID = rdo->identify();
333 std::array<InDetDD::PixelDiodeTree::CellIndexType,2> diode_idx
335 m_pixelID->eta_index(rdoID));
336 InDetDD::PixelDiodeTree::DiodeProxy si_param ( design.diodeProxyFromIdx(diode_idx));
337 std::uint32_t fe = design.getFE(si_param);
338
339 // check if good RDO
340 // the pixel RDO tool here says always good if m_useModuleMap is false
341 if (not pixelDetElStatus.isChipGood(idHash, fe)) {
342 continue;
343 }
344
345 const int lvl1 = rdo->getLVL1A();
346 const int tot = rdo->getToT();
347
348 cells.emplace_back(m_pixelID->phi_index(rdoID),
349 m_pixelID->eta_index(rdoID),
350 tot,
351 lvl1,
352 rdoID.get_compact());
353
354 if ( m_checkGanged ) {
355 std::optional<Identifier> gangedID = isGanged(rdoID, element);
356 if (gangedID.has_value()) {
357 cells.emplace_back(m_pixelID->phi_index(*gangedID),
358 m_pixelID->eta_index(*gangedID),
359 tot,
360 lvl1,
361 gangedID->get_compact());
362 }
363 }
364
365 }
366
367 return cells;
368}
369
370inline std::optional<Identifier>
372 const InDetDD::SiDetectorElement& element)
373{
374 // If the pixel is ganged, returns a new identifier for it
375 InDetDD::SiCellId cellID = element.cellIdFromIdentifier( rdoID );
376 if ( element.numberOfConnectedCells( cellID ) > 1 ) {
377 InDetDD::SiCellId gangedCellID = element.connectedCell( cellID, 1 );
378 return element.identifierFromCellId( gangedCellID );
379 }
380 return std::nullopt;
381}
382
383} // namespace ActsTrk
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
double charge(const T &p)
Definition AtlasPID.h:997
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
PixelClusteringTool(const std::string &type, const std::string &name, const IInterface *parent)
IPixelClusteringTool::CellCollection unpackRDOs(const RawDataCollection &RDOs, const InDet::SiDetectorElementStatus &stripDetElStatus, const InDetDD::SiDetectorElement &element) const
Gaudi::Property< bool > m_broadErrors
virtual StatusCode clusterize(const EventContext &ctx, const RawDataCollection &RDOs, const InDet::SiDetectorElementStatus &pixelDetElStatus, const InDetDD::SiDetectorElement &element, Acts::Ccl::ClusteringData &data, std::vector< ClusterCollection > &collection) const override
SG::ReadCondHandleKey< PixelChargeCalibCondData > m_chargeDataKey
virtual StatusCode initialize() override
StatusCode makeCluster(PixelClusteringTool::Cluster &cluster, const InDetDD::SiDetectorElement *element, const InDetDD::PixelModuleDesign &design, const PixelChargeCalibCondData *calibData, const PixelChargeCalibCondData::CalibrationStrategy calibStrategy, double lorentz_shift, size_t icluster, xAOD::PixelCluster::ClusterVars &clusterVars) const
static std::optional< Identifier > isGanged(const Identifier &rdoID, const InDetDD::SiDetectorElement &element)
Gaudi::Property< bool > m_checkGanged
virtual std::any makeVars(SG::AuxVectorData &cont) const override
virtual StatusCode makeClusters(const EventContext &ctx, typename IPixelClusteringTool::ClusterCollection &clusters, const InDetDD::SiDetectorElement &element, size_t icluster, std::any &vars, typename ClusterContainer::iterator itrContainer) const override
Gaudi::Property< bool > m_addCorners
ToolHandle< ISiLorentzAngleTool > m_pixelLorentzAngleTool
Gaudi::Property< bool > m_isITk
Gaudi::Property< bool > m_useWeightedPos
This is a "hash" representation of an Identifier.
value_type get_compact() const
Get the compact id.
static constexpr std::array< PixelDiodeTree::CellIndexType, 2 > makeCellIndex(T local_x_idx, T local_y_idx)
Create a 2D cell index from the indices in local-x (phi, row) and local-y (eta, column) direction.
Class used to describe the design of a module (diode segmentation and readout scheme)
PixelDiodeTree::DiodeProxyWithPosition diodeProxyFromIdxCachePosition(const std::array< PixelDiodeTree::IndexType, 2 > &idx) const
PixelReadoutTechnology getReadoutTechnology() const
PixelDiodeTree::DiodeProxy diodeProxyFromIdx(const std::array< PixelDiodeTree::IndexType, 2 > &idx) const
static InDetDD::PixelDiodeType getDiodeType(const PixelDiodeTree::DiodeProxy &diode_proxy)
static unsigned int getFE(const PixelDiodeTree::DiodeProxy &diode_proxy)
Identifier for the strip or pixel cell.
Definition SiCellId.h:29
Class to hold geometrical description of a silicon detector element.
virtual SiCellId cellIdFromIdentifier(const Identifier &identifier) const override final
SiCellId from Identifier.
virtual const SiDetectorDesign & design() const override final
access to the local description (inline):
virtual Identifier identifierFromCellId(const SiCellId &cellId) const override final
Identifier <-> SiCellId (ie strip number or pixel eta_index,phi_index) Identifier from SiCellId (ie s...
SiCellId connectedCell(const SiCellId cellId, int number) const
Get the cell ids sharing the readout for this cell.
virtual IdentifierHash identifyHash() const override final
identifier hash (inline)
int numberOfConnectedCells(const SiCellId cellId) const
Test if readout cell has more than one diode associated with it.
Trk::Surface & surface()
Element Surface.
bool isChipGood(IdentifierHash hash, unsigned int chip) const
bool isGood(IdentifierHash hash) const
CalibrationStrategy getCalibrationStrategy(unsigned int moduleHash) const
float getCharge(InDetDD::PixelDiodeType type, unsigned int moduleHash, unsigned int FE, float ToT) const
Manage lookup of vectors of auxiliary data.
const_pointer_type cptr()
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
static int getCellRow(const typename PixelClusteringTool::Cell &cell)
static void clusterAddCell(PixelClusteringTool::Cluster &cl, const PixelClusteringTool::Cell &cell)
static int getCellColumn(const typename PixelClusteringTool::Cell &cell)
static void clusterReserve(PixelClusteringTool::Cluster &cl, std::size_t n)
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
@ locY
local cartesian
Definition ParamDefs.h:38
@ locX
Definition ParamDefs.h:37
Eigen::Map< MeasVector< N > > VectorMap
Eigen::Map< MeasMatrix< N > > MatrixMap
A diode proxy which caches the position of a diode.
double xPhiMax() const
for backward compatibility, return the position of the lower edge of the diode in local-y(phi,...
double xEtaMin() const
for backward compatibility, return the position of the lower edge of the diode in local-y(eta,...
double xPhiMin() const
for backward compatibility, return the position of the lower edge of the diode in local-x(phi,...
const Vector2D & position() const
get the cached position of this diode
double xEtaMax() const
for backward compatibility, return the position of the upper edge of the diode in local-y(eta,...
Helper class to access parameters of a diode.