49 double cot(
double x) {
51 constexpr
double dX = std::numeric_limits<float>::epsilon();
56 template <
typename T> constexpr
T absmax(
const T&
a,
const T&
b) {
57 return std::abs(
a) > std::abs(
b) ?
a :
b;}
61 using namespace MuonStationIndex;
64 ATH_CHECK(m_mdtKey.initialize(m_removeDeltas && !m_mdtKey.empty()));
66 ATH_CHECK(m_DetectorManagerKey.initialize());
68 ATH_CHECK(m_mdtCreatorT0.retrieve(DisableTool{m_mdtCreatorT0.empty()}));
70 ATH_CHECK(m_compClusterCreator.retrieve());
75 ATH_CHECK(m_segmentSelectionTool.retrieve());
76 ATH_CHECK(m_segmentFitter.retrieve(DisableTool{!m_refitParameters}));
77 ATH_CHECK(m_dcslFitProvider.retrieve(DisableTool{m_dcslFitProvider.empty()}));
81 return StatusCode::SUCCESS;
85 const std::vector<const MdtDriftCircleOnTrack*>& mdts,
86 const std::vector<const MuonClusterOnTrack*>&
clusters,
bool hasPhiMeasurements,
88 const EventContext& ctx = Gaudi::Hive::currentContext();
96 if (mdts.size() < 3)
return;
100 if (!firstRot) {
return; }
113 bool isEndcap = m_idHelperSvc->mdtIdHelper().isEndcap(chid);
124 double chamber_angleYZ = std::atan2(dirCh.z(), dirCh.y());
127 double dotprod = globalDirCh.perp() *
std::sin(roaddir2.theta()) + globalDirCh.z() *
std::cos(roaddir2.theta());
128 if (dotprod < 0) roaddir2 = -roaddir2;
133 double road_angleXZ = std::atan2(
d.z(),
d.x());
134 double road_angleYZ = std::atan2(
d.z(),
d.y());
136 if (!hasPhiMeasurements) road_angleXZ =
M_PI;
138 << isEndcap <<
" central phi " << detEl->
center().phi() <<
" r " << detEl->
center().perp()
139 <<
" z " << detEl->
center().z());
142 double errorScale = errorScaleFactor(chid,
momentum, hasPhiMeasurements);
148 spVecs = create2DClusters(
clusters);
150 spVecs = create1DClusters(
clusters);
155 std::stringstream sstr{};
157 sstr<<m_printer->print(*mdt)<<std::endl;
158 ATH_MSG_VERBOSE(
" adding mdts " << mdts.size()<<std::endl<<sstr.str());
162 std::set<Identifier> chamberSet;
163 double phimin{-9999}, phimax{9999};
165 TrkDriftCircleMath::DCVec dcs = createDCVec(mdts, errorScale, chamberSet, phimin, phimax, dcStatistics, gToStation, amdbToGlobal);
168 std::shared_ptr<const TrkDriftCircleMath::ChamberGeometry> multiGeo;
170 ATH_MSG_VERBOSE(
" using chamber geometry with #chambers " << chamberSet.size());
172 std::vector<TrkDriftCircleMath::MdtChamberGeometry> geos{};
175 geos.reserve(chamberSet.size());
178 geos.push_back(createChamberGeometry(
id, gToStation));
181 multiGeo = std::make_unique<TrkDriftCircleMath::MdtMultiChamberGeometry>(geos);
186 double angle = m_sinAngleCut;
187 if (sinAngleCut > 0)
angle = sinAngleCut;
194 std::stringstream sstr{};
195 unsigned int seg_n{0};
198 sstr<<
"Segment number "<<seg_n<<
" is at ("<<seg.line().x0()<<
","<<seg.line().y0()<<
") pointing to "<<seg.line().phi()*toDeg<<
" chi2: "<<
199 (seg.chi2()/seg.ndof())<<
"("<<seg.ndof()<<
")"<<std::endl;
200 sstr<<
"Mdt measurements: "<<seg.dcs().size()<<std::endl;
202 sstr<<
" **** "<<m_printer->print(*mdt_meas.rot());
203 sstr<<
" ("<<mdt_meas.state()<<
")"<<std::endl;
205 sstr<<
"Cluster measurements "<<seg.clusters().size()<<std::endl;
207 sstr<<
" ---- "<<m_printer->print(*clus.rot())<<std::endl;
212 ATH_MSG_VERBOSE(
"Found " << segs.size() <<
" segments "<<std::endl<<sstr.str());
216 if (segs.empty()) {
return; }
219 segmentCreationInfo sInfo(spVecs, multiGeo.get(), gToStation, amdbToGlobal, phimin, phimax);
221 std::unique_ptr<MuonSegment>
segment = createSegment(ctx, seg, chid, roadpos, roaddir2, mdts, hasPhiMeasurements, sInfo,
beta);
229 const std::vector<const MdtDriftCircleOnTrack*>& mdts,
bool hasPhiMeasurements,
231 bool isEndcap = m_idHelperSvc->isEndcap(chid);
236 const bool isCurvedSegment =
segment.hasCurvatureParameters() &&
240 if (
segment.hitsOnTrack() < 3)
return nullptr;
246 <<
line.position().y() <<
" phi " <<
line.phi() <<
" associated clusters "
256 if (hasPhiMeasurements) {
260 double cphi = lroaddir.x();
270 double shortestTubeLen = 1e9;
276 int lay = m_idHelperSvc->mdtIdHelper().tubeLayer(riodc->identify());
277 int tube = m_idHelperSvc->mdtIdHelper().tube(riodc->identify());
278 double tubelen = 0.5 * riodc->prepRawData()->detectorElement()->getActiveTubeLength(lay,
tube);
279 if (tubelen < shortestTubeLen) shortestTubeLen = tubelen;
282 if (std::abs(lxroad) > shortestTubeLen) {
283 ATH_MSG_DEBUG(
"coordinates far outside chamber! using global position of first hit ");
284 if (lxroad < 0.) shortestTubeLen *= -1.;
285 lxroad = shortestTubeLen;
288 lxroad = (sInfo.
globalTrans * mdts[0]->prepRawData()->detectorElement()->surface(mdts[0]->
identify()).center()).
x();
299 surfaceTransform.pretranslate(gpos);
300 double surfDim = 500.;
301 std::unique_ptr<Trk::PlaneSurface> surf = std::make_unique<Trk::PlaneSurface>(surfaceTransform, surfDim, surfDim);
305 double linephi =
line.phi();
309 Amg::Vector3D gdir = updateDirection(linephi, *surf, roaddir2, isCurvedSegment);
312 std::vector<std::pair<double, std::unique_ptr<const Trk::MeasurementBase>> > rioDistVec;
315 std::set<Identifier> deltaVec;
316 std::set<Identifier> outoftimeVec;
319 std::vector<std::pair<double, std::unique_ptr<const Trk::MeasurementBase>>> garbage_collector;
323 if (m_redo2DFit && !isCurvedSegment) {
333 linephi =
result.line().phi();
334 lpos[1] =
result.line().position().x();
335 lpos[2] =
result.line().position().y();
340 surfaceTransform.pretranslate(gpos);
341 surf = std::make_unique<Trk::PlaneSurface>(surfaceTransform, surfDim, surfDim);
344 gdir = updateDirection(linephi, *surf, roaddir2, isCurvedSegment);
361 if (
std::min(std::abs(diff_phi), std::abs( std::abs(diff_phi) -
M_PI)) > 1.
e-3 ||
362 std::min(std::abs(diff_prec), std::abs(std::abs(diff_prec) -
M_PI)) > 1.
e-3) {
363 ATH_MSG_WARNING(
" ALARM updated angles wrong: diff phi " << diff_phi <<
" prec " << diff_prec <<
" phi rdir " << roaddir2.phi()
364 <<
" gdir " << gdir.phi() <<
" lphi " << linephi <<
" seg "
369 std::pair<std::pair<int, int>,
bool> netaPhiHits =
372 if (rioDistVec.empty()){
378 auto meas_for_fit = [&rioDistVec] () {
379 std::vector<const Trk::MeasurementBase*>
out{};
380 out.reserve(rioDistVec.size());
382 for (
const std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>>& ele : rioDistVec)
out.push_back(ele.second.get());
387 double dlocx{1000.}, dangleXZ{1000.}, qoverp{-99999.}, dqoverp{-99999.};
388 bool hasMeasuredCoordinate =
false;
389 if (m_refitParameters && netaPhiHits.second) {
390 ATH_MSG_DEBUG(
" distance between first and last phi hit sufficient to perform 4D fit: phi " << gdir.phi() <<
" theta "
393 std::unique_ptr<Trk::Track>
track{m_segmentFitter->fit(gpos, gdir, *surf, meas_for_fit())};
396 if (isCurvedSegment &&
track->perigeeParameters() &&
track->perigeeParameters()->covariance()) {
400 hasMeasuredCoordinate =
true;
403 updatedCov.setZero();
404 m_segmentFitter->updateSegmentParameters(*
track, *surf, segLocPos, segLocDir, updatedCov);
416 if (
track->measurementsOnTrack() && rioDistVec.size() !=
track->measurementsOnTrack()->size()) {
417 if (
track->measurementsOnTrack()->empty()) {
421 ATH_MSG_DEBUG(
" ROT vector size changed after fit, updating ");
422 garbage_collector = std::move(rioDistVec);
423 rioDistVec.reserve(
track->measurementsOnTrack()->size());
428 if (!firstPars) firstPars =
pars;
435 rioDistVec.emplace_back(dist, meas->
uniqueClone());
440 netaPhiHits.second =
false;
446 if (m_updatePhiUsingPhiHits && !netaPhiHits.second) {
447 if (updateSegmentPhi(gpos, gdir, segLocPos, segLocDir, *surf, meas_for_fit(), sInfo.
phimin, sInfo.
phimax)) {
450 hasMeasuredCoordinate =
true;
457 std::vector<const Trk::MeasurementBase*> debug_meas = meas_for_fit();
458 ATH_MSG_DEBUG(
" number of hits " << debug_meas.size() <<
" of which trigger " << netaPhiHits.first.first <<
" eta and "
459 << netaPhiHits.first.second <<
" phi ");
467 <<
" radius " << std::setw(6) << mdt->
driftRadius() <<
" time " << std::setw(6) << mdt->
driftTime());
480 std::vector<Identifier> holeVec = calculateHoles(ctx, chid, gpos, gdir, hasMeasuredCoordinate, deltaVec, outoftimeVec, rioDistVec);
483 if (!outoftimeVec.empty()) holeVec.insert(holeVec.end(), std::make_move_iterator(outoftimeVec.begin()),
484 std::make_move_iterator(outoftimeVec.end()));
489 if (dcslFitter && !
segment.hasT0Shift() && m_outputFittedT0) {
496 bool hasFittedT0 =
false;
497 double fittedT0{0}, errorFittedT0{1.};
498 if (m_outputFittedT0 && (
segment.hasT0Shift() || (dcslFitter &&
result.hasT0Shift()))) {
502 errorFittedT0 =
segment.t0Error();
503 }
else if (dcslFitter &&
result.hasT0Shift()) {
504 fittedT0 =
result.t0Shift();
505 errorFittedT0 =
result.t0Error();
512 std::unique_ptr<MuonSegment> msegment;
513 if (isCurvedSegment) {
514 if (qoverp == -99999.) {
518 constexpr
double BILALPHA(28.4366), BMLALPHA(62.8267), BMSALPHA(53.1259), BOLALPHA(29.7554);
521 dqoverp = M_SQRT2 *
segment.dtheta() / BILALPHA;
524 dqoverp = M_SQRT2 *
segment.dtheta() / BMLALPHA;
527 dqoverp = M_SQRT2 *
segment.dtheta() / BMSALPHA;
530 dqoverp = M_SQRT2 *
segment.dtheta() / BOLALPHA;
541 std::vector<Trk::DefinedParameter> defPars;
544 defPars.emplace_back(gdir.phi(),
Trk::phi);
545 defPars.emplace_back(gdir.theta(),
Trk::theta);
548 msegment = std::make_unique<MuonSegment>(
549 std::move(segLocPar),
552 createROTVec(rioDistVec),
564 std::make_unique<MuonSegment>(segLocPos,
568 createROTVec(rioDistVec),
573 if (hasFittedT0) msegment->setT0Error(fittedT0, errorFittedT0);
576 int segmentQuality = m_segmentSelectionTool->quality(*msegment);
579 ATH_MSG_DEBUG(m_printer->print(*msegment) <<
" quality " << segmentQuality);
584 if (segmentQuality < 0) {
return nullptr; }
589 std::vector<const MdtDriftCircleOnTrack*> mdts;
590 std::vector<const MuonClusterOnTrack*>
clusters;
594 if (m_idHelperSvc->isMdt(
id)) {
596 if (!mdt) {
ATH_MSG_WARNING(
"failed dynamic_cast, not a MDT but hit has MDT id!!!"); }
598 }
else if (m_idHelperSvc->isTrigger(
id)) {
600 if (!clus) {
ATH_MSG_WARNING(
"failed dynamic_cast, not a cluster but hit has RPC/TGC id!!!"); }
609 if (mdts.empty())
return;
614 bool hasPhiMeasurements =
false;
617 find(gpos, gdir, mdts,
clusters, hasPhiMeasurements, segColl);
621 const std::vector<const Trk::RIO_OnTrack*>& rios2)
const {
622 std::vector<const Trk::RIO_OnTrack*> rios = rios1;
623 rios.insert(rios.end(), rios2.begin(), rios2.end());
629 bool hasPhiMeasurements,
double momentum)
const {
631 std::vector<const MdtDriftCircleOnTrack*> all_mdts;
632 for (
const std::vector<const MdtDriftCircleOnTrack*>& circle_vec : mdts) {
std::copy(circle_vec.begin(), circle_vec.end(), std::back_inserter(all_mdts)); }
635 std::vector<const MuonClusterOnTrack*> all_clus;
636 for (
const std::vector<const MuonClusterOnTrack*>& clus_vec :
clusters) {
std::copy(clus_vec.begin(), clus_vec.end(), std::back_inserter(all_clus)); }
645 if (!m_curvedErrorScaling)
return scale;
647 if (!errorScalingRegion(
id))
return scale;
649 double scaleMax = 5.;
650 if (m_curvedErrorScaling && curvature > 2) {
657 if (!hasPhiMeasurements) {
658 double phiScale = 1.;
660 int stRegion = m_idHelperSvc->mdtIdHelper().stationRegion(
id);
663 else if (stRegion == 1)
665 else if (stRegion == 2)
682 bool isEndcap = m_idHelperSvc->isEndcap(
id);
685 std::string
stName = m_idHelperSvc->mdtIdHelper().stationNameString(m_idHelperSvc->mdtIdHelper().stationName(
id));
686 if (
stName[1] ==
'I')
return true;
706 const Identifier gasGapId = m_idHelperSvc->gasGapId(
id);
708 if (m_idHelperSvc->measuresPhi(
id)) {
709 phiVec.push_back(createSpacePoint(gasGapId,
nullptr, clust));
710 if (phiVec.back().corrupt()) phiVec.pop_back();
712 clVec.push_back(createSpacePoint(gasGapId, clust,
nullptr));
713 if (clVec.back().corrupt()) clVec.pop_back();
729 const Identifier chId = m_idHelperSvc->chamberId(
id);
730 const Identifier gasGapId = m_idHelperSvc->gasGapId(
id);
732 if (!m_idHelperSvc->measuresPhi(
id))
733 gasGapHitMap[chId][gasGapId].first.push_back(clus);
735 gasGapHitMap[chId][gasGapId].second.push_back(clus);
738 return createSpacePoints(gasGapHitMap);
747 for (
const auto& [
id, gasGapHits] : chIdHitMap) {
751 std::make_move_iterator(
cls.first.end()), std::back_inserter(
spacePoints));
753 std::make_move_iterator(
cls.second.end()), std::back_inserter(phiVec));
756 return std::make_pair(std::move(
spacePoints), std::move(phiVec));
761 bool isEndcap = m_idHelperSvc->isEndcap((*(gasGapHitMap.begin())).first);
763 ATH_MSG_VERBOSE(
" creating Space points for " << gasGapHitMap.size() <<
" gas gaps ");
765 for (
const auto& [gasGapId, etaPhiHits] : gasGapHitMap) {
767 std::vector<bool> flagPhihit(etaPhiHits.second.size(), 0);
772 ATH_MSG_VERBOSE(
" New gasgap " << m_idHelperSvc->toString(gasGapId) <<
" neta " << etaPhiHits.first.size() <<
" nphi "
773 << etaPhiHits.second.size());
777 if (etaHit->
identify() == prevEtaId)
continue;
784 bool foundSP =
false;
790 if (phiHit->
identify() == prevPhiId)
continue;
795 Cluster2D sp = createTgcSpacePoint(gasGapId, etaHit, phiHit);
800 flagPhihit[phi_idx] =
true;
805 Cluster2D sp = createSpacePoint(gasGapId, etaHit,
nullptr);
810 Cluster2D sp = createRpcSpacePoint(gasGapId, etaHit, etaPhiHits.second);
813 flagPhihit = std::vector<bool>(etaPhiHits.second.size(), 1);
820 for (
unsigned int i = 0;
i < flagPhihit.size(); ++
i) {
821 if (flagPhihit[
i])
continue;
824 if (etaPhiHits.second[
i]->identify() == prevPhiId)
continue;
825 prevPhiId = etaPhiHits.second[
i]->identify();
827 Cluster2D sp = createTgcSpacePoint(gasGapId,
nullptr, etaPhiHits.second[
i]);
829 phiVec.push_back(std::move(sp));
831 }
else if (etaPhiHits.first.empty() && !etaPhiHits.second.empty()) {
833 Cluster2D sp = createRpcSpacePoint(gasGapId,
nullptr, etaPhiHits.second);
835 phiVec.push_back(std::move(sp));
839 ATH_MSG_VERBOSE(
" Creating space points, number of gas-gaps " << gasGapHitMap.size() <<
" space points " <<
spacePoints.size());
841 return std::make_pair(std::move(
spacePoints), std::move(phiVec));
846 bool isEndcap = m_idHelperSvc->isEndcap(gasGapId);
847 double error{1.}, lpx{0.}, lpy{0.};
857 }
else if (!phiHit) {
860 }
else if (etaHit && phiHit) {
862 return createTgcSpacePoint(gasGapId, etaHit, phiHit);
864 std::vector<const MuonClusterOnTrack*> phiVec{phiHit};
865 return createRpcSpacePoint(gasGapId, etaHit, phiVec);
868 Identifier detElId = m_idHelperSvc->detElId(gasGapId);
869 if (std::abs(
error) < 0.001) {
870 ATH_MSG_WARNING(
" Unphysical error assigned for gasgap " << m_idHelperSvc->toString(gasGapId));
879 double error{1.}, lpx{0.}, lpy{0.};
880 Identifier detElId = m_idHelperSvc->detElId(gasGapId);
885 }
else if (!phiHit) {
888 }
else if (etaHit && phiHit) {
897 lpx = lSpacePoint.x();
898 lpy = lSpacePoint.y();
900 if (
error <= std::numeric_limits<double>::epsilon()) {
906 <<
" " << m_idHelperSvc->toString(etaHit->
identify()) << std::endl
907 <<
" " << m_idHelperSvc->toString(phiHit->
identify()));
909 if (std::abs(
error) < 0.001) {
910 ATH_MSG_WARNING(
" Unphysical error assigned for gasgap " << m_idHelperSvc->toString(gasGapId));
913 ATH_MSG_VERBOSE(
"New space point for "<<m_idHelperSvc->toStringGasGap(gasGapId)<<
" at ("<<lpx<<
","<<lpy<<
")");
918 const std::vector<const MuonClusterOnTrack*>& phiHits)
const {
920 std::vector<const MuonClusterOnTrack*> cleanPhihits;
921 cleanPhihits.reserve(phiHits.size());
923 double error{1.}, lpx{0.}, lpy{0.};
926 lpx = phiHits.front()->localParameters()[
Trk::locX];
932 if (clus->identify() == prevId)
continue;
933 prevId = clus->identify();
934 cleanPhihits.push_back(clus);
936 }
else if (phiHits.empty()) {
939 }
else if (etaHit && !phiHits.empty()) {
944 <<
" " << m_idHelperSvc->toString(etaHit->
identify()));
946 double minPos{1e9}, maxPos{-1e9};
952 if (phiHit->identify() == prevId)
continue;
953 prevId = phiHit->identify();
961 ATH_MSG_DEBUG(
" " << m_idHelperSvc->toString(phiHit->identify()));
962 cleanPhihits.push_back(phiHit);
965 if (cleanPhihits.size() > 1)
966 ATH_MSG_DEBUG(
" multiple phi hits: nhits " << cleanPhihits.size() <<
" cl width " << maxPos - minPos);
970 Identifier detElId = m_idHelperSvc->detElId(gasGapId);
971 if (std::abs(
error) < 0.001) {
972 ATH_MSG_WARNING(
" Unphysical error assigned for gasgap " << m_idHelperSvc->toString(gasGapId));
982 const int chPhi = m_idHelperSvc->mdtIdHelper().stationPhi(chid);
986 cls.reserve(spVec.size());
992 const int measuresPhi = m_idHelperSvc->measuresPhi(
id);
993 const int eta = m_idHelperSvc->stationEta(
id);
994 const int phi = m_idHelperSvc->stationPhi(
id);
995 const int isTgc = m_idHelperSvc->isTgc(
id);
996 const int name = isTgc ? m_idHelperSvc->tgcIdHelper().stationName(
id) : m_idHelperSvc->rpcIdHelper().stationName(
id);
999 ATH_MSG_VERBOSE(
" Discarding cluster, wrong station phi " << m_idHelperSvc->toString(
id));
1009 if (std::abs(lp.
y()) > m_maxAssociateClusterDistance) {
1010 ATH_MSG_VERBOSE(
" Discarding cluster with large distance from chamber " << m_idHelperSvc->toString(
id));
1013 ATH_MSG_VERBOSE(
" " << m_idHelperSvc->toString(
id) <<
" clid: " << clid.id() <<
" central phi "
1015 cls.emplace_back(lp, clust.error, clid, meas,
index);
1021 std::set<Identifier>& chamberSet,
double& phimin,
double& phimax,
1025 dcs.reserve(mdts.size());
1027 bool firstMdt =
true;
1032 Identifier elId = m_idHelperSvc->mdtIdHelper().elementID(
id);
1035 Amg::Vector3D locPos = gToStation * rot->prepRawData()->globalPosition();
1038 double r = rot->localParameters()[
Trk::locR];
1042 TrkDriftCircleMath::MdtId mdtid(m_idHelperSvc->mdtIdHelper().isBarrel(
id), m_idHelperSvc->mdtIdHelper().multilayer(
id) - 1,
1043 m_idHelperSvc->mdtIdHelper().tubeLayer(
id) - 1, m_idHelperSvc->mdtIdHelper().tube(
id) - 1);
1046 double preciseError =
dr;
1047 if (m_usePreciseError) { preciseError = m_preciseErrorScale * (0.23 *
std::exp(-std::abs(
r) / 6.06) + 0.0362); }
1051 TubeEnds tubeEnds = localTubeEnds(*rot, gToStation, amdbToGlobal);
1053 phimin = tubeEnds.
phimin;
1054 phimax = tubeEnds.
phimax;
1057 updatePhiRanges(tubeEnds.
phimin, tubeEnds.
phimax, phimin, phimax);
1060 ATH_MSG_VERBOSE(
" new MDT hit " << m_idHelperSvc->toString(
id) <<
" x " << lpos.
x() <<
" y " << lpos.
y() <<
" time "
1061 << rot->driftTime() <<
" r " <<
r <<
" dr " <<
dr <<
" phi range " << tubeEnds.
phimin <<
" "
1062 << tubeEnds.
phimax<<
" precise error "<<preciseError);
1063 dcs.push_back(std::move(dc));
1065 chamberSet.insert(elId);
1067 ++dcStatistics[rot->prepRawData()->detectorElement()];
1091 int eta = m_idHelperSvc->mdtIdHelper().stationEta(chid);
1092 int phi = m_idHelperSvc->mdtIdHelper().stationPhi(chid);
1093 int name = m_idHelperSvc->mdtIdHelper().stationName(chid);
1098 ATH_MSG_ERROR(
"Null pointer to the read MuonDetectorManager conditions object");
1104 MuonDetMgr->getMdtReadoutElement(m_idHelperSvc->mdtIdHelper().channelID(
name,
eta,
phi, 1, 1, 1));
1113 detEl2 = MuonDetMgr->getMdtReadoutElement(firstIdml1);
1114 firstTubeMl1 = gToStation * (detEl2->
surface(firstIdml1).
center());
1124 firstTubeMl0 = gToStation * (detEl1->
surface(firstIdml0).
center());
1137 double tubeDist = (secondTubeMl0 - firstTubeMl0).
y();
1138 double tubeStage = (firstTubeMl0lay1 - firstTubeMl0).
y();
1139 double layDist = (firstTubeMl0lay1 - firstTubeMl0).
z();
1141 TrkDriftCircleMath::MdtChamberGeometry mdtgeo(chid, m_idHelperSvc.get(), nml, nlay, ntube1, ntube2, firstTube0, firstTube1, tubeDist, tubeStage,
1152 std::set<Identifier>& deltaVec, std::set<Identifier>& outoftimeVec,
1153 std::vector<std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>> >& rioDistVec,
double beta)
const {
1160 if (
segment.hasCurvatureParameters()) {
1162 double ml2phi =
line.phi() -
segment.deltaAlpha();
1167 double chamberMidPtY = (ml1LocPos.
y() + ml2LocPos.
y()) / 2.0;
1173 toLineml2 = tmptoLine;
1187 if (m_idHelperSvc->mdtIdHelper().multilayer(riodc->identify()) == 2) toLine = toLineml2;
1198 Amg::Vector3D posAlong = gToStation * riodc->globalPosition();
1201 posAlong[1] = pointOnLineAMDB.
x();
1202 posAlong[2] = pointOnLineAMDB.
y();
1209 ATH_MSG_WARNING(
" dynamic cast to StraightLineSurface failed for mdt!!! ");
1220 std::unique_ptr<MdtDriftCircleOnTrack> nonconstDC;
1221 bool hasT0 =
segment.hasT0Shift();
1222 if (!hasT0 || m_mdtCreatorT0.empty()) {
1224 nonconstDC.reset(m_mdtCreator->createRIO_OnTrack(*riodc->prepRawData(), mdtGP, &gdir, 0.,
nullptr,
beta, 0.));
1225 if (hasT0)
ATH_MSG_WARNING(
"Attempted to change t0 without a properly configured MDT creator tool. ");
1228 nonconstDC.reset(m_mdtCreatorT0->createRIO_OnTrack(*riodc->prepRawData(), mdtGP, &gdir,
segment.t0Shift()));
1235 ATH_MSG_VERBOSE(
"Post calibrated hit "<<m_printer->print(*nonconstDC));
1239 dcit.driftState(), dcit.id(),
1242 dcit = std::move(new_dc_on_track);
1246 double shift = riodc->driftTime() - nonconstDC->driftTime();
1247 ATH_MSG_VERBOSE(
" t0 shift " <<
segment.t0Shift() <<
" from hit " << shift <<
" recal " << nonconstDC->driftRadius()
1248 <<
" t " << nonconstDC->driftTime() <<
" from fit " << dcit.r() <<
" old "
1249 << riodc->driftRadius() <<
" t " << riodc->driftTime());
1250 if (std::abs(std::abs(nonconstDC->driftRadius()) - std::abs(dcit.r())) > 0.1 && nonconstDC->driftRadius() < 19. &&
1251 nonconstDC->driftRadius() > 1.) {
1256 m_mdtCreator->updateSign(*nonconstDC,
side);
1257 double dist = pointOnHit.
x();
1258 rioDistVec.emplace_back(dist, std::move(nonconstDC));
1278 bool operator()(
const std::pair<double, DCMathSegmentMaker::Cluster2D>&
d1,
1279 const std::pair<double, DCMathSegmentMaker::Cluster2D>&
d2) {
1280 return std::abs(
d1.first) < std::abs(
d2.first);
1286 double phimin,
double phimax, std::vector<std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>> >& rioDistVec)
const {
1289 typedef std::vector<ChamberData> ChamberDataVec;
1290 ChamberDataVec chamberDataVec;
1291 bool isEndcap = m_idHelperSvc->isEndcap(chid);
1295 std::pair<std::pair<int, int>,
bool> netaPhiHits(std::make_pair(0, 0),
false);
1296 if (
segment.clusters().empty())
return netaPhiHits;
1298 std::vector<const Trk::MeasurementBase*> phiHits;
1304 std::set<Identifier> detElOnSegments;
1305 std::set<MuonStationIndex::PhiIndex> phiIndices;
1307 ATH_MSG_DEBUG(
" Associating clusters: " <<
segment.clusters().size() <<
" number of space points " << spVecs.first.size());
1312 const Cluster2D& spacePoint = spVecs.first[clust.index()];
1316 ATH_MSG_DEBUG(
" Found corrupt space point: index " << clust.index());
1320 if (m_reject1DTgcSpacePoints && !spacePoint.
is2D() && m_idHelperSvc->isTgc(spacePoint.
identify())) {
1324 if (m_assumePointingPhi && spacePoint.
is2D() && !checkPhiConsistency(spacePoint.
globalPos.phi(), phimin, phimax)) {
1325 ATH_MSG_DEBUG(
" Inconsistent phi angle, dropping space point: phi " << spacePoint.
globalPos.phi() <<
" range " << phimin
1330 std::pair<double, double> resPull = residualAndPullWithSegment(
segment, spacePoint, gToStation);
1333 if (chamberDataVec.empty() || chamberDataVec.back().id != spacePoint.
detElId) {
1334 detElOnSegments.insert(spacePoint.
detElId);
1335 chamberDataVec.emplace_back(spacePoint.
detElId);
1341 ChamberData&
chamber = chamberDataVec.back();
1353 gasGap.data.emplace_back(resPull.second, spacePoint);
1357 double posFirstPhiStation{FLT_MAX}, posLastPhiStation{0.};
1360 for (ChamberData& chamb : chamberDataVec) {
1362 std::list<const Trk::PrepRawData*> etaClusterVec{}, phiClusterVec{};
1363 std::set<Identifier> etaIds;
1370 double bestPull = std::abs(
gasGap.data.front().first);
1373 unsigned int nassociatedSp = 0;
1374 GasGapData::EntryVec::const_iterator cl_it =
gasGap.data.begin();
1375 while (cl_it !=
gasGap.data.end() && std::abs(cl_it->first) - bestPull < 1.) {
1380 << std::abs(cl_it->first) <<
" distance to segment " << dist <<
" phi "
1388 if (m_createCompetingROTsEta)
1392 ++netaPhiHits.first.first;
1397 if (m_createCompetingROTsPhi) {
1401 return clus->prepRawData();
1406 rioDistVec.emplace_back(dist, phi_hit->
uniqueClone());
1407 ++netaPhiHits.first.second;
1408 phiHits.push_back(phi_hit);
1412 posFirstPhiStation =
std::min(phiPos, posFirstPhiStation);
1413 posLastPhiStation =
std::max(phiPos, posLastPhiStation);
1415 if (sp.
phiHits.size() > 1) refit =
false;
1422 if (!m_createCompetingROTsPhi && nassociatedSp > 1) refit =
false;
1425 if (m_createCompetingROTsEta) {
1427 if (!etaClusterVec.empty()) {
1428 std::unique_ptr<const CompetingMuonClustersOnTrack> etaCompCluster = m_compClusterCreator->createBroadCluster(etaClusterVec, 0.);
1429 if (!etaCompCluster) {
1430 ATH_MSG_DEBUG(
" failed to create competing ETA ROT " << etaClusterVec.size());
1432 double dist = distanceToSegment(
segment, etaCompCluster->globalPosition(), gToStation);
1433 ++netaPhiHits.first.first;
1435 ATH_MSG_VERBOSE(
" selected cluster: " << m_idHelperSvc->toString(etaClusterVec.front()->identify()));
1436 for (
unsigned int i = 0;
i < etaCompCluster->containedROTs().
size(); ++
i) {
1438 " content: " << m_idHelperSvc->toString(etaCompCluster->containedROTs()[
i]->identify()));
1441 rioDistVec.emplace_back(dist, std::move(etaCompCluster));
1446 if (m_createCompetingROTsPhi) {
1448 if (!phiClusterVec.empty()) {
1449 std::unique_ptr<const CompetingMuonClustersOnTrack> phiCompCluster = m_compClusterCreator->createBroadCluster(phiClusterVec, 0.);
1450 if (!phiCompCluster) {
1451 ATH_MSG_DEBUG(
" failed to create competing PHI ROT " << phiClusterVec.size());
1453 double dist = distanceToSegment(
segment, phiCompCluster->globalPosition(), gToStation);
1454 phiHits.push_back(phiCompCluster.get());
1456 ++netaPhiHits.first.second;
1459 ATH_MSG_VERBOSE(
" selected cluster: " << m_idHelperSvc->toString(phiClusterVec.front()->identify()));
1460 for (
unsigned int i = 0;
i < phiCompCluster->containedROTs().
size(); ++
i) {
1462 " content: " << m_idHelperSvc->toString(phiCompCluster->containedROTs()[
i]->identify()));
1468 double phiPos = isEndcap ? std::abs(phiCompCluster->globalPosition().z()) :
1469 phiCompCluster->globalPosition().perp();
1470 posFirstPhiStation =
std::min(phiPos,posFirstPhiStation);
1471 posLastPhiStation =
std::max(phiPos,posLastPhiStation);
1472 rioDistVec.emplace_back(dist, std::move(phiCompCluster));
1480 if ((!spVecs.second.empty() || m_recoverBadRpcCabling) && m_addUnassociatedPhiHits && !isEndcap) {
1483 std::map<Identifier, std::list<const Trk::PrepRawData*> > phiClusterMap;
1485 std::set<const MuonClusterOnTrack*> selectedClusters;
1486 std::vector<const Cluster2D*> phiClusters;
1487 phiClusters.reserve(spVecs.second.size());
1490 for (
const Cluster2D& phi_clus :spVecs.second) {
1495 phiClusters.push_back(&phi_clus);
1496 selectedClusters.insert(phi_clus.
phiHit);
1499 unsigned int recoveredUnassociatedPhiHits(0);
1500 if (m_recoverBadRpcCabling) {
1503 for (
const Cluster2D& rpc_clust : spVecs.first) {
1508 if (detElOnSegments.count(rpc_clust.
detElId))
continue;
1512 if (phiIndices.count(
phiIndex))
continue;
1514 bool wasFound =
false;
1517 if (!selectedClusters.insert(phi_hit).second) {
1524 if (erase_me == phi_hit)
break;
1525 selectedClusters.erase(erase_me);
1530 if (wasFound)
continue;
1533 phiClusters.push_back(&rpc_clust);
1534 ++recoveredUnassociatedPhiHits;
1538 unsigned int addedPhiHits(0);
1539 for (
const Cluster2D* phi_clus : phiClusters) {
1543 if (detElOnSegments.count(detElId))
continue;
1547 if (phiIndices.count(
phiIndex))
continue;
1555 double segError = std::sqrt(resWithSegment.
trackError2(
cl));
1564 bool inBounds = std::abs(
residual) < 0.5 * stripLength + 2. + segError;
1567 <<
" pos y " <<
cl.position().y() <<
" : residual " <<
residual <<
" strip half length "
1568 << 0.5 * stripLength <<
" segment error " << segError);
1576 std::list<const Trk::PrepRawData*>& cham_hits{phiClusterMap[detElId]};
1579 return clus->prepRawData();
1585 for (
const auto& [phi_id, prds] : phiClusterMap) {
1587 ATH_MSG_WARNING(
" chamber without phi hits " << m_idHelperSvc->toString(phi_id));
1591 std::unique_ptr<const CompetingMuonClustersOnTrack> phiCompCluster = m_compClusterCreator->createBroadCluster(prds, 0.);
1592 if (!phiCompCluster) {
1593 ATH_MSG_DEBUG(
" failed to create competing PHI ROT " << prds.size());
1595 double dist = distanceToSegment(
segment, phiCompCluster->globalPosition(), gToStation);
1597 if (std::abs(dist) > m_maxAssociateClusterDistance) {
1599 ATH_MSG_VERBOSE(
" rejected unassociated cluster: " << m_idHelperSvc->toString(prds.front()->identify())
1600 <<
" distance to segment " << dist);
1603 phiHits.push_back(phiCompCluster.get());
1604 ++netaPhiHits.first.second;
1607 ATH_MSG_VERBOSE(
" selected unassociated cluster: " << m_idHelperSvc->toString(prds.front()->identify())
1608 <<
" distance to segment " << dist);
1609 for (
unsigned int i = 0;
i < phiCompCluster->containedROTs().
size(); ++
i) {
1611 " content: " << m_idHelperSvc->toString(phiCompCluster->containedROTs()[
i]->identify()));
1614 rioDistVec.emplace_back(dist, std::move(phiCompCluster));
1617 ATH_MSG_VERBOSE(
"Added " << addedPhiHits <<
" unass phi hits out of " << spVecs.second.size()
1618 <<
" phi hits without eta hit and " << recoveredUnassociatedPhiHits <<
" with unassociated eta hit ");
1622 double phiDistanceMax = posLastPhiStation - posFirstPhiStation;
1623 if (isEndcap && phiDistanceMax < 1000.)
1625 else if (phiDistanceMax < 400.)
1628 netaPhiHits.second = refit;
1636 double cos_sinLine = cot(
line.phi());
1644 double delta_y = lpos.
y() -
line.position().y();
1652 return pointOnHit.
x();
1656 std::vector<std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>> >& rioDistVec) {
1661 rioVec.reserve(rioDistVec.size());
1662 for (std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>>& rdit : rioDistVec) { rioVec.push_back(std::move(rdit.second)); }
1671 double cos_sinLine = cot(
line.phi());
1678 double delta_y = lpos.
y() -
line.position().y();
1684 double residual = lpos.
x() - lineSurfaceIntersect.
x();
1691 std::set<Identifier>& outoftimeVec,
const std::vector<std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>> >& rioDistVec)
const {
1694 if (!InterSectSvc.isValid()) {
1695 ATH_MSG_ERROR(
"Null pointer to the read MuonDetectorManager conditions object");
1704 std::set<Identifier> hitsOnSegment, chambersOnSegment;
1705 int firstLayer{-1}, lastLayer{-1};
1706 for (
const std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>>& rdit : rioDistVec) {
1710 int layer = (m_idHelperSvc->mdtIdHelper().tubeLayer(
id) - 1) + 4 * (m_idHelperSvc->mdtIdHelper().multilayer(
id) - 1);
1711 if (firstLayer == -1)
1716 hitsOnSegment.insert(
id);
1717 chambersOnSegment.insert(m_idHelperSvc->chamberId(
id));
1721 if (firstLayer > lastLayer) {
std::swap(firstLayer, lastLayer); }
1722 ATH_MSG_VERBOSE(
" Tube layer ranges: " << firstLayer <<
" -- " << lastLayer <<
" crossed tubes "
1725 std::vector<Identifier> holeVec;
1727 if (!chambersOnSegment.count(m_idHelperSvc->chamberId(tint.tubeId))) {
1728 ATH_MSG_VERBOSE(
" chamber not on segment, not counting tube " << tint.rIntersect <<
" l " << tint.xIntersect <<
" "
1729 << m_idHelperSvc->toString(tint.tubeId));
1734 int layer = (m_idHelperSvc->mdtIdHelper().tubeLayer(
id) - 1) + 4 * (m_idHelperSvc->mdtIdHelper().multilayer(
id) - 1);
1736 bool notBetweenHits = layer < firstLayer || layer > lastLayer;
1737 double distanceCut = hasMeasuredCoordinate ? -20 : -200.;
1739 if (notBetweenHits && (std::abs(tint.rIntersect) > innerRadius || (!m_allMdtHoles && tint.xIntersect > distanceCut))) {
1740 ATH_MSG_VERBOSE(
" not counting tube: distance to wire " << tint.rIntersect <<
" dist to tube end " << tint.xIntersect
1741 <<
" " << m_idHelperSvc->toString(tint.tubeId));
1745 if (hitsOnSegment.count(tint.tubeId)) {
1746 ATH_MSG_VERBOSE(
" tube on segment: distance to wire " << tint.rIntersect <<
" dist to tube end " << tint.xIntersect
1747 <<
" " << m_idHelperSvc->toString(tint.tubeId));
1751 if (m_removeDeltas) {
1752 if (deltaVec.count(tint.tubeId)) {
1753 ATH_MSG_VERBOSE(
" removing delta, distance to wire " << tint.rIntersect <<
" dist to tube end " << tint.xIntersect
1754 <<
" " << m_idHelperSvc->toString(tint.tubeId));
1760 ATH_MSG_VERBOSE(
" found and removed delta, distance to wire " << tint.rIntersect <<
" dist to tube end "
1761 << tint.xIntersect <<
" "
1762 << m_idHelperSvc->toString(tint.tubeId));
1766 ATH_MSG_VERBOSE((outoftimeVec.count(tint.tubeId) ?
"Out-of-time" :
"hole") <<
" distance to wire "
1767 << tint.rIntersect <<
" dist to tube end " << tint.xIntersect <<
" "
1768 << m_idHelperSvc->toString(tint.tubeId)<<(notBetweenHits ?
"outside hits" :
"between hits"));
1770 holeVec.push_back(tint.tubeId);
1777 if (m_idHelperSvc->mdtIdHelper().get_module_hash(m_idHelperSvc->chamberId(
id), colHash)){
1778 ATH_MSG_VERBOSE(
"Invalid Mdt identifier "<<m_idHelperSvc->toString(
id));
1782 if (!MdtCont.isValid()) {
1787 if (!collptr)
return nullptr;
1789 if (prd->identify() ==
id)
return prd;
1795 const std::vector<const MdtDriftCircleOnTrack*>& mdts)
const {
1796 int hitsInChamberWithMostHits = 0;
1797 std::map<Identifier, int> hitsPerChamber;
1798 int currentSector = -1;
1807 Identifier chId = m_idHelperSvc->chamberId(rot->identify());
1808 int sector = m_idHelperSvc->sector(chId);
1809 if (currentSector == -1) {
1810 currentSector = sector;
1811 }
else if (sector != currentSector) {
1814 int& hitsInCh = hitsPerChamber[chId];
1816 if (hitsInCh > hitsInChamberWithMostHits) {
1817 hitsInChamberWithMostHits = hitsInCh;
1818 rotInChamberWithMostHits = rot;
1821 return rotInChamberWithMostHits;
1825 const std::vector<DCMathSegmentMaker::HitInXZ>&
hits)
const {
1830 bool outBounds =
false;
1831 double locExX = xline + dXdZ * (hit.z - zline);
1832 if (hit.isMdt && (locExX < hit.xmin - 1. || locExX > hit.xmax + 1.)) {
1839 ATH_MSG_DEBUG(
" " << std::setw(65) << m_idHelperSvc->toString(hit.id) <<
" pos (" << std::setw(6) << (
int)hit.x <<
","
1840 << std::setw(6) << (
int)hit.z <<
") ex pos " << std::setw(6) << (
int)locExX <<
" min " << std::setw(6)
1841 << (
int)hit.xmin <<
" max " << std::setw(6) << (
int)hit.xmax <<
" phimin " << std::setw(6)
1842 << hit.phimin <<
" phimax " << std::setw(6) << hit.phimax <<
" outBounds, cross-check");
1850 const std::vector<const Trk::MeasurementBase*>& rots,
double seg_phimin,
1851 double seg_phimax)
const {
1852 bool hasUpdated =
false;
1859 if (ldir.z() < 0.0001)
return false;
1861 double dXdZ = ldir.x() / ldir.z();
1863 double xline = lsegPos.x();
1864 double zline = lsegPos.z();
1865 ATH_MSG_VERBOSE(
" Associated hits " << rots.size() <<
" angleXZ " << 90. * segLocDir.
angleXZ() / (M_PI_2) <<
" dXdZ " << dXdZ
1866 <<
" seg Pos (" << xline <<
" " << zline <<
") " << segLocPos);
1868 std::vector<HitInXZ>
hits;
1869 hits.reserve(rots.size());
1871 unsigned int nphiHits(0);
1872 const HitInXZ* firstPhiHit{
nullptr}, *lastPhiHit{
nullptr};
1875 Identifier id = m_edmHelperSvc->getIdentifier(*meas);
1876 if (!
id.is_valid())
continue;
1878 double lxmin{0}, lxmax{0}, phimin{0}, phimax{0};
1879 bool isMdt = m_idHelperSvc->isMdt(
id);
1880 bool measuresPhi = m_idHelperSvc->measuresPhi(
id);
1884 TubeEnds tubeEnds = localTubeEnds(*mdt, gToSegment, segmentToGlobal);
1886 lxmin = tubeEnds.
lxmin;
1887 lxmax = tubeEnds.
lxmax;
1888 phimin = tubeEnds.
phimin;
1889 phimax = tubeEnds.
phimax;
1891 lpos = gToSegment * meas->globalPosition();
1903 lxmin = lpos.x() - 0.5 * stripLength;
1904 lxmax = lpos.x() + 0.5 * stripLength;
1908 locPosition[0] = lxmin;
1910 double phi1 = globalPos.phi();
1912 locPosition[0] = lxmax;
1913 globalPos = segmentToGlobal * locPosition;
1914 double phi2 = globalPos.phi();
1919 if (m_idHelperSvc->isTgc(
id)) {
1925 int stripNo = m_idHelperSvc->tgcIdHelper().channel(
id);
1926 int gasGap = m_idHelperSvc->tgcIdHelper().gasGap(
id);
1928 ATH_MSG_WARNING(
"dynamic cast failed for CompetingMuonClustersOnTrack");
1935 const Amg::Vector3D segFrame_stripPos = gToSegment * detEl->channelPos(
id);
1937 lpos = segFrame_stripPos +
1938 Amg::intersect<3>(lsegPos, ldir, segFrame_stripPos, segFrame_StripDir).value_or(0) * segFrame_StripDir;
1945 phimin = globalPos.phi();
1949 bool phiOk = checkPhiConsistency(phimin, seg_phimin, seg_phimax);
1951 ATH_MSG_DEBUG(
" Inconsistent phi " << phimin <<
" range " << seg_phimin <<
" " << seg_phimax);
1956 hits.emplace_back(
id, isMdt, measuresPhi, lpos.x(), lpos.z(), lxmin, lxmax, phimin, phimax);
1960 firstPhiHit = &
hits.back();
1962 double distPhiHits = std::abs(firstPhiHit->z -
hits.back().z);
1963 if (distPhiHits > 500.) {
1964 lastPhiHit = &
hits.back();
1973 double locExX = xline + dXdZ * (lpos.z() - zline);
1974 ATH_MSG_VERBOSE(
" " << std::setw(65) << m_idHelperSvc->toString(
id) <<
" pos (" << std::setw(6) << (
int)lpos.x() <<
","
1975 << std::setw(6) << (
int)lpos.z() <<
") ex pos " << std::setw(6) << (
int)locExX <<
" min "
1976 << std::setw(6) << (
int)lxmin <<
" max " << std::setw(6) << (
int)lxmax <<
" phimin " << std::setw(6)
1977 << phimin <<
" phimax " << std::setw(6) << phimax);
1978 if (lpos.x() < lxmin || lpos.x() > lxmax)
ATH_MSG_VERBOSE(
" outBounds");
1982 if (nphiHits == 1) {
1984 ATH_MSG_WARNING(
" Pointer to first phi hit not set, this should not happen! ");
1986 if (xline != firstPhiHit->x) {
1990 xline = firstPhiHit->x;
1991 zline = firstPhiHit->z;
1993 if (m_assumePointingPhi) {
1997 double dz = ipLocPos.z() - zline;
1998 if (std::abs(dz) > 0.001) {
1999 ATH_MSG_VERBOSE(
" hit (" << xline <<
"," << zline <<
") IP (" << ipLocPos.x() <<
"," << ipLocPos.z()
2000 <<
") dXdZ " << (ipLocPos.x() - xline) / dz <<
" old " << dXdZ);
2001 dXdZ = (ipLocPos.x() - xline) / dz;
2006 }
else if (nphiHits == 2) {
2007 if (!firstPhiHit || !lastPhiHit) {
2008 ATH_MSG_WARNING(
" Pointer to one of the two phi hit not set, this should not happen! ");
2010 double dz = lastPhiHit->z - firstPhiHit->z;
2012 xline = firstPhiHit->x;
2013 zline = firstPhiHit->z;
2014 if (std::abs(dz) > 300.) {
2015 double dx = lastPhiHit->x - firstPhiHit->x;
2028 double segX = xline - dXdZ * zline;
2031 bool ok = checkBoundsInXZ(segX, 0., dXdZ,
hits);
2034 ATH_MSG_DEBUG(
"still several out of bounds hits after rotation: posx(" << segX <<
") dXdZ " << dXdZ
2035 <<
" keeping old result ");
2039 double alphaYZ = segLocDir.
angleYZ();
2040 double alphaXZ = std::atan2(1, dXdZ);
2059 double tubeLen = (lropos - lhvpos).
mag();
2060 double activeTubeLen =
2062 double scaleFactor = activeTubeLen / tubeLen;
2063 lropos[0] = scaleFactor * lropos.x();
2064 lhvpos[0] = scaleFactor * lhvpos.x();
2071 const double phiRO = ropos.phi();
2072 const double phiHV = hvpos.phi();
2080 if (phiminRef * phimaxRef < 0.) {
2081 if (phiminRef < -1.1) {
2082 if (phiminRef > phiminNew) phiminRef = phiminNew;
2083 if (phimaxRef < phimaxNew) phimaxRef = phimaxNew;
2085 if (phiminRef < phiminNew) phiminRef = phiminNew;
2086 if (phimaxRef > phimaxNew) phimaxRef = phimaxNew;
2090 if (phiminRef < 0.) {
2091 if (phiminRef < phiminNew) phiminRef = phiminNew;
2092 if (phimaxRef > phimaxNew) phimaxRef = phimaxNew;
2094 if (phiminRef > phiminNew) phiminRef = phiminNew;
2095 if (phimaxRef < phimaxNew) phimaxRef = phimaxNew;
2102 if (!m_assumePointingPhi)
return true;
2106 if (phimin * phimax < 0.) {
2109 if (
phi < phimin -
offset) phiOk =
false;
2111 if (
phi > phimin +
offset) phiOk =
false;
2115 if (
phi < phimax -
offset) phiOk =
false;
2117 if (
phi > phimax +
offset) phiOk =
false;
2121 if (phi < phimin - offset || phi > phimax +
offset) phiOk =
false;
2127 bool isCurvedSegment)
const {
2141 double dz =
std::cos(gdirs.theta());
2147 double dzo =
std::cos(gdiro.theta());
2157 if (b0 < 1e-8 && b0 > 0) b0 = 1
e-8;
2158 if (b0 > -1
e-8 && b0 < 0) b0 = -1
e-8;
2159 double dxn =
dx -
a0 * dxo / b0;
2160 double dyn =
dy -
a0 * dyo / b0;
2161 double dzn = dz -
a0 * dzo / b0;
2162 double norm = std::sqrt(dxn * dxn + dyn * dyn + dzn * dzn);
2165 if (m_assumePointingPhi) {
2166 if (dxn * roaddir.x() + dyn * roaddir.y() + dzn * roaddir.z() < 0.) {
norm = -
norm; }
2168 if (dxn * roaddir.x() + dyn * roaddir.y() < 0.) {
norm = -
norm; }
2171 if (isCurvedSegment)
norm =
norm / 2.;