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){
185 cylR = std::abs(
rpos(sample,
result.IDCaloBoundary_eta(), subpos));
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)));
194 cylZ = std::abs(
zpos(sample,
result.IDCaloBoundary_eta(), subpos));
196 double mineta, maxeta,
eta;
199 eta =
result.IDCaloBoundary_eta() > 0 ? mineta : maxeta;
201 double theta = 2*std::atan(std::exp(-
eta));
203 cylR = std::abs(cylZ*std::sqrt((1/(std::cos(
theta)*std::cos(
theta))) - 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());
216 extPos = scale * extPos;
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());
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()){
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;
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);
469 Trk::Intersection PCACylBounds = line.straightLineIntersection(hitPos1, hitDir.unit(),
false,
true);
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);
570 double dx, dy,
A, B,
C, det, t;
575 A = dx * dx + dy * dy;
579 det = B * B - 4 *
A *
C;
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) > 1e-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;
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.
std::vector< size_t > vec
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
const TLorentzVector & vertex() 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)
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