ATLAS Offline Software
FastCaloSimCaloExtrapolation.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 /* Athena includes */
7 #include "GaudiKernel/ToolHandle.h"
8 #include "GaudiKernel/IPartPropSvc.h"
9 
10 #include "CxxUtils/inline_hints.h"
11 /* Header include */
13 
14 /* ISF includes */
18 
19 /* Geometry primitives */
22 
23 /* Particle data */
24 #include "HepPDT/ParticleDataTable.hh"
25 
26 /* Tracking includes */
28 
29 /* G4FieldTrack used to store transportation steps */
30 #include "G4FieldTrack.hh"
31 
32 
33 /* Preprocessor macro to use
34  -- DEBUG if CONDITION is True
35  -- WARNING if CONDITION is False
36  */
37 #define ATH_MSG_COND(MSG, CONDITION) \
38 do { \
39  if (CONDITION) { \
40  ATH_MSG_DEBUG(MSG); \
41  } else { \
42  ATH_MSG_WARNING(MSG); \
43  } \
44 } while (0)
45 
46 
47 FastCaloSimCaloExtrapolation::FastCaloSimCaloExtrapolation(const std::string& t, const std::string& n, const IInterface* p)
48  : base_class(t,n,p)
49 {
50 }
51 
53 {
54  ATH_MSG_INFO( "Initializing FastCaloSimCaloExtrapolation" );
55 
56  // Retrieve the fast calo sim geometry helper
57  ATH_CHECK(m_CaloGeometryHelper.retrieve());
58  // Retrieve the tool to transport particles through calorimeter with ATLAS tracking tools
59  ATH_CHECK(m_CaloTransportation.retrieve());
60 
61  return StatusCode::SUCCESS;
62 
63 
64 }
65 
67  ATH_MSG_INFO( "Finalizing FastCaloSimCaloExtrapolation" );
68  return StatusCode::SUCCESS;
69 }
70 
71 
72 void FastCaloSimCaloExtrapolation::extrapolate(TFCSExtrapolationState& result, const TFCSTruthState* truth, const std::vector<G4FieldTrack>& caloSteps) const{
73 
74  ATH_MSG_DEBUG("[extrapolate] Initializing extrapolation to ID-Calo boundary");
75  extrapolateToID(result, caloSteps, truth);
76 
77  ATH_MSG_DEBUG("[extrapolate] Initializing extrapolation to calorimeter layers");
78  extrapolateToLayers(result, caloSteps, truth);
79 
80  ATH_MSG_DEBUG("[extrapolate] Extrapolation done");
81 
82 }
83 
85 
86  ATH_MSG_DEBUG("[extrapolate] Initializing transport of track through calorimeter system with ATLAS tracking tools.");
87  std::vector<G4FieldTrack> caloSteps = m_CaloTransportation -> transport(truth, false);
88  ATH_MSG_DEBUG("[extrapolate] Finalized transport of track through calorimeter system with ATLAS tracking tools.");
89 
90  extrapolate(result, truth, caloSteps);
91 }
92 
93 
94 void FastCaloSimCaloExtrapolation::extrapolateToID(TFCSExtrapolationState& result, const std::vector<G4FieldTrack>& caloSteps, const TFCSTruthState* truth) const{
95 
96  ATH_MSG_DEBUG("Start extrapolateToID()");
97 
98  //pT threshold of truth particles over which extrapolation failures will be printed as warnings
99  const float transverseMomWarningLimit = 500;
100 
101  //initialize values
102  result.set_IDCaloBoundary_eta(-999.);
103  result.set_IDCaloBoundary_phi(-999.);
104  result.set_IDCaloBoundary_r(0);
105  result.set_IDCaloBoundary_z(0);
106  result.set_IDCaloBoundary_AngleEta(-999.);
107  result.set_IDCaloBoundary_Angle3D(-999.);
108 
109  //magnitude of extrapolated position
110  double extPosDist = -1;
111 
112  for (unsigned int surfID = 0; surfID<3; surfID++){
113 
114  double R = m_CaloBoundaryR.value().at(surfID);
115  double Z = m_CaloBoundaryZ.value().at(surfID);
116 
117  ATH_MSG_DEBUG("[ExtrapolateToID] Extrapolating to ID-Calo boundary with ID="<<surfID<<" R="<<R<<" Z="<<Z);
118 
119  //extrapolated position and momentum direction at IDCaloBoundary
120  Amg::Vector3D extPos, momDir;
121 
122  //main extrapolation call
123  if(!extrapolateToCylinder(caloSteps, R, Z, extPos, momDir)) continue;
124 
125  double tolerance = 0.001;
126 
127  //test if z inside previous cylinder within some tolerance
128  ATH_MSG_DEBUG("[ExtrapolateToID] Testing condition 1: hit z="<< extPos[Amg::z]);
129  if(surfID > 0 && std::abs(extPos[Amg::z]) < m_CaloBoundaryZ[surfID-1] - tolerance) continue;
130  ATH_MSG_DEBUG("[ExtrapolateToID] Passed condition 1.");
131 
132  //test if r inside next cylinder within some tolerance
133  ATH_MSG_DEBUG("[ExtrapolateToID] Testing condition 2: hit r="<< extPos.perp());
134  if(surfID < m_CaloBoundaryR.size()-1 && extPos.perp() < m_CaloBoundaryR[surfID + 1] - tolerance) continue;
135  ATH_MSG_DEBUG("[ExtrapolateToID] Passed condition 2.");
136 
137  ATH_MSG_DEBUG("[ExtrapolateToID] Testing condition 3: hit magnitude="<< extPos.mag());
138  if(extPosDist >= 0 && extPos.mag() > extPosDist) continue;
139  ATH_MSG_DEBUG("[ExtrapolateToID] Passed condition 3.");
140 
141  extPosDist = extPos.mag();
142 
143  result.set_IDCaloBoundary_eta(extPos.eta());
144  result.set_IDCaloBoundary_phi(extPos.phi());
145  result.set_IDCaloBoundary_r(extPos.perp());
146  result.set_IDCaloBoundary_z(extPos[Amg::z]);
147 
148  ATH_MSG_DEBUG("[ExtrapolateToID] Setting IDCaloBoundary to eta="<<extPos.eta()<<" phi="<<extPos.phi()<< " r="<<extPos.perp()<<" z="<<extPos.z());
149 
150  //compute angle between extrapolated position vector and momentum at IDCaloBoundary
151  //can be used to correct shower shapes for particles which do not originate from {0,0,0}
152  double Angle3D = Amg::angle(extPos, momDir);
153  double AngleEta = extPos.theta() - momDir.theta();
154  result.set_IDCaloBoundary_AngleEta(AngleEta);
155  result.set_IDCaloBoundary_Angle3D(Angle3D);
156 
157  } //end of loop over surfaces
158 
159  if(result.IDCaloBoundary_eta() == -999) ATH_MSG_COND("[ExtrapolateToID] Failed extrapolation to ID-Calo boundary. \n[ExtrapolateToID] Particle with truth vertex at (" << truth->vertex().X() <<","<<truth->vertex().Y()<<","<<truth->vertex().Z()<<")"<<" with"<<" PdgId="<<truth->pdgid()<<" pT="<<truth->Pt()<<" eta="<<truth->Eta()<<" phi="<<truth->Phi()<<" E="<<truth->E()<<" Ekin_off="<<truth->Ekin_off(), truth->Pt() < transverseMomWarningLimit);
160 
161  ATH_MSG_DEBUG("[ExtrapolateToID] End extrapolateToID()");
162 
163 }
164 
165 
166 void FastCaloSimCaloExtrapolation::extrapolateToLayers(TFCSExtrapolationState& result, const std::vector<G4FieldTrack>& caloSteps, const TFCSTruthState* truth) const
167 {
168  ATH_MSG_DEBUG("[extrapolateToLayers] Start extrapolate");
169 
170  //pT threshold of truth particles over which extrapolation failures will be printed as warnings
171  const float transverseMomWarningLimit = 500;
172 
174  // Start calo extrapolation
176 
177  //only continue if inside the calo
178  if(std::abs(result.IDCaloBoundary_eta()) < 6){
179  //now try to extrapolate to all calo layers that contain energy
181  for(int subpos=SUBPOS_MID; subpos<=SUBPOS_EXT; ++subpos){
182 
183  float cylR, cylZ;
184  if(isCaloBarrel(sample)){
185  cylR = std::abs(rpos(sample, result.IDCaloBoundary_eta(), subpos));
186  //EMB0 - EMB3 use z position of EME1 front end surface for extrapolation
187  //else extrapolate to cylinder with symmetrized maximum Z bounds
188  //set eta to a dummy value of 1000 and -1000 to force detector side
189  if(sample < 4) cylZ = result.IDCaloBoundary_eta() > 0 ? std::abs(zpos(5, 1000, 1)) : std::abs(zpos(5, -1000, 1));
190  else cylZ = 0.5*(std::abs(zpos(sample, 1000, subpos)) + std::abs(zpos(sample, -1000, subpos)));
191  }
192  else{
193  //if we are not at barrel surface, extrapolate to cylinder with maximum R to reduce extrapolation length
194  cylZ = std::abs(zpos(sample, result.IDCaloBoundary_eta(), subpos));
195  //calculate radius of cylinder we will extrapolate to
196  double mineta, maxeta, eta;
197  minmaxeta(sample, result.IDCaloBoundary_eta(), mineta, maxeta);
198  //get eta where we will look up the layer radius
199  eta = result.IDCaloBoundary_eta() > 0 ? mineta : maxeta;
200  //calculate azimuthal angle from pseudorapidity
201  double theta = 2*std::atan(std::exp(-eta));
202  //calculate maximum R of last cell of layer from z and theta
203  cylR = std::abs(cylZ*std::sqrt((1/(std::cos(theta)*std::cos(theta))) - 1));
204  }
205 
206  Amg::Vector3D extPos, momDir;
207  if(extrapolateToCylinder(caloSteps, cylR, cylZ, extPos, momDir)){
208 
209  //scale the extrapolation to fit the radius of the cylinder in the case of barrel and scale extrapolation to fit z component in case of endcap layer
210  //scale is only non-unitary in case we extrapolate to the endcaps of the cylinder for barrel and in case we extrapolate to cover for endcaps
211  //this will keep phi, eta intact and only scale r and z to fit a sensible position on the cylinder
212  double scale = 1;
213  if (isCaloBarrel(sample) && std::abs(extPos.perp()) > 1e-6) scale = cylR / extPos.perp();
214  else if (!isCaloBarrel(sample) && std::abs(extPos.z()) > 1e-6) scale = cylZ / std::abs(extPos.z());
215  //scale extrapolated position accordingly
216  extPos = scale * extPos;
217 
218  result.set_OK(sample, subpos, true);
219  result.set_phi(sample, subpos, extPos.phi());
220  result.set_z (sample, subpos, extPos.z());
221  result.set_eta(sample, subpos, extPos.eta());
222  result.set_r (sample, subpos, extPos.perp());
223  }
224  else{
225  ATH_MSG_COND(" [extrapolateToLayers] Extrapolation to cylinder failed. Sample="<<sample<<" subpos="<<subpos<<" eta="<<result.IDCaloBoundary_eta()<<" phi="<<result.IDCaloBoundary_phi()<<" r="<<result.IDCaloBoundary_r()<<" z="<<result.IDCaloBoundary_z(), truth->Pt() < transverseMomWarningLimit);
226  }
227  } //for pos
228  } //for sample
229  } //inside calo
230 
231  else ATH_MSG_COND("[extrapolateToLayers] Ups. Not inside calo. result.IDCaloBoundary_eta()="<<result.IDCaloBoundary_eta()<< "\n[extrapolateToLayers] Particle with truth vertex at (" << truth->vertex().X() <<","<<truth->vertex().Y()<<","<<truth->vertex().Z()<<")"<<" with"<<" PdgId="<<truth->pdgid()<<" pT="<<truth->Pt()<<" eta="<<truth->Eta()<<" phi="<<truth->Phi()<<" E="<<truth->E()<<" Ekin_off="<<truth->Ekin_off(), truth->Pt() < transverseMomWarningLimit);
232 
233 
234  ATH_MSG_DEBUG("[extrapolateToLayers] End extrapolateToLayers()");
235 }
236 
237 bool FastCaloSimCaloExtrapolation::extrapolateToCylinder(const std::vector<G4FieldTrack>& caloSteps, float cylR, float cylZ, Amg::Vector3D& extPos, Amg::Vector3D& momDir) const{
238 
239  if(caloSteps.size() == 1){
240  Amg::Vector3D hitPos = Amg::Hep3VectorToEigen(caloSteps.at(0).GetPosition());
241  ATH_MSG_DEBUG("[extrapolateWithPCA(R="<<cylR<<",Z="<<cylZ<<")] Extrapolating single hit position to surface.");
242  extPos = projectOnCylinder(cylR, cylZ, hitPos);
243  momDir = Amg::Hep3VectorToEigen(caloSteps.at(0).GetMomentum());
244  return true;
245  }
246 
247  //if we do not find any good intersections, extrapolate to closest point on surface
248  bool foundHit = extrapolateWithIntersection(caloSteps, cylR, cylZ, extPos, momDir) ? true : extrapolateWithPCA(caloSteps, cylR, cylZ, extPos, momDir);
249 
250  if(foundHit){
251  ATH_MSG_DEBUG("[extrapolateToCylinder(R="<<cylR<<",Z="<<cylZ<<")::END] Extrapolated to cylinder with R="<<cylR<<" and Z="<<cylZ<<" at ("<< extPos[Amg::x]<<","<<extPos[Amg::y]<<","<<extPos[Amg::z]<<")");
252  }
253  else{
254  //this is not expected to ever happen
255  ATH_MSG_DEBUG("(R="<<cylR<<", Z="<<cylZ<<"::END) Extrapolation to cylinder surface failed!");
256  }
257 
258 
259  return foundHit;
260 
261 }
262 
263 
264 bool FastCaloSimCaloExtrapolation::extrapolateWithIntersection(const std::vector<G4FieldTrack>& caloSteps, float cylR, float cylZ, Amg::Vector3D& extPos, Amg::Vector3D& momDir) const{
265 
266  ATH_MSG_DEBUG("[extrapolateWithIntersection(R="<<cylR<<",Z="<<cylZ<<")] Checking for cylinder intersections of line segments.");
267 
268  //counter for number of computed extrapolations, does not count cases of rejected extrapolations due to close by hit positions
269  unsigned int nExtrapolations = 0;
270  for (size_t hitID = 1; hitID < caloSteps.size(); hitID++){
271  //initialize intersection result variables
272  //get current and consecutive hit position and build hitLine
273  Amg::Vector3D hitPos1 = Amg::Hep3VectorToEigen(caloSteps.at(hitID-1).GetPosition());
274  Amg::Vector3D hitPos2 = Amg::Hep3VectorToEigen(caloSteps.at(hitID).GetPosition());
275  Amg::Vector3D hitDir = hitPos2 - hitPos1;
276 
277  ATH_MSG_DEBUG("[extrapolateWithIntersection(R="<<cylR<<",Z="<<cylZ<<")] Considering line segment between ("<<hitPos1[Amg::x]<<","<<hitPos1[Amg::y]<<","<<hitPos1[Amg::z]<<") and ("
278  <<hitPos2[Amg::x]<<","<<hitPos2[Amg::y]<<","<<hitPos2[Amg::z]<<")");
279  //get position of the hit positions on the cylinder
280  HITPOSITION cylPosHit1 = whereOnCylinder(cylR, cylZ, hitPos1);
281  HITPOSITION cylPosHit2 = whereOnCylinder(cylR, cylZ, hitPos2);
282 
283  //check if one of the hit positions already lays on the cylinder surface
284  if(cylPosHit1 == ON || cylPosHit2 == ON){
285  extPos = cylPosHit1 == ON ? hitPos1 : hitPos2;
286  momDir = cylPosHit1 == ON ? Amg::Hep3VectorToEigen(caloSteps.at(hitID-1).GetMomentum()) : Amg::Hep3VectorToEigen(caloSteps.at(hitID).GetMomentum());
287  ATH_MSG_DEBUG("[extrapolateWithIntersection(R="<<cylR<<",Z="<<cylZ<<")] Hit position already on cylinder surface.");
288  return true;
289  }
290 
291  //do not try to extrapolate with intersections if the hit position are very close together
292  if(hitDir.norm() < 0.01) continue;
293 
294  //get intersections through cylinder
295  CylinderIntersections intersections = getCylinderIntersections(cylR, cylZ, hitPos1, hitPos2);
296  nExtrapolations++;
297 
298  Amg::Vector3D selectedIntersection(0, 0, 0);
299 
300  //select the best intersection
301  if(intersections.number == 1) selectedIntersection = intersections.first;
302  else if(intersections.number > 1) selectedIntersection = whichIntersection(cylR, cylZ, hitPos1, hitPos2, intersections.first, intersections.second) == 0 ?
303  intersections.first : intersections.second;
304 
305  if(intersections.number > 0){
306 
307  bool isForwardExtrapolation = (selectedIntersection[Amg::x] - hitPos1[Amg::x]) / (hitPos2[Amg::x] - hitPos1[Amg::x]) >= 0;
308  bool travelThroughSurface = doesTravelThroughSurface(cylR, cylZ, hitPos1, hitPos2);
309 
310  //do not allow for backward extrapolation except in the case of first two (distinguishable) hit positions outside cylinder
311  //and in the case we detect a travel though the surface
312  if(nExtrapolations > 1 && !isForwardExtrapolation && !travelThroughSurface) continue;
313 
314  //check if the intersection between infinite line and cylinder lays on segment spanned by hit positions
315  bool intersectionOnSegment = isOnSegment(selectedIntersection, hitPos1, hitPos2);
316  //check if both hit positions lay outside of the cylinder
317  bool hitPosOutside = cylPosHit1 == OUTSIDE && cylPosHit2 == OUTSIDE;
318 
319  //we found our extrapolated hit position in case that either
320  //we detect that the line segment crosses the surface of the cylinder
321  //the intersection between the infinite lines and the cylinder lays on the line segment
322  //both hit positions are outside of the cylinder and there is a backwards extrapolation for the first two hit positions
323  //if this is not the case for any of the hit position pairs we will use the last two hit position for the linear extrapolation
324  //if these do not have any intersection, then we will pass back to extrapolateWithPCA
325  if(travelThroughSurface || intersectionOnSegment || (hitPosOutside && !isForwardExtrapolation && nExtrapolations == 1) || caloSteps.size()-1 == hitID){
326  //take momentum direction of hit position closest to cylinder surface
327  //alternatively one could also take the extrapolated direction normDir = hitPos2 - hitPos1
328  double distHitPos1 = (hitPos1 - projectOnCylinder(cylR, cylZ, hitPos1)).norm();
329  double distHitPos2 = (hitPos2 - projectOnCylinder(cylR, cylZ, hitPos2)).norm();
330  momDir = distHitPos1 < distHitPos2 ? Amg::Hep3VectorToEigen(caloSteps.at(hitID-1).GetMomentum()) : Amg::Hep3VectorToEigen(caloSteps.at(hitID).GetMomentum());
331  extPos = selectedIntersection;
332  return true;
333  }
334  ATH_MSG_DEBUG("[extrapolateWithIntersection(R="<<cylR<<",Z="<<cylZ<<")] Extrapolated position at ("<<selectedIntersection[Amg::x]<<","<<selectedIntersection[Amg::y]<<","<<selectedIntersection[Amg::z]<<")");
335  }
336  } //end of loop over hit positions
337 
338  return false;
339 }
340 
341 
342 bool FastCaloSimCaloExtrapolation::extrapolateWithPCA(const std::vector<G4FieldTrack>& caloSteps, float cylR, float cylZ, Amg::Vector3D& extPos, Amg::Vector3D& momDir) const{
343 
344  bool foundHit = false;
345  ATH_MSG_DEBUG("[extrapolateWithPCA(R="<<cylR<<",Z="<<cylZ<<")] No forward intersections with cylinder surface. Extrapolating to closest point on surface.");
346 
347  //here we also need to consider distances from line segments to the cylinder
348  double minDistToSurface = 100000;
349  for (size_t hitID = 1; hitID < caloSteps.size(); hitID++){
350 
351  Amg::Vector3D hitPos1 = Amg::Hep3VectorToEigen(caloSteps.at(hitID-1).GetPosition());
352  Amg::Vector3D hitPos2 = Amg::Hep3VectorToEigen(caloSteps.at(hitID).GetPosition());
353 
354  ATH_MSG_DEBUG("[extrapolateWithPCA(R="<<cylR<<",Z="<<cylZ<<")] Considering line segment between ("<<hitPos1[Amg::x]<<","<<hitPos1[Amg::y]<<","<<hitPos1[Amg::z]<<") and ("<<hitPos2[Amg::x]<<","<<hitPos2[Amg::y]<<","<<hitPos2[Amg::z]<<")");
355 
356  Amg::Vector3D PCA;
357  //find the point of closest approach (PCA) to the cylinder on the line segment
358  findPCA(cylR, cylZ, hitPos1, hitPos2, PCA);
359  //compute distance between PCA and cylinder
360  Amg::Vector3D cylinderSurfacePCA = projectOnCylinder(cylR, cylZ, PCA);
361  double tmpMinDistToSurface = (PCA - cylinderSurfacePCA).norm();
362 
363  ATH_MSG_DEBUG("[extrapolateWithPCA(R="<<cylR<<",Z="<<cylZ<<")] Extrapolated line segment to ("<<cylinderSurfacePCA[Amg::x]<<","<<cylinderSurfacePCA[Amg::y]<<","<<cylinderSurfacePCA[Amg::z]<<") with distance "<<tmpMinDistToSurface);
364 
365  if(tmpMinDistToSurface < minDistToSurface){
366  foundHit = true;
367  extPos = cylinderSurfacePCA;
368  //take momentum direction of hit position closest to cylinder surface
369  //alternatively one could also take the extrapolated direction normDir = hitPos2 - hitPos1
370  double distHitPos1 = (hitPos1 - projectOnCylinder(cylR, cylZ, hitPos1)).norm();
371  double distHitPos2 = (hitPos2 - projectOnCylinder(cylR, cylZ, hitPos2)).norm();
372  momDir = distHitPos1 < distHitPos2 ? Amg::Hep3VectorToEigen(caloSteps.at(hitID-1).GetMomentum()) : Amg::Hep3VectorToEigen(caloSteps.at(hitID).GetMomentum());
373 
374  minDistToSurface = tmpMinDistToSurface;
375  }
376  } //end over loop of hit postions
377 
378  return foundHit;
379 }
380 
381 
382 void FastCaloSimCaloExtrapolation::findPCA(float cylR, float cylZ, Amg::Vector3D& hitPos1, Amg::Vector3D& hitPos2, Amg::Vector3D& PCA) const{
383  //in the following we will try to find the closest point-of-approach (PCA) to the cylinder on the line segment
384  //hit direction
385  Amg::Vector3D hitDir = hitPos2 - hitPos1;
386 
387  //project both hit positions onto the cylinder
388  Amg::Vector3D projCylinderHitPos1 = projectOnCylinder(cylR, cylZ, hitPos1);
389  Amg::Vector3D projCylinderHitPos2 = projectOnCylinder(cylR, cylZ, hitPos2);
390  //direction of line spanned by the two projected points on the cylinder surface
391  Amg::Vector3D cylinderProjDir = projCylinderHitPos2 - projCylinderHitPos1;
392 
393  //CASE A: projections on the cylinder are close enough, take one of the hit positions as PCA
394  if(cylinderProjDir.norm() < 0.0001) {PCA = hitPos1; return;};
395 
396  //CASE B: we are outside the Z bounds of the cylinder
397  if((hitPos1[Amg::z] > cylZ || hitPos1[Amg::z] < -cylZ) || (hitPos2[Amg::z] > cylZ || hitPos2[Amg::z] < -cylZ)){
398 
399  //calculate PCA to point on endcap
400  Amg::Vector3D cylZEndcap(0, 0, cylZ);
401  bool isParallelToEndcap = std::abs(hitPos1[Amg::z] - hitPos2[Amg::z]) < 0.00001;
402 
403  //Check if parallel to endcap plane
404  if(isParallelToEndcap){
405 
406  //if both inside there are infinite solutions take one in the middle
407  Amg::Vector3D intersectA, intersectB;
408  intersectA.setZero();
409  intersectB.setZero();
410  int nIntersections = circleLineIntersection2D(cylR, hitPos1, hitPos2, intersectA, intersectB);
411 
412  if(nIntersections == 2){
413 
414  bool IntAOnSegment = isOnSegment(intersectA, hitPos1, hitPos2);
415  bool IntBOnSegment = isOnSegment(intersectB, hitPos1, hitPos2);
416 
417  if(IntAOnSegment && IntBOnSegment) PCA = intersectA + 0.5*(intersectB-intersectA);
418  else if(IntAOnSegment) PCA = hitPos1.perp() <= cylR ? intersectA + 0.5*(hitPos1 - intersectA) : intersectA + 0.5*(hitPos2 - intersectA);
419  else if(IntBOnSegment) PCA = hitPos1.perp() <= cylR ? intersectB + 0.5*(hitPos1 - intersectB) : intersectB + 0.5*(hitPos2 - intersectB);
420  //intersections are not on line segment, i.e. line segment is within extended cylinder
421  else PCA = hitPos1 + 0.5*hitDir;
422 
423  }
424  else if(!intersectA.isZero() || !intersectB.isZero()){
425  //this can only happen if the extended line is tangetial to the cylinder
426  //if intersection lays on segment PCA will be intersection, if not it will be the corresponding end points
427  Amg::Vector3D intersect = intersectA.isZero() ? intersectB : intersectA;
428  Amg::Vector3D hitPos = (hitPos1 - intersect).norm() < (hitPos2 - intersect).norm() ? hitPos1 : hitPos2;
429  bool IntOnSegment = isOnSegment(intersectA, hitPos1, hitPos2);
430  PCA = IntOnSegment ? intersect : hitPos;
431 
432  }
433  else{
434  //line segment is outside extended cylinder
435  //PCA corresponds to closest distance to center {0, 0, cylZ}
436  Amg::Vector3D infLinePCA = hitPos1 + ((cylZEndcap-hitPos1).dot(hitDir)/hitDir.dot(hitDir))*(hitDir);
437 
438  if(isOnSegment(infLinePCA, hitPos1, hitPos2)) PCA = infLinePCA;
439  else PCA = (hitPos1 - infLinePCA).norm() < (hitPos2 - infLinePCA).norm() ? hitPos1 : hitPos2;
440 
441  }
442  }
443 
444  else{
445 
446  //figure out all other cases iteratively beginning with BoundA and BoundB
447  Amg::Vector3D BoundA, BoundB;
448  //this is point on line closest to {0, 0, cylZ}, always on segment
449  double t = ((cylZEndcap-hitPos1).dot(hitDir)/hitDir.dot(hitDir));
450  BoundA = t <= 0 ? hitPos1 : (t >= 1 ? hitPos2 : hitPos1 + t*hitDir);
451 
452  //calculate intersection point of line segment and endcap plane and project intersection onto cylinder
453  //check if t is between 0 and 1, if not, take hitpos as starting bound
454  t = (cylZ-hitPos1[Amg::z]) / hitDir[Amg::z];
455  BoundB = t <= 0 ? hitPos1 : (t >= 1 ? hitPos2 : hitPos1 + t*hitDir);
456  //looks for the PCA iteratively in cases there is no easy analytical solution
457  getIterativePCA(cylR, cylZ, BoundA, BoundB, PCA);
458 
459  }
460 
461  return;
462  }
463 
464  //CASE C: we are inside the Z bounds of the cylinder
465  //construct Z axis as straight line surface
466  Trk::StraightLineSurface line(Amg::Transform3D(Trk::s_idTransform), 0, cylZ);
467  //compute point of closest approach to z axis
468  //this is analogous to finding the PCA of two 3D lines
469  Trk::Intersection PCACylBounds = line.straightLineIntersection(hitPos1, hitDir.unit(), false, true);
470 
471  double distSurfHit1 = (projCylinderHitPos1 - hitPos1).norm();
472  double distSurfHit2 = (projCylinderHitPos2 - hitPos2).norm();
473 
474  //take PCA on line in case it lays on segment, otherwise take closest hit position to surface
475  PCA = isOnSegment(PCACylBounds.position, hitPos1, hitPos2) ? PCACylBounds.position : (distSurfHit1 < distSurfHit2 ? hitPos1 : hitPos2);
476 
477 }
478 
479 
480 #if defined(FLATTEN)
481 // We compile this package with optimization, even in debug builds; otherwise,
482 // the heavy use of Eigen makes it too slow. However, from here we may call
483 // to out-of-line Eigen code that is linked from other DSOs; in that case,
484 // it would not be optimized. Avoid this by forcing all Eigen code
485 // to be inlined here if possible.
487 #endif
488 void FastCaloSimCaloExtrapolation::getIterativePCA(float cylR, float cylZ, Amg::Vector3D& BoundA, Amg::Vector3D& BoundB, Amg::Vector3D& PCA) const{
489 
490  ATH_MSG_DEBUG("[getIterativePCA] Finding PCA iteratively.");
491 
492  Amg::Vector3D boundDir = BoundB - BoundA;
493  double distBounds = boundDir.norm();
494 
495  //this sets the precision of the iterative finding procedure
496  const double stepSize = 0.01;
497 
498  //if bounds are close enough together, there is nothing to do
499  //should make sure that nHalfDivisions >= 2
500  if (distBounds <= 4*stepSize){PCA = BoundA + 0.5*(BoundB - BoundA); return;}
501 
502  Amg::Vector3D tmpBoundA, tmpBoundB, tmpOnCylinderBoundA, tmpOnCylinderBoundB;
503  Amg::Vector3D resBoundA, resBoundB, resOnCylinderBoundA, resOnCylinderBoundB;
504 
505 
506  //initial positions on cylinder and distance to line segment
507  Amg::Vector3D OnCylinderBoundA = projectOnCylinder(cylR, cylZ, BoundA);
508  Amg::Vector3D OnCylinderBoundB = projectOnCylinder(cylR, cylZ, BoundB);
509 
510  double minDistA = (BoundA - OnCylinderBoundA).norm();
511  double minDistB = (BoundB - OnCylinderBoundB).norm();
512 
513  //initialize result bounds with closest input bounds as fall back option
514  if(minDistA < minDistB){
515  resBoundA = BoundA;
516  resBoundB = BoundA;
517  }
518  else{
519  resBoundA = BoundB;
520  resBoundB = BoundB;
521  }
522  double tmpMinDistA, tmpMinDistB;
523  unsigned int nHalfDivisions = (distBounds/stepSize)/2;
524  for(unsigned int step = 0; step < nHalfDivisions; step++){
525 
526  //temporary bounds on line segment
527  tmpBoundA = BoundA + (step+1)*stepSize*(boundDir/distBounds);
528  tmpBoundB = BoundB - (step+1)*stepSize*(boundDir/distBounds);
529 
530  //temporary projected bounds on cylinder
531  tmpOnCylinderBoundA = projectOnCylinder(cylR, cylZ, tmpBoundA);
532  tmpOnCylinderBoundB = projectOnCylinder(cylR, cylZ, tmpBoundB);
533 
534  //temporary minimum distance between bound on segment and bound on cylinder
535  tmpMinDistA = (tmpBoundA - tmpOnCylinderBoundA).norm();
536  tmpMinDistB = (tmpBoundB - tmpOnCylinderBoundB).norm();
537 
538  if(minDistA >= tmpMinDistA){
539  minDistA = tmpMinDistA;
540  }
541  else{
542  double t = (step*stepSize)/distBounds;
543  resBoundA = BoundA + t*boundDir;
544  resBoundB = tmpBoundA;
545  break;
546  }
547 
548  if(minDistB >= tmpMinDistB){
549  minDistB = tmpMinDistB;
550  }
551  else{
552  double t = (step*stepSize)/distBounds;
553  resBoundB = BoundB - t*boundDir;
554  resBoundA = tmpBoundB;
555  break;
556  }
557  }
558 
559  //return middle of best bounds
560  PCA = resBoundA + 0.5*(resBoundB - resBoundA);
561 
562 }
563 
564 
565 int FastCaloSimCaloExtrapolation::circleLineIntersection2D(float circR, Amg::Vector3D& pointA, Amg::Vector3D& pointB, Amg::Vector3D& intersectA, Amg::Vector3D& intersectB) const{
566  //find intersections intA and intB with line spanned by pointA and pointB
567  //returns number of intersections
568  //assumes circle lays in xy plane
569 
570  double dx, dy, A, B, C, det, t;
571 
572  dx = pointB[Amg::x] - pointA[Amg::x];
573  dy = pointB[Amg::y] - pointA[Amg::y];
574 
575  A = dx * dx + dy * dy;
576  B = 2 * (dx * pointA[Amg::x] + dy * pointA[Amg::y]);
577  C = pointA[Amg::x] * pointA[Amg::x] + pointA[Amg::y] * pointA[Amg::y] - circR * circR;
578 
579  det = B * B - 4 * A * C;
580 
581  if (A <= 0.0000001 || det < 0){
582  ATH_MSG_DEBUG("[circleLineIntersection2D] No intersections.");
583  return 0;
584  }
585  else if (std::abs(det) < 0.00001){
586  //one solution, tangential case.
587  t = -B / (2 * A);
588  intersectA = {pointA[Amg::x] + t * dx, pointA[Amg::y] + t * dy, pointA[Amg::z]};
589  ATH_MSG_DEBUG("[circleLineIntersection2D] One intersection at ("<<intersectA[Amg::x]<<","<<intersectA[Amg::y]<<","<<intersectA[Amg::z]<<").");
590  return 1;
591  }
592  else{
593  // two solutions
594  t = (-B + std::sqrt(det)) / (2 * A);
595  intersectA = {pointA[Amg::x] + t * dx, pointA[Amg::y] + t * dy, pointA[Amg::z]};
596  t = (-B - std::sqrt(det)) / (2 * A);
597  intersectB = {pointA[Amg::x] + t * dx, pointA[Amg::y] + t * dy, pointB[Amg::z]};
598  ATH_MSG_DEBUG("[circleLineIntersection2D] Two intersections at ("<<intersectA[Amg::x]<<","<<intersectA[Amg::y]<<","<<intersectA[Amg::z]<<") and at ("<<intersectB[Amg::x]<<","<<intersectB[Amg::y]<<","<<intersectB[Amg::z]<<").");
599  return 2;
600  }
601 
602 
603 }
604 
605 
606 #if defined(FLATTEN)
607 // We compile this package with optimization, even in debug builds; otherwise,
608 // the heavy use of Eigen makes it too slow. However, from here we may call
609 // to out-of-line Eigen code that is linked from other DSOs; in that case,
610 // it would not be optimized. Avoid this by forcing all Eigen code
611 // to be inlined here if possible.
613 #endif
615 
616  Amg::Vector3D closestPointOnCylinder;
617  Amg::Vector3D cylAxis(0, 0, cylZ);
618 
619  //positive side
620  if(hitPos[Amg::z] >= cylZ){
621  //project hit position on x-y plane at positive side
622  Amg::Vector3D projHitPos(hitPos[Amg::x], hitPos[Amg::y], cylZ);
623 
624  //if r of hit position outside cylinder, closest hit is always on edge
625  if(hitPos.perp() > cylR) closestPointOnCylinder = cylAxis + cylR * (projHitPos - cylAxis).unit();
626  else closestPointOnCylinder = cylAxis + hitPos.perp() * (projHitPos - cylAxis).unit();
627 
628  }
629  //negative side
630  else if (hitPos[Amg::z] <= -cylZ){
631  //project hit position on x-y plane at negative side
632  Amg::Vector3D projHitPos(hitPos[Amg::x], hitPos[Amg::y], -cylZ);
633 
634  if(hitPos.perp() > cylR) closestPointOnCylinder = -cylAxis + cylR * (projHitPos + cylAxis).unit();
635  else closestPointOnCylinder = -cylAxis + hitPos.perp() * (projHitPos + cylAxis).unit();
636 
637  }
638  else{
639  Amg::Vector3D hitPosZ(0, 0, hitPos[Amg::z]);
640  closestPointOnCylinder = hitPosZ + cylR * (hitPos - hitPosZ).unit();
641  }
642 
643  return closestPointOnCylinder;
644 
645 }
646 
647 
648 
650  //calculates intersection of infinite line with cylinder --> can have 0 or 2 intersections
651  CylinderIntersections intersections;
652 
653  //look for intersections with the cover of the cylinder
654  unsigned int nCoverIntersections = cylinderLineIntersection(cylR, cylZ, hitPos1, hitPos2, intersections.first, intersections.second);
655  if(nCoverIntersections == 2){
656  ATH_MSG_DEBUG("[getCylinderIntersections(R="<<cylR<<",Z="<<cylZ<<")] Found two cylinder intersections through cylinder cover.");
657  intersections.number = 2;
658  return intersections;
659  }
660  else if (nCoverIntersections == 1){
661 
662  Amg::Vector3D positiveEndcapIntersection, negativeEndcapIntersection;
663  bool IsPositiveEndcapIntersection = cylinderEndcapIntersection(cylR, cylZ, true, hitPos1, hitPos2, positiveEndcapIntersection);
664  bool IsNegativeEndcapIntersection = cylinderEndcapIntersection(cylR, cylZ, false, hitPos1, hitPos2, negativeEndcapIntersection);
665 
666  if(IsPositiveEndcapIntersection && IsNegativeEndcapIntersection){
667  //if we have a cover intersection we only expect one additional endcap intersection
668  //both endcap intersections can be valid in case the intersection is at the edge of the cylinder cover and endcap
669  //in that case take the endcap intersection which is further away from the cylinder cover intersection to prevent taking the same intersection twice
670  ATH_MSG_DEBUG("[getCylinderIntersections(R="<<cylR<<",Z="<<cylZ<<")] Found intersection through cylinder cover and both endcaps. Intersection seems to be at edge of cover and endcap.");
671  intersections.second = (positiveEndcapIntersection - intersections.first).norm() > (negativeEndcapIntersection - intersections.first).norm() ? positiveEndcapIntersection : negativeEndcapIntersection;
672  intersections.number = 2;
673  }
674  else if(IsPositiveEndcapIntersection) {
675  ATH_MSG_DEBUG("[getCylinderIntersections(R="<<cylR<<",Z="<<cylZ<<")] Found intersection through cylinder cover and positive endcap.");
676  intersections.second = positiveEndcapIntersection;
677  intersections.number = 2;
678  }
679  else if(IsNegativeEndcapIntersection) {
680  ATH_MSG_DEBUG("[getCylinderIntersections(R="<<cylR<<",Z="<<cylZ<<")] Found intersection through cylinder cover and negative endcap.");
681  intersections.second = negativeEndcapIntersection;
682  intersections.number = 2;
683  }
684  else{
685  //line is tangential to cylinder cover
686  ATH_MSG_DEBUG("[getCylinderIntersections(R="<<cylR<<",Z="<<cylZ<<")] Found single intersection through cylinder cover.");
687  intersections.number = 1;
688  }
689 
690  }
691  else{
692  //no cylinder cover intersections
693  Amg::Vector3D positiveEndcapIntersection, negativeEndcapIntersection;
694  bool IsPositiveEndcapIntersection = cylinderEndcapIntersection(cylR, cylZ, true, hitPos1, hitPos2, positiveEndcapIntersection);
695  bool IsNegativeEndcapIntersection = cylinderEndcapIntersection(cylR, cylZ, false, hitPos1, hitPos2, negativeEndcapIntersection);
696 
697  if(IsPositiveEndcapIntersection && IsNegativeEndcapIntersection){
698  ATH_MSG_DEBUG("[getCylinderIntersections(R="<<cylR<<",Z="<<cylZ<<")] Found intersections through both endcaps.");
699  intersections.first = positiveEndcapIntersection;
700  intersections.second = negativeEndcapIntersection;
701  intersections.number = 2;
702  }
703  else if(IsPositiveEndcapIntersection) {
704  //dont expect this to ever happen
705  ATH_MSG_DEBUG("[getCylinderIntersections(R="<<cylR<<",Z="<<cylZ<<")] Found single intersection through positive endcap. This should not happen.");
706  intersections.first = positiveEndcapIntersection;
707  intersections.number = 1;
708  }
709  else if(IsNegativeEndcapIntersection) {
710  //dont expect this to ever happen
711  ATH_MSG_DEBUG("[getCylinderIntersections(R="<<cylR<<",Z="<<cylZ<<")] Found single intersection through negative endcap. This should not happen.");
712  intersections.first = negativeEndcapIntersection;
713  intersections.number = 1;
714  }
715  else{
716  ATH_MSG_DEBUG("[getCylinderIntersections(R="<<cylR<<",Z="<<cylZ<<")] Found no cylinder intersections.");
717  //no intersections at all
718  intersections.number = 0;
719 
720  }
721  }
722 
723  return intersections;
724 
725 
726 }
727 
728 
729 //calculates the intersection between the line defined by pointA and pointB and the cylinder cover definded by cylR and cylZ
730 int FastCaloSimCaloExtrapolation::cylinderLineIntersection(float cylR, float cylZ, Amg::Vector3D& pointA, Amg::Vector3D& pointB, Amg::Vector3D& intersectA, Amg::Vector3D& intersectB) const{
731 
732  //projections of points spanning the line onto the xy plane
733  Amg::Vector3D projPointA(pointA[Amg::x], pointA[Amg::y], 0);
734  Amg::Vector3D projPointB(pointB[Amg::x], pointB[Amg::y], 0);
735  Amg::Vector3D projDiff = projPointA - projPointB;
736 
737  //calculate distance from (0,0,0) to line spanned by projPointA and projPointB
738  double projDiffNorm2 = projDiff.dot(projDiff);
739  double t = projPointA.dot(projDiff) / projDiffNorm2;
740  double d2 = projPointA.dot(projPointA) - t*t*projDiffNorm2;
741 
742  if(d2 < 0){
743  ATH_MSG_COND("[cylinderLineIntersection] Got negative distance (d2="<<d2<<"). Forcing to 0.", d2 > -0.001);
744  d2 = 0;
745  }
746 
747  //if distance larger than cylinder radius then there are no intersection and we are done
748  if(d2 > cylR*cylR) return 0;
749 
750  double k = std::sqrt((cylR*cylR - d2)/projDiffNorm2);
751 
752  intersectA = pointA + (t+k)*(pointB - pointA);
753  intersectB = pointA + (t-k)*(pointB - pointA);
754 
755  //check if intersection is outside z bounds
756  bool IntAisValid = (intersectA[Amg::z] <= cylZ && intersectA[Amg::z] >= -cylZ);
757  bool IntBisValid = (intersectB[Amg::z] <= cylZ && intersectB[Amg::z] >= -cylZ);
758 
759  if(IntAisValid && IntBisValid) return 2;
760  else if(IntAisValid) return 1;
761  else if(IntBisValid){
762  intersectA = intersectB;
763  return 1;
764  }
765 
766 
767  return 0;
768 
769 }
770 
771 
772 bool FastCaloSimCaloExtrapolation::cylinderEndcapIntersection(float cylR, float cylZ, bool positiveEndcap, Amg::Vector3D& pointA, Amg::Vector3D& pointB, Amg::Vector3D& intersection) {
773 
774  //normal and point on endcap defines the plane
775  Amg::Vector3D pointOnEndcap;
776  Amg::Vector3D normal(0, 0, 1);
777  positiveEndcap ? pointOnEndcap = {0, 0, cylZ} : pointOnEndcap = {0, 0, -cylZ};
778  Amg::Vector3D hitDir = (pointB - pointA);
779 
780  double denom = normal.dot(hitDir);
781  if (std::abs(denom) > 1e-6) {
782  double t = normal.dot(pointOnEndcap - pointB)/denom;
783  //compute intersection regardless of direction (t>0 or t<0)
784  intersection = pointB + t*hitDir;
785  Amg::Vector3D v = intersection - pointOnEndcap;
786 
787  //check if intersection is within cylR bounds
788  return std::sqrt(v.dot(v)) <= cylR;
789 
790  }
791 
792  return false;
793 
794  }
795 
796 int FastCaloSimCaloExtrapolation::whichIntersection(float cylR, float cylZ, Amg::Vector3D& hitPos1, Amg::Vector3D& hitPos2, Amg::Vector3D& intersectionA, Amg::Vector3D intersectionB) const{
797 
798  //check if the hit positions are outside or inside the cylinder surface
799  HITPOSITION cylPosHit1 = whereOnCylinder(cylR, cylZ, hitPos1);
800  HITPOSITION cylPosHit2 = whereOnCylinder(cylR, cylZ, hitPos2);
801 
802  if((cylPosHit1 == INSIDE) ^ (cylPosHit2 == INSIDE)){
803  /* CASE A: one hit position inside and one outside of the cylinder (travel through surface),
804  one intersection is on cylinder, take intersection closest to line segment */
805  ATH_MSG_DEBUG("[whichIntersection] Travel through surface.");
806  return getPointLineSegmentDistance(intersectionA, hitPos1, hitPos2) > getPointLineSegmentDistance(intersectionB, hitPos1, hitPos2);
807  }
808  else if(cylPosHit1 == INSIDE && cylPosHit2 == INSIDE){
809  /* CASE B: both hit position inside, take intersection which points towards travel direction of particle */
810  Amg::Vector3D directionA = intersectionA - hitPos2;
811  Amg::Vector3D directionB = intersectionB - hitPos2;
812  Amg::Vector3D hitDir = hitPos2 - hitPos1;
813  ATH_MSG_DEBUG("[whichIntersection] Both hit positions inside.");
814  return directionA.dot(hitDir) < directionB.dot(hitDir);
815  }
816  else{
817  // /* CASE C: both hit position outside and the intersections lay on the segment, take intersection closest to second hit position */
818  // /* CASE D: both hit positions are outside and the intersections are not on the line segment, take intersection closest to one of the hit positions */
819  double distHitPosIntersectA = (hitPos2 - intersectionA).norm();
820  double distHitPosIntersectB = (hitPos2 - intersectionB).norm();
821  ATH_MSG_DEBUG("[whichIntersection] Both hit positions outside.");
822  return distHitPosIntersectA > distHitPosIntersectB;
823  }
824 }
825 
826 #if defined(FLATTEN)
827 // We compile this package with optimization, even in debug builds; otherwise,
828 // the heavy use of Eigen makes it too slow. However, from here we may call
829 // to out-of-line Eigen code that is linked from other DSOs; in that case,
830 // it would not be optimized. Avoid this by forcing all Eigen code
831 // to be inlined here if possible.
833 #endif
835 
836  Amg::Vector3D hitDir = hitPos2 - hitPos1;
837  Amg::Vector3D w = point - hitPos1;
838 
839  double c1 = w.dot(hitDir);
840  if(c1 <= 0) return Amg::distance(point, hitPos1);
841  double c2 = hitDir.dot(hitDir);
842  if(c2 <= c1) return Amg::distance(point, hitPos2);
843  double t = c1/c2;
844  Amg::Vector3D vec = hitPos1 + t*hitDir;
845  return Amg::distance(point, vec);
846 
847 }
848 
850  //set a 1mm tolerance within which the hit position is considered to be on the cylinder surface
851  //setting this higher can lead to extrapolation failures around truth particle eta ~4
852  float tolerance = 1;
853 
854  bool isOnEndcap = hitPos.perp() <= cylR + tolerance && (hitPos[Amg::z] > 0 ? std::abs(hitPos[Amg::z] - cylZ) < tolerance : std::abs(hitPos[Amg::z] + cylZ) < tolerance);
855  bool isOnCover = std::abs(hitPos.perp() - cylR) < tolerance && hitPos[Amg::z] < cylZ && hitPos[Amg::z] > -cylZ;
856 
857  //check if hit position is on endcap or cover of cylinder
858  if(isOnEndcap || isOnCover) return HITPOSITION::ON;
859 
860  //check if hit position is inside cover
861  if(hitPos[Amg::z] < cylZ && hitPos[Amg::z] > -cylZ && hitPos.perp() < cylR) return HITPOSITION::INSIDE;
862 
863  return HITPOSITION::OUTSIDE;
864 }
865 
867  //travel through surface in case one hit position is outside and the other outside of cylinder surface
868  return (whereOnCylinder(cylR, cylZ, hitPos1) == INSIDE) ^ (whereOnCylinder(cylR, cylZ, hitPos2) == INSIDE);
869 }
870 
872  return getPointLineSegmentDistance(point, hitPos1, hitPos2) < 0.001;
873 }
874 
876 {
878 }
879 
881 {
882  return GetCaloGeometry()->deta(sample, eta);
883 }
884 
885 void FastCaloSimCaloExtrapolation::minmaxeta(int sample, double eta, double& mineta, double& maxeta) const
886 {
887  GetCaloGeometry()->minmaxeta(sample, eta, mineta, maxeta);
888 }
889 
891 {
892  return GetCaloGeometry()->rmid(sample, eta);
893 }
894 
896 {
897  return GetCaloGeometry()->zmid(sample, eta);
898 }
899 
901 {
902  return GetCaloGeometry()->rzmid(sample, eta);
903 }
904 
906 {
907  return GetCaloGeometry()->rent(sample, eta);
908 }
909 
911 {
912  return GetCaloGeometry()->zent(sample, eta);
913 }
914 
916 {
917  return GetCaloGeometry()->rzent(sample, eta);
918 }
919 
921 {
922  return GetCaloGeometry()->rext(sample, eta);
923 }
924 
926 {
927  return GetCaloGeometry()->zext(sample, eta);
928 }
929 
931 {
932  return GetCaloGeometry()->rzext(sample, eta);
933 }
934 
935 double FastCaloSimCaloExtrapolation::rpos(int sample, double eta, int subpos) const
936 {
937  return GetCaloGeometry()->rpos(sample, eta, subpos);
938 }
939 
940 double FastCaloSimCaloExtrapolation::zpos(int sample, double eta, int subpos) const
941 {
942  return GetCaloGeometry()->zpos(sample, eta, subpos);
943 }
944 
945 double FastCaloSimCaloExtrapolation::rzpos(int sample, double eta, int subpos) const
946 {
947  return GetCaloGeometry()->rzpos(sample, eta, subpos);
948 }
FastCaloSimCaloExtrapolation::rzext
double rzext(int sample, double eta) const
Definition: FastCaloSimCaloExtrapolation.cxx:930
FastCaloSimCaloExtrapolation::doesTravelThroughSurface
static bool doesTravelThroughSurface(float cylR, float cylZ, Amg::Vector3D &hitPos1, Amg::Vector3D &hitPos2)
Returns true if the line segment spanned by hitPos1 and hitPos2 crosses the cylinder surface,...
Definition: FastCaloSimCaloExtrapolation.cxx:866
ICaloGeometry::deta
virtual double deta(int sample, double eta) const =0
PlotCalibFromCool.norm
norm
Definition: PlotCalibFromCool.py:100
checkFileSG.line
line
Definition: checkFileSG.py:75
FastCaloSimCaloExtrapolation.h
tolerance
constexpr double tolerance
Definition: runMdtGeoComparison.cxx:105
Trk::Intersection
Definition: Intersection.h:24
inline_hints.h
get_generator_info.result
result
Definition: get_generator_info.py:21
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
IDTPM::R
float R(const U &p)
Definition: TrackParametersHelper.h:101
Amg::angle
double angle(const Amg::Vector3D &v1, const Amg::Vector3D &v2)
calculates the opening angle between two vectors
Definition: GeoPrimitivesHelpers.h:41
CaloCell_ID_FCS::FirstSample
@ FirstSample
Definition: FastCaloSim_CaloCell_ID.h:18
FastCaloSimCaloExtrapolation::SUBPOS_EXT
@ SUBPOS_EXT
Definition: FastCaloSimCaloExtrapolation.h:45
ICaloGeometry::rpos
virtual double rpos(int sample, double eta, int subpos=CaloSubPos::SUBPOS_MID) const =0
eta
Scalar eta() const
pseudorapidity method
Definition: AmgMatrixBasePlugin.h:79
Monitored::Z
@ Z
Definition: HistogramFillerUtils.h:24
FastCaloSimCaloExtrapolation::deta
double deta(int sample, double eta) const
Definition: FastCaloSimCaloExtrapolation.cxx:880
FastCaloSimCaloExtrapolation::rext
double rext(int sample, double eta) const
Definition: FastCaloSimCaloExtrapolation.cxx:920
theta
Scalar theta() const
theta method
Definition: AmgMatrixBasePlugin.h:71
extractSporadic.c1
c1
Definition: extractSporadic.py:134
DMTest::C
C_v1 C
Definition: C.h:26
FastCaloSimCaloExtrapolation::circleLineIntersection2D
int circleLineIntersection2D(float circR, Amg::Vector3D &pointA, Amg::Vector3D &pointB, Amg::Vector3D &intersectA, Amg::Vector3D &intersectB) const
Analytically computes 2D intersections between circle of radius circR and (infinite) line spanned by ...
Definition: FastCaloSimCaloExtrapolation.cxx:565
Amg::y
@ y
Definition: GeoPrimitives.h:35
FastCaloSimCaloExtrapolation::isOnSegment
static bool isOnSegment(Amg::Vector3D &point, Amg::Vector3D &hitPos1, Amg::Vector3D &hitPos2)
Returns true if point lies on the line segment spanned by hitPos1 and hitPos2, otherwise returns fals...
Definition: FastCaloSimCaloExtrapolation.cxx:871
FastCaloSimCaloExtrapolation::zpos
double zpos(int sample, double eta, int subpos=CaloSubPos::SUBPOS_MID) const
Definition: FastCaloSimCaloExtrapolation.cxx:940
CylinderIntersections::second
Amg::Vector3D second
Definition: FastCaloSimCaloExtrapolation.h:25
vec
std::vector< size_t > vec
Definition: CombinationsGeneratorTest.cxx:12
TFCSExtrapolationState
Definition: TFCSExtrapolationState.h:13
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
drawFromPickle.cos
cos
Definition: drawFromPickle.py:36
ICaloGeometry::rmid
virtual double rmid(int sample, double eta) const =0
drawFromPickle.exp
exp
Definition: drawFromPickle.py:36
yodamerge_tmp.scale
scale
Definition: yodamerge_tmp.py:138
FastCaloSimCaloExtrapolation::FastCaloSimCaloExtrapolation
FastCaloSimCaloExtrapolation(const std::string &t, const std::string &n, const IInterface *p)
Definition: FastCaloSimCaloExtrapolation.cxx:47
intersection
std::vector< std::string > intersection(std::vector< std::string > &v1, std::vector< std::string > &v2)
Definition: compareFlatTrees.cxx:25
FastCaloSimCaloExtrapolation::extrapolateWithIntersection
bool extrapolateWithIntersection(const std::vector< G4FieldTrack > &caloSteps, float cylR, float cylZ, Amg::Vector3D &extPos, Amg::Vector3D &momDir) const
Extrapolates position on cylinder by finding intersections of subsequent hit positions,...
Definition: FastCaloSimCaloExtrapolation.cxx:264
FastCaloSimCaloExtrapolation::initialize
virtual StatusCode initialize() override final
Definition: FastCaloSimCaloExtrapolation.cxx:52
FastCaloSimCaloExtrapolation::projectOnCylinder
static Amg::Vector3D projectOnCylinder(float cylR, float cylZ, Amg::Vector3D &hitPos)
Projects position hitPos onto the cylinder surface and returns projected position.
Definition: FastCaloSimCaloExtrapolation.cxx:614
TFCSTruthState::vertex
const TLorentzVector & vertex() const
Definition: TFCSTruthState.h:28
CylinderIntersections::first
Amg::Vector3D first
Definition: FastCaloSimCaloExtrapolation.h:24
drawFromPickle.atan
atan
Definition: drawFromPickle.py:36
ICaloGeometry::zext
virtual double zext(int sample, double eta) const =0
Amg::Hep3VectorToEigen
Amg::Vector3D Hep3VectorToEigen(const CLHEP::Hep3Vector &CLHEPvector)
Converts a CLHEP-based CLHEP::Hep3Vector into an Eigen-based Amg::Vector3D.
Definition: CLHEPtoEigenConverter.h:137
FastCaloSimCaloExtrapolation::findPCA
void findPCA(float cylR, float cylZ, Amg::Vector3D &hitPos1, Amg::Vector3D &hitPos2, Amg::Vector3D &PCA) const
Finds Point of Closest Approach (PCA) on the cylinder defined by radius cylR and half-length cylZ of ...
Definition: FastCaloSimCaloExtrapolation.cxx:382
FastCaloSimCaloExtrapolation::zext
double zext(int sample, double eta) const
Definition: FastCaloSimCaloExtrapolation.cxx:925
dqt_zlumi_alleff_HIST.A
A
Definition: dqt_zlumi_alleff_HIST.py:110
FastCaloSimCaloExtrapolation::getCylinderIntersections
CylinderIntersections getCylinderIntersections(float cylR, float cylZ, Amg::Vector3D &hitPos1, Amg::Vector3D &hitPos2) const
Analytically computes the intersection between the (infinite) line spanned by hitPos1 and hitPos2 wit...
Definition: FastCaloSimCaloExtrapolation.cxx:649
FastCaloSimCaloExtrapolation::finalize
virtual StatusCode finalize() override final
Definition: FastCaloSimCaloExtrapolation.cxx:66
FastCaloSimCaloExtrapolation::m_CaloBoundaryR
FloatArrayProperty m_CaloBoundaryR
Definition: FastCaloSimCaloExtrapolation.h:122
FastCaloSimCaloExtrapolation::zent
double zent(int sample, double eta) const
Definition: FastCaloSimCaloExtrapolation.cxx:910
IFastCaloSimCaloTransportation.h
Amg::z
@ z
Definition: GeoPrimitives.h:36
FastCaloSimCaloExtrapolation::getPointLineSegmentDistance
static double getPointLineSegmentDistance(Amg::Vector3D &point, Amg::Vector3D &hitPos1, Amg::Vector3D &hitPos2)
Computes the distance between a point and the line segment spanned by hitPos1 and hitPos2.
Definition: FastCaloSimCaloExtrapolation.cxx:834
CaloCell_ID_FCS::MaxSample
@ MaxSample
Definition: FastCaloSim_CaloCell_ID.h:47
FastCaloSimCaloExtrapolation::INSIDE
@ INSIDE
Definition: FastCaloSimCaloExtrapolation.h:49
FastCaloSimCaloExtrapolation::ON
@ ON
Definition: FastCaloSimCaloExtrapolation.h:51
ICaloGeometry::zmid
virtual double zmid(int sample, double eta) const =0
ICaloGeometry::isCaloBarrel
virtual bool isCaloBarrel(int sample) const =0
FullCPAlgorithmsTest_eljob.sample
sample
Definition: FullCPAlgorithmsTest_eljob.py:100
FastCaloSimCaloExtrapolation::isCaloBarrel
bool isCaloBarrel(int sample) const
Definition: FastCaloSimCaloExtrapolation.cxx:875
ATH_FLATTEN
#define ATH_FLATTEN
Definition: inline_hints.h:52
beamspotman.n
n
Definition: beamspotman.py:731
FastCaloSimCaloExtrapolation::rmid
double rmid(int sample, double eta) const
Definition: FastCaloSimCaloExtrapolation.cxx:890
ICaloGeometry::minmaxeta
virtual void minmaxeta(int sample, double eta, double &mineta, double &maxeta) const =0
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
Amg::x
@ x
Definition: GeoPrimitives.h:34
WritePulseShapeToCool.det
det
Definition: WritePulseShapeToCool.py:204
Amg::Transform3D
Eigen::Affine3d Transform3D
Definition: GeoPrimitives.h:46
AthAlgTool.h
ICaloGeometry::rext
virtual double rext(int sample, double eta) const =0
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
FastCaloSimCaloExtrapolation::whichIntersection
int whichIntersection(float cylR, float cylZ, Amg::Vector3D &hitPos1, Amg::Vector3D &hitPos2, Amg::Vector3D &intersectionA, Amg::Vector3D intersectionB) const
Returns ID of more sensible intersection between line segment spanned by hitPos1 and hitPos2 and cyli...
Definition: FastCaloSimCaloExtrapolation.cxx:796
FastCaloSimCaloExtrapolation::rzent
double rzent(int sample, double eta) const
Definition: FastCaloSimCaloExtrapolation.cxx:915
FastCaloSimCaloExtrapolation::whereOnCylinder
static enum HITPOSITION whereOnCylinder(float cylR, float cylZ, Amg::Vector3D &hitPos)
Checks if position of hitPos is inside, outside or on the cylinder bounds.
Definition: FastCaloSimCaloExtrapolation.cxx:849
Trk::Intersection::position
Amg::Vector3D position
Definition: Intersection.h:25
FastCaloSimCaloExtrapolation::m_CaloBoundaryZ
FloatArrayProperty m_CaloBoundaryZ
Definition: FastCaloSimCaloExtrapolation.h:123
dot.dot
def dot(G, fn, nodesToHighlight=[])
Definition: dot.py:5
FastCaloSimCaloExtrapolation::rzpos
double rzpos(int sample, double eta, int subpos=CaloSubPos::SUBPOS_MID) const
Definition: FastCaloSimCaloExtrapolation.cxx:945
compute_lumi.denom
denom
Definition: compute_lumi.py:76
FastCaloSimCaloExtrapolation::OUTSIDE
@ OUTSIDE
Definition: FastCaloSimCaloExtrapolation.h:50
FastCaloSimCaloExtrapolation::m_CaloGeometryHelper
PublicToolHandle< IFastCaloSimGeometryHelper > m_CaloGeometryHelper
Definition: FastCaloSimCaloExtrapolation.h:128
CLHEPtoEigenConverter.h
tolerance
Definition: suep_shower.h:17
ATH_MSG_COND
#define ATH_MSG_COND(MSG, CONDITION)
Definition: FastCaloSimCaloExtrapolation.cxx:37
CylinderIntersections::number
unsigned int number
Definition: FastCaloSimCaloExtrapolation.h:26
FastCaloSimCaloExtrapolation::cylinderEndcapIntersection
static bool cylinderEndcapIntersection(float cylR, float cylZ, bool positiveEndcap, Amg::Vector3D &pointA, Amg::Vector3D &pointB, Amg::Vector3D &intersection)
Computes intersection between the (infinite) line spanned by pointA and pointB with the positive (neg...
Definition: FastCaloSimCaloExtrapolation.cxx:772
FastCaloSimCaloExtrapolation::cylinderLineIntersection
int cylinderLineIntersection(float cylR, float cylZ, Amg::Vector3D &pointA, Amg::Vector3D &pointB, Amg::Vector3D &intersectA, Amg::Vector3D &intersectB) const
Analytically computes the intersection between the (infinite) line defined by pointA and pointB and t...
Definition: FastCaloSimCaloExtrapolation.cxx:730
compileRPVLLRates.c2
c2
Definition: compileRPVLLRates.py:361
FastCaloSimCaloExtrapolation::rzmid
double rzmid(int sample, double eta) const
Definition: FastCaloSimCaloExtrapolation.cxx:900
dqt_zlumi_alleff_HIST.B
B
Definition: dqt_zlumi_alleff_HIST.py:110
TFCSTruthState::pdgid
int pdgid() const
Definition: TFCSTruthState.h:25
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
ICaloGeometry::rent
virtual double rent(int sample, double eta) const =0
FastCaloSimCaloExtrapolation::m_CaloTransportation
PublicToolHandle< IFastCaloSimCaloTransportation > m_CaloTransportation
Definition: FastCaloSimCaloExtrapolation.h:126
python.PyAthena.v
v
Definition: PyAthena.py:157
makeTRTBarrelCans.dy
tuple dy
Definition: makeTRTBarrelCans.py:21
FastCaloSimCaloExtrapolation::extrapolate
virtual void extrapolate(TFCSExtrapolationState &result, const TFCSTruthState *truth, const std::vector< G4FieldTrack > &caloSteps) const override final
Definition: FastCaloSimCaloExtrapolation.cxx:72
TFCSTruthState::Ekin_off
double Ekin_off() const
Definition: TFCSTruthState.h:27
FastCaloSimCaloExtrapolation::extrapolateToLayers
void extrapolateToLayers(TFCSExtrapolationState &result, const std::vector< G4FieldTrack > &caloSteps, const TFCSTruthState *truth) const
Extrapolates to all other layers of the calorimeter.
Definition: FastCaloSimCaloExtrapolation.cxx:166
DiTauMassTools::MaxHistStrategyV2::e
e
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:26
TFCSTruthState.h
FastCaloSimCaloExtrapolation::SUBPOS_MID
@ SUBPOS_MID
Definition: FastCaloSimCaloExtrapolation.h:43
Amg::intersect
std::optional< double > intersect(const AmgVector(N)&posA, const AmgVector(N)&dirA, const AmgVector(N)&posB, const AmgVector(N)&dirB)
Calculates the closest approach of two lines.
Definition: GeoPrimitivesHelpers.h:302
ICaloGeometry::rzent
virtual double rzent(int sample, double eta) const =0
GeoPrimitivesHelpers.h
unit
const PlainObject unit() const
This is a plugin that makes Eigen look like CLHEP & defines some convenience methods.
Definition: AmgMatrixBasePlugin.h:20
dq_defect_virtual_defect_validation.d2
d2
Definition: dq_defect_virtual_defect_validation.py:81
makeTRTBarrelCans.dx
tuple dx
Definition: makeTRTBarrelCans.py:20
ICaloGeometry::zpos
virtual double zpos(int sample, double eta, int subpos=CaloSubPos::SUBPOS_MID) const =0
FastCaloSimCaloExtrapolation::rpos
double rpos(int sample, double eta, int subpos=CaloSubPos::SUBPOS_MID) const
Definition: FastCaloSimCaloExtrapolation.cxx:935
CylinderIntersections
Definition: FastCaloSimCaloExtrapolation.h:23
LArCellBinning.step
step
Definition: LArCellBinning.py:158
FastCaloSimCaloExtrapolation::getIterativePCA
void getIterativePCA(float cylR, float cylZ, Amg::Vector3D &BoundA, Amg::Vector3D &BoundB, Amg::Vector3D &PCA) const
Finds PCA iteratively given two bounds A and B on a line segment, used for (rare) cases with no easy ...
Definition: FastCaloSimCaloExtrapolation.cxx:488
FastCaloSimCaloExtrapolation::extrapolateToCylinder
bool extrapolateToCylinder(const std::vector< G4FieldTrack > &caloSteps, float cylR, float cylZ, Amg::Vector3D &extPos, Amg::Vector3D &momDir) const
Finds best extrapolation extPos from the caloSteps for a cylinder defined by radius cylR and half-len...
Definition: FastCaloSimCaloExtrapolation.cxx:237
TrackingGeometry.h
ICaloGeometry::zent
virtual double zent(int sample, double eta) const =0
FastCaloSimCaloExtrapolation::zmid
double zmid(int sample, double eta) const
Definition: FastCaloSimCaloExtrapolation.cxx:895
FastCaloSim_CaloCell_ID.h
FastCaloSimCaloExtrapolation::GetCaloGeometry
const IFastCaloSimGeometryHelper * GetCaloGeometry() const
Definition: FastCaloSimCaloExtrapolation.h:59
python.IoTestsLib.w
def w
Definition: IoTestsLib.py:200
ICaloGeometry::rzpos
virtual double rzpos(int sample, double eta, int subpos=CaloSubPos::SUBPOS_MID) const =0
Amg::distance
float distance(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the distance between two point in 3D space
Definition: GeoPrimitivesHelpers.h:54
FastCaloSimCaloExtrapolation::rent
double rent(int sample, double eta) const
Definition: FastCaloSimCaloExtrapolation.cxx:905
TFCSTruthState
Definition: TFCSTruthState.h:13
FastCaloSimCaloExtrapolation::extrapolateToID
void extrapolateToID(TFCSExtrapolationState &result, const std::vector< G4FieldTrack > &caloSteps, const TFCSTruthState *truth) const
Extrapolates to ID using three uniquely defined cylinder surfaces.
Definition: FastCaloSimCaloExtrapolation.cxx:94
FastCaloSimCaloExtrapolation::minmaxeta
void minmaxeta(int sample, double eta, double &mineta, double &maxeta) const
Definition: FastCaloSimCaloExtrapolation.cxx:885
FastCaloSimCaloExtrapolation::HITPOSITION
HITPOSITION
Definition: FastCaloSimCaloExtrapolation.h:48
Trk::StraightLineSurface
Definition: StraightLineSurface.h:51
fitman.k
k
Definition: fitman.py:528
ICaloGeometry::rzext
virtual double rzext(int sample, double eta) const =0
FastCaloSimCaloExtrapolation::extrapolateWithPCA
bool extrapolateWithPCA(const std::vector< G4FieldTrack > &caloSteps, float cylR, float cylZ, Amg::Vector3D &extPos, Amg::Vector3D &momDir) const
Extrapolates to the cylinder using the PCA to the polygon spanned by the individual line segments fro...
Definition: FastCaloSimCaloExtrapolation.cxx:342
ICaloGeometry::rzmid
virtual double rzmid(int sample, double eta) const =0