ATLAS Offline Software
Loading...
Searching...
No Matches
PixelDiodeTree.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4#ifndef INDETDD_PIXELDIODETREE_H
5#define INDETDD_PIXELDIODETREE_H
6
8
9#include <limits>
10#include <vector>
11#include <array>
12#include <cassert>
13#include <cmath>
14#include <string>
15#include <type_traits>
16
17namespace InDetDD {
18
19 namespace {
20 // round to the integer which is smaller than or equal to val
21 template <typename T_Int,typename T_Float>
22 inline T_Int intFloor(T_Float val) {
23 bool negative=val<static_cast<T_Float>(0.);
24 // negative numbers should become int(val)-1 e.g. -0.1 should become -1 not 0
25 return static_cast<T_Int>(val)-negative;
26 }
27 }
28
33{
34public:
36 using FloatType = Amg::Vector2D::Scalar;
37 using CellIndexType = int;
38 using IndexType = int; // must be signed
39 using AttributeType = unsigned int;
40 static constexpr IndexType s_invalid = std::numeric_limits<IndexType>::min(); // maximum negative number
41
43 struct DiodeParam {
44 std::vector<Vector2D > m_width;
45 std::vector<Vector2D > m_invWidth;
46 std::vector<AttributeType> m_attribute;
47
48 // Add parameters of a new diode to the diode parameter lists.
50 assert( m_width.size() == m_invWidth.size());
51 assert( m_width.size() == m_attribute.size());
52 assert( m_width.size() < std::numeric_limits<unsigned int>::max());
53 unsigned int idx = m_width.size();
54 m_width.push_back(width);
55 m_invWidth.push_back(Vector2D{static_cast<FloatType>(1.)/width[0], static_cast<FloatType>(1.)/width[1]});
56 m_attribute.push_back(attribute);
57 return idx;
58 }
59 };
60
61 PixelDiodeTree(const Vector2D &total_width) {
62 m_diodeParam.addDiode(total_width); // dummy diode representing the total width of the entire diode matrix
63 }
64
65 // add the parameters of a new diode to the diode parameter lists
67 assert( m_diodeParam.m_width.size()>0);
68 return m_diodeParam.addDiode(width, attribute);
69 }
70
71 // set the diode type of all diodes in a certain split region of a sub-matrix
72 // @param sub_matrix_idx the index of the sub-matrix
73 // @param split_i index of the area of the split sub-matrix
74 // @param diode_idx the index to get the diode parameters from the list of diode parameters
75 // The split regions are numbered in the following way 2 | 3 ^ local-y (eta,column) direction
76 // ----- |
77 // 0 | 1 |
78 // --> local-x (phi, rows) direction
79 void setDiodeForSubMatrix( unsigned int sub_matrix_idx, unsigned int split_i, unsigned int diode_idx) {
80 assert( diode_idx > 0 && diode_idx < std::numeric_limits<IndexType>::max());
81 assert( sub_matrix_idx < m_subMatrixIndex.size());
82 assert( split_i <m_subMatrixIndex[sub_matrix_idx].size() );
83 m_subMatrixIndex.at(sub_matrix_idx)[split_i]=-static_cast<IndexType>(diode_idx);
84 }
85
86 // Split a (sub-) matrix into 4 rectangular (sub-)sub-matrices.
87 // @param idx_split the absolute index (row,column) at the center of split (lower edge of the upper-most sub-matrix)
88 // @param pos_split the absolute position at indicating the center position of the split
89 // @param parent_idx if this matrix is a sub-matrix, the index of the parent otherwise an invalid index.
90 // @param split_i if this matrix is a sub-matrix this index indicates which of the split areas (0..3) this matrix represents.
91 // @return the index of this matrix to provide access to the parameters of the split.
92 unsigned int split( const std::array<CellIndexType, 2> &idx_split,
93 const Vector2D &pos_split,
94 AttributeType an_attribute,
95 unsigned int parent_idx=std::numeric_limits<unsigned int>::max(),
96 unsigned int split_i=0) {
97 assert( m_idxSplit.size() == m_posSplit.size());
98 assert( m_idxSplit.size() == m_subMatrixIndex.size());
99 assert( m_idxSplit.size() == m_attribute.size());
100 unsigned int this_submatrix_idx = m_idxSplit.size();
101 m_idxSplit.push_back(idx_split);
102 m_posSplit.push_back(pos_split);
103 assert( PixelDiodeTree::s_invalid < 0);
104 assert( -static_cast<IndexType>(m_diodeParam.m_width.size()) > PixelDiodeTree::s_invalid);
105 m_subMatrixIndex.push_back(std::array<PixelDiodeTree::IndexType,4>{PixelDiodeTree::s_invalid, PixelDiodeTree::s_invalid,
107 m_attribute.push_back(an_attribute);
108 if (parent_idx != std::numeric_limits<unsigned int>::max()) {
109 assert( split_i < m_subMatrixIndex[parent_idx].size());
110 m_subMatrixIndex.at(parent_idx)[split_i]=this_submatrix_idx;
111 }
112
113 return this_submatrix_idx;
114 }
115
117 template <typename T>
118 std::tuple<IndexType,IndexType, IndexType>
119 findFromT(const T &val,
120 const std::vector< T > &split) const {
121 IndexType sub_matrix_idx=0;
122 IndexType last_sub_matrix_idx=0;
123 unsigned int submatrix_i=0;
124 while (sub_matrix_idx>=0) {
125 assert( static_cast<std::size_t>(sub_matrix_idx) < split.size() );
126 last_sub_matrix_idx=sub_matrix_idx;
127 submatrix_i = (val[0] >= split[sub_matrix_idx][0]) + (val[1] >= split[sub_matrix_idx][1])*2;
128 sub_matrix_idx=m_subMatrixIndex[sub_matrix_idx][submatrix_i];
129 }
130 assert( sub_matrix_idx != s_invalid);
131 assert( static_cast<size_t>(std::abs(sub_matrix_idx)) < m_diodeParam.m_width.size() );
132 return std::make_tuple(last_sub_matrix_idx, std::abs(sub_matrix_idx), submatrix_i);
133 }
134
142 const std::array<CellIndexType,2> &idx) const {
143 // pos = (idx - split-index) + 0.5) * pitch + split-position
144 Vector2D pos;
145 assert( diode_idx>0);
146 assert( static_cast<unsigned int>(diode_idx) < m_diodeParam.m_width.size() ) ;
147 assert( static_cast<unsigned int>(sub_matrix_idx) < m_idxSplit.size() );
148 for (unsigned int axis_i=0; axis_i<2; ++axis_i) {
149 assert( axis_i < m_diodeParam.m_width[diode_idx].size() );
150 pos[axis_i] = ( m_posSplit[sub_matrix_idx][axis_i]
151 + ((idx[axis_i]-m_idxSplit[sub_matrix_idx][axis_i])
152 + static_cast<FloatType>(.5)) * m_diodeParam.m_width[diode_idx][axis_i]);
153 };
154 return pos;
155 }
156
162 std::array<CellIndexType,2> computeIndex(PixelDiodeTree::IndexType sub_matrix_idx,
164 const Vector2D &pos) const {
165 // pos = (idx - split-index) + 0.5) * pitch + split-position
166 // idx = inr( (pos - split-position)/pitch - 0.5 + split-index + 0.5 (rounding) )
167 std::array<CellIndexType,2> idx;
168 assert( diode_idx>0);
169 assert( static_cast<unsigned int>(diode_idx) < m_diodeParam.m_invWidth.size() ) ;
170 assert( static_cast<unsigned int>(sub_matrix_idx) < m_idxSplit.size() );
171 assert( static_cast<unsigned int>(sub_matrix_idx) < m_posSplit.size() );
172 for (unsigned int axis_i=0; axis_i<2; ++axis_i) {
173 assert( axis_i < m_diodeParam.m_invWidth[diode_idx].size() );
174
175 idx[axis_i] = intFloor<CellIndexType>( m_idxSplit[sub_matrix_idx][axis_i]
176 + (pos[axis_i]-m_posSplit[sub_matrix_idx][axis_i])
177 * m_diodeParam.m_invWidth[diode_idx][axis_i]);
178 };
179 return idx;
180 }
181
183 struct DiodeProxy {
184 friend class PixelDiodeTree;
185 protected:
186 const PixelDiodeTree *m_diodeTree = nullptr;
191 : m_diodeTree(diodeTree), m_subMatrixIdx(subMatrixIdx), m_diodeIdx(diodeIdx) {}
192 void setInvalid() { m_diodeTree=nullptr; }
193 public:
196 assert( static_cast<unsigned int>(m_diodeIdx)<m_diodeTree->m_diodeParam.m_width.size());
197 return m_diodeTree->m_diodeParam.m_width[m_diodeIdx];
198 }
199
201 assert( static_cast<unsigned int>(m_diodeIdx)<m_diodeTree->m_diodeParam.m_invWidth.size());
202 return m_diodeTree->m_diodeParam.m_invWidth[m_diodeIdx];
203 }
204
205 unsigned int diodeAttribute() const {
206 assert( static_cast<unsigned int>(m_diodeIdx)<m_diodeTree->m_diodeParam.m_attribute.size());
207 return m_diodeTree->m_diodeParam.m_attribute[m_diodeIdx];
208 }
209
210 unsigned int subMatrixAttribute() const {
211 assert( static_cast<unsigned int>(m_subMatrixIdx)<m_diodeTree->m_attribute.size());
212 return m_diodeTree->m_attribute[m_subMatrixIdx];
213 }
214
216 PixelDiodeTree::Vector2D computePosition(const std::array<CellIndexType,2> &idx) const {
217 return m_diodeTree->computePosition(m_subMatrixIdx, m_diodeIdx, idx);
218 }
219
220 std::array<PixelDiodeTree::CellIndexType,2> computeIndex(const Vector2D &pos) const {
221 return m_diodeTree->computeIndex(m_subMatrixIdx, m_diodeIdx, pos);
222 }
223
224 bool isValid() const { return m_diodeTree != nullptr; }
226 operator bool() const { return isValid(); }
227 };
228
231 friend class PixelDiodeTree;
234 PixelDiodeTree::IndexType subMatrixIdx,
237 : DiodeProxy{diodeTree, subMatrixIdx, diodeIdx},
238 m_position(std::move(position))
239 {}
240
241 const Vector2D &position() const { return m_position; }
243 double phiWidth() const { return width()[0]; }
245 double etaWidth() const { return width()[1]; }
248 double xPhiMin() const { return m_position[0]-width()[0]*.5; }
251 double xPhiMax() const { return m_position[0]+width()[0]*.5; }
254 double xEtaMin() const { return m_position[1]-width()[1]*.5; }
257 double xEtaMax() const { return m_position[1]+width()[1]*.5; }
258
259 protected:
261 };
262
264 Vector2D findFromIdx(const std::array<CellIndexType,2> &idx) const {
265 auto [sub_matrix_idx,diode_idx, submatrix_i] = findFromT(idx,m_idxSplit);
266 return computePosition(sub_matrix_idx, diode_idx,idx);
267 }
268
270 DiodeProxy diodeProxyFromIdx(const std::array<CellIndexType,2> &idx) const {
271 auto [sub_matrix_idx,diode_idx, submatrix_i] = findFromT(idx,m_idxSplit);
272 return DiodeProxy{this, sub_matrix_idx, diode_idx};
273 }
274
276 DiodeProxyWithPosition diodeProxyFromIdxCachePosition(const std::array<CellIndexType,2> &idx) const {
277 auto [sub_matrix_idx,diode_idx, submatrix_i] = findFromT(idx,m_idxSplit);
278 DiodeProxyWithPosition proxy(this, sub_matrix_idx, diode_idx, computePosition(sub_matrix_idx, diode_idx, idx));
279 return proxy;
280 }
281
282 std::array<CellIndexType,2> findFromPos(const Vector2D &pos) const {
283 auto [sub_matrix_idx,diode_idx, submatrix_i] = findFromT(pos,m_posSplit);
284 return computeIndex(sub_matrix_idx,diode_idx,pos);
285 }
286
289 auto [sub_matrix_idx,diode_idx, submatrix_i] = findFromT(pos,m_posSplit);
290 return DiodeProxy{this, sub_matrix_idx, diode_idx};
291 }
292
294 bool empty() const { return m_subMatrixIndex.empty(); }
295
297 const Vector2D &totalWidth() const {
298 // constructor should store total width here, empty means that this diode tree is not properly constructed.
299 assert(!m_diodeParam.m_width.empty());
300 return m_diodeParam.m_width[0];
301 }
302
304 std::string debugStringRepr() const;
305
308 template <typename T>
309 static constexpr bool validCellIndex(T cell_index) {
310 if constexpr( std::is_signed_v<T>) {
311 return cell_index>= std::numeric_limits<CellIndexType>::min() && cell_index < std::numeric_limits<CellIndexType>::max();
312 }
313 else {
314 return cell_index < std::numeric_limits<CellIndexType>::max();
315 }
316 }
317
319 template <typename T>
320 static constexpr std::array<PixelDiodeTree::CellIndexType,2> makeCellIndex(T local_x_idx, T local_y_idx) {
321 assert( validCellIndex(local_x_idx) && validCellIndex(local_y_idx) );
322 return std::array<PixelDiodeTree::CellIndexType,2>{
323 static_cast<PixelDiodeTree::CellIndexType>(local_x_idx),
324 static_cast<PixelDiodeTree::CellIndexType>(local_y_idx)};
325 }
326
329 return m_attribute.at(idx);
330 }
331
334 void setAttribute(IndexType idx, AttributeType new_attribute) {
335 m_attribute.at(idx)=new_attribute;
336 }
337
345 unsigned int cloneSingleSplitsToUnusedHalf();
346
350 PixelDiodeTree::Vector2D computeTolerance(const std::array<PixelDiodeTree::CellIndexType,2> &matrix_dim) const;
351
356 void computeMatrixCorner(const std::array<PixelDiodeTree::CellIndexType,2> &matrix_dim);
357
359 bool isInsideMatrix(const std::array<PixelDiodeTree::IndexType,2> &idx) const {
360 return idx[0]>=0 && idx[1]>=0 && idx[0] < m_matrixDim[0] && idx[1] < m_matrixDim[1];
361 }
362
364 bool isInsideMatrix(const Amg::Vector2D &local_position) const {
365 // corner positions are moved to the inside of the matrix to account for floating point
366 // tolerances so >= && <= means "well" inside the matrix.
367 return ( local_position[0]>=m_matrixCorner[0][0] && local_position[0]<=m_matrixCorner[1][0]
368 && local_position[1]>=m_matrixCorner[0][1] && local_position[1]<=m_matrixCorner[1][1]);
369 }
370
372 template <typename T_CellID>
373 static void neighboursOfCell(const std::array<CellIndexType,2> &idx,
374 const std::array<CellIndexType,2> &max_idx,
375 std::vector<T_CellID > &neighbours);
376
377protected:
378 std::vector<std::array<CellIndexType, 2>> m_idxSplit;
379 std::vector<Vector2D > m_posSplit;
380 std::vector<AttributeType> m_attribute;
381
382 std::vector<std::array<IndexType, 4> > m_subMatrixIndex;
384 std::array<Vector2D,2> m_matrixCorner{};
385 std::array<CellIndexType,2> m_matrixDim{};
386};
387
388template <typename T_CellID>
389void PixelDiodeTree::neighboursOfCell(const std::array<CellIndexType,2> &idx,
390 const std::array<CellIndexType,2> &max_idx,
391 std::vector<T_CellID > &neighbours) {
392 neighbours.reserve(8);
393 std::array<std::array<PixelDiodeTree::CellIndexType,2>,2> outer_idx {
394 std::array<PixelDiodeTree::CellIndexType,2>{idx[0]-1,idx[0]+1},
395 std::array<PixelDiodeTree::CellIndexType,2>{idx[1]-1,idx[1]+1}
396 };
397
398 if (outer_idx[0][0]>=0 && outer_idx[1][0]>=0) neighbours.emplace_back(outer_idx[0][0],outer_idx[1][0]);
399 if ( outer_idx[1][0]>=0) neighbours.emplace_back(idx[0], outer_idx[1][0]);
400 if (outer_idx[0][1]<max_idx[0] && outer_idx[1][0]>=0) neighbours.emplace_back(outer_idx[0][1],outer_idx[1][0]);
401 if (outer_idx[0][1]<max_idx[0]) neighbours.emplace_back(outer_idx[0][1],idx[1]);
402 if (outer_idx[0][1]<max_idx[0] && outer_idx[1][1]<max_idx[1]) neighbours.emplace_back(outer_idx[0][1],outer_idx[1][1]);
403 if ( outer_idx[1][1]<max_idx[1]) neighbours.emplace_back(idx[0], outer_idx[1][1]);
404 if (outer_idx[0][0]>=0 && outer_idx[1][1]<max_idx[1]) neighbours.emplace_back(outer_idx[0][0],outer_idx[1][1]);
405 if (outer_idx[0][0]>=0 ) neighbours.emplace_back(outer_idx[0][0],idx[1]);
406}
407
408}
409
410#endif
const double width
bool isInsideMatrix(const std::array< PixelDiodeTree::IndexType, 2 > &idx) const
Return true if the given index describes a valid location inside the matrix.
bool empty() const
Return true if no sub-matrices are defined, indicates an invalid state.
std::array< CellIndexType, 2 > m_matrixDim
static constexpr bool validCellIndex(T cell_index)
Test whether the cell_index either row or column index could be valid The index may still be outside ...
bool isInsideMatrix(const Amg::Vector2D &local_position) const
Test whether the given local position is well within the matrix.
static void neighboursOfCell(const std::array< CellIndexType, 2 > &idx, const std::array< CellIndexType, 2 > &max_idx, std::vector< T_CellID > &neighbours)
Get indices of all adjacent cells.
std::tuple< IndexType, IndexType, IndexType > findFromT(const T &val, const std::vector< T > &split) const
helper template to find the final node in a quad tree.
std::array< CellIndexType, 2 > findFromPos(const Vector2D &pos) const
Find a diode by the position relative to the center of the full diode matrix and compute its 2D index...
std::array< CellIndexType, 2 > computeIndex(PixelDiodeTree::IndexType sub_matrix_idx, PixelDiodeTree::IndexType diode_idx, const Vector2D &pos) const
Compute the 2D index (row, column) of a certain diode in a certain sub-matrix.
AttributeType attribute(IndexType idx) const
Get the attribute associated to a sub-matrix.
static constexpr IndexType s_invalid
void setAttribute(IndexType idx, AttributeType new_attribute)
Set the attribute associated to a sub-matrix.
std::vector< std::array< IndexType, 4 > > m_subMatrixIndex
std::array< Vector2D, 2 > m_matrixCorner
DiodeProxy diodeProxyFromIdx(const std::array< CellIndexType, 2 > &idx) const
find a diode by its 2D index (row, column) the returned proxy allows to compute the position and prov...
PixelDiodeTree::Vector2D computeTolerance(const std::array< PixelDiodeTree::CellIndexType, 2 > &matrix_dim) const
Compute tolerance to ensure that a position is within the expected cell Due to limited floating point...
Amg::Vector2D::Scalar FloatType
Vector2D findFromIdx(const std::array< CellIndexType, 2 > &idx) const
find a diode by its 2D index (row, column) and compute the position relative to the center of the ful...
unsigned int addDiode(const Vector2D &width, AttributeType attribute)
unsigned int cloneSingleSplitsToUnusedHalf()
Clone half with valid split indices to "unused" half with invalid split indices.
std::vector< AttributeType > m_attribute
Vector2D computePosition(PixelDiodeTree::IndexType sub_matrix_idx, PixelDiodeTree::IndexType diode_idx, const std::array< CellIndexType, 2 > &idx) const
Compute the position of a certain diode in a certain sub-matrix.
std::vector< Vector2D > m_posSplit
DiodeProxy diodeProxyFromPos(const Vector2D &pos) const
Find a diode by the position relative to the center of the full diode matrix.
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.
PixelDiodeTree(const Vector2D &total_width)
std::vector< std::array< CellIndexType, 2 > > m_idxSplit
std::string debugStringRepr() const
Dump the diode tree structure into a string.
void computeMatrixCorner(const std::array< PixelDiodeTree::CellIndexType, 2 > &matrix_dim)
Compute the effective maximum lower and upper corner positions of the matrix.
void setDiodeForSubMatrix(unsigned int sub_matrix_idx, unsigned int split_i, unsigned int diode_idx)
DiodeProxyWithPosition diodeProxyFromIdxCachePosition(const std::array< CellIndexType, 2 > &idx) const
find a diode by its 2D index (row, column) and compute the position of the diode the returned proxy c...
unsigned int split(const std::array< CellIndexType, 2 > &idx_split, const Vector2D &pos_split, AttributeType an_attribute, unsigned int parent_idx=std::numeric_limits< unsigned int >::max(), unsigned int split_i=0)
const Vector2D & totalWidth() const
Return the total width of the diode matrix.
Eigen::Matrix< double, 2, 1 > Vector2D
Message Stream Member.
STL namespace.
std::vector< Vector2D > m_width
std::vector< Vector2D > m_invWidth
unsigned int addDiode(const Vector2D &width, AttributeType attribute=AttributeType{})
std::vector< AttributeType > m_attribute
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 phiWidth() const
for backward compatibility, return the pitch of a diode in local-x(phi, row) direction
DiodeProxyWithPosition(const PixelDiodeTree *diodeTree, PixelDiodeTree::IndexType subMatrixIdx, PixelDiodeTree::IndexType diodeIdx, Vector2D &&position)
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 etaWidth() const
for backward compatibility, return the pitch of a diode in local-y(eta, column) direction
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.
unsigned int diodeAttribute() const
get the attribute associated to this diode (to be interpreted)
std::array< PixelDiodeTree::CellIndexType, 2 > computeIndex(const Vector2D &pos) const
Compute the full 2D index (row, column) of the diode in the full diode matrix.
PixelDiodeTree::IndexType m_diodeIdx
DiodeProxy(const PixelDiodeTree *diodeTree, PixelDiodeTree::IndexType subMatrixIdx, PixelDiodeTree::IndexType diodeIdx)
unsigned int subMatrixAttribute() const
get the attribute associated to the sub-matrix of this diode (to be interpreted)
bool isValid() const
return true if this proxy refers to a valide diode
PixelDiodeTree::Vector2D computePosition(const std::array< CellIndexType, 2 > &idx) const
Compute the position of the diode.
const PixelDiodeTree::Vector2D & invWidth() const
get the inverse of the width of this diode.
PixelDiodeTree::IndexType m_subMatrixIdx
const PixelDiodeTree::Vector2D & width() const
get the width stored for this diode.