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