ATLAS Offline Software
Loading...
Searching...
No Matches
PixelClusteringTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
5
6#include <Acts/Clusterization/Clusterization.hpp>
7
13#include <TrkSurfaces/Surface.h>
14
15#include <unordered_set>
16#include <stdexcept>
17
18using CLHEP::micrometer;
19
20// Helper functions for use with ACTS clusterization
21// Put these in the InDet namespace so that ACTS can find them
22// via ADL.
23//
24namespace ActsTrk {
25 static inline int getCellRow(const typename PixelClusteringTool::Cell& cell) { return cell.ROW; }
26 static inline int getCellColumn(const typename PixelClusteringTool::Cell& cell) { return cell.COL; }
27 static inline void clusterReserve(PixelClusteringTool::Cluster& cl,
28 std::size_t n)
29 {
30 cl.ids.reserve(n);
31 cl.tots.reserve(n);
32 }
33 static inline void clusterAddCell(PixelClusteringTool::Cluster& cl,
34 const PixelClusteringTool::Cell& cell)
35 {
36 cl.ids.push_back(cell.ID);
37 cl.tots.push_back(cell.TOT);
38 if (cell.LVL1 < cl.lvl1min)
39 cl.lvl1min = cell.LVL1;
40 }
41
43{
44 ATH_MSG_DEBUG("Initializing " << name() << " ...");
45
50
52
53 ATH_CHECK(m_chargeDataKey.initialize(not m_chargeDataKey.empty()));
54
55 ATH_MSG_INFO(" Charge Data Key:" << m_chargeDataKey);
56
57 ATH_CHECK( detStore()->retrieve(m_pixelID, "PixelID") );
58
59 ATH_MSG_DEBUG(name() << " successfully initialized");
60 return StatusCode::SUCCESS;
61}
62
64 const std::string& type, const std::string& name, const IInterface* parent)
65 : base_class(type,name,parent)
66{}
67
68StatusCode
69PixelClusteringTool::makeCluster(PixelClusteringTool::Cluster &cluster,
70 const InDetDD::SiDetectorElement* element,
71 const InDetDD::PixelModuleDesign& design,
72 const PixelChargeCalibCondData *calibData,
74 const double lorentz_shift,
75 xAOD::PixelCluster& xaodcluster) 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 xaodcluster.setMeasurement<2>(moduleHash, localPosition, localCovariance);
225 xaodcluster.setIdentifier( cluster.ids.front() );
226 xaodcluster.setRDOlist(std::move(cluster.ids));
227 xaodcluster.globalPosition() = globalPos.cast<float>();
229 xaodcluster.setToTlist(std::move(cluster.tots));
231 xaodcluster.setChargelist(std::move(chargeList));
232 xaodcluster.setLVL1A(cluster.lvl1min);
233 xaodcluster.setChannelsInPhiEta(rowWidth,colWidth);
234 xaodcluster.setWidthInEta(static_cast<float>(etaWidth));
235 xaodcluster.setIsSplit(false);
236 xaodcluster.setSplitProbabilities(0.0, 0.0);
237
238 return StatusCode::SUCCESS;
239}
240
241StatusCode
242PixelClusteringTool::clusterize(const EventContext& /*ctx*/,
243 const RawDataCollection& RDOs,
244 const InDet::SiDetectorElementStatus& pixelDetElStatus,
245 const InDetDD::SiDetectorElement& element,
246 Acts::Ccl::ClusteringData& data,
247 std::vector<ClusterCollection>& collection) const
248{
249 IdentifierHash idHash = RDOs.identifyHash();
250 collection.emplace_back();
251 if ( not pixelDetElStatus.isGood(idHash) ) {
252 // the module being flagged as bad is not a failure
253 // An empty cluster collection needs to be added because the assumption
254 // is that there is one element per element RawDataCollection.
255 return StatusCode::SUCCESS;
256 }
257
258 // Retrieve the cells from the detector element
259 CellCollection cells = unpackRDOs(RDOs, pixelDetElStatus, element);
260
261 Acts::Ccl::createClusters<CellCollection, ClusterCollection, 2>
262 (data, cells, collection.back(), Acts::Ccl::DefaultConnect<Cell, 2>(m_addCorners));
263
264 return StatusCode::SUCCESS;
265}
266
267
268StatusCode
269PixelClusteringTool::makeClusters(const EventContext& ctx,
271 const InDetDD::SiDetectorElement& element,
272 typename ClusterContainer::iterator itrContainer) const
273{
274 // We'd need a smarter move here!!!
275
276 // Retrieve the calibration data
277 const PixelChargeCalibCondData *calibData = nullptr;
278 if (not m_chargeDataKey.empty()) {
280 calibData = calibDataHandle.cptr();
281
282 if (!calibData) {
283 ATH_MSG_ERROR("PixelChargeCalibCondData requested but couldn't be retrieved from " << m_chargeDataKey.key());
284 return StatusCode::FAILURE;
285 }
286 }
287
288 // Get the element design
289 const InDetDD::PixelModuleDesign& design =
290 static_cast<const InDetDD::PixelModuleDesign&>(element.design());
291
292 // Get the calibration strategy for this module.
293 // Default to RD53 if the calibData is not available. That is fine because it won't be used anyway
294 auto calibrationStrategy = calibData ? calibData->getCalibrationStrategy(element.identifyHash()) : PixelChargeCalibCondData::CalibrationStrategy::RD53;
295
296 double lorentz_shift = m_pixelLorentzAngleTool->getLorentzShift(element.identifyHash(), ctx);
297
298 for (typename IPixelClusteringTool::Cluster& cl : clusters) {
299 xAOD::PixelCluster* xaodCluster = *itrContainer;
301 &element,
302 design,
303 calibData,
304 calibrationStrategy,
305 lorentz_shift,
306 *xaodCluster));
307 ++itrContainer;
308 }
309
310 return StatusCode::SUCCESS;
311}
312
314PixelClusteringTool::unpackRDOs(const RawDataCollection& RDOs,
315 const InDet::SiDetectorElementStatus& pixelDetElStatus,
316 const InDetDD::SiDetectorElement& element) const
317{
318 // Get the element design
319 const InDetDD::PixelModuleDesign& design =
320 static_cast<const InDetDD::PixelModuleDesign&>(element.design());
321 CellCollection cells;
322 cells.reserve(300);
323
324 const IdentifierHash& idHash = RDOs.identifyHash();
325 for (const auto *const rdo : RDOs) {
326 const Identifier& rdoID = rdo->identify();
327 std::array<InDetDD::PixelDiodeTree::CellIndexType,2> diode_idx
329 m_pixelID->eta_index(rdoID));
330 InDetDD::PixelDiodeTree::DiodeProxy si_param ( design.diodeProxyFromIdx(diode_idx));
331 std::uint32_t fe = design.getFE(si_param);
332
333 // check if good RDO
334 // the pixel RDO tool here says always good if m_useModuleMap is false
335 if (not pixelDetElStatus.isChipGood(idHash, fe)) {
336 continue;
337 }
338
339 const int lvl1 = rdo->getLVL1A();
340 const int tot = rdo->getToT();
341
342 cells.emplace_back(m_pixelID->phi_index(rdoID),
343 m_pixelID->eta_index(rdoID),
344 tot,
345 lvl1,
346 rdoID.get_compact());
347
348 if ( m_checkGanged ) {
349 std::optional<Identifier> gangedID = isGanged(rdoID, element);
350 if (gangedID.has_value()) {
351 cells.emplace_back(m_pixelID->phi_index(*gangedID),
352 m_pixelID->eta_index(*gangedID),
353 tot,
354 lvl1,
355 gangedID->get_compact());
356 }
357 }
358
359 }
360
361 return cells;
362}
363
364inline std::optional<Identifier>
366 const InDetDD::SiDetectorElement& element)
367{
368 // If the pixel is ganged, returns a new identifier for it
369 InDetDD::SiCellId cellID = element.cellIdFromIdentifier( rdoID );
370 if ( element.numberOfConnectedCells( cellID ) > 1 ) {
371 InDetDD::SiCellId gangedCellID = element.connectedCell( cellID, 1 );
372 return element.identifierFromCellId( gangedCellID );
373 }
374 return std::nullopt;
375}
376
377} // 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
virtual StatusCode makeClusters(const EventContext &ctx, typename IPixelClusteringTool::ClusterCollection &clusters, const InDetDD::SiDetectorElement &element, typename ClusterContainer::iterator itrContainer) const override
SG::ReadCondHandleKey< PixelChargeCalibCondData > m_chargeDataKey
virtual StatusCode initialize() override
static std::optional< Identifier > isGanged(const Identifier &rdoID, const InDetDD::SiDetectorElement &element)
Gaudi::Property< bool > m_checkGanged
StatusCode makeCluster(PixelClusteringTool::Cluster &cluster, const InDetDD::SiDetectorElement *element, const InDetDD::PixelModuleDesign &design, const PixelChargeCalibCondData *calibData, const PixelChargeCalibCondData::CalibrationStrategy calibStrategy, double lorentz_shift, xAOD::PixelCluster &container) const
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
const_pointer_type cptr()
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
void setTotalCharge(float totalCharge)
Sets the total charge.
void setChannelsInPhiEta(int channelsInPhi, int channelsInEta)
Sets the dimensions of the cluster in numbers of channels in phi (x) and eta (y) directions.
void setTotalToT(int totalToT)
Sets the total ToT.
void setSplitProbabilities(float prob1, float prob2)
Sets the splitting probabilities for the cluster.
ConstVectorMap< 3 > globalPosition() const
Returns the global position of the pixel cluster.
void setChargelist(const std::vector< float > &charges)
Sets the list of charges of the channels building the cluster.
void setToTlist(const std::vector< int > &tots)
Sets the list of ToT of the channels building the cluster.
void setLVL1A(int lvl1a)
Sets the LVL1 accept.
void setRDOlist(const std::vector< Identifier > &rdolist)
Sets the list of identifiers of the channels building the cluster.
void setIsSplit(bool isSplit)
Sets if the cluster is split or not.
void setWidthInEta(float widthInEta)
Sets the width of the cluster in eta (y) direction.
void setMeasurement(const DetectorIDHashType idHash, MeasVector< N > locPos, MeasMatrix< N > locCov)
Sets IdentifierHash, local position and local covariance of the measurement.
void setIdentifier(const DetectorIdentType measId)
Sets the full Identifier of the measurement.
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
PixelCluster_v1 PixelCluster
Define the version of the pixel cluster class.
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.