7 #include "GaudiKernel/ToolHandle.h"
8 #include "GaudiKernel/IPartPropSvc.h"
24 #include "HepPDT/ParticleDataTable.hh"
30 #include "G4FieldTrack.hh"
37 #define ATH_MSG_COND(MSG, CONDITION) \
42 ATH_MSG_WARNING(MSG); \
54 ATH_MSG_INFO(
"Initializing FastCaloSimCaloExtrapolation" );
61 return StatusCode::SUCCESS;
67 ATH_MSG_INFO(
"Finalizing FastCaloSimCaloExtrapolation" );
68 return StatusCode::SUCCESS;
74 ATH_MSG_DEBUG(
"[extrapolate] Initializing extrapolation to ID-Calo boundary");
77 ATH_MSG_DEBUG(
"[extrapolate] Initializing extrapolation to calorimeter layers");
86 ATH_MSG_DEBUG(
"[extrapolate] Initializing transport of track through calorimeter system with ATLAS tracking tools.");
88 ATH_MSG_DEBUG(
"[extrapolate] Finalized transport of track through calorimeter system with ATLAS tracking tools.");
99 const float transverseMomWarningLimit = 500;
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.);
110 double extPosDist = -1;
112 for (
unsigned int surfID = 0; surfID<3; surfID++){
117 ATH_MSG_DEBUG(
"[ExtrapolateToID] Extrapolating to ID-Calo boundary with ID="<<surfID<<
" R="<<
R<<
" Z="<<
Z);
133 ATH_MSG_DEBUG(
"[ExtrapolateToID] Testing condition 2: hit r="<< extPos.perp());
137 ATH_MSG_DEBUG(
"[ExtrapolateToID] Testing condition 3: hit magnitude="<< extPos.mag());
138 if(extPosDist >= 0 && extPos.mag() > extPosDist)
continue;
141 extPosDist = extPos.mag();
143 result.set_IDCaloBoundary_eta(extPos.eta());
144 result.set_IDCaloBoundary_phi(extPos.phi());
145 result.set_IDCaloBoundary_r(extPos.perp());
148 ATH_MSG_DEBUG(
"[ExtrapolateToID] Setting IDCaloBoundary to eta="<<extPos.eta()<<
" phi="<<extPos.phi()<<
" r="<<extPos.perp()<<
" z="<<extPos.z());
153 double AngleEta = extPos.theta() - momDir.theta();
154 result.set_IDCaloBoundary_AngleEta(AngleEta);
155 result.set_IDCaloBoundary_Angle3D(Angle3D);
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);
171 const float transverseMomWarningLimit = 500;
178 if(std::abs(
result.IDCaloBoundary_eta()) < 6){
189 if(
sample < 4) cylZ =
result.IDCaloBoundary_eta() > 0 ? std::abs(
zpos(5, 1000, 1)) : std::abs(
zpos(5, -1000, 1));
196 double mineta, maxeta,
eta;
199 eta =
result.IDCaloBoundary_eta() > 0 ? mineta : maxeta;
216 extPos =
scale * extPos;
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);
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);
234 ATH_MSG_DEBUG(
"[extrapolateToLayers] End extrapolateToLayers()");
239 if(caloSteps.size() == 1){
241 ATH_MSG_DEBUG(
"[extrapolateWithPCA(R="<<cylR<<
",Z="<<cylZ<<
")] Extrapolating single hit position to surface.");
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]<<
")");
255 ATH_MSG_DEBUG(
"(R="<<cylR<<
", Z="<<cylZ<<
"::END) Extrapolation to cylinder surface failed!");
266 ATH_MSG_DEBUG(
"[extrapolateWithIntersection(R="<<cylR<<
",Z="<<cylZ<<
")] Checking for cylinder intersections of line segments.");
269 unsigned int nExtrapolations = 0;
270 for (
size_t hitID = 1; hitID < caloSteps.size(); hitID++){
277 ATH_MSG_DEBUG(
"[extrapolateWithIntersection(R="<<cylR<<
",Z="<<cylZ<<
")] Considering line segment between ("<<hitPos1[
Amg::x]<<
","<<hitPos1[
Amg::y]<<
","<<hitPos1[
Amg::z]<<
") and ("
284 if(cylPosHit1 ==
ON || cylPosHit2 ==
ON){
285 extPos = cylPosHit1 ==
ON ? hitPos1 : hitPos2;
287 ATH_MSG_DEBUG(
"[extrapolateWithIntersection(R="<<cylR<<
",Z="<<cylZ<<
")] Hit position already on cylinder surface.");
292 if(hitDir.norm() < 0.01)
continue;
301 if(intersections.
number == 1) selectedIntersection = intersections.
first;
305 if(intersections.
number > 0){
307 bool isForwardExtrapolation = (selectedIntersection[
Amg::x] - hitPos1[
Amg::x]) / (hitPos2[
Amg::x] - hitPos1[
Amg::x]) >= 0;
312 if(nExtrapolations > 1 && !isForwardExtrapolation && !travelThroughSurface)
continue;
315 bool intersectionOnSegment =
isOnSegment(selectedIntersection, hitPos1, hitPos2);
317 bool hitPosOutside = cylPosHit1 ==
OUTSIDE && cylPosHit2 ==
OUTSIDE;
325 if(travelThroughSurface || intersectionOnSegment || (hitPosOutside && !isForwardExtrapolation && nExtrapolations == 1) || caloSteps.size()-1 == hitID){
331 extPos = selectedIntersection;
334 ATH_MSG_DEBUG(
"[extrapolateWithIntersection(R="<<cylR<<
",Z="<<cylZ<<
")] Extrapolated position at ("<<selectedIntersection[
Amg::x]<<
","<<selectedIntersection[
Amg::y]<<
","<<selectedIntersection[
Amg::z]<<
")");
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.");
348 double minDistToSurface = 100000;
349 for (
size_t hitID = 1; hitID < caloSteps.size(); hitID++){
358 findPCA(cylR, cylZ, hitPos1, hitPos2, PCA);
361 double tmpMinDistToSurface = (PCA - cylinderSurfacePCA).
norm();
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);
365 if(tmpMinDistToSurface < minDistToSurface){
367 extPos = cylinderSurfacePCA;
374 minDistToSurface = tmpMinDistToSurface;
391 Amg::Vector3D cylinderProjDir = projCylinderHitPos2 - projCylinderHitPos1;
394 if(cylinderProjDir.norm() < 0.0001) {PCA = hitPos1;
return;};
401 bool isParallelToEndcap = std::abs(hitPos1[
Amg::z] - hitPos2[
Amg::z]) < 0.00001;
404 if(isParallelToEndcap){
408 intersectA.setZero();
409 intersectB.setZero();
412 if(nIntersections == 2){
414 bool IntAOnSegment =
isOnSegment(intersectA, hitPos1, hitPos2);
415 bool IntBOnSegment =
isOnSegment(intersectB, hitPos1, hitPos2);
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);
421 else PCA = hitPos1 + 0.5*hitDir;
424 else if(!intersectA.isZero() || !intersectB.isZero()){
429 bool IntOnSegment =
isOnSegment(intersectA, hitPos1, hitPos2);
436 Amg::Vector3D infLinePCA = hitPos1 + ((cylZEndcap-hitPos1).
dot(hitDir)/hitDir.dot(hitDir))*(hitDir);
438 if(
isOnSegment(infLinePCA, hitPos1, hitPos2)) PCA = infLinePCA;
439 else PCA = (hitPos1 - infLinePCA).
norm() < (hitPos2 - infLinePCA).
norm() ? hitPos1 : hitPos2;
449 double t = ((cylZEndcap-hitPos1).
dot(hitDir)/hitDir.dot(hitDir));
450 BoundA =
t <= 0 ? hitPos1 : (
t >= 1 ? hitPos2 : hitPos1 +
t*hitDir);
455 BoundB =
t <= 0 ? hitPos1 : (
t >= 1 ? hitPos2 : hitPos1 +
t*hitDir);
471 double distSurfHit1 = (projCylinderHitPos1 - hitPos1).
norm();
472 double distSurfHit2 = (projCylinderHitPos2 - hitPos2).
norm();
475 PCA =
isOnSegment(PCACylBounds.
position, hitPos1, hitPos2) ? PCACylBounds.
position : (distSurfHit1 < distSurfHit2 ? hitPos1 : hitPos2);
493 double distBounds = boundDir.norm();
496 const double stepSize = 0.01;
500 if (distBounds <= 4*stepSize){PCA = BoundA + 0.5*(BoundB - BoundA);
return;}
502 Amg::Vector3D tmpBoundA, tmpBoundB, tmpOnCylinderBoundA, tmpOnCylinderBoundB;
503 Amg::Vector3D resBoundA, resBoundB, resOnCylinderBoundA, resOnCylinderBoundB;
510 double minDistA = (BoundA - OnCylinderBoundA).
norm();
511 double minDistB = (BoundB - OnCylinderBoundB).
norm();
514 if(minDistA < minDistB){
522 double tmpMinDistA, tmpMinDistB;
523 unsigned int nHalfDivisions = (distBounds/stepSize)/2;
524 for(
unsigned int step = 0;
step < nHalfDivisions;
step++){
527 tmpBoundA = BoundA + (
step+1)*stepSize*(boundDir/distBounds);
528 tmpBoundB = BoundB - (
step+1)*stepSize*(boundDir/distBounds);
535 tmpMinDistA = (tmpBoundA - tmpOnCylinderBoundA).
norm();
536 tmpMinDistB = (tmpBoundB - tmpOnCylinderBoundB).
norm();
538 if(minDistA >= tmpMinDistA){
539 minDistA = tmpMinDistA;
542 double t = (
step*stepSize)/distBounds;
543 resBoundA = BoundA +
t*boundDir;
544 resBoundB = tmpBoundA;
548 if(minDistB >= tmpMinDistB){
549 minDistB = tmpMinDistB;
552 double t = (
step*stepSize)/distBounds;
553 resBoundB = BoundB -
t*boundDir;
554 resBoundA = tmpBoundB;
560 PCA = resBoundA + 0.5*(resBoundB - resBoundA);
581 if (
A <= 0.0000001 ||
det < 0){
582 ATH_MSG_DEBUG(
"[circleLineIntersection2D] No intersections.");
585 else if (std::abs(
det) < 0.00001){
594 t = (-
B + std::sqrt(
det)) / (2 *
A);
596 t = (-
B - std::sqrt(
det)) / (2 *
A);
620 if(hitPos[
Amg::z] >= cylZ){
625 if(hitPos.perp() > cylR) closestPointOnCylinder = cylAxis + cylR * (projHitPos - cylAxis).
unit();
626 else closestPointOnCylinder = cylAxis + hitPos.perp() * (projHitPos - cylAxis).
unit();
630 else if (hitPos[
Amg::z] <= -cylZ){
634 if(hitPos.perp() > cylR) closestPointOnCylinder = -cylAxis + cylR * (projHitPos + cylAxis).
unit();
635 else closestPointOnCylinder = -cylAxis + hitPos.perp() * (projHitPos + cylAxis).
unit();
640 closestPointOnCylinder = hitPosZ + cylR * (hitPos - hitPosZ).
unit();
643 return closestPointOnCylinder;
655 if(nCoverIntersections == 2){
656 ATH_MSG_DEBUG(
"[getCylinderIntersections(R="<<cylR<<
",Z="<<cylZ<<
")] Found two cylinder intersections through cylinder cover.");
658 return intersections;
660 else if (nCoverIntersections == 1){
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);
666 if(IsPositiveEndcapIntersection && IsNegativeEndcapIntersection){
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;
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;
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;
686 ATH_MSG_DEBUG(
"[getCylinderIntersections(R="<<cylR<<
",Z="<<cylZ<<
")] Found single intersection through cylinder cover.");
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);
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;
703 else if(IsPositiveEndcapIntersection) {
705 ATH_MSG_DEBUG(
"[getCylinderIntersections(R="<<cylR<<
",Z="<<cylZ<<
")] Found single intersection through positive endcap. This should not happen.");
706 intersections.
first = positiveEndcapIntersection;
709 else if(IsNegativeEndcapIntersection) {
711 ATH_MSG_DEBUG(
"[getCylinderIntersections(R="<<cylR<<
",Z="<<cylZ<<
")] Found single intersection through negative endcap. This should not happen.");
712 intersections.
first = negativeEndcapIntersection;
716 ATH_MSG_DEBUG(
"[getCylinderIntersections(R="<<cylR<<
",Z="<<cylZ<<
")] Found no cylinder intersections.");
723 return intersections;
738 double projDiffNorm2 = projDiff.dot(projDiff);
739 double t = projPointA.dot(projDiff) / projDiffNorm2;
740 double d2 = projPointA.dot(projPointA) -
t*
t*projDiffNorm2;
743 ATH_MSG_COND(
"[cylinderLineIntersection] Got negative distance (d2="<<
d2<<
"). Forcing to 0.",
d2 > -0.001);
748 if(
d2 > cylR*cylR)
return 0;
750 double k = std::sqrt((cylR*cylR -
d2)/projDiffNorm2);
752 intersectA = pointA + (
t+
k)*(pointB - pointA);
753 intersectB = pointA + (
t-
k)*(pointB - pointA);
756 bool IntAisValid = (intersectA[
Amg::z] <= cylZ && intersectA[
Amg::z] >= -cylZ);
757 bool IntBisValid = (intersectB[
Amg::z] <= cylZ && intersectB[
Amg::z] >= -cylZ);
759 if(IntAisValid && IntBisValid)
return 2;
760 else if(IntAisValid)
return 1;
761 else if(IntBisValid){
762 intersectA = intersectB;
777 positiveEndcap ? pointOnEndcap = {0, 0, cylZ} : pointOnEndcap = {0, 0, -cylZ};
780 double denom = normal.dot(hitDir);
781 if (std::abs(
denom) > 1
e-6) {
782 double t = normal.dot(pointOnEndcap - pointB)/
denom;
788 return std::sqrt(
v.dot(
v)) <= cylR;
805 ATH_MSG_DEBUG(
"[whichIntersection] Travel through surface.");
813 ATH_MSG_DEBUG(
"[whichIntersection] Both hit positions inside.");
814 return directionA.dot(hitDir) < directionB.dot(hitDir);
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;
839 double c1 =
w.dot(hitDir);
841 double c2 = hitDir.dot(hitDir);
855 bool isOnCover = std::abs(hitPos.perp() - cylR) <
tolerance && hitPos[
Amg::z] < cylZ && hitPos[
Amg::z] > -cylZ;
858 if(isOnEndcap || isOnCover)
return HITPOSITION::ON;
861 if(hitPos[
Amg::z] < cylZ && hitPos[
Amg::z] > -cylZ && hitPos.perp() < cylR)
return HITPOSITION::INSIDE;
863 return HITPOSITION::OUTSIDE;