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;}
64 declareInterface<IMuonSegmentMaker>(
this);
88 return StatusCode::SUCCESS;
92 const std::vector<const MdtDriftCircleOnTrack*>& mdts,
93 const std::vector<const MuonClusterOnTrack*>&
clusters,
bool hasPhiMeasurements,
95 const EventContext& ctx = Gaudi::Hive::currentContext();
103 if (mdts.size() < 3)
return;
107 if (!firstRot) {
return; }
131 double chamber_angleYZ = std::atan2(dirCh.z(), dirCh.y());
134 double dotprod = globalDirCh.perp() *
std::sin(roaddir2.theta()) + globalDirCh.z() *
std::cos(roaddir2.theta());
135 if (dotprod < 0) roaddir2 = -roaddir2;
140 double road_angleXZ = std::atan2(
d.z(),
d.x());
141 double road_angleYZ = std::atan2(
d.z(),
d.y());
143 if (!hasPhiMeasurements) road_angleXZ =
M_PI;
145 << isEndcap <<
" central phi " << detEl->
center().phi() <<
" r " << detEl->
center().perp()
146 <<
" z " << detEl->
center().z());
162 std::stringstream sstr{};
165 ATH_MSG_VERBOSE(
" adding mdts " << mdts.size()<<std::endl<<sstr.str());
169 std::set<Identifier> chamberSet;
170 double phimin{-9999}, phimax{9999};
175 std::shared_ptr<const TrkDriftCircleMath::ChamberGeometry> multiGeo;
177 ATH_MSG_VERBOSE(
" using chamber geometry with #chambers " << chamberSet.size());
179 std::vector<TrkDriftCircleMath::MdtChamberGeometry> geos{};
182 geos.reserve(chamberSet.size());
188 multiGeo = std::make_unique<TrkDriftCircleMath::MdtMultiChamberGeometry>(geos);
194 if (sinAngleCut > 0)
angle = sinAngleCut;
201 std::stringstream sstr{};
202 unsigned int seg_n{0};
205 sstr<<
"Segment number "<<seg_n<<
" is at ("<<seg.line().x0()<<
","<<seg.line().y0()<<
") pointing to "<<seg.line().phi()*toDeg<<
" chi2: "<<
206 (seg.chi2()/seg.ndof())<<
"("<<seg.ndof()<<
")"<<std::endl;
207 sstr<<
"Mdt measurements: "<<seg.dcs().size()<<std::endl;
209 sstr<<
" **** "<<
m_printer->print(*mdt_meas.rot());
210 sstr<<
" ("<<mdt_meas.state()<<
")"<<std::endl;
212 sstr<<
"Cluster measurements "<<seg.clusters().size()<<std::endl;
214 sstr<<
" ---- "<<
m_printer->print(*clus.rot())<<std::endl;
219 ATH_MSG_VERBOSE(
"Found " << segs.size() <<
" segments "<<std::endl<<sstr.str());
223 if (segs.empty()) {
return; }
226 segmentCreationInfo sInfo(spVecs, multiGeo.get(), gToStation, amdbToGlobal, phimin, phimax);
228 std::unique_ptr<MuonSegment>
segment =
createSegment(ctx, seg, chid, roadpos, roaddir2, mdts, hasPhiMeasurements, sInfo);
236 const std::vector<const MdtDriftCircleOnTrack*>& mdts,
bool hasPhiMeasurements,
244 const bool isCurvedSegment =
segment.hasCurvatureParameters() &&
245 std::find(statWithField.begin(), statWithField.end(), chIndex) != statWithField.end();
248 if (
segment.hitsOnTrack() < 3)
return nullptr;
254 <<
line.position().y() <<
" phi " <<
line.phi() <<
" associated clusters "
264 if (hasPhiMeasurements) {
268 double cphi = lroaddir.x();
278 double shortestTubeLen = 1e9;
284 int lay =
m_idHelperSvc->mdtIdHelper().tubeLayer(riodc->identify());
286 double tubelen = 0.5 * riodc->prepRawData()->detectorElement()->getActiveTubeLength(lay,
tube);
287 if (tubelen < shortestTubeLen) shortestTubeLen = tubelen;
290 if (std::abs(lxroad) > shortestTubeLen) {
291 ATH_MSG_DEBUG(
"coordinates far outside chamber! using global position of first hit ");
292 if (lxroad < 0.) shortestTubeLen *= -1.;
293 lxroad = shortestTubeLen;
296 lxroad = (sInfo.
globalTrans * mdts[0]->prepRawData()->detectorElement()->surface(mdts[0]->identify()).center()).
x();
307 surfaceTransform.pretranslate(gpos);
308 double surfDim = 500.;
309 std::unique_ptr<Trk::PlaneSurface> surf = std::make_unique<Trk::PlaneSurface>(surfaceTransform, surfDim, surfDim);
313 double linephi =
line.phi();
320 std::vector<std::pair<double, std::unique_ptr<const Trk::MeasurementBase>> > rioDistVec;
323 std::set<Identifier> deltaVec;
324 std::set<Identifier> outoftimeVec;
327 std::vector<std::pair<double, std::unique_ptr<const Trk::MeasurementBase>>> garbage_collector;
341 linephi =
result.line().phi();
342 lpos[1] =
result.line().position().x();
343 lpos[2] =
result.line().position().y();
348 surfaceTransform.pretranslate(gpos);
349 surf = std::make_unique<Trk::PlaneSurface>(surfaceTransform, surfDim, surfDim);
369 if (
std::min(std::abs(diff_phi), std::abs( std::abs(diff_phi) -
M_PI)) > 1.
e-3 ||
370 std::min(std::abs(diff_prec), std::abs(std::abs(diff_prec) -
M_PI)) > 1.
e-3) {
371 ATH_MSG_WARNING(
" ALARM updated angles wrong: diff phi " << diff_phi <<
" prec " << diff_prec <<
" phi rdir " << roaddir2.phi()
372 <<
" gdir " << gdir.phi() <<
" lphi " << linephi <<
" seg "
377 std::pair<std::pair<int, int>,
bool> netaPhiHits =
380 if (rioDistVec.empty()){
386 auto meas_for_fit = [&rioDistVec] () {
387 std::vector<const Trk::MeasurementBase*>
out{};
388 out.reserve(rioDistVec.size());
390 for (
const std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>>& ele : rioDistVec)
out.push_back(ele.second.get());
395 double dlocx{1000.}, dangleXZ{1000.}, qoverp{-99999.}, dqoverp{-99999.};
396 bool hasMeasuredCoordinate =
false;
398 ATH_MSG_DEBUG(
" distance between first and last phi hit sufficient to perform 4D fit: phi " << gdir.phi() <<
" theta "
404 if (isCurvedSegment &&
track->perigeeParameters() &&
track->perigeeParameters()->covariance()) {
408 hasMeasuredCoordinate =
true;
411 updatedCov.setZero();
424 if (
track->measurementsOnTrack() && rioDistVec.size() !=
track->measurementsOnTrack()->size()) {
425 if (
track->measurementsOnTrack()->empty()) {
429 ATH_MSG_DEBUG(
" ROT vector size changed after fit, updating ");
430 garbage_collector = std::move(rioDistVec);
431 rioDistVec.reserve(
track->measurementsOnTrack()->size());
436 if (!firstPars) firstPars =
pars;
443 rioDistVec.emplace_back(dist, meas->
uniqueClone());
448 netaPhiHits.second =
false;
458 hasMeasuredCoordinate =
true;
465 std::vector<const Trk::MeasurementBase*> debug_meas = meas_for_fit();
466 ATH_MSG_DEBUG(
" number of hits " << debug_meas.size() <<
" of which trigger " << netaPhiHits.first.first <<
" eta and "
467 << netaPhiHits.first.second <<
" phi ");
475 <<
" radius " << std::setw(6) << mdt->
driftRadius() <<
" time " << std::setw(6) << mdt->
driftTime());
488 std::vector<Identifier> holeVec =
calculateHoles(ctx, chid, gpos, gdir, hasMeasuredCoordinate, deltaVec, outoftimeVec, rioDistVec);
491 if (!outoftimeVec.empty()) holeVec.insert(holeVec.end(), std::make_move_iterator(outoftimeVec.begin()),
492 std::make_move_iterator(outoftimeVec.end()));
504 bool hasFittedT0 =
false;
505 double fittedT0{0}, errorFittedT0{1.};
510 errorFittedT0 =
segment.t0Error();
511 }
else if (dcslFitter &&
result.hasT0Shift()) {
512 fittedT0 =
result.t0Shift();
513 errorFittedT0 =
result.t0Error();
520 std::unique_ptr<MuonSegment> msegment;
521 if (isCurvedSegment) {
522 if (qoverp == -99999.) {
526 constexpr
double BILALPHA(28.4366), BMLALPHA(62.8267), BMSALPHA(53.1259), BOLALPHA(29.7554);
529 dqoverp = M_SQRT2 *
segment.dtheta() / BILALPHA;
532 dqoverp = M_SQRT2 *
segment.dtheta() / BMLALPHA;
535 dqoverp = M_SQRT2 *
segment.dtheta() / BMSALPHA;
538 dqoverp = M_SQRT2 *
segment.dtheta() / BOLALPHA;
549 std::vector<Trk::DefinedParameter> defPars;
552 defPars.emplace_back(gdir.phi(),
Trk::phi);
553 defPars.emplace_back(gdir.theta(),
Trk::theta);
556 msegment = std::make_unique<MuonSegment>(
557 std::move(segLocPar),
572 std::make_unique<MuonSegment>(segLocPos,
581 if (hasFittedT0) msegment->setT0Error(fittedT0, errorFittedT0);
592 if (segmentQuality < 0) {
return nullptr; }
597 std::vector<const MdtDriftCircleOnTrack*> mdts;
598 std::vector<const MuonClusterOnTrack*>
clusters;
604 if (!mdt) {
ATH_MSG_WARNING(
"failed dynamic_cast, not a MDT but hit has MDT id!!!"); }
608 if (!clus) {
ATH_MSG_WARNING(
"failed dynamic_cast, not a cluster but hit has RPC/TGC id!!!"); }
617 if (mdts.empty())
return;
622 bool hasPhiMeasurements =
false;
625 find(gpos, gdir, mdts,
clusters, hasPhiMeasurements, segColl);
629 const std::vector<const Trk::RIO_OnTrack*>& rios2)
const {
630 std::vector<const Trk::RIO_OnTrack*> rios = rios1;
631 rios.insert(rios.end(), rios2.begin(), rios2.end());
637 bool hasPhiMeasurements,
double momentum)
const {
639 std::vector<const MdtDriftCircleOnTrack*> all_mdts;
640 for (
const std::vector<const MdtDriftCircleOnTrack*>& circle_vec : mdts) {
std::copy(circle_vec.begin(), circle_vec.end(), std::back_inserter(all_mdts)); }
643 std::vector<const MuonClusterOnTrack*> all_clus;
644 for (
const std::vector<const MuonClusterOnTrack*>& clus_vec :
clusters) {
std::copy(clus_vec.begin(), clus_vec.end(), std::back_inserter(all_clus)); }
657 double scaleMax = 5.;
665 if (!hasPhiMeasurements) {
666 double phiScale = 1.;
668 int stRegion =
m_idHelperSvc->mdtIdHelper().stationRegion(
id);
671 else if (stRegion == 1)
673 else if (stRegion == 2)
694 if (stName[1] ==
'I')
return true;
718 if (phiVec.back().corrupt()) phiVec.pop_back();
721 if (clVec.back().corrupt()) clVec.pop_back();
741 gasGapHitMap[chId][gasGapId].first.push_back(clus);
743 gasGapHitMap[chId][gasGapId].second.push_back(clus);
752 spacePoints.reserve(20);
755 for (
const auto& [
id, gasGapHits] : chIdHitMap) {
759 std::make_move_iterator(
cls.first.end()), std::back_inserter(spacePoints));
761 std::make_move_iterator(
cls.second.end()), std::back_inserter(phiVec));
764 return std::make_pair(std::move(spacePoints), std::move(phiVec));
769 bool isEndcap =
m_idHelperSvc->isEndcap((*(gasGapHitMap.begin())).first);
771 ATH_MSG_VERBOSE(
" creating Space points for " << gasGapHitMap.size() <<
" gas gaps ");
773 for (
const auto& [gasGapId, etaPhiHits] : gasGapHitMap) {
775 std::vector<bool> flagPhihit(etaPhiHits.second.size(), 0);
781 << etaPhiHits.second.size());
785 if (etaHit->
identify() == prevEtaId)
continue;
792 bool foundSP =
false;
798 if (phiHit->
identify() == prevPhiId)
continue;
805 spacePoints.push_back(std::move(sp));
808 flagPhihit[phi_idx] =
true;
815 spacePoints.push_back(std::move(sp));
821 flagPhihit = std::vector<bool>(etaPhiHits.second.size(), 1);
822 spacePoints.push_back(std::move(sp));
828 for (
unsigned int i = 0;
i < flagPhihit.size(); ++
i) {
829 if (flagPhihit[
i])
continue;
832 if (etaPhiHits.second[
i]->identify() == prevPhiId)
continue;
833 prevPhiId = etaPhiHits.second[
i]->identify();
837 phiVec.push_back(std::move(sp));
839 }
else if (etaPhiHits.first.empty() && !etaPhiHits.second.empty()) {
843 phiVec.push_back(std::move(sp));
847 ATH_MSG_VERBOSE(
" Creating space points, number of gas-gaps " << gasGapHitMap.size() <<
" space points " << spacePoints.size());
849 return std::make_pair(std::move(spacePoints), std::move(phiVec));
855 double error{1.}, lpx{0.}, lpy{0.};
865 }
else if (!phiHit) {
868 }
else if (etaHit && phiHit) {
872 std::vector<const MuonClusterOnTrack*> phiVec{phiHit};
877 if (std::abs(
error) < 0.001) {
887 double error{1.}, lpx{0.}, lpy{0.};
893 }
else if (!phiHit) {
896 }
else if (etaHit && phiHit) {
905 lpx = lSpacePoint.x();
906 lpy = lSpacePoint.y();
908 if (
error <= std::numeric_limits<double>::epsilon()) {
917 if (std::abs(
error) < 0.001) {
926 const std::vector<const MuonClusterOnTrack*>& phiHits)
const {
928 std::vector<const MuonClusterOnTrack*> cleanPhihits;
929 cleanPhihits.reserve(phiHits.size());
931 double error{1.}, lpx{0.}, lpy{0.};
934 lpx = phiHits.front()->localParameters()[
Trk::locX];
940 if (clus->identify() == prevId)
continue;
941 prevId = clus->identify();
942 cleanPhihits.push_back(clus);
944 }
else if (phiHits.empty()) {
947 }
else if (etaHit && !phiHits.empty()) {
954 double minPos{1e9}, maxPos{-1e9};
960 if (phiHit->identify() == prevId)
continue;
961 prevId = phiHit->identify();
970 cleanPhihits.push_back(phiHit);
973 if (cleanPhihits.size() > 1)
974 ATH_MSG_DEBUG(
" multiple phi hits: nhits " << cleanPhihits.size() <<
" cl width " << maxPos - minPos);
979 if (std::abs(
error) < 0.001) {
990 const int chPhi =
m_idHelperSvc->mdtIdHelper().stationPhi(chid);
994 cls.reserve(spVec.size());
1023 cls.emplace_back(lp, clust.error, clid, meas,
index);
1029 std::set<Identifier>& chamberSet,
double& phimin,
double& phimax,
1033 dcs.reserve(mdts.size());
1035 bool firstMdt =
true;
1043 Amg::Vector3D locPos = gToStation * rot->prepRawData()->globalPosition();
1046 double r = rot->localParameters()[
Trk::locR];
1054 double preciseError =
dr;
1061 phimin = tubeEnds.
phimin;
1062 phimax = tubeEnds.
phimax;
1069 << rot->driftTime() <<
" r " <<
r <<
" dr " <<
dr <<
" phi range " << tubeEnds.
phimin <<
" "
1070 << tubeEnds.
phimax<<
" precise error "<<preciseError);
1071 dcs.push_back(std::move(dc));
1073 chamberSet.insert(elId);
1075 ++dcStatistics[rot->prepRawData()->detectorElement()];
1106 ATH_MSG_ERROR(
"Null pointer to the read MuonDetectorManager conditions object");
1121 detEl2 = MuonDetMgr->getMdtReadoutElement(firstIdml1);
1122 firstTubeMl1 = gToStation * (detEl2->
surface(firstIdml1).
center());
1132 firstTubeMl0 = gToStation * (detEl1->
surface(firstIdml0).
center());
1145 double tubeDist = (secondTubeMl0 - firstTubeMl0).
y();
1146 double tubeStage = (firstTubeMl0lay1 - firstTubeMl0).
y();
1147 double layDist = (firstTubeMl0lay1 - firstTubeMl0).
z();
1149 TrkDriftCircleMath::MdtChamberGeometry mdtgeo(chid,
m_idHelperSvc.get(), nml, nlay, ntube1, ntube2, firstTube0, firstTube1, tubeDist, tubeStage,
1160 std::set<Identifier>& deltaVec, std::set<Identifier>& outoftimeVec,
1161 std::vector<std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>> >& rioDistVec)
const {
1168 if (
segment.hasCurvatureParameters()) {
1170 double ml2phi =
line.phi() -
segment.deltaAlpha();
1175 double chamberMidPtY = (ml1LocPos.
y() + ml2LocPos.
y()) / 2.0;
1181 toLineml2 = tmptoLine;
1195 if (
m_idHelperSvc->mdtIdHelper().multilayer(riodc->identify()) == 2) toLine = toLineml2;
1206 Amg::Vector3D posAlong = gToStation * riodc->globalPosition();
1209 posAlong[1] = pointOnLineAMDB.
x();
1210 posAlong[2] = pointOnLineAMDB.
y();
1217 ATH_MSG_WARNING(
" dynamic cast to StraightLineSurface failed for mdt!!! ");
1228 std::unique_ptr<MdtDriftCircleOnTrack> nonconstDC;
1229 bool hasT0 =
segment.hasT0Shift();
1232 nonconstDC.reset(
m_mdtCreator->createRIO_OnTrack(*riodc->prepRawData(), mdtGP, &gdir));
1233 if (hasT0)
ATH_MSG_WARNING(
"Attempted to change t0 without a properly configured MDT creator tool. ");
1236 nonconstDC.reset(
m_mdtCreatorT0->createRIO_OnTrack(*riodc->prepRawData(), mdtGP, &gdir,
segment.t0Shift()));
1247 dcit.driftState(), dcit.id(),
1250 dcit = std::move(new_dc_on_track);
1254 double shift = riodc->driftTime() - nonconstDC->driftTime();
1255 ATH_MSG_VERBOSE(
" t0 shift " <<
segment.t0Shift() <<
" from hit " << shift <<
" recal " << nonconstDC->driftRadius()
1256 <<
" t " << nonconstDC->driftTime() <<
" from fit " << dcit.r() <<
" old "
1257 << riodc->driftRadius() <<
" t " << riodc->driftTime());
1258 if (std::abs(std::abs(nonconstDC->driftRadius()) - std::abs(dcit.r())) > 0.1 && nonconstDC->driftRadius() < 19. &&
1259 nonconstDC->driftRadius() > 1.) {
1265 double dist = pointOnHit.
x();
1266 rioDistVec.emplace_back(dist, std::move(nonconstDC));
1286 bool operator()(
const std::pair<double, DCMathSegmentMaker::Cluster2D>&
d1,
1287 const std::pair<double, DCMathSegmentMaker::Cluster2D>&
d2) {
1288 return std::abs(
d1.first) < std::abs(
d2.first);
1294 double phimin,
double phimax, std::vector<std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>> >& rioDistVec)
const {
1297 typedef std::vector<ChamberData> ChamberDataVec;
1298 ChamberDataVec chamberDataVec;
1303 std::pair<std::pair<int, int>,
bool> netaPhiHits(std::make_pair(0, 0),
false);
1304 if (
segment.clusters().empty())
return netaPhiHits;
1306 std::vector<const Trk::MeasurementBase*> phiHits;
1312 std::set<Identifier> detElOnSegments;
1313 std::set<MuonStationIndex::PhiIndex> phiIndices;
1315 ATH_MSG_DEBUG(
" Associating clusters: " <<
segment.clusters().size() <<
" number of space points " << spVecs.first.size());
1320 const Cluster2D& spacePoint = spVecs.first[clust.index()];
1324 ATH_MSG_DEBUG(
" Found corrupt space point: index " << clust.index());
1333 ATH_MSG_DEBUG(
" Inconsistent phi angle, dropping space point: phi " << spacePoint.
globalPos.phi() <<
" range " << phimin
1341 if (chamberDataVec.empty() || chamberDataVec.back().id != spacePoint.
detElId) {
1342 detElOnSegments.insert(spacePoint.
detElId);
1343 chamberDataVec.emplace_back(spacePoint.
detElId);
1349 ChamberData&
chamber = chamberDataVec.back();
1361 gasGap.data.emplace_back(resPull.second, spacePoint);
1365 double posFirstPhiStation{FLT_MAX}, posLastPhiStation{0.};
1368 for (ChamberData& chamb : chamberDataVec) {
1370 std::list<const Trk::PrepRawData*> etaClusterVec{}, phiClusterVec{};
1371 std::set<Identifier> etaIds;
1378 double bestPull = std::abs(
gasGap.data.front().first);
1381 unsigned int nassociatedSp = 0;
1382 GasGapData::EntryVec::const_iterator cl_it =
gasGap.data.begin();
1383 while (cl_it !=
gasGap.data.end() && std::abs(cl_it->first) - bestPull < 1.) {
1388 << std::abs(cl_it->first) <<
" distance to segment " << dist <<
" phi "
1400 ++netaPhiHits.first.first;
1409 return clus->prepRawData();
1414 rioDistVec.emplace_back(dist, phi_hit->
uniqueClone());
1415 ++netaPhiHits.first.second;
1416 phiHits.push_back(phi_hit);
1420 posFirstPhiStation =
std::min(phiPos, posFirstPhiStation);
1421 posLastPhiStation =
std::max(phiPos, posLastPhiStation);
1423 if (sp.
phiHits.size() > 1) refit =
false;
1435 if (!etaClusterVec.empty()) {
1436 std::unique_ptr<const CompetingMuonClustersOnTrack> etaCompCluster =
m_compClusterCreator->createBroadCluster(etaClusterVec, 0.);
1437 if (!etaCompCluster) {
1438 ATH_MSG_DEBUG(
" failed to create competing ETA ROT " << etaClusterVec.size());
1441 ++netaPhiHits.first.first;
1444 for (
unsigned int i = 0;
i < etaCompCluster->containedROTs().
size(); ++
i) {
1446 " content: " <<
m_idHelperSvc->toString(etaCompCluster->containedROTs()[
i]->identify()));
1449 rioDistVec.emplace_back(dist, std::move(etaCompCluster));
1456 if (!phiClusterVec.empty()) {
1457 std::unique_ptr<const CompetingMuonClustersOnTrack> phiCompCluster =
m_compClusterCreator->createBroadCluster(phiClusterVec, 0.);
1458 if (!phiCompCluster) {
1459 ATH_MSG_DEBUG(
" failed to create competing PHI ROT " << phiClusterVec.size());
1462 phiHits.push_back(phiCompCluster.get());
1464 ++netaPhiHits.first.second;
1468 for (
unsigned int i = 0;
i < phiCompCluster->containedROTs().
size(); ++
i) {
1470 " content: " <<
m_idHelperSvc->toString(phiCompCluster->containedROTs()[
i]->identify()));
1476 double phiPos = isEndcap ? std::abs(phiCompCluster->globalPosition().z()) :
1477 phiCompCluster->globalPosition().perp();
1478 posFirstPhiStation =
std::min(phiPos,posFirstPhiStation);
1479 posLastPhiStation =
std::max(phiPos,posLastPhiStation);
1480 rioDistVec.emplace_back(dist, std::move(phiCompCluster));
1491 std::map<Identifier, std::list<const Trk::PrepRawData*> > phiClusterMap;
1493 std::set<const MuonClusterOnTrack*> selectedClusters;
1494 std::vector<const Cluster2D*> phiClusters;
1495 phiClusters.reserve(spVecs.second.size());
1498 for (
const Cluster2D& phi_clus :spVecs.second) {
1503 phiClusters.push_back(&phi_clus);
1504 selectedClusters.insert(phi_clus.
phiHit);
1507 unsigned int recoveredUnassociatedPhiHits(0);
1511 for (
const Cluster2D& rpc_clust : spVecs.first) {
1516 if (detElOnSegments.count(rpc_clust.
detElId))
continue;
1520 if (phiIndices.count(
phiIndex))
continue;
1522 bool wasFound =
false;
1525 if (!selectedClusters.insert(phi_hit).second) {
1532 if (erase_me == phi_hit)
break;
1533 selectedClusters.erase(erase_me);
1538 if (wasFound)
continue;
1541 phiClusters.push_back(&rpc_clust);
1542 ++recoveredUnassociatedPhiHits;
1546 unsigned int addedPhiHits(0);
1547 for (
const Cluster2D* phi_clus : phiClusters) {
1551 if (detElOnSegments.count(detElId))
continue;
1555 if (phiIndices.count(
phiIndex))
continue;
1563 double segError = std::sqrt(resWithSegment.
trackError2(
cl));
1572 bool inBounds = std::abs(
residual) < 0.5 * stripLength + 2. + segError;
1575 <<
" pos y " <<
cl.position().y() <<
" : residual " <<
residual <<
" strip half length "
1576 << 0.5 * stripLength <<
" segment error " << segError);
1584 std::list<const Trk::PrepRawData*>& cham_hits{phiClusterMap[detElId]};
1587 return clus->prepRawData();
1593 for (
const auto& [phi_id, prds] : phiClusterMap) {
1599 std::unique_ptr<const CompetingMuonClustersOnTrack> phiCompCluster =
m_compClusterCreator->createBroadCluster(prds, 0.);
1600 if (!phiCompCluster) {
1601 ATH_MSG_DEBUG(
" failed to create competing PHI ROT " << prds.size());
1608 <<
" distance to segment " << dist);
1611 phiHits.push_back(phiCompCluster.get());
1612 ++netaPhiHits.first.second;
1616 <<
" distance to segment " << dist);
1617 for (
unsigned int i = 0;
i < phiCompCluster->containedROTs().
size(); ++
i) {
1619 " content: " <<
m_idHelperSvc->toString(phiCompCluster->containedROTs()[
i]->identify()));
1622 rioDistVec.emplace_back(dist, std::move(phiCompCluster));
1625 ATH_MSG_VERBOSE(
"Added " << addedPhiHits <<
" unass phi hits out of " << spVecs.second.size()
1626 <<
" phi hits without eta hit and " << recoveredUnassociatedPhiHits <<
" with unassociated eta hit ");
1630 double phiDistanceMax = posLastPhiStation - posFirstPhiStation;
1631 if (isEndcap && phiDistanceMax < 1000.)
1633 else if (phiDistanceMax < 400.)
1636 netaPhiHits.second = refit;
1644 double cos_sinLine = cot(
line.phi());
1652 double delta_y = lpos.
y() -
line.position().y();
1660 return pointOnHit.
x();
1664 std::vector<std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>> >& rioDistVec) {
1669 rioVec.reserve(rioDistVec.size());
1670 for (std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>>& rdit : rioDistVec) { rioVec.push_back(std::move(rdit.second)); }
1679 double cos_sinLine = cot(
line.phi());
1686 double delta_y = lpos.
y() -
line.position().y();
1692 double residual = lpos.
x() - lineSurfaceIntersect.
x();
1699 std::set<Identifier>& outoftimeVec,
const std::vector<std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>> >& rioDistVec)
const {
1702 if (!InterSectSvc.isValid()) {
1703 ATH_MSG_ERROR(
"Null pointer to the read MuonDetectorManager conditions object");
1710 std::set<Identifier> hitsOnSegment, chambersOnSegment;
1711 int firstLayer{-1}, lastLayer{-1};
1712 for (
const std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>>& rdit : rioDistVec) {
1717 if (firstLayer == -1)
1722 hitsOnSegment.insert(
id);
1727 if (firstLayer > lastLayer) {
std::swap(firstLayer, lastLayer); }
1728 ATH_MSG_VERBOSE(
" Tube layer ranges: " << firstLayer <<
" -- " << lastLayer <<
" crossed tubes "
1731 std::vector<Identifier> holeVec;
1733 if (!chambersOnSegment.count(
m_idHelperSvc->chamberId(tint.tubeId))) {
1734 ATH_MSG_VERBOSE(
" chamber not on segment, not counting tube " << tint.rIntersect <<
" l " << tint.xIntersect <<
" "
1742 bool notBetweenHits = layer < firstLayer || layer > lastLayer;
1743 double distanceCut = hasMeasuredCoordinate ? -20 : -200.;
1745 if (notBetweenHits && (std::abs(tint.rIntersect) > innerRadius || (!
m_allMdtHoles && tint.xIntersect > distanceCut))) {
1746 ATH_MSG_VERBOSE(
" not counting tube: distance to wire " << tint.rIntersect <<
" dist to tube end " << tint.xIntersect
1751 if (hitsOnSegment.count(tint.tubeId)) {
1752 ATH_MSG_VERBOSE(
" tube on segment: distance to wire " << tint.rIntersect <<
" dist to tube end " << tint.xIntersect
1758 if (deltaVec.count(tint.tubeId)) {
1759 ATH_MSG_VERBOSE(
" removing delta, distance to wire " << tint.rIntersect <<
" dist to tube end " << tint.xIntersect
1766 ATH_MSG_VERBOSE(
" found and removed delta, distance to wire " << tint.rIntersect <<
" dist to tube end "
1767 << tint.xIntersect <<
" "
1772 ATH_MSG_VERBOSE((outoftimeVec.count(tint.tubeId) ?
"Out-of-time" :
"hole") <<
" distance to wire "
1773 << tint.rIntersect <<
" dist to tube end " << tint.xIntersect <<
" "
1774 <<
m_idHelperSvc->toString(tint.tubeId)<<(notBetweenHits ?
"outside hits" :
"between hits"));
1776 holeVec.push_back(tint.tubeId);
1788 if (!MdtCont.isValid()) {
1793 if (!collptr)
return nullptr;
1795 if (prd->identify() ==
id)
return prd;
1801 const std::vector<const MdtDriftCircleOnTrack*>& mdts)
const {
1802 int hitsInChamberWithMostHits = 0;
1803 std::map<Identifier, int> hitsPerChamber;
1804 int currentSector = -1;
1815 if (currentSector == -1) {
1816 currentSector = sector;
1817 }
else if (sector != currentSector) {
1820 int& hitsInCh = hitsPerChamber[chId];
1822 if (hitsInCh > hitsInChamberWithMostHits) {
1823 hitsInChamberWithMostHits = hitsInCh;
1824 rotInChamberWithMostHits = rot;
1827 return rotInChamberWithMostHits;
1831 const std::vector<DCMathSegmentMaker::HitInXZ>&
hits)
const {
1836 bool outBounds =
false;
1837 double locExX = xline + dXdZ * (hit.z - zline);
1838 if (hit.isMdt && (locExX < hit.xmin - 1. || locExX > hit.xmax + 1.)) {
1846 << std::setw(6) << (
int)hit.z <<
") ex pos " << std::setw(6) << (
int)locExX <<
" min " << std::setw(6)
1847 << (
int)hit.xmin <<
" max " << std::setw(6) << (
int)hit.xmax <<
" phimin " << std::setw(6)
1848 << hit.phimin <<
" phimax " << std::setw(6) << hit.phimax <<
" outBounds, cross-check");
1856 const std::vector<const Trk::MeasurementBase*>& rots,
double seg_phimin,
1857 double seg_phimax)
const {
1858 bool hasUpdated =
false;
1865 if (ldir.z() < 0.0001)
return false;
1867 double dXdZ = ldir.x() / ldir.z();
1869 double xline = lsegPos.x();
1870 double zline = lsegPos.z();
1871 ATH_MSG_VERBOSE(
" Associated hits " << rots.size() <<
" angleXZ " << 90. * segLocDir.
angleXZ() / (M_PI_2) <<
" dXdZ " << dXdZ
1872 <<
" seg Pos (" << xline <<
" " << zline <<
") " << segLocPos);
1874 std::vector<HitInXZ>
hits;
1875 hits.reserve(rots.size());
1877 unsigned int nphiHits(0);
1878 const HitInXZ* firstPhiHit{
nullptr}, *lastPhiHit{
nullptr};
1882 if (!
id.is_valid())
continue;
1884 double lxmin{0}, lxmax{0}, phimin{0}, phimax{0};
1892 lxmin = tubeEnds.
lxmin;
1893 lxmax = tubeEnds.
lxmax;
1894 phimin = tubeEnds.
phimin;
1895 phimax = tubeEnds.
phimax;
1897 lpos = gToSegment * meas->globalPosition();
1909 lxmin = lpos.x() - 0.5 * stripLength;
1910 lxmax = lpos.x() + 0.5 * stripLength;
1914 locPosition[0] = lxmin;
1916 double phi1 = globalPos.phi();
1918 locPosition[0] = lxmax;
1919 globalPos = segmentToGlobal * locPosition;
1920 double phi2 = globalPos.phi();
1934 ATH_MSG_WARNING(
"dynamic cast failed for CompetingMuonClustersOnTrack");
1941 const Amg::Vector3D segFrame_stripPos = gToSegment * detEl->channelPos(
id);
1943 lpos = segFrame_stripPos +
1944 Amg::intersect<3>(lsegPos, ldir, segFrame_stripPos, segFrame_StripDir).value_or(0) * segFrame_StripDir;
1951 phimin = globalPos.phi();
1957 ATH_MSG_DEBUG(
" Inconsistent phi " << phimin <<
" range " << seg_phimin <<
" " << seg_phimax);
1962 hits.emplace_back(
id, isMdt, measuresPhi, lpos.x(), lpos.z(), lxmin, lxmax, phimin, phimax);
1966 firstPhiHit = &
hits.back();
1968 double distPhiHits = std::abs(firstPhiHit->z -
hits.back().z);
1969 if (distPhiHits > 500.) {
1970 lastPhiHit = &
hits.back();
1979 double locExX = xline + dXdZ * (lpos.z() - zline);
1981 << std::setw(6) << (
int)lpos.z() <<
") ex pos " << std::setw(6) << (
int)locExX <<
" min "
1982 << std::setw(6) << (
int)lxmin <<
" max " << std::setw(6) << (
int)lxmax <<
" phimin " << std::setw(6)
1983 << phimin <<
" phimax " << std::setw(6) << phimax);
1984 if (lpos.x() < lxmin || lpos.x() > lxmax)
ATH_MSG_VERBOSE(
" outBounds");
1988 if (nphiHits == 1) {
1990 ATH_MSG_WARNING(
" Pointer to first phi hit not set, this should not happen! ");
1992 if (xline != firstPhiHit->x) {
1996 xline = firstPhiHit->x;
1997 zline = firstPhiHit->z;
2003 double dz = ipLocPos.z() - zline;
2004 if (std::abs(dz) > 0.001) {
2005 ATH_MSG_VERBOSE(
" hit (" << xline <<
"," << zline <<
") IP (" << ipLocPos.x() <<
"," << ipLocPos.z()
2006 <<
") dXdZ " << (ipLocPos.x() - xline) / dz <<
" old " << dXdZ);
2007 dXdZ = (ipLocPos.x() - xline) / dz;
2012 }
else if (nphiHits == 2) {
2013 if (!firstPhiHit || !lastPhiHit) {
2014 ATH_MSG_WARNING(
" Pointer to one of the two phi hit not set, this should not happen! ");
2016 double dz = lastPhiHit->z - firstPhiHit->z;
2018 xline = firstPhiHit->x;
2019 zline = firstPhiHit->z;
2020 if (std::abs(dz) > 300.) {
2021 double dx = lastPhiHit->x - firstPhiHit->x;
2034 double segX = xline - dXdZ * zline;
2040 ATH_MSG_DEBUG(
"still several out of bounds hits after rotation: posx(" << segX <<
") dXdZ " << dXdZ
2041 <<
" keeping old result ");
2045 double alphaYZ = segLocDir.
angleYZ();
2046 double alphaXZ = std::atan2(1, dXdZ);
2065 double tubeLen = (lropos - lhvpos).
mag();
2066 double activeTubeLen =
2068 double scaleFactor = activeTubeLen / tubeLen;
2069 lropos[0] = scaleFactor * lropos.x();
2070 lhvpos[0] = scaleFactor * lhvpos.x();
2077 const double phiRO = ropos.phi();
2078 const double phiHV = hvpos.phi();
2086 if (phiminRef * phimaxRef < 0.) {
2087 if (phiminRef < -1.1) {
2088 if (phiminRef > phiminNew) phiminRef = phiminNew;
2089 if (phimaxRef < phimaxNew) phimaxRef = phimaxNew;
2091 if (phiminRef < phiminNew) phiminRef = phiminNew;
2092 if (phimaxRef > phimaxNew) phimaxRef = phimaxNew;
2096 if (phiminRef < 0.) {
2097 if (phiminRef < phiminNew) phiminRef = phiminNew;
2098 if (phimaxRef > phimaxNew) phimaxRef = phimaxNew;
2100 if (phiminRef > phiminNew) phiminRef = phiminNew;
2101 if (phimaxRef < phimaxNew) phimaxRef = phimaxNew;
2112 if (phimin * phimax < 0.) {
2115 if (
phi < phimin -
offset) phiOk =
false;
2117 if (
phi > phimin +
offset) phiOk =
false;
2121 if (
phi < phimax -
offset) phiOk =
false;
2123 if (
phi > phimax +
offset) phiOk =
false;
2127 if (phi < phimin - offset || phi > phimax +
offset) phiOk =
false;
2133 bool isCurvedSegment)
const {
2147 double dz =
std::cos(gdirs.theta());
2153 double dzo =
std::cos(gdiro.theta());
2163 if (b0 < 1e-8 && b0 > 0) b0 = 1
e-8;
2164 if (b0 > -1
e-8 && b0 < 0) b0 = -1
e-8;
2165 double dxn =
dx -
a0 * dxo / b0;
2166 double dyn =
dy -
a0 * dyo / b0;
2167 double dzn = dz -
a0 * dzo / b0;
2168 double norm = std::sqrt(dxn * dxn + dyn * dyn + dzn * dzn);
2172 if (dxn * roaddir.x() + dyn * roaddir.y() + dzn * roaddir.z() < 0.) {
norm = -
norm; }
2174 if (dxn * roaddir.x() + dyn * roaddir.y() < 0.) {
norm = -
norm; }
2177 if (isCurvedSegment)
norm =
norm / 2.;