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#include "GaudiKernel/IPartPropSvc.h"
9
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) \
38do { \
39 if (CONDITION) { \
40 ATH_MSG_DEBUG(MSG); \
41 } else { \
42 ATH_MSG_WARNING(MSG); \
43 } \
44} while (0)
45
46
47FastCaloSimCaloExtrapolation::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
58 // Retrieve the tool to transport particles through calorimeter with ATLAS tracking tools
60
61 return StatusCode::SUCCESS;
62
63
64}
65
67 ATH_MSG_INFO( "Finalizing FastCaloSimCaloExtrapolation" );
68 return StatusCode::SUCCESS;
69}
70
71
72void 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
94void 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
166void 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
180 for(int sample=CaloCell_ID_FCS::FirstSample; sample<CaloCell_ID_FCS::MaxSample; ++sample){
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
237bool 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
264bool 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
342bool 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
382void 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
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
488void 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
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
730int 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
772bool 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
796int 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
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{
877 return GetCaloGeometry()->isCaloBarrel(sample);
878}
879
880double FastCaloSimCaloExtrapolation::deta(int sample, double eta) const
881{
882 return GetCaloGeometry()->deta(sample, eta);
883}
884
885void FastCaloSimCaloExtrapolation::minmaxeta(int sample, double eta, double& mineta, double& maxeta) const
886{
887 GetCaloGeometry()->minmaxeta(sample, eta, mineta, maxeta);
888}
889
890double FastCaloSimCaloExtrapolation::rmid(int sample, double eta) const
891{
892 return GetCaloGeometry()->rmid(sample, eta);
893}
894
895double FastCaloSimCaloExtrapolation::zmid(int sample, double eta) const
896{
897 return GetCaloGeometry()->zmid(sample, eta);
898}
899
900double FastCaloSimCaloExtrapolation::rzmid(int sample, double eta) const
901{
902 return GetCaloGeometry()->rzmid(sample, eta);
903}
904
905double FastCaloSimCaloExtrapolation::rent(int sample, double eta) const
906{
907 return GetCaloGeometry()->rent(sample, eta);
908}
909
910double FastCaloSimCaloExtrapolation::zent(int sample, double eta) const
911{
912 return GetCaloGeometry()->zent(sample, eta);
913}
914
915double FastCaloSimCaloExtrapolation::rzent(int sample, double eta) const
916{
917 return GetCaloGeometry()->rzent(sample, eta);
918}
919
920double FastCaloSimCaloExtrapolation::rext(int sample, double eta) const
921{
922 return GetCaloGeometry()->rext(sample, eta);
923}
924
925double FastCaloSimCaloExtrapolation::zext(int sample, double eta) const
926{
927 return GetCaloGeometry()->zext(sample, eta);
928}
929
930double FastCaloSimCaloExtrapolation::rzext(int sample, double eta) const
931{
932 return GetCaloGeometry()->rzext(sample, eta);
933}
934
935double FastCaloSimCaloExtrapolation::rpos(int sample, double eta, int subpos) const
936{
937 return GetCaloGeometry()->rpos(sample, eta, subpos);
938}
939
940double FastCaloSimCaloExtrapolation::zpos(int sample, double eta, int subpos) const
941{
942 return GetCaloGeometry()->zpos(sample, eta, subpos);
943}
944
945double FastCaloSimCaloExtrapolation::rzpos(int sample, double eta, int subpos) const
946{
947 return GetCaloGeometry()->rzpos(sample, eta, subpos);
948}
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