7#include "GaudiKernel/ToolHandle.h"
26#include "G4FieldTrack.hh"
33#define ATH_MSG_COND(MSG, CONDITION) \
38 ATH_MSG_WARNING(MSG); \
50 ATH_MSG_INFO(
"Initializing FastCaloSimCaloExtrapolation" );
57 return StatusCode::SUCCESS;
63 ATH_MSG_INFO(
"Finalizing FastCaloSimCaloExtrapolation" );
64 return StatusCode::SUCCESS;
70 ATH_MSG_DEBUG(
"[extrapolate] Initializing extrapolation to ID-Calo boundary");
73 ATH_MSG_DEBUG(
"[extrapolate] Initializing extrapolation to calorimeter layers");
82 ATH_MSG_DEBUG(
"[extrapolate] Initializing transport of track through calorimeter system with ATLAS tracking tools.");
84 ATH_MSG_DEBUG(
"[extrapolate] Finalized transport of track through calorimeter system with ATLAS tracking tools.");
95 const float transverseMomWarningLimit = 500;
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.);
106 double extPosDist = -1;
108 for (
unsigned int surfID = 0; surfID<3; surfID++){
113 ATH_MSG_DEBUG(
"[ExtrapolateToID] Extrapolating to ID-Calo boundary with ID="<<surfID<<
" R="<<R<<
" Z="<<Z);
129 ATH_MSG_DEBUG(
"[ExtrapolateToID] Testing condition 2: hit r="<< extPos.perp());
133 ATH_MSG_DEBUG(
"[ExtrapolateToID] Testing condition 3: hit magnitude="<< extPos.mag());
134 if(extPosDist >= 0 && extPos.mag() > extPosDist)
continue;
137 extPosDist = extPos.mag();
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]);
144 ATH_MSG_DEBUG(
"[ExtrapolateToID] Setting IDCaloBoundary to eta="<<extPos.eta()<<
" phi="<<extPos.phi()<<
" r="<<extPos.perp()<<
" z="<<extPos.z());
149 double AngleEta = extPos.theta() - momDir.theta();
150 result.set_IDCaloBoundary_AngleEta(AngleEta);
151 result.set_IDCaloBoundary_Angle3D(Angle3D);
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);
167 const float transverseMomWarningLimit = 500;
174 if(std::abs(result.IDCaloBoundary_eta()) < 6){
181 cylR = std::abs(
rpos(sample, result.IDCaloBoundary_eta(), subpos));
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)));
190 cylZ = std::abs(
zpos(sample, result.IDCaloBoundary_eta(), subpos));
192 double mineta, maxeta,
eta;
193 minmaxeta(sample, result.IDCaloBoundary_eta(), mineta, maxeta);
195 eta = result.IDCaloBoundary_eta() > 0 ? mineta : maxeta;
197 double theta = 2*std::atan(std::exp(-
eta));
199 cylR = std::abs(cylZ*std::sqrt((1/(std::cos(
theta)*std::cos(
theta))) - 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());
212 extPos = scale * extPos;
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());
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);
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);
230 ATH_MSG_DEBUG(
"[extrapolateToLayers] End extrapolateToLayers()");
235 if(caloSteps.size() == 1){
237 ATH_MSG_DEBUG(
"[extrapolateWithPCA(R="<<cylR<<
",Z="<<cylZ<<
")] Extrapolating single hit position to surface.");
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]<<
")");
251 ATH_MSG_DEBUG(
"(R="<<cylR<<
", Z="<<cylZ<<
"::END) Extrapolation to cylinder surface failed!");
262 ATH_MSG_DEBUG(
"[extrapolateWithIntersection(R="<<cylR<<
",Z="<<cylZ<<
")] Checking for cylinder intersections of line segments.");
265 unsigned int nExtrapolations = 0;
266 for (
size_t hitID = 1; hitID < caloSteps.size(); hitID++){
273 ATH_MSG_DEBUG(
"[extrapolateWithIntersection(R="<<cylR<<
",Z="<<cylZ<<
")] Considering line segment between ("<<hitPos1[
Amg::x]<<
","<<hitPos1[
Amg::y]<<
","<<hitPos1[
Amg::z]<<
") and ("
280 if(cylPosHit1 ==
ON || cylPosHit2 ==
ON){
281 extPos = cylPosHit1 ==
ON ? hitPos1 : hitPos2;
283 ATH_MSG_DEBUG(
"[extrapolateWithIntersection(R="<<cylR<<
",Z="<<cylZ<<
")] Hit position already on cylinder surface.");
288 if(hitDir.norm() < 0.01)
continue;
297 if(intersections.
number == 1) selectedIntersection = intersections.
first;
301 if(intersections.
number > 0){
303 bool isForwardExtrapolation = (selectedIntersection[
Amg::x] - hitPos1[
Amg::x]) / (hitPos2[
Amg::x] - hitPos1[
Amg::x]) >= 0;
308 if(nExtrapolations > 1 && !isForwardExtrapolation && !travelThroughSurface)
continue;
311 bool intersectionOnSegment =
isOnSegment(selectedIntersection, hitPos1, hitPos2);
313 bool hitPosOutside = cylPosHit1 ==
OUTSIDE && cylPosHit2 ==
OUTSIDE;
321 if(travelThroughSurface || intersectionOnSegment || (hitPosOutside && !isForwardExtrapolation && nExtrapolations == 1) || caloSteps.size()-1 == hitID){
327 extPos = selectedIntersection;
330 ATH_MSG_DEBUG(
"[extrapolateWithIntersection(R="<<cylR<<
",Z="<<cylZ<<
")] Extrapolated position at ("<<selectedIntersection[
Amg::x]<<
","<<selectedIntersection[
Amg::y]<<
","<<selectedIntersection[
Amg::z]<<
")");
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.");
344 double minDistToSurface = 100000;
345 for (
size_t hitID = 1; hitID < caloSteps.size(); hitID++){
354 findPCA(cylR, cylZ, hitPos1, hitPos2, PCA);
357 double tmpMinDistToSurface = (PCA - cylinderSurfacePCA).norm();
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);
361 if(tmpMinDistToSurface < minDistToSurface){
363 extPos = cylinderSurfacePCA;
370 minDistToSurface = tmpMinDistToSurface;
387 Amg::Vector3D cylinderProjDir = projCylinderHitPos2 - projCylinderHitPos1;
390 if(cylinderProjDir.norm() < 0.0001) {PCA = hitPos1;
return;};
397 bool isParallelToEndcap = std::abs(hitPos1[
Amg::z] - hitPos2[
Amg::z]) < 0.00001;
400 if(isParallelToEndcap){
404 intersectA.setZero();
405 intersectB.setZero();
408 if(nIntersections == 2){
410 bool IntAOnSegment =
isOnSegment(intersectA, hitPos1, hitPos2);
411 bool IntBOnSegment =
isOnSegment(intersectB, hitPos1, hitPos2);
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);
417 else PCA = hitPos1 + 0.5*hitDir;
420 else if(!intersectA.isZero() || !intersectB.isZero()){
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;
432 Amg::Vector3D infLinePCA = hitPos1 + ((cylZEndcap-hitPos1).dot(hitDir)/hitDir.dot(hitDir))*(hitDir);
434 if(
isOnSegment(infLinePCA, hitPos1, hitPos2)) PCA = infLinePCA;
435 else PCA = (hitPos1 - infLinePCA).norm() < (hitPos2 - infLinePCA).norm() ? hitPos1 : hitPos2;
445 double t = ((cylZEndcap-hitPos1).dot(hitDir)/hitDir.dot(hitDir));
446 BoundA = t <= 0 ? hitPos1 : (t >= 1 ? hitPos2 : hitPos1 + t*hitDir);
451 BoundB = t <= 0 ? hitPos1 : (t >= 1 ? hitPos2 : hitPos1 + t*hitDir);
465 Trk::Intersection PCACylBounds = line.straightLineIntersection(hitPos1, hitDir.unit(),
false,
true);
467 double distSurfHit1 = (projCylinderHitPos1 - hitPos1).norm();
468 double distSurfHit2 = (projCylinderHitPos2 - hitPos2).norm();
471 PCA =
isOnSegment(PCACylBounds.
position, hitPos1, hitPos2) ? PCACylBounds.
position : (distSurfHit1 < distSurfHit2 ? hitPos1 : hitPos2);
489 double distBounds = boundDir.norm();
492 const double stepSize = 0.01;
496 if (distBounds <= 4*stepSize){PCA = BoundA + 0.5*(BoundB - BoundA);
return;}
498 Amg::Vector3D tmpBoundA, tmpBoundB, tmpOnCylinderBoundA, tmpOnCylinderBoundB;
499 Amg::Vector3D resBoundA, resBoundB, resOnCylinderBoundA, resOnCylinderBoundB;
506 double minDistA = (BoundA - OnCylinderBoundA).norm();
507 double minDistB = (BoundB - OnCylinderBoundB).norm();
510 if(minDistA < minDistB){
518 double tmpMinDistA, tmpMinDistB;
519 unsigned int nHalfDivisions = (distBounds/stepSize)/2;
520 for(
unsigned int step = 0; step < nHalfDivisions; step++){
523 tmpBoundA = BoundA + (step+1)*stepSize*(boundDir/distBounds);
524 tmpBoundB = BoundB - (step+1)*stepSize*(boundDir/distBounds);
531 tmpMinDistA = (tmpBoundA - tmpOnCylinderBoundA).norm();
532 tmpMinDistB = (tmpBoundB - tmpOnCylinderBoundB).norm();
534 if(minDistA >= tmpMinDistA){
535 minDistA = tmpMinDistA;
538 double t = (step*stepSize)/distBounds;
539 resBoundA = BoundA + t*boundDir;
540 resBoundB = tmpBoundA;
544 if(minDistB >= tmpMinDistB){
545 minDistB = tmpMinDistB;
548 double t = (step*stepSize)/distBounds;
549 resBoundB = BoundB - t*boundDir;
550 resBoundA = tmpBoundB;
556 PCA = resBoundA + 0.5*(resBoundB - resBoundA);
566 double dx, dy,
A, B,
C, det, t;
571 A = dx * dx + dy * dy;
575 det = B * B - 4 *
A *
C;
577 if (
A <= 0.0000001 || det < 0){
578 ATH_MSG_DEBUG(
"[circleLineIntersection2D] No intersections.");
581 else if (std::abs(det) < 0.00001){
590 t = (-B + std::sqrt(det)) / (2 *
A);
592 t = (-B - std::sqrt(det)) / (2 *
A);
616 if(hitPos[
Amg::z] >= cylZ){
621 if(hitPos.perp() > cylR) closestPointOnCylinder = cylAxis + cylR * (projHitPos - cylAxis).
unit();
622 else closestPointOnCylinder = cylAxis + hitPos.perp() * (projHitPos - cylAxis).
unit();
626 else if (hitPos[
Amg::z] <= -cylZ){
630 if(hitPos.perp() > cylR) closestPointOnCylinder = -cylAxis + cylR * (projHitPos + cylAxis).
unit();
631 else closestPointOnCylinder = -cylAxis + hitPos.perp() * (projHitPos + cylAxis).
unit();
636 closestPointOnCylinder = hitPosZ + cylR * (hitPos - hitPosZ).
unit();
639 return closestPointOnCylinder;
651 if(nCoverIntersections == 2){
652 ATH_MSG_DEBUG(
"[getCylinderIntersections(R="<<cylR<<
",Z="<<cylZ<<
")] Found two cylinder intersections through cylinder cover.");
654 return intersections;
656 else if (nCoverIntersections == 1){
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);
662 if(IsPositiveEndcapIntersection && IsNegativeEndcapIntersection){
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;
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;
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;
682 ATH_MSG_DEBUG(
"[getCylinderIntersections(R="<<cylR<<
",Z="<<cylZ<<
")] Found single intersection through cylinder cover.");
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);
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;
699 else if(IsPositiveEndcapIntersection) {
701 ATH_MSG_DEBUG(
"[getCylinderIntersections(R="<<cylR<<
",Z="<<cylZ<<
")] Found single intersection through positive endcap. This should not happen.");
702 intersections.
first = positiveEndcapIntersection;
705 else if(IsNegativeEndcapIntersection) {
707 ATH_MSG_DEBUG(
"[getCylinderIntersections(R="<<cylR<<
",Z="<<cylZ<<
")] Found single intersection through negative endcap. This should not happen.");
708 intersections.
first = negativeEndcapIntersection;
712 ATH_MSG_DEBUG(
"[getCylinderIntersections(R="<<cylR<<
",Z="<<cylZ<<
")] Found no cylinder intersections.");
719 return intersections;
734 double projDiffNorm2 = projDiff.dot(projDiff);
735 double t = projPointA.dot(projDiff) / projDiffNorm2;
736 double d2 = projPointA.dot(projPointA) - t*t*projDiffNorm2;
739 ATH_MSG_COND(
"[cylinderLineIntersection] Got negative distance (d2="<<d2<<
"). Forcing to 0.", d2 > -0.001);
744 if(d2 > cylR*cylR)
return 0;
746 double k = std::sqrt((cylR*cylR - d2)/projDiffNorm2);
748 intersectA = pointA + (t+k)*(pointB - pointA);
749 intersectB = pointA + (t-k)*(pointB - pointA);
752 bool IntAisValid = (intersectA[
Amg::z] <= cylZ && intersectA[
Amg::z] >= -cylZ);
753 bool IntBisValid = (intersectB[
Amg::z] <= cylZ && intersectB[
Amg::z] >= -cylZ);
755 if(IntAisValid && IntBisValid)
return 2;
756 else if(IntAisValid)
return 1;
757 else if(IntBisValid){
758 intersectA = intersectB;
773 positiveEndcap ? pointOnEndcap = {0, 0, cylZ} : pointOnEndcap = {0, 0, -cylZ};
776 double denom = normal.dot(hitDir);
777 if (std::abs(denom) > 1e-6) {
778 double t = normal.dot(pointOnEndcap - pointB)/denom;
784 return std::sqrt(v.dot(v)) <= cylR;
801 ATH_MSG_DEBUG(
"[whichIntersection] Travel through surface.");
809 ATH_MSG_DEBUG(
"[whichIntersection] Both hit positions inside.");
810 return directionA.dot(hitDir) < directionB.dot(hitDir);
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;
835 double c1 = w.dot(hitDir);
837 double c2 = hitDir.dot(hitDir);
851 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