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;}
63 base_class(
t,
n,
p) {}
83 return StatusCode::SUCCESS;
87 const std::vector<const MdtDriftCircleOnTrack*>& mdts,
88 const std::vector<const MuonClusterOnTrack*>&
clusters,
bool hasPhiMeasurements,
90 const EventContext& ctx = Gaudi::Hive::currentContext();
98 if (mdts.size() < 3)
return;
102 if (!firstRot) {
return; }
126 double chamber_angleYZ = std::atan2(dirCh.z(), dirCh.y());
129 double dotprod = globalDirCh.perp() *
std::sin(roaddir2.theta()) + globalDirCh.z() *
std::cos(roaddir2.theta());
130 if (dotprod < 0) roaddir2 = -roaddir2;
135 double road_angleXZ = std::atan2(
d.z(),
d.x());
136 double road_angleYZ = std::atan2(
d.z(),
d.y());
138 if (!hasPhiMeasurements) road_angleXZ =
M_PI;
140 << isEndcap <<
" central phi " << detEl->
center().phi() <<
" r " << detEl->
center().perp()
141 <<
" z " << detEl->
center().z());
157 std::stringstream sstr{};
160 ATH_MSG_VERBOSE(
" adding mdts " << mdts.size()<<std::endl<<sstr.str());
164 std::set<Identifier> chamberSet;
165 double phimin{-9999}, phimax{9999};
170 std::shared_ptr<const TrkDriftCircleMath::ChamberGeometry> multiGeo;
172 ATH_MSG_VERBOSE(
" using chamber geometry with #chambers " << chamberSet.size());
174 std::vector<TrkDriftCircleMath::MdtChamberGeometry> geos{};
177 geos.reserve(chamberSet.size());
183 multiGeo = std::make_unique<TrkDriftCircleMath::MdtMultiChamberGeometry>(geos);
189 if (sinAngleCut > 0)
angle = sinAngleCut;
196 std::stringstream sstr{};
197 unsigned int seg_n{0};
200 sstr<<
"Segment number "<<seg_n<<
" is at ("<<seg.line().x0()<<
","<<seg.line().y0()<<
") pointing to "<<seg.line().phi()*toDeg<<
" chi2: "<<
201 (seg.chi2()/seg.ndof())<<
"("<<seg.ndof()<<
")"<<std::endl;
202 sstr<<
"Mdt measurements: "<<seg.dcs().size()<<std::endl;
204 sstr<<
" **** "<<
m_printer->print(*mdt_meas.rot());
205 sstr<<
" ("<<mdt_meas.state()<<
")"<<std::endl;
207 sstr<<
"Cluster measurements "<<seg.clusters().size()<<std::endl;
209 sstr<<
" ---- "<<
m_printer->print(*clus.rot())<<std::endl;
214 ATH_MSG_VERBOSE(
"Found " << segs.size() <<
" segments "<<std::endl<<sstr.str());
218 if (segs.empty()) {
return; }
221 segmentCreationInfo sInfo(spVecs, multiGeo.get(), gToStation, amdbToGlobal, phimin, phimax);
223 std::unique_ptr<MuonSegment>
segment =
createSegment(ctx, seg, chid, roadpos, roaddir2, mdts, hasPhiMeasurements, sInfo);
231 const std::vector<const MdtDriftCircleOnTrack*>& mdts,
bool hasPhiMeasurements,
239 const bool isCurvedSegment =
segment.hasCurvatureParameters() &&
240 std::find(statWithField.begin(), statWithField.end(), chIndex) != statWithField.end();
243 if (
segment.hitsOnTrack() < 3)
return nullptr;
249 <<
line.position().y() <<
" phi " <<
line.phi() <<
" associated clusters "
259 if (hasPhiMeasurements) {
263 double cphi = lroaddir.x();
273 double shortestTubeLen = 1e9;
279 int lay =
m_idHelperSvc->mdtIdHelper().tubeLayer(riodc->identify());
281 double tubelen = 0.5 * riodc->prepRawData()->detectorElement()->getActiveTubeLength(lay,
tube);
282 if (tubelen < shortestTubeLen) shortestTubeLen = tubelen;
285 if (std::abs(lxroad) > shortestTubeLen) {
286 ATH_MSG_DEBUG(
"coordinates far outside chamber! using global position of first hit ");
287 if (lxroad < 0.) shortestTubeLen *= -1.;
288 lxroad = shortestTubeLen;
291 lxroad = (sInfo.
globalTrans * mdts[0]->prepRawData()->detectorElement()->surface(mdts[0]->
identify()).center()).
x();
302 surfaceTransform.pretranslate(gpos);
303 double surfDim = 500.;
304 std::unique_ptr<Trk::PlaneSurface> surf = std::make_unique<Trk::PlaneSurface>(surfaceTransform, surfDim, surfDim);
308 double linephi =
line.phi();
315 std::vector<std::pair<double, std::unique_ptr<const Trk::MeasurementBase>> > rioDistVec;
318 std::set<Identifier> deltaVec;
319 std::set<Identifier> outoftimeVec;
322 std::vector<std::pair<double, std::unique_ptr<const Trk::MeasurementBase>>> garbage_collector;
336 linephi =
result.line().phi();
337 lpos[1] =
result.line().position().x();
338 lpos[2] =
result.line().position().y();
343 surfaceTransform.pretranslate(gpos);
344 surf = std::make_unique<Trk::PlaneSurface>(surfaceTransform, surfDim, surfDim);
364 if (
std::min(std::abs(diff_phi), std::abs( std::abs(diff_phi) -
M_PI)) > 1.
e-3 ||
365 std::min(std::abs(diff_prec), std::abs(std::abs(diff_prec) -
M_PI)) > 1.
e-3) {
366 ATH_MSG_WARNING(
" ALARM updated angles wrong: diff phi " << diff_phi <<
" prec " << diff_prec <<
" phi rdir " << roaddir2.phi()
367 <<
" gdir " << gdir.phi() <<
" lphi " << linephi <<
" seg "
372 std::pair<std::pair<int, int>,
bool> netaPhiHits =
375 if (rioDistVec.empty()){
381 auto meas_for_fit = [&rioDistVec] () {
382 std::vector<const Trk::MeasurementBase*>
out{};
383 out.reserve(rioDistVec.size());
385 for (
const std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>>& ele : rioDistVec)
out.push_back(ele.second.get());
390 double dlocx{1000.}, dangleXZ{1000.}, qoverp{-99999.}, dqoverp{-99999.};
391 bool hasMeasuredCoordinate =
false;
393 ATH_MSG_DEBUG(
" distance between first and last phi hit sufficient to perform 4D fit: phi " << gdir.phi() <<
" theta "
399 if (isCurvedSegment &&
track->perigeeParameters() &&
track->perigeeParameters()->covariance()) {
403 hasMeasuredCoordinate =
true;
406 updatedCov.setZero();
419 if (
track->measurementsOnTrack() && rioDistVec.size() !=
track->measurementsOnTrack()->size()) {
420 if (
track->measurementsOnTrack()->empty()) {
424 ATH_MSG_DEBUG(
" ROT vector size changed after fit, updating ");
425 garbage_collector = std::move(rioDistVec);
426 rioDistVec.reserve(
track->measurementsOnTrack()->size());
431 if (!firstPars) firstPars =
pars;
438 rioDistVec.emplace_back(dist, meas->
uniqueClone());
443 netaPhiHits.second =
false;
453 hasMeasuredCoordinate =
true;
460 std::vector<const Trk::MeasurementBase*> debug_meas = meas_for_fit();
461 ATH_MSG_DEBUG(
" number of hits " << debug_meas.size() <<
" of which trigger " << netaPhiHits.first.first <<
" eta and "
462 << netaPhiHits.first.second <<
" phi ");
470 <<
" radius " << std::setw(6) << mdt->
driftRadius() <<
" time " << std::setw(6) << mdt->
driftTime());
483 std::vector<Identifier> holeVec =
calculateHoles(ctx, chid, gpos, gdir, hasMeasuredCoordinate, deltaVec, outoftimeVec, rioDistVec);
486 if (!outoftimeVec.empty()) holeVec.insert(holeVec.end(), std::make_move_iterator(outoftimeVec.begin()),
487 std::make_move_iterator(outoftimeVec.end()));
499 bool hasFittedT0 =
false;
500 double fittedT0{0}, errorFittedT0{1.};
505 errorFittedT0 =
segment.t0Error();
506 }
else if (dcslFitter &&
result.hasT0Shift()) {
507 fittedT0 =
result.t0Shift();
508 errorFittedT0 =
result.t0Error();
515 std::unique_ptr<MuonSegment> msegment;
516 if (isCurvedSegment) {
517 if (qoverp == -99999.) {
521 constexpr
double BILALPHA(28.4366), BMLALPHA(62.8267), BMSALPHA(53.1259), BOLALPHA(29.7554);
524 dqoverp = M_SQRT2 *
segment.dtheta() / BILALPHA;
527 dqoverp = M_SQRT2 *
segment.dtheta() / BMLALPHA;
530 dqoverp = M_SQRT2 *
segment.dtheta() / BMSALPHA;
533 dqoverp = M_SQRT2 *
segment.dtheta() / BOLALPHA;
544 std::vector<Trk::DefinedParameter> defPars;
547 defPars.emplace_back(gdir.phi(),
Trk::phi);
548 defPars.emplace_back(gdir.theta(),
Trk::theta);
551 msegment = std::make_unique<MuonSegment>(
552 std::move(segLocPar),
567 std::make_unique<MuonSegment>(segLocPos,
576 if (hasFittedT0) msegment->setT0Error(fittedT0, errorFittedT0);
587 if (segmentQuality < 0) {
return nullptr; }
592 std::vector<const MdtDriftCircleOnTrack*> mdts;
593 std::vector<const MuonClusterOnTrack*>
clusters;
599 if (!mdt) {
ATH_MSG_WARNING(
"failed dynamic_cast, not a MDT but hit has MDT id!!!"); }
603 if (!clus) {
ATH_MSG_WARNING(
"failed dynamic_cast, not a cluster but hit has RPC/TGC id!!!"); }
612 if (mdts.empty())
return;
617 bool hasPhiMeasurements =
false;
620 find(gpos, gdir, mdts,
clusters, hasPhiMeasurements, segColl);
624 const std::vector<const Trk::RIO_OnTrack*>& rios2)
const {
625 std::vector<const Trk::RIO_OnTrack*> rios = rios1;
626 rios.insert(rios.end(), rios2.begin(), rios2.end());
632 bool hasPhiMeasurements,
double momentum)
const {
634 std::vector<const MdtDriftCircleOnTrack*> all_mdts;
635 for (
const std::vector<const MdtDriftCircleOnTrack*>& circle_vec : mdts) {
std::copy(circle_vec.begin(), circle_vec.end(), std::back_inserter(all_mdts)); }
638 std::vector<const MuonClusterOnTrack*> all_clus;
639 for (
const std::vector<const MuonClusterOnTrack*>& clus_vec :
clusters) {
std::copy(clus_vec.begin(), clus_vec.end(), std::back_inserter(all_clus)); }
652 double scaleMax = 5.;
660 if (!hasPhiMeasurements) {
661 double phiScale = 1.;
663 int stRegion =
m_idHelperSvc->mdtIdHelper().stationRegion(
id);
666 else if (stRegion == 1)
668 else if (stRegion == 2)
689 if (stName[1] ==
'I')
return true;
713 if (phiVec.back().corrupt()) phiVec.pop_back();
716 if (clVec.back().corrupt()) clVec.pop_back();
736 gasGapHitMap[chId][gasGapId].first.push_back(clus);
738 gasGapHitMap[chId][gasGapId].second.push_back(clus);
747 spacePoints.reserve(20);
750 for (
const auto& [
id, gasGapHits] : chIdHitMap) {
754 std::make_move_iterator(
cls.first.end()), std::back_inserter(spacePoints));
756 std::make_move_iterator(
cls.second.end()), std::back_inserter(phiVec));
759 return std::make_pair(std::move(spacePoints), std::move(phiVec));
764 bool isEndcap =
m_idHelperSvc->isEndcap((*(gasGapHitMap.begin())).first);
766 ATH_MSG_VERBOSE(
" creating Space points for " << gasGapHitMap.size() <<
" gas gaps ");
768 for (
const auto& [gasGapId, etaPhiHits] : gasGapHitMap) {
770 std::vector<bool> flagPhihit(etaPhiHits.second.size(), 0);
776 << etaPhiHits.second.size());
780 if (etaHit->
identify() == prevEtaId)
continue;
787 bool foundSP =
false;
793 if (phiHit->
identify() == prevPhiId)
continue;
800 spacePoints.push_back(std::move(sp));
803 flagPhihit[phi_idx] =
true;
810 spacePoints.push_back(std::move(sp));
816 flagPhihit = std::vector<bool>(etaPhiHits.second.size(), 1);
817 spacePoints.push_back(std::move(sp));
823 for (
unsigned int i = 0;
i < flagPhihit.size(); ++
i) {
824 if (flagPhihit[
i])
continue;
827 if (etaPhiHits.second[
i]->identify() == prevPhiId)
continue;
828 prevPhiId = etaPhiHits.second[
i]->identify();
832 phiVec.push_back(std::move(sp));
834 }
else if (etaPhiHits.first.empty() && !etaPhiHits.second.empty()) {
838 phiVec.push_back(std::move(sp));
842 ATH_MSG_VERBOSE(
" Creating space points, number of gas-gaps " << gasGapHitMap.size() <<
" space points " << spacePoints.size());
844 return std::make_pair(std::move(spacePoints), std::move(phiVec));
850 double error{1.}, lpx{0.}, lpy{0.};
860 }
else if (!phiHit) {
863 }
else if (etaHit && phiHit) {
867 std::vector<const MuonClusterOnTrack*> phiVec{phiHit};
872 if (std::abs(
error) < 0.001) {
882 double error{1.}, lpx{0.}, lpy{0.};
888 }
else if (!phiHit) {
891 }
else if (etaHit && phiHit) {
900 lpx = lSpacePoint.x();
901 lpy = lSpacePoint.y();
903 if (
error <= std::numeric_limits<double>::epsilon()) {
912 if (std::abs(
error) < 0.001) {
921 const std::vector<const MuonClusterOnTrack*>& phiHits)
const {
923 std::vector<const MuonClusterOnTrack*> cleanPhihits;
924 cleanPhihits.reserve(phiHits.size());
926 double error{1.}, lpx{0.}, lpy{0.};
929 lpx = phiHits.front()->localParameters()[
Trk::locX];
935 if (clus->identify() == prevId)
continue;
936 prevId = clus->identify();
937 cleanPhihits.push_back(clus);
939 }
else if (phiHits.empty()) {
942 }
else if (etaHit && !phiHits.empty()) {
949 double minPos{1e9}, maxPos{-1e9};
955 if (phiHit->identify() == prevId)
continue;
956 prevId = phiHit->identify();
965 cleanPhihits.push_back(phiHit);
968 if (cleanPhihits.size() > 1)
969 ATH_MSG_DEBUG(
" multiple phi hits: nhits " << cleanPhihits.size() <<
" cl width " << maxPos - minPos);
974 if (std::abs(
error) < 0.001) {
985 const int chPhi =
m_idHelperSvc->mdtIdHelper().stationPhi(chid);
989 cls.reserve(spVec.size());
1018 cls.emplace_back(lp, clust.error, clid, meas,
index);
1024 std::set<Identifier>& chamberSet,
double& phimin,
double& phimax,
1028 dcs.reserve(mdts.size());
1030 bool firstMdt =
true;
1038 Amg::Vector3D locPos = gToStation * rot->prepRawData()->globalPosition();
1041 double r = rot->localParameters()[
Trk::locR];
1049 double preciseError =
dr;
1056 phimin = tubeEnds.
phimin;
1057 phimax = tubeEnds.
phimax;
1064 << rot->driftTime() <<
" r " <<
r <<
" dr " <<
dr <<
" phi range " << tubeEnds.
phimin <<
" "
1065 << tubeEnds.
phimax<<
" precise error "<<preciseError);
1066 dcs.push_back(std::move(dc));
1068 chamberSet.insert(elId);
1070 ++dcStatistics[rot->prepRawData()->detectorElement()];
1101 ATH_MSG_ERROR(
"Null pointer to the read MuonDetectorManager conditions object");
1107 MuonDetMgr->getMdtReadoutElement(
m_idHelperSvc->mdtIdHelper().channelID(
name, eta, phi, 1, 1, 1));
1116 detEl2 = MuonDetMgr->getMdtReadoutElement(firstIdml1);
1117 firstTubeMl1 = gToStation * (detEl2->
surface(firstIdml1).
center());
1127 firstTubeMl0 = gToStation * (detEl1->
surface(firstIdml0).
center());
1140 double tubeDist = (secondTubeMl0 - firstTubeMl0).
y();
1141 double tubeStage = (firstTubeMl0lay1 - firstTubeMl0).
y();
1142 double layDist = (firstTubeMl0lay1 - firstTubeMl0).
z();
1144 TrkDriftCircleMath::MdtChamberGeometry mdtgeo(chid,
m_idHelperSvc.get(), nml, nlay, ntube1, ntube2, firstTube0, firstTube1, tubeDist, tubeStage,
1155 std::set<Identifier>& deltaVec, std::set<Identifier>& outoftimeVec,
1156 std::vector<std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>> >& rioDistVec)
const {
1163 if (
segment.hasCurvatureParameters()) {
1165 double ml2phi =
line.phi() -
segment.deltaAlpha();
1170 double chamberMidPtY = (ml1LocPos.
y() + ml2LocPos.
y()) / 2.0;
1176 toLineml2 = tmptoLine;
1190 if (
m_idHelperSvc->mdtIdHelper().multilayer(riodc->identify()) == 2) toLine = toLineml2;
1201 Amg::Vector3D posAlong = gToStation * riodc->globalPosition();
1204 posAlong[1] = pointOnLineAMDB.
x();
1205 posAlong[2] = pointOnLineAMDB.
y();
1212 ATH_MSG_WARNING(
" dynamic cast to StraightLineSurface failed for mdt!!! ");
1223 std::unique_ptr<MdtDriftCircleOnTrack> nonconstDC;
1224 bool hasT0 =
segment.hasT0Shift();
1227 nonconstDC.reset(
m_mdtCreator->createRIO_OnTrack(*riodc->prepRawData(), mdtGP, &gdir));
1228 if (hasT0)
ATH_MSG_WARNING(
"Attempted to change t0 without a properly configured MDT creator tool. ");
1231 nonconstDC.reset(
m_mdtCreatorT0->createRIO_OnTrack(*riodc->prepRawData(), mdtGP, &gdir,
segment.t0Shift()));
1242 dcit.driftState(), dcit.id(),
1245 dcit = std::move(new_dc_on_track);
1249 double shift = riodc->driftTime() - nonconstDC->driftTime();
1250 ATH_MSG_VERBOSE(
" t0 shift " <<
segment.t0Shift() <<
" from hit " << shift <<
" recal " << nonconstDC->driftRadius()
1251 <<
" t " << nonconstDC->driftTime() <<
" from fit " << dcit.r() <<
" old "
1252 << riodc->driftRadius() <<
" t " << riodc->driftTime());
1253 if (std::abs(std::abs(nonconstDC->driftRadius()) - std::abs(dcit.r())) > 0.1 && nonconstDC->driftRadius() < 19. &&
1254 nonconstDC->driftRadius() > 1.) {
1260 double dist = pointOnHit.
x();
1261 rioDistVec.emplace_back(dist, std::move(nonconstDC));
1281 bool operator()(
const std::pair<double, DCMathSegmentMaker::Cluster2D>&
d1,
1282 const std::pair<double, DCMathSegmentMaker::Cluster2D>&
d2) {
1283 return std::abs(
d1.first) < std::abs(
d2.first);
1289 double phimin,
double phimax, std::vector<std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>> >& rioDistVec)
const {
1292 typedef std::vector<ChamberData> ChamberDataVec;
1293 ChamberDataVec chamberDataVec;
1298 std::pair<std::pair<int, int>,
bool> netaPhiHits(std::make_pair(0, 0),
false);
1299 if (
segment.clusters().empty())
return netaPhiHits;
1301 std::vector<const Trk::MeasurementBase*> phiHits;
1307 std::set<Identifier> detElOnSegments;
1308 std::set<MuonStationIndex::PhiIndex> phiIndices;
1310 ATH_MSG_DEBUG(
" Associating clusters: " <<
segment.clusters().size() <<
" number of space points " << spVecs.first.size());
1315 const Cluster2D& spacePoint = spVecs.first[clust.index()];
1319 ATH_MSG_DEBUG(
" Found corrupt space point: index " << clust.index());
1328 ATH_MSG_DEBUG(
" Inconsistent phi angle, dropping space point: phi " << spacePoint.
globalPos.phi() <<
" range " << phimin
1336 if (chamberDataVec.empty() || chamberDataVec.back().id != spacePoint.
detElId) {
1337 detElOnSegments.insert(spacePoint.
detElId);
1338 chamberDataVec.emplace_back(spacePoint.
detElId);
1344 ChamberData&
chamber = chamberDataVec.back();
1356 gasGap.data.emplace_back(resPull.second, spacePoint);
1360 double posFirstPhiStation{FLT_MAX}, posLastPhiStation{0.};
1363 for (ChamberData& chamb : chamberDataVec) {
1365 std::list<const Trk::PrepRawData*> etaClusterVec{}, phiClusterVec{};
1366 std::set<Identifier> etaIds;
1373 double bestPull = std::abs(
gasGap.data.front().first);
1376 unsigned int nassociatedSp = 0;
1377 GasGapData::EntryVec::const_iterator cl_it =
gasGap.data.begin();
1378 while (cl_it !=
gasGap.data.end() && std::abs(cl_it->first) - bestPull < 1.) {
1383 << std::abs(cl_it->first) <<
" distance to segment " << dist <<
" phi "
1395 ++netaPhiHits.first.first;
1404 return clus->prepRawData();
1409 rioDistVec.emplace_back(dist, phi_hit->
uniqueClone());
1410 ++netaPhiHits.first.second;
1411 phiHits.push_back(phi_hit);
1415 posFirstPhiStation =
std::min(phiPos, posFirstPhiStation);
1416 posLastPhiStation =
std::max(phiPos, posLastPhiStation);
1418 if (sp.
phiHits.size() > 1) refit =
false;
1430 if (!etaClusterVec.empty()) {
1431 std::unique_ptr<const CompetingMuonClustersOnTrack> etaCompCluster =
m_compClusterCreator->createBroadCluster(etaClusterVec, 0.);
1432 if (!etaCompCluster) {
1433 ATH_MSG_DEBUG(
" failed to create competing ETA ROT " << etaClusterVec.size());
1436 ++netaPhiHits.first.first;
1439 for (
unsigned int i = 0;
i < etaCompCluster->containedROTs().
size(); ++
i) {
1441 " content: " <<
m_idHelperSvc->toString(etaCompCluster->containedROTs()[
i]->identify()));
1444 rioDistVec.emplace_back(dist, std::move(etaCompCluster));
1451 if (!phiClusterVec.empty()) {
1452 std::unique_ptr<const CompetingMuonClustersOnTrack> phiCompCluster =
m_compClusterCreator->createBroadCluster(phiClusterVec, 0.);
1453 if (!phiCompCluster) {
1454 ATH_MSG_DEBUG(
" failed to create competing PHI ROT " << phiClusterVec.size());
1457 phiHits.push_back(phiCompCluster.get());
1459 ++netaPhiHits.first.second;
1463 for (
unsigned int i = 0;
i < phiCompCluster->containedROTs().
size(); ++
i) {
1465 " content: " <<
m_idHelperSvc->toString(phiCompCluster->containedROTs()[
i]->identify()));
1471 double phiPos = isEndcap ? std::abs(phiCompCluster->globalPosition().z()) :
1472 phiCompCluster->globalPosition().perp();
1473 posFirstPhiStation =
std::min(phiPos,posFirstPhiStation);
1474 posLastPhiStation =
std::max(phiPos,posLastPhiStation);
1475 rioDistVec.emplace_back(dist, std::move(phiCompCluster));
1486 std::map<Identifier, std::list<const Trk::PrepRawData*> > phiClusterMap;
1488 std::set<const MuonClusterOnTrack*> selectedClusters;
1489 std::vector<const Cluster2D*> phiClusters;
1490 phiClusters.reserve(spVecs.second.size());
1493 for (
const Cluster2D& phi_clus :spVecs.second) {
1498 phiClusters.push_back(&phi_clus);
1499 selectedClusters.insert(phi_clus.
phiHit);
1502 unsigned int recoveredUnassociatedPhiHits(0);
1506 for (
const Cluster2D& rpc_clust : spVecs.first) {
1511 if (detElOnSegments.count(rpc_clust.
detElId))
continue;
1515 if (phiIndices.count(
phiIndex))
continue;
1517 bool wasFound =
false;
1520 if (!selectedClusters.insert(phi_hit).second) {
1527 if (erase_me == phi_hit)
break;
1528 selectedClusters.erase(erase_me);
1533 if (wasFound)
continue;
1536 phiClusters.push_back(&rpc_clust);
1537 ++recoveredUnassociatedPhiHits;
1541 unsigned int addedPhiHits(0);
1542 for (
const Cluster2D* phi_clus : phiClusters) {
1546 if (detElOnSegments.count(detElId))
continue;
1550 if (phiIndices.count(
phiIndex))
continue;
1558 double segError = std::sqrt(resWithSegment.
trackError2(
cl));
1567 bool inBounds = std::abs(
residual) < 0.5 * stripLength + 2. + segError;
1570 <<
" pos y " <<
cl.position().y() <<
" : residual " <<
residual <<
" strip half length "
1571 << 0.5 * stripLength <<
" segment error " << segError);
1579 std::list<const Trk::PrepRawData*>& cham_hits{phiClusterMap[detElId]};
1582 return clus->prepRawData();
1588 for (
const auto& [phi_id, prds] : phiClusterMap) {
1594 std::unique_ptr<const CompetingMuonClustersOnTrack> phiCompCluster =
m_compClusterCreator->createBroadCluster(prds, 0.);
1595 if (!phiCompCluster) {
1596 ATH_MSG_DEBUG(
" failed to create competing PHI ROT " << prds.size());
1603 <<
" distance to segment " << dist);
1606 phiHits.push_back(phiCompCluster.get());
1607 ++netaPhiHits.first.second;
1611 <<
" distance to segment " << dist);
1612 for (
unsigned int i = 0;
i < phiCompCluster->containedROTs().
size(); ++
i) {
1614 " content: " <<
m_idHelperSvc->toString(phiCompCluster->containedROTs()[
i]->identify()));
1617 rioDistVec.emplace_back(dist, std::move(phiCompCluster));
1620 ATH_MSG_VERBOSE(
"Added " << addedPhiHits <<
" unass phi hits out of " << spVecs.second.size()
1621 <<
" phi hits without eta hit and " << recoveredUnassociatedPhiHits <<
" with unassociated eta hit ");
1625 double phiDistanceMax = posLastPhiStation - posFirstPhiStation;
1626 if (isEndcap && phiDistanceMax < 1000.)
1628 else if (phiDistanceMax < 400.)
1631 netaPhiHits.second = refit;
1639 double cos_sinLine = cot(
line.phi());
1647 double delta_y = lpos.
y() -
line.position().y();
1655 return pointOnHit.
x();
1659 std::vector<std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>> >& rioDistVec) {
1664 rioVec.reserve(rioDistVec.size());
1665 for (std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>>& rdit : rioDistVec) { rioVec.push_back(std::move(rdit.second)); }
1674 double cos_sinLine = cot(
line.phi());
1681 double delta_y = lpos.
y() -
line.position().y();
1687 double residual = lpos.
x() - lineSurfaceIntersect.
x();
1694 std::set<Identifier>& outoftimeVec,
const std::vector<std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>> >& rioDistVec)
const {
1697 if (!InterSectSvc.isValid()) {
1698 ATH_MSG_ERROR(
"Null pointer to the read MuonDetectorManager conditions object");
1705 std::set<Identifier> hitsOnSegment, chambersOnSegment;
1706 int firstLayer{-1}, lastLayer{-1};
1707 for (
const std::pair<
double, std::unique_ptr<const Trk::MeasurementBase>>& rdit : rioDistVec) {
1712 if (firstLayer == -1)
1717 hitsOnSegment.insert(
id);
1722 if (firstLayer > lastLayer) {
std::swap(firstLayer, lastLayer); }
1723 ATH_MSG_VERBOSE(
" Tube layer ranges: " << firstLayer <<
" -- " << lastLayer <<
" crossed tubes "
1726 std::vector<Identifier> holeVec;
1728 if (!chambersOnSegment.count(
m_idHelperSvc->chamberId(tint.tubeId))) {
1729 ATH_MSG_VERBOSE(
" chamber not on segment, not counting tube " << tint.rIntersect <<
" l " << tint.xIntersect <<
" "
1737 bool notBetweenHits = layer < firstLayer || layer > lastLayer;
1738 double distanceCut = hasMeasuredCoordinate ? -20 : -200.;
1740 if (notBetweenHits && (std::abs(tint.rIntersect) > innerRadius || (!
m_allMdtHoles && tint.xIntersect > distanceCut))) {
1741 ATH_MSG_VERBOSE(
" not counting tube: distance to wire " << tint.rIntersect <<
" dist to tube end " << tint.xIntersect
1746 if (hitsOnSegment.count(tint.tubeId)) {
1747 ATH_MSG_VERBOSE(
" tube on segment: distance to wire " << tint.rIntersect <<
" dist to tube end " << tint.xIntersect
1753 if (deltaVec.count(tint.tubeId)) {
1754 ATH_MSG_VERBOSE(
" removing delta, distance to wire " << tint.rIntersect <<
" dist to tube end " << tint.xIntersect
1761 ATH_MSG_VERBOSE(
" found and removed delta, distance to wire " << tint.rIntersect <<
" dist to tube end "
1762 << tint.xIntersect <<
" "
1767 ATH_MSG_VERBOSE((outoftimeVec.count(tint.tubeId) ?
"Out-of-time" :
"hole") <<
" distance to wire "
1768 << tint.rIntersect <<
" dist to tube end " << tint.xIntersect <<
" "
1769 <<
m_idHelperSvc->toString(tint.tubeId)<<(notBetweenHits ?
"outside hits" :
"between hits"));
1771 holeVec.push_back(tint.tubeId);
1783 if (!MdtCont.isValid()) {
1788 if (!collptr)
return nullptr;
1790 if (prd->identify() ==
id)
return prd;
1796 const std::vector<const MdtDriftCircleOnTrack*>& mdts)
const {
1797 int hitsInChamberWithMostHits = 0;
1798 std::map<Identifier, int> hitsPerChamber;
1799 int currentSector = -1;
1810 if (currentSector == -1) {
1811 currentSector = sector;
1812 }
else if (sector != currentSector) {
1815 int& hitsInCh = hitsPerChamber[chId];
1817 if (hitsInCh > hitsInChamberWithMostHits) {
1818 hitsInChamberWithMostHits = hitsInCh;
1819 rotInChamberWithMostHits = rot;
1822 return rotInChamberWithMostHits;
1826 const std::vector<DCMathSegmentMaker::HitInXZ>&
hits)
const {
1831 bool outBounds =
false;
1832 double locExX = xline + dXdZ * (hit.z - zline);
1833 if (hit.isMdt && (locExX < hit.xmin - 1. || locExX > hit.xmax + 1.)) {
1841 << std::setw(6) << (
int)hit.z <<
") ex pos " << std::setw(6) << (
int)locExX <<
" min " << std::setw(6)
1842 << (
int)hit.xmin <<
" max " << std::setw(6) << (
int)hit.xmax <<
" phimin " << std::setw(6)
1843 << hit.phimin <<
" phimax " << std::setw(6) << hit.phimax <<
" outBounds, cross-check");
1851 const std::vector<const Trk::MeasurementBase*>& rots,
double seg_phimin,
1852 double seg_phimax)
const {
1853 bool hasUpdated =
false;
1860 if (ldir.z() < 0.0001)
return false;
1862 double dXdZ = ldir.x() / ldir.z();
1864 double xline = lsegPos.x();
1865 double zline = lsegPos.z();
1866 ATH_MSG_VERBOSE(
" Associated hits " << rots.size() <<
" angleXZ " << 90. * segLocDir.
angleXZ() / (M_PI_2) <<
" dXdZ " << dXdZ
1867 <<
" seg Pos (" << xline <<
" " << zline <<
") " << segLocPos);
1869 std::vector<HitInXZ>
hits;
1870 hits.reserve(rots.size());
1872 unsigned int nphiHits(0);
1873 const HitInXZ* firstPhiHit{
nullptr}, *lastPhiHit{
nullptr};
1877 if (!
id.is_valid())
continue;
1879 double lxmin{0}, lxmax{0}, phimin{0}, phimax{0};
1887 lxmin = tubeEnds.
lxmin;
1888 lxmax = tubeEnds.
lxmax;
1889 phimin = tubeEnds.
phimin;
1890 phimax = tubeEnds.
phimax;
1892 lpos = gToSegment * meas->globalPosition();
1904 lxmin = lpos.x() - 0.5 * stripLength;
1905 lxmax = lpos.x() + 0.5 * stripLength;
1909 locPosition[0] = lxmin;
1911 double phi1 = globalPos.phi();
1913 locPosition[0] = lxmax;
1914 globalPos = segmentToGlobal * locPosition;
1915 double phi2 = globalPos.phi();
1929 ATH_MSG_WARNING(
"dynamic cast failed for CompetingMuonClustersOnTrack");
1936 const Amg::Vector3D segFrame_stripPos = gToSegment * detEl->channelPos(
id);
1938 lpos = segFrame_stripPos +
1939 Amg::intersect<3>(lsegPos, ldir, segFrame_stripPos, segFrame_StripDir).value_or(0) * segFrame_StripDir;
1946 phimin = globalPos.phi();
1952 ATH_MSG_DEBUG(
" Inconsistent phi " << phimin <<
" range " << seg_phimin <<
" " << seg_phimax);
1957 hits.emplace_back(
id, isMdt, measuresPhi, lpos.x(), lpos.z(), lxmin, lxmax, phimin, phimax);
1961 firstPhiHit = &
hits.back();
1963 double distPhiHits = std::abs(firstPhiHit->z -
hits.back().z);
1964 if (distPhiHits > 500.) {
1965 lastPhiHit = &
hits.back();
1974 double locExX = xline + dXdZ * (lpos.z() - zline);
1976 << std::setw(6) << (
int)lpos.z() <<
") ex pos " << std::setw(6) << (
int)locExX <<
" min "
1977 << std::setw(6) << (
int)lxmin <<
" max " << std::setw(6) << (
int)lxmax <<
" phimin " << std::setw(6)
1978 << phimin <<
" phimax " << std::setw(6) << phimax);
1979 if (lpos.x() < lxmin || lpos.x() > lxmax)
ATH_MSG_VERBOSE(
" outBounds");
1983 if (nphiHits == 1) {
1985 ATH_MSG_WARNING(
" Pointer to first phi hit not set, this should not happen! ");
1987 if (xline != firstPhiHit->x) {
1991 xline = firstPhiHit->x;
1992 zline = firstPhiHit->z;
1998 double dz = ipLocPos.z() - zline;
1999 if (std::abs(dz) > 0.001) {
2000 ATH_MSG_VERBOSE(
" hit (" << xline <<
"," << zline <<
") IP (" << ipLocPos.x() <<
"," << ipLocPos.z()
2001 <<
") dXdZ " << (ipLocPos.x() - xline) / dz <<
" old " << dXdZ);
2002 dXdZ = (ipLocPos.x() - xline) / dz;
2007 }
else if (nphiHits == 2) {
2008 if (!firstPhiHit || !lastPhiHit) {
2009 ATH_MSG_WARNING(
" Pointer to one of the two phi hit not set, this should not happen! ");
2011 double dz = lastPhiHit->z - firstPhiHit->z;
2013 xline = firstPhiHit->x;
2014 zline = firstPhiHit->z;
2015 if (std::abs(dz) > 300.) {
2016 double dx = lastPhiHit->x - firstPhiHit->x;
2029 double segX = xline - dXdZ * zline;
2035 ATH_MSG_DEBUG(
"still several out of bounds hits after rotation: posx(" << segX <<
") dXdZ " << dXdZ
2036 <<
" keeping old result ");
2040 double alphaYZ = segLocDir.
angleYZ();
2041 double alphaXZ = std::atan2(1, dXdZ);
2060 double tubeLen = (lropos - lhvpos).
mag();
2061 double activeTubeLen =
2063 double scaleFactor = activeTubeLen / tubeLen;
2064 lropos[0] = scaleFactor * lropos.x();
2065 lhvpos[0] = scaleFactor * lhvpos.x();
2072 const double phiRO = ropos.phi();
2073 const double phiHV = hvpos.phi();
2081 if (phiminRef * phimaxRef < 0.) {
2082 if (phiminRef < -1.1) {
2083 if (phiminRef > phiminNew) phiminRef = phiminNew;
2084 if (phimaxRef < phimaxNew) phimaxRef = phimaxNew;
2086 if (phiminRef < phiminNew) phiminRef = phiminNew;
2087 if (phimaxRef > phimaxNew) phimaxRef = phimaxNew;
2091 if (phiminRef < 0.) {
2092 if (phiminRef < phiminNew) phiminRef = phiminNew;
2093 if (phimaxRef > phimaxNew) phimaxRef = phimaxNew;
2095 if (phiminRef > phiminNew) phiminRef = phiminNew;
2096 if (phimaxRef < phimaxNew) phimaxRef = phimaxNew;
2107 if (phimin * phimax < 0.) {
2110 if (phi < phimin -
offset) phiOk =
false;
2112 if (phi > phimin +
offset) phiOk =
false;
2116 if (phi < phimax -
offset) phiOk =
false;
2118 if (phi > phimax +
offset) phiOk =
false;
2122 if (phi < phimin - offset || phi > phimax +
offset) phiOk =
false;
2128 bool isCurvedSegment)
const {
2142 double dz =
std::cos(gdirs.theta());
2148 double dzo =
std::cos(gdiro.theta());
2158 if (b0 < 1e-8 && b0 > 0) b0 = 1
e-8;
2159 if (b0 > -1
e-8 && b0 < 0) b0 = -1
e-8;
2160 double dxn =
dx -
a0 * dxo / b0;
2161 double dyn =
dy -
a0 * dyo / b0;
2162 double dzn = dz -
a0 * dzo / b0;
2163 double norm = std::sqrt(dxn * dxn + dyn * dyn + dzn * dzn);
2167 if (dxn * roaddir.x() + dyn * roaddir.y() + dzn * roaddir.z() < 0.) {
norm = -
norm; }
2169 if (dxn * roaddir.x() + dyn * roaddir.y() < 0.) {
norm = -
norm; }
2172 if (isCurvedSegment)
norm =
norm / 2.;