ATLAS Offline Software
PixelDistortionData.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 #include "CLHEP/Units/SystemOfUnits.h"
7 #include "CxxUtils/restrict.h"
8 
9 #include "cmath"
10 namespace {
11 
12 //constexpr binomial
13 //copied over from TMath but in constxpr
14 //fashion
15 constexpr double Binomial(int n, int k) {
16 
17  if (n < 0 || k < 0 || n < k) {
18  return std::numeric_limits<double>::signaling_NaN();
19  }
20  if (k == 0 || n == k) {
21  return 1;
22  }
23 
24  int k1 = std::min(k, n - k);
25  int k2 = n - k1;
26  double fact = k2 + 1;
27  for (double i = k1; i > 1.; --i) {
28  fact *= (k2 + i) / i;
29  }
30  return fact;
31 }
32 
33 constexpr int PolyDegree = 20;
34 constexpr int PolyNCoeff = PolyDegree + 1;
35 
36 constexpr std::array<double, PolyNCoeff> BinomialCache() {
37  constexpr double b0 = Binomial(20, 0);
38  constexpr double b1 = Binomial(20, 1);
39  constexpr double b2 = Binomial(20, 2);
40  constexpr double b3 = Binomial(20, 3);
41  constexpr double b4 = Binomial(20, 4);
42  constexpr double b5 = Binomial(20, 5);
43  constexpr double b6 = Binomial(20, 6);
44  constexpr double b7 = Binomial(20, 7);
45  constexpr double b8 = Binomial(20, 8);
46  constexpr double b9 = Binomial(20, 9);
47  constexpr double b10 = Binomial(20, 10);
48 
49  std::array<double, PolyNCoeff> res = {b0, b1, b2, b3, b4, b5, b6,
50  b7, b8, b9, b10, b9, b8, b7,
51  b6, b5, b4, b3, b2, b1, b0};
52 
53  return res;
54 }
55 
56 // We just have a static const array in the anonymous
57 // as cache
58 constexpr std::array<double, PolyNCoeff> s_binomialCache = BinomialCache();
59 
60 template <int N>
61 double bernstein_grundpolynom(const double t, const int i) {
62  static_assert(s_binomialCache.size() > N,
63  " Binomial cache must be larger than N");
64 
65  return s_binomialCache[i] * std::pow(t, i) * std::pow(1. - t, N - i);
66 }
67 
68 double bernstein_bezier(const double u, const double v, const float *P) {
69  double r = 0.;
70  //So here we calculate the 21+21 polynomial values we need
71  //for the inputs u , v for 0....n each (m==n)
72  std::array<double,PolyNCoeff> bernstein_grundpolynomU{};
73  std::array<double,PolyNCoeff> bernstein_grundpolynomV{};
74  for (int i = 0; i < PolyNCoeff; ++i) {
75  bernstein_grundpolynomU[i] = bernstein_grundpolynom<PolyDegree>(u, i);
76  bernstein_grundpolynomV[i] = bernstein_grundpolynom<PolyDegree>(v, i);
77  }
78 
79  for (int i = 0; i < PolyNCoeff; ++i) {
80 
81  //the one we passed u and 0 ....n
82  const double bernstein_grundpolynom_i = bernstein_grundpolynomU[i];
83 
84  for (int j = 0; j < PolyNCoeff; ++j) {
85 
86  const int k = (i * (PolyDegree + 1)) + j;
87  if (P[k] < -998.9){
88  continue;
89  }
90 
91  //the one we passed v and 0 ....n
92  const double bernstein_grundpolynom_j = bernstein_grundpolynomV[j];
93  r += bernstein_grundpolynom_i * bernstein_grundpolynom_j * P[k];
94  }
95  }
96  return r;
97 }
98 } // namespace
99 
100 std::vector<float> PixelDistortionData::getDistortionMap(uint32_t hashID) const {
101  int distosize;
102  if (m_version < 2) distosize = 3;
103  else distosize = 441;
104 
105  auto itr = m_distortionMap.find(hashID);
106  if (itr!=m_distortionMap.end()) {
107  return itr->second;
108  }
109  std::vector<float> map(distosize, 0.0);
110  return map;
111 }
112 
113 unsigned long long PixelDistortionData::getId(uint32_t hashID) const {
114  auto search = m_ids.find(hashID);
115  if (search != m_ids.end()) return search->second;
116 
117  return 0;
118 }
119 
120 Amg::Vector2D PixelDistortionData::correction(uint32_t hashID, const Amg::Vector2D & locpos, const Amg::Vector3D & direction) const {
121  double localphi = locpos[0];
122  double localeta = locpos[1];
123  const Amg::Vector2D nullCorrection(0.0,0.0);
124  const unsigned long long ull_id = getId(hashID);
125 
126  // No corrections available for this module
127  if (ull_id == 0 && m_version > 1) { return nullCorrection; }
128 
129  // This is needed to avoid rounding errors if the z component of the
130  // direction vector is too small.
131  if (std::fabs(direction.z())<1.*CLHEP::micrometer) { return nullCorrection; }
132 
133  // If a particle has a too shallow trajectory with respect to the
134  // module direction, it is likely to be a secondary particle and no
135  // shift should be applied.
136  double invtanphi = direction.x()/direction.z();
137  double invtaneta = direction.y()/direction.z();
138  if (sqrt(invtanphi*invtanphi+invtaneta*invtaneta)>100.0) { return nullCorrection; }
139 
140  double localZ = 0;
141  std::vector<float> map = getDistortionMap(hashID);
142 
143  // If old database versions, the corrections are from the pixel survey, otherwise corrections are from
144  // insitu shape measurements.
145  if (m_version < 2) {
146  localZ = getSurveyZ(localeta, localphi, map.data());
147  } else if (isOldParam(ull_id)) {
148  localZ = getSurveyZ(localeta, localphi, map.data());
149  } else {
150  float modEtaSize, modPhiSize;
151 
152  // set module sizes in millimetre
153  if (ull_id >= 0x200000000000000 && ull_id <= 0x20d980000000000) {
154  if (isIBL3D(ull_id)) {
155  modEtaSize = 19.75 * CLHEP::millimeter;
156  modPhiSize = 16.75 * CLHEP::millimeter;
157  } else {
158  modEtaSize = 40.4 * CLHEP::millimeter;
159  modPhiSize = 16.8 * CLHEP::millimeter;
160  }
161  } else {
162  modEtaSize = 60.2 * CLHEP::millimeter;
163  modPhiSize = 16.44 * CLHEP::millimeter;
164  }
165 
166  localZ = getInSituZ(localeta, modEtaSize, localphi, modPhiSize, map.data());
167  }
168 
169  double localetaCor = -localZ * invtaneta;
170  double localphiCor = -localZ * invtanphi;
171 
172  // In earlies code version there was a bug in the sign of the correction.
173  // In MC this was not seen as reco just corrects back what was done in digitization.
174  // In order to maintain backward compatibilty in older MC we need to reproduce this wrong behaviour.
175  if (getVersion()==0) { localphiCor = -localphiCor; }
176 
177  return Amg::Vector2D(localphiCor, localetaCor);
178 }
179 
181  Amg::Vector2D newlocpos(locpos);
182  newlocpos += correction(hashID, locpos, direction);
183  return newlocpos;
184 }
185 
187  Amg::Vector2D newlocpos(locpos);
188  newlocpos -= correction(hashID, locpos, direction);
189  return newlocpos;
190 }
191 
192 double PixelDistortionData::getInSituZ(const double localeta, const double eta_size, const double localphi, const double phi_size, const float *disto)
193 {
194  double etaHalfRangeBB = eta_size * 10. / 21.;
195  double phiHalfRangeBB = phi_size * 10. / 21.;
196  double etaRangeBB = eta_size * 20. / 21.;
197  double phiRangeBB = phi_size * 20. / 21.;
198  double eta, phi;
199 
200  // map positions on interval [- edge, 1 + edge]
201  // edge is the part outside of the Bezier-Bernstein range
202  if (std::abs(localeta) - etaHalfRangeBB > 0) {
203  if (localeta < 0)
204  eta = (localeta + etaHalfRangeBB) / etaRangeBB;
205  else
206  eta = 1. + (localeta - etaHalfRangeBB) / etaRangeBB;
207  } else {
208  eta = localeta / etaRangeBB + 0.5;
209  }
210  if (std::abs(localphi) - phiHalfRangeBB > 0) {
211  if (localphi < 0)
212  phi = (localphi + phiHalfRangeBB) / phiRangeBB;
213  else
214  phi = 1. + (localphi - phiHalfRangeBB) / phiRangeBB;
215  } else {
216  phi = localphi / phiRangeBB + 0.5;
217  }
218  return bernstein_bezier(eta, phi, disto);
219 }
220 
221 double PixelDistortionData::getSurveyZ(const double localeta, const double localphi, const float *disto)
222 {
223  const double xFE = 22.0 * CLHEP::millimeter; // Distance between the 2 Front-End line, where bows have been measured
224  const double yFE = 60.8 * CLHEP::millimeter; // Length of the active surface of each module
225 
226  double data0 = disto[0] / CLHEP::meter; // curvature is in m-1
227  double data1 = disto[1] / CLHEP::meter; // curvature is in m-1
228  double data2 = tan(0.5 * disto[2] * CLHEP::degree); // twist angle in degree
229 
230  double twist1 = -data2;
231  double twist2 = data2;
232  double b1 = sqrt((1. + twist1*twist1) * (1. + twist1*twist1) * (1. + twist1*twist1));
233  double b2 = sqrt((1. + twist2*twist2) * (1. + twist2*twist2) * (1. + twist2*twist2));
234  double z1 = localeta * twist1 - 0.5 * b1 * localeta*localeta * data1;
235  double z2 = localeta * twist2 - 0.5 * b2 * localeta*localeta * data0;
236  double zoff1 = (b1 * yFE*yFE * data1) / 24.;
237  double zoff2 = (b2 * yFE*yFE * data0) / 24.;
238  z1 = z1 + zoff1;
239  z2 = z2 + zoff2;
240 
241  return z1 + ((z2 - z1) / xFE) * (localphi + xFE / 2.);
242 }
243 
244 bool PixelDistortionData::isOldParam(const unsigned long long ull_id)
245 {
246  // Only pixel modules can have the old parametrisation
247  if (ull_id < 0x240000000000000) return false;
248 
249  // For now: no new parametrisation for Pixel
250  return true;
251 }
252 
253 bool PixelDistortionData::isIBL3D(const unsigned long long ull_id)
254 {
255  // Stave 1
256  if (ull_id >= 0x200000000000000 && ull_id <= 0x200180000000000) return true;
257  if (ull_id >= 0x200800000000000 && ull_id <= 0x200980000000000) return true;
258 
259  // Stave 2
260  if (ull_id >= 0x201000000000000 && ull_id <= 0x201180000000000) return true;
261  if (ull_id >= 0x201800000000000 && ull_id <= 0x201980000000000) return true;
262 
263  // Stave 3
264  if (ull_id >= 0x202000000000000 && ull_id <= 0x202180000000000) return true;
265  if (ull_id >= 0x202800000000000 && ull_id <= 0x202980000000000) return true;
266 
267  // Stave 4
268  if (ull_id >= 0x203000000000000 && ull_id <= 0x203180000000000) return true;
269  if (ull_id >= 0x203800000000000 && ull_id <= 0x203980000000000) return true;
270 
271  // Stave 5
272  if (ull_id >= 0x204000000000000 && ull_id <= 0x204180000000000) return true;
273  if (ull_id >= 0x204800000000000 && ull_id <= 0x204980000000000) return true;
274 
275  // Stave 6
276  if (ull_id >= 0x205000000000000 && ull_id <= 0x205180000000000) return true;
277  if (ull_id >= 0x205800000000000 && ull_id <= 0x205980000000000) return true;
278 
279  // Stave 7
280  if (ull_id >= 0x206000000000000 && ull_id <= 0x206180000000000) return true;
281  if (ull_id >= 0x206800000000000 && ull_id <= 0x206980000000000) return true;
282 
283  // Stave 8
284  if (ull_id >= 0x207000000000000 && ull_id <= 0x207180000000000) return true;
285  if (ull_id >= 0x207800000000000 && ull_id <= 0x207980000000000) return true;
286 
287  // Stave 9
288  if (ull_id >= 0x208000000000000 && ull_id <= 0x208180000000000) return true;
289  if (ull_id >= 0x208800000000000 && ull_id <= 0x208980000000000) return true;
290 
291  // Stave 10
292  if (ull_id >= 0x209000000000000 && ull_id <= 0x209180000000000) return true;
293  if (ull_id >= 0x209800000000000 && ull_id <= 0x209980000000000) return true;
294 
295  // Stave 11
296  if (ull_id >= 0x20a000000000000 && ull_id <= 0x20a180000000000) return true;
297  if (ull_id >= 0x20a800000000000 && ull_id <= 0x20a980000000000) return true;
298 
299  // Stave 12
300  if (ull_id >= 0x20b000000000000 && ull_id <= 0x20b180000000000) return true;
301  if (ull_id >= 0x20b800000000000 && ull_id <= 0x20b980000000000) return true;
302 
303  // Stave 13
304  if (ull_id >= 0x20c000000000000 && ull_id <= 0x20c180000000000) return true;
305  if (ull_id >= 0x20c800000000000 && ull_id <= 0x20c980000000000) return true;
306 
307  // Stave 14
308  if (ull_id >= 0x20d000000000000 && ull_id <= 0x20d180000000000) return true;
309  if (ull_id >= 0x20d800000000000 && ull_id <= 0x20d980000000000) return true;
310 
311  return false;
312 }
313 
315  m_distortionMap.clear();
316 }
317 
beamspotman.r
def r
Definition: beamspotman.py:676
PixelDistortionData.h
Hold pixel distortion data produced by PixelDistortionAlg.
phi
Scalar phi() const
phi method
Definition: AmgMatrixBasePlugin.h:67
xAOD::uint32_t
setEventNumber uint32_t
Definition: EventInfo_v1.cxx:127
eta
Scalar eta() const
pseudorapidity method
Definition: AmgMatrixBasePlugin.h:83
Amg::Vector2D
Eigen::Matrix< double, 2, 1 > Vector2D
Definition: GeoPrimitives.h:48
DMTest::P
P_v1 P
Definition: P.h:23
PixelDistortionData::correctSimulation
Amg::Vector2D correctSimulation(uint32_t hashID, const Amg::Vector2D &locpos, const Amg::Vector3D &direction) const
Definition: PixelDistortionData.cxx:186
min
constexpr double min()
Definition: ap_fixedTest.cxx:26
PixelDistortionData::correctReconstruction
Amg::Vector2D correctReconstruction(uint32_t hashID, const Amg::Vector2D &locpos, const Amg::Vector3D &direction) const
Definition: PixelDistortionData.cxx:180
PixelDistortionData::clear
void clear()
Definition: PixelDistortionData.cxx:314
JetTiledMap::N
@ N
Definition: TiledEtaPhiMap.h:44
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
search
void search(TDirectory *td, const std::string &s, std::string cwd, node *n)
recursive directory search for TH1 and TH2 and TProfiles
Definition: hcg.cxx:738
Trk::u
@ u
Enums for curvilinear frames.
Definition: ParamDefs.h:77
RTTAlgmain.data2
data2
Definition: RTTAlgmain.py:54
python.SystemOfUnits.millimeter
int millimeter
Definition: SystemOfUnits.py:53
python.SystemOfUnits.meter
int meter
Definition: SystemOfUnits.py:61
PixelDistortionData::getVersion
int getVersion() const
Definition: PixelDistortionData.h:50
lumiFormat.i
int i
Definition: lumiFormat.py:85
beamspotman.n
n
Definition: beamspotman.py:731
PixelDistortionData::m_distortionMap
std::unordered_map< uint32_t, std::vector< float > > m_distortionMap
Definition: PixelDistortionData.h:43
PixelDistortionData::isIBL3D
static bool isIBL3D(const unsigned long long ull_id)
Definition: PixelDistortionData.cxx:253
res
std::pair< std::vector< unsigned int >, bool > res
Definition: JetGroupProductTest.cxx:14
drawFromPickle.tan
tan
Definition: drawFromPickle.py:36
python.SystemOfUnits.micrometer
int micrometer
Definition: SystemOfUnits.py:71
PixelDistortionData::isOldParam
static bool isOldParam(const unsigned long long ull_id)
Definition: PixelDistortionData.cxx:244
restrict.h
Macro wrapping the nonstandard restrict keyword.
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
RTTAlgmain.data1
data1
Definition: RTTAlgmain.py:54
python.PyAthena.v
v
Definition: PyAthena.py:154
PixelDistortionData::getId
unsigned long long getId(uint32_t hashID) const
Definition: PixelDistortionData.cxx:113
PixelDistortionData::getSurveyZ
static double getSurveyZ(const double localeta, const double localphi, const float *disto)
Definition: PixelDistortionData.cxx:221
PixelDistortionData::m_ids
std::unordered_map< uint32_t, unsigned long long > m_ids
Definition: PixelDistortionData.h:42
PixelDistortionData::correction
Amg::Vector2D correction(uint32_t hashID, const Amg::Vector2D &locpos, const Amg::Vector3D &direction) const
Definition: PixelDistortionData.cxx:120
PixelDistortionData::getDistortionMap
std::vector< float > getDistortionMap(uint32_t id) const
Definition: PixelDistortionData.cxx:100
PixelDistortionData::m_version
int m_version
Definition: PixelDistortionData.h:41
pow
constexpr int pow(int base, int exp) noexcept
Definition: ap_fixedTest.cxx:15
python.SystemOfUnits.degree
tuple degree
Definition: SystemOfUnits.py:106
PixelDistortionData::getInSituZ
static double getInSituZ(const double localeta, const double eta_size, const double localphi, const double phi_size, const float *disto)
Definition: PixelDistortionData.cxx:192
fitman.k
k
Definition: fitman.py:528