56 const EventContext& ctx)
const {
58 rngWrapper->
setSeed(name(), ctx);
59 CLHEP::HepRandomEngine* rndmEngine = rngWrapper->
getEngine(ctx);
62 ATH_CHECK(xAODVxContainer.
record(std::make_unique<xAOD::VertexContainer>(), std::make_unique<xAOD::VertexAuxContainer>()));
64 if (tracklets.size() < 3) {
65 ATH_MSG_DEBUG(
"Fewer than 3 tracks found, vertexing not possible. Exiting...");
66 return StatusCode::SUCCESS;
70 ATH_MSG_DEBUG(
"Too many tracklets found globally. Exiting...");
71 return StatusCode::SUCCESS;
75 std::vector<Tracklet> BarrelTracklets;
76 std::vector<Tracklet> EndcapTracklets;
77 for (
const Tracklet &tracklet : tracklets){
78 if (
m_idHelperSvc->mdtIdHelper().isBarrel(tracklet.muonIdentifier()))
79 BarrelTracklets.push_back(tracklet);
80 else if (
m_idHelperSvc->mdtIdHelper().isEndcap(tracklet.muonIdentifier()))
81 EndcapTracklets.push_back(tracklet);
85 ATH_MSG_DEBUG(
"Too many tracklets found in barrel or endcap for clustering. Exiting...");
86 return StatusCode::SUCCESS;
89 ATH_MSG_DEBUG(
"Running on event with " << BarrelTracklets.size() <<
" barrel tracklets, " << EndcapTracklets.size()
90 <<
" endcap tracklets.");
93 std::vector<Muon::MSVertexRecoTool::TrkCluster> BarrelClusters =
findTrackClusters(BarrelTracklets);
94 std::vector<Muon::MSVertexRecoTool::TrkCluster> EndcapClusters =
findTrackClusters(EndcapTracklets);
98 std::vector<Tracklet> BarrelSystTracklets, EndcapSystTracklets;
99 for (
const Tracklet &BarrelTracklet : BarrelTracklets) {
100 double prob = CLHEP::RandFlat::shoot(rndmEngine, 0, 1);
103 if (BarrelSystTracklets.size() >= 3) {
104 std::vector<Muon::MSVertexRecoTool::TrkCluster> BarrelSystClusters =
findTrackClusters(BarrelSystTracklets);
106 BarrelSystCluster.isSystematic =
true;
107 BarrelClusters.push_back(BarrelSystCluster);
111 for (
const Tracklet &EndcapTracklet : EndcapTracklets) {
112 double prob = CLHEP::RandFlat::shoot(rndmEngine, 0, 1);
115 if (EndcapSystTracklets.size() >= 3) {
116 std::vector<Muon::MSVertexRecoTool::TrkCluster> EndcapSystClusters =
findTrackClusters(EndcapSystTracklets);
118 EndcapSystCluster.isSystematic =
true;
119 EndcapClusters.push_back(EndcapSystCluster);
127 if (BarrelCluster.ntrks < 3)
continue;
128 ATH_MSG_DEBUG(
"Attempting to build vertex from " << BarrelCluster.ntrks <<
" tracklets in the barrel");
129 std::unique_ptr<MSVertex> barvertex(
nullptr);
130 MSVxFinder(BarrelCluster.tracks, barvertex, ctx);
131 if (!barvertex)
continue;
136 ATH_MSG_DEBUG(
"Vertex found in the barrel with n_trk = " << barvertex->getNTracks() <<
" located at (eta,phi) = ("
137 << barvertex->getPosition().eta() <<
", "
138 << barvertex->getPosition().phi() <<
")");
139 if (BarrelCluster.isSystematic) barvertex->setAuthor(3);
140 vertices.push_back(std::move(barvertex));
147 if (EndcapCluster.ntrks < 3)
continue;
148 ATH_MSG_DEBUG(
"Attempting to build vertex from " << EndcapCluster.ntrks <<
" tracklets in the endcap");
150 std::unique_ptr<MSVertex> endvertex(
nullptr);
156 if (!endvertex)
continue;
159 std::abs(endvertex->getPosition().z()) >
m_MinZEndcap && endvertex->getNTracks() >= 3) {
162 ATH_MSG_DEBUG(
"Vertex found in the endcap with n_trk = " << endvertex->getNTracks() <<
" located at (eta,phi) = ("
163 << endvertex->getPosition().eta() <<
", "
164 << endvertex->getPosition().phi() <<
")");
165 if (EndcapCluster.isSystematic) endvertex->setAuthor(4);
166 vertices.push_back(std::move(endvertex));
173 return StatusCode::SUCCESS;
308 const EventContext& ctx)
const {
313 for (
const Tracklet &trk : tracklets) aveTrkPos += trk.globalPosition();
314 aveTrkPos /= tracklets.size();
317 double avePhi = aveTrkPos.phi();
318 double LoF = std::atan2(aveTrkPos.perp(), aveTrkPos.z());
322 std::vector<double> Rpos;
324 double LoFdist = std::abs(RadialDist / std::sin(LoF));
326 double PlaneSpacing = std::abs(
m_VxPlaneDist / std::cos(LoF));
330 std::array< std::vector<std::unique_ptr<Trk::TrackParameters>>, MAXPLANES> TracksForVertexing{};
331 std::array< std::vector<std::unique_ptr<Trk::TrackParameters>>, MAXPLANES> TracksForErrors{};
332 std::array< std::vector<bool>, MAXPLANES> isNeutralTrack{};
334 for (
const Tracklet &trk : tracklets) {
338 Amg::Vector3D trkgpos(trk.globalPosition().perp() * std::cos(avePhi),
339 trk.globalPosition().perp() * std::sin(avePhi),
340 trk.globalPosition().z());
341 double x0 = trkgpos.x();
342 double y0 = trkgpos.y();
343 double r0 = trkgpos.perp();
347 double NominalTrkAng = anglesign * NominalAngle;
348 double MaxTrkAng = anglesign * RotationAngle;
351 for (
int k = 0; k < nplanes; ++k) {
353 if (Rpos[k] > trk.globalPosition().perp())
break;
356 double Xp = Rpos[k] * std::cos(avePhi);
357 double Yp = Rpos[k] * std::sin(avePhi);
360 double DelR = std::hypot(x0 - Xp, y0 - Yp) / std::cos(NominalAngle);
361 double X1 = DelR * std::cos(NominalTrkAng + avePhi) + Xp;
362 double Y1 = DelR * std::sin(NominalTrkAng + avePhi) + Yp;
363 double R1 = std::hypot(X1, Y1);
364 double Norm = r0 / R1;
367 double Dirmag = std::hypot(X1 - Xp, Y1 - Yp);
368 double Xdir = (X1 - Xp) / Dirmag;
369 double Ydir = (Y1 - Yp) / Dirmag;
370 double trkpx = Xdir * trk.momentum().perp();
371 double trkpy = Ydir * trk.momentum().perp();
372 double trkpz = trk.momentum().z();
375 double charge = trk.charge();
376 if (std::abs(
charge) < 0.1) {
378 isNeutralTrack[k].push_back(
true);
380 isNeutralTrack[k].push_back(
false);
386 TracksForVertexing[k].push_back(std::make_unique<Trk::Perigee>(0., 0., trkmomentum.phi(), trkmomentum.theta(),
charge / trkmomentum.mag(),
Trk::PerigeeSurface(trkgpos), covariance));
389 double xp = Rpos[k] * std::cos(avePhi);
390 double yp = Rpos[k] * std::sin(avePhi);
391 double delR = std::hypot(x0 - xp, y0 - yp) / std::cos(RotationAngle);
392 double x1 = delR * std::cos(MaxTrkAng + avePhi) + xp;
393 double y1 = delR * std::sin(MaxTrkAng + avePhi) + yp;
394 double r1 = std::hypot(x1, y1);
395 double norm = r0 / r1;
398 double dirmag = std::hypot(x1 - xp, y1 - yp);
399 double xdir = (x1 - xp) / dirmag;
400 double ydir = (y1 - yp) / dirmag;
401 double errpx = xdir * trk.momentum().perp();
402 double errpy = ydir * trk.momentum().perp();
403 double errpz = trk.momentum().z();
409 TracksForErrors[k].push_back(std::make_unique<Trk::Perigee>(0., 0., trkerrmom.phi(), trkerrmom.theta(),
charge / trkerrmom.mag(),
Trk::PerigeeSurface(trkerrpos), covariance2));
414 if (nTrkToVertex < 3)
return;
417 bool boundaryCheck =
true;
418 std::array<std::vector<double>, MAXPLANES> ExtrapZ{};
419 std::array<std::vector<double>, MAXPLANES> dlength{};
420 std::array<std::vector<std::pair<unsigned int, unsigned int>>, MAXPLANES> UsedTracks{};
421 std::array<std::vector<bool>, MAXPLANES> ExtrapSuc{};
422 std::vector<std::unique_ptr<MSVertex>> vertices; vertices.reserve(nplanes);
423 std::array<std::vector<double>, MAXPLANES> sigmaZ{};
424 std::array<std::vector<Amg::Vector3D>, MAXPLANES> pAtVx{};
427 for (
int k = 0; k < nplanes; ++k) {
428 double rpos = Rpos[k];
429 for (
unsigned int i = 0; i < TracksForVertexing[k].size(); ++i) {
431 if (TracksForVertexing[k].size() < 3)
break;
434 surfaceTransformMatrix.setIdentity();
437 std::unique_ptr<const Trk::TrackParameters> extrap_par(
445 if (isNeutralTrack[k].at(i)) {
446 double pTot = std::hypot(TracksForVertexing[k].at(i)->momentum().
perp(), TracksForVertexing[k].at(i)->momentum().
z());
448 double extrapRdist = TracksForVertexing[k].at(i)->position().perp() - Rpos[k];
449 double sz = std::abs(20 * dirErr * extrapRdist * std::pow(pTot,2) / std::pow(TracksForVertexing[k].at(i)->momentum().
perp(), 2));
450 double ExtrapErr =
sz;
452 ExtrapSuc[k].push_back(
false);
454 ExtrapSuc[k].push_back(
true);
455 std::pair<unsigned int, unsigned int> trkmap(ExtrapZ[k].size(), i);
456 UsedTracks[k].push_back(trkmap);
458 sigmaZ[k].push_back(
sz);
459 pAtVx[k].push_back(extrap->
momentum());
460 dlength[k].push_back(0);
467 srfTransMat2.setIdentity();
469 std::unique_ptr<const Trk::TrackParameters> extrap_par2(
477 double ExtrapErr = std::hypot(
sz, zdiff);
479 ExtrapSuc[k].push_back(
false);
482 ExtrapSuc[k].push_back(
true);
483 std::pair<unsigned int, unsigned int> trkmap(ExtrapZ[k].size(), i);
484 UsedTracks[k].push_back(trkmap);
486 sigmaZ[k].push_back(
sz);
487 pAtVx[k].push_back(extrap->
momentum());
488 dlength[k].push_back(zdiff);
491 ExtrapSuc[k].push_back(
false);
496 ExtrapSuc[k].push_back(
false);
502 std::array<std::vector<Amg::Vector3D>, MAXPLANES> trkp{};
504 for (
int k = 0; k < nplanes; ++k) {
505 if (ExtrapZ[k].size() < 3)
continue;
507 double zLoF = Rpos[k] / std::tan(LoF);
509 double aveZpos(0), posWeight(0);
510 for (
unsigned int i = 0; i < ExtrapZ[k].size(); ++i) {
511 double ExtrapErr = std::hypot(sigmaZ[k][i], dlength[k][i], dzLoF);
512 if (isNeutralTrack[k][i]) ExtrapErr = std::hypot(sigmaZ[k][i], dzLoF);
513 aveZpos += ExtrapZ[k][i] / std::pow(ExtrapErr,2);
514 posWeight += 1. / std::pow(ExtrapErr,2);
517 zLoF = aveZpos / posWeight;
518 double zpossigma(dzLoF), Chi2(0), Chi2Prob(-1);
519 unsigned int Nitr(0);
520 std::vector<unsigned int> vxtracks;
521 std::vector<bool> blocklist(ExtrapZ[k].size(),
false);
525 vxtracks.clear(); trkp[k].clear();
527 double tmpzLoF(0), tmpzpossigma(0), tmpchi2(0), posWeight(0), worstdelz(0);
528 unsigned int iworst(0);
530 for (
unsigned int i = 0; i < ExtrapZ[k].size(); ++i) {
531 if (blocklist[i])
continue;
532 trkp[k].push_back(pAtVx[k][i]);
533 double delz = zLoF - ExtrapZ[k][i];
534 double ExtrapErr = std::hypot(sigmaZ[k][i], dlength[k][i], dzLoF);
535 double trkchi2 = std::pow(delz,2) / std::pow(ExtrapErr,2);
536 if (trkchi2 > worstdelz) {
540 tmpzLoF += ExtrapZ[k][i] / std::pow(ExtrapErr,2);
541 posWeight += 1. / std::pow(ExtrapErr,2);
542 tmpzpossigma += std::pow(delz,2);
547 if (tmpnTrks < 3)
break;
548 tmpzpossigma = std::sqrt(tmpzpossigma / (
double)tmpnTrks);
549 zLoF = tmpzLoF / posWeight;
550 zpossigma = tmpzpossigma;
551 double testChi2 = TMath::Prob(tmpchi2, tmpnTrks - 1);
553 blocklist[iworst] =
true;
558 for (
unsigned int i = 0; i < ExtrapZ[k].size(); ++i) {
559 double delz = zLoF - ExtrapZ[k][i];
560 double ExtrapErr = std::hypot(sigmaZ[k][i], dlength[k][i], dzLoF);
561 double trkErr = std::hypot(ExtrapErr, zpossigma) + 0.001;
562 double trkNsigma = std::abs(delz / trkErr);
563 if (trkNsigma < 3) vxtracks.push_back(i);
567 if (Nitr >= (ExtrapZ[k].size() - 3))
break;
571 if (vxtracks.size() < 3)
continue;
574 std::vector<const xAOD::TrackParticle*> vxTrackParticles;
575 vxTrackParticles.reserve(vxtracks.size());
576 for (std::vector<unsigned int>::iterator vxtrk = vxtracks.begin(); vxtrk != vxtracks.end(); ++vxtrk) {
577 for (
unsigned int i = 0; i < UsedTracks[k].size(); ++i) {
578 if ((*vxtrk) != UsedTracks[k].at(i).first)
continue;
579 const Tracklet& trklt = tracklets.at(UsedTracks[k].at(i).second);
584 Amg::Vector3D position(Rpos[k] * std::cos(avePhi), Rpos[k] * std::sin(avePhi), zLoF);
585 vertices.push_back(std::make_unique<MSVertex>(1, position, vxTrackParticles, Chi2Prob, Chi2, 0, 0, 0));
588 if (vertices.empty())
return;
592 unsigned int bestVx(0);
593 for (
unsigned int k = 1; k < vertices.size(); ++k) {
594 if (vertices[k]->getChi2Probability() <
m_VxChi2ProbCUT || vertices[k]->getNTracks() < 3)
continue;
595 if (vertices[k]->getNTracks() < vertices[bestVx]->getNTracks())
continue;
596 if (vertices[k]->getNTracks() == vertices[bestVx]->getNTracks() &&
597 vertices[k]->getChi2Probability() < vertices[bestVx]->getChi2Probability())
601 vtx = std::make_unique<MSVertex>(*vertices[bestVx]);
608 const EventContext& ctx)
const {
610 std::set<std::set<int> > prelim_vx;
614 if (trks.size() > 40) {
621 for (
unsigned int i = 0; i < trks.size() - 2; ++i) {
622 for (
unsigned int j = i + 1; j < trks.size() - 1; ++j) {
623 for (
unsigned int k = j + 1; k < trks.size(); ++k) {
624 std::set<int> tmpTracks;
631 if (MyVx.perp() < 10000 && std::abs(MyVx.z()) > 7000 && std::abs(MyVx.z()) < 15000 &&
633 prelim_vx.insert(tmpTracks);
639 if (prelim_vx.empty())
return;
643 if (trks.size() <= 20) {
644 std::set<std::set<int> > new_prelim_vx = prelim_vx;
645 std::set<std::set<int> > old_prelim_vx;
647 int foundNewVx =
true;
651 old_prelim_vx = new_prelim_vx;
652 new_prelim_vx.clear();
654 for (std::set<std::set<int> >
::iterator itr = old_prelim_vx.begin(); itr != old_prelim_vx.end(); ++itr) {
655 for (
unsigned int i_trks = 0; i_trks < trks.size(); ++i_trks) {
656 std::set<int> tempCluster = *itr;
657 if (tempCluster.insert(i_trks).second) {
659 if (MyVx.perp() < 10000 && std::abs(MyVx.z()) > 7000 && std::abs(MyVx.z()) < 15000 &&
661 new_prelim_vx.insert(tempCluster);
662 prelim_vx.insert(tempCluster);
679 std::set<std::set<int> >
::iterator prelim_vx_max = prelim_vx.begin();
680 for (std::set<std::set<int> >
::iterator itr = prelim_vx.begin(); itr != prelim_vx.end(); ++itr) {
681 if ((*itr).size() > (*prelim_vx_max).size()) prelim_vx_max = itr;
684 std::vector<Tracklet> tracklets =
getTracklets(trks, *prelim_vx_max);
688 for (
const Tracklet &trk : tracklets) {
689 aveX += trk.globalPosition().x();
690 aveY += trk.globalPosition().y();
694 double vxtheta = std::atan2(MyVx.x(), MyVx.z());
695 double tracklet_vxphi = std::atan2(aveY, aveX);
696 double vxphi =
vxPhiFinder(std::abs(vxtheta), tracklet_vxphi, ctx);
698 Amg::Vector3D vxpos(MyVx.x() * std::cos(vxphi), MyVx.x() * std::sin(vxphi), MyVx.z());
700 std::vector<const xAOD::TrackParticle*> vxTrackParticles;
701 for (
const Tracklet &trk : tracklets) vxTrackParticles.push_back(trk.getTrackParticle());
703 vtx = std::make_unique<MSVertex>(2, vxpos, vxTrackParticles, 1, vxTrackParticles.size(), 0, 0, 0);
934 int nHighOccupancy(0);
935 int stationRegion(-1);
939 if (msVtxPos.x() == 0 && msVtxPos.y() == 0 && msVtxPos.z() != 0) {
940 ATH_MSG_WARNING(
"given MSVertex has position x=y=0 and z!=0, eta() method will cause FPE, returning...");
947 int nmdt(0), nmdt_inwards(0), nmdt_I(0), nmdt_E(0), nmdt_M(0), nmdt_O(0);
950 if (MDT_coll->empty())
continue;
952 Amg::Vector3D ChamberCenter = (*mdtItr)->detectorElement()->center();
953 double deta = msVtxPos.eta() - ChamberCenter.eta();
959 stationRegion =
m_idHelperSvc->mdtIdHelper().stationRegion(
id);
960 auto [tubeLayerMin, tubeLayerMax] =
m_idHelperSvc->mdtIdHelper().tubeLayerMinMax(
id);
962 double nTubes = (tubeLayerMax - tubeLayerMin + 1) * (
tubeMax - tubeMin + 1);
964 int nChHits(0), nChHits_inwards(0);
967 if (mdt->adc() < 50)
continue;
968 if (mdt->status() != 1)
continue;
969 if (mdt->localPosition()[
Trk::locR] == 0.)
continue;
971 if (mdt->globalPosition().mag() < msVtxPos.mag()) ++nChHits_inwards;
974 nmdt_inwards += nChHits_inwards;
975 double ChamberOccupancy = nChHits / nTubes;
978 if (stationRegion == 0) nmdt_I += nChHits;
979 else if (stationRegion == 1) nmdt_E += nChHits;
980 else if (stationRegion == 2) nmdt_M += nChHits;
981 else if (stationRegion == 3) nmdt_O += nChHits;
989 int nrpc(0), nrpc_inwards(0), nrpc_I(0), nrpc_E(0), nrpc_M(0), nrpc_O(0);
992 stationRegion =
m_idHelperSvc->rpcIdHelper().stationRegion((*rpcItr)->identify());
993 int nChHits(0), nChHits_inwards(0);
995 double rpcEta = rpc->globalPosition().eta();
996 double rpcPhi = rpc->globalPosition().phi();
1000 if (rpc->globalPosition().mag() < msVtxPos.mag()) ++nChHits_inwards;
1002 if (DR > 1.2)
break;
1005 nrpc_inwards += nChHits_inwards;
1006 if (stationRegion == 0) nrpc_I += nChHits;
1007 else if (stationRegion == 1) nrpc_E += nChHits;
1008 else if (stationRegion == 2) nrpc_M += nChHits;
1009 else if (stationRegion == 3) nrpc_O += nChHits;
1015 int ntgc(0), ntgc_inwards(0), ntgc_I(0), ntgc_E(0), ntgc_M(0), ntgc_O(0);
1018 stationRegion =
m_idHelperSvc->tgcIdHelper().stationRegion((*tgcItr)->identify());
1019 int nChHits(0), nChHits_inwards(0);
1021 double tgcEta = tgc->globalPosition().eta();
1022 double tgcPhi = tgc->globalPosition().phi();
1026 if (tgc->globalPosition().mag() < msVtxPos.mag()) ++nChHits_inwards;
1028 if (DR > 1.2)
break;
1031 ntgc_inwards += nChHits_inwards;
1032 if (stationRegion == 0) ntgc_I += nChHits;
1033 else if (stationRegion == 1) ntgc_E += nChHits;
1034 else if (stationRegion == 2) ntgc_M += nChHits;
1035 else if (stationRegion == 3) ntgc_O += nChHits;
1039 MSRecoVx->
setNMDT(nmdt, nmdt_inwards, nmdt_I, nmdt_E, nmdt_M, nmdt_O);
1040 MSRecoVx->
setNRPC(nrpc, nrpc_inwards, nrpc_I, nrpc_E, nrpc_M, nrpc_O);
1041 MSRecoVx->
setNTGC(ntgc, ntgc_inwards, ntgc_I, ntgc_E, ntgc_M, ntgc_O);