14 #include "GaudiKernel/IInterface.h"
35 #include "Acts/Surfaces/StrawSurface.hpp"
36 #include "Acts/Surfaces/PerigeeSurface.hpp"
37 #include "Acts/Surfaces/PlaneSurface.hpp"
39 #include "Acts/Definitions/Units.hpp"
40 #include "Acts/EventData/TrackParameters.hpp"
41 #include "Acts/EventData/VectorTrackContainer.hpp"
42 #include "Acts/EventData/TransformationHelpers.hpp"
43 #include "Acts/Geometry/TrackingGeometry.hpp"
44 #include "Acts/Propagator/detail/JacobianEngine.hpp"
46 #include "Acts/EventData/TrackStatePropMask.hpp"
47 #include "Acts/EventData/SourceLink.hpp"
62 #pragma GCC diagnostic push
63 #pragma GCC diagnostic ignored "-Wunused-function"
64 static void ActsMeasurementCheck(
const Acts::GeometryContext &gctx,
66 const Acts::Surface &surface,
67 const Acts::BoundVector &loc);
68 #pragma GCC diagnostic pop
70 static void ActsTrackParameterCheck(
71 const Acts::BoundTrackParameters &actsParameter,
72 const Acts::GeometryContext &gctx,
const Acts::BoundSquareMatrix &covpc,
73 const Acts::BoundVector &targetPars,
const Acts::BoundSquareMatrix &targetCov,
89 surface->associatedDetectorElement());
102 <<
" has two ACTS surfaces: "
103 <<
it->second->geometryId() <<
" and "
104 << surface->geometryId());
119 for (
auto readoutElement : muonMgr->getAllReadoutElements()) {
120 std::vector<std::shared_ptr<Acts::Surface>> reSurfaces = readoutElement->getSurfaces();
121 for (
const auto& surf : reSurfaces) {
128 return StatusCode::SUCCESS;
132 const Acts::Surface &actsSurface)
const {
134 const auto *detEleBase=
dynamic_cast<const IDetectorElementBase*
>(actsSurface.associatedDetectorElement());
137 throw std::domain_error(
"ActsToTrkConverterTool() - Surface does not have an associated detector element. ");
139 switch (detEleBase->detectorType()) {
158 if (!
SG::get(detMgr,
m_muonMgrKey, Gaudi::Hive::currentContext()).isSuccess() || !detMgr) {
161 return detMgr->getReadoutElement(detEleBase->identify())->surface(detEleBase->identify());
166 throw std::domain_error(
"ActsToTrkConverterTool() - No ATLAS surface corresponding to the Acts one");
177 ATH_MSG_ERROR(
"No Acts surface corresponding to this ATLAS surface: "<<atlasID);
179 throw std::domain_error(
"No Acts surface corresponding to the ATLAS one");
182 std::vector<Acts::SourceLink>
184 std::vector<Acts::SourceLink> sourceLinks{};
185 sourceLinks.reserve(
track.measurementsOnTrack()->size() +
186 track.outliersOnTrack()->size());
194 std::vector<Acts::SourceLink>& sourceLinks)
const{
195 if (sourceLinks.capacity() < sourceLinks.size() + measSet.size()) {
196 sourceLinks.reserve(sourceLinks.size() + measSet.size());
203 std::vector<Acts::SourceLink>&
links)
const {
204 if (
links.capacity() <
links.size() + prdSet.size()) {
212 const Acts::BoundTrackParameters
214 const Acts::GeometryContext & gctx,
217 using namespace Acts::UnitLiterals;
218 std::shared_ptr<const Acts::Surface> actsSurface;
227 ATH_MSG_ERROR(
"Could not find ACTS detector surface for this TrackParameter:");
235 "trkTrackParametersToActsParameters:: No associated surface found (owner: "<<atlasParameter.
associatedSurface().
owner()<<
236 "). Creating a free surface. Trk parameters:");
241 actsSurface = Acts::Surface::makeShared<const Acts::PlaneSurface>(
trf);
244 actsSurface = Acts::Surface::makeShared<const Acts::PerigeeSurface>(
trf);
247 actsSurface = Acts::Surface::makeShared<const Acts::StrawSurface>(
trf);
251 std::stringstream surfStr{};
252 atlasParameter.
dump(surfStr);
253 throw std::domain_error(
std::format(
"Failed to translate parameters {:}", surfStr.str()));
259 const auto& atlasParam{atlasParameter.parameters()};
260 if (actsSurface->bounds().type() == Acts::SurfaceBounds::BoundsType::eAnnulus) {
264 auto result = actsSurface->globalToLocal(gctx, position, atlasParameter.
momentum());
268 atlasParameter.
charge() / (atlasParameter.
momentum().mag() * 1_MeV),
271 ATH_MSG_WARNING(
"Unable to convert annulus surface - globalToLocal failed");
276 atlasParameter.
charge() / (atlasParameter.
momentum().mag() * 1_MeV), 0.;
279 Acts::BoundSquareMatrix
cov = Acts::BoundSquareMatrix::Identity();
280 if (atlasParameter.covariance()) {
281 cov.topLeftCorner(5, 5) = *atlasParameter.covariance();
286 for (
int i = 0;
i <
cov.rows();
i++) {
289 for (
int i = 0;
i <
cov.cols();
i++) {
294 return Acts::BoundTrackParameters(actsSurface,
params,
cov,
298 std::unique_ptr<Trk::TrackParameters>
300 const Acts::BoundTrackParameters &actsParameter,
301 const Acts::GeometryContext &gctx)
const {
303 using namespace Acts::UnitLiterals;
305 if (actsParameter.covariance()) {
306 AmgSymMatrix(5) newcov(actsParameter.covariance()->topLeftCorner<5, 5>());
308 for (
int i = 0;
i < newcov.rows();
i++) {
309 newcov(
i, 4) = newcov(
i, 4) * 1_MeV;
311 for (
int i = 0;
i < newcov.cols();
i++) {
312 newcov(4,
i) = newcov(4,
i) * 1_MeV;
314 cov = std::optional<AmgSymMatrix(5)>(newcov);
317 const Acts::Surface &actsSurface = actsParameter.referenceSurface();
318 switch (actsSurface.type()) {
321 return std::make_unique<Trk::AtaCone>(
322 actsParameter.get<Acts::eBoundLoc0>(),
323 actsParameter.get<Acts::eBoundLoc1>(),
324 actsParameter.get<Acts::eBoundPhi>(),
325 actsParameter.get<Acts::eBoundTheta>(),
326 actsParameter.get<Acts::eBoundQOverP>() * 1_MeV, coneSurface,
cov);
329 return std::make_unique<Trk::AtaCylinder>(
330 actsParameter.get<Acts::eBoundLoc0>(),
331 actsParameter.get<Acts::eBoundLoc1>(),
332 actsParameter.get<Acts::eBoundPhi>(),
333 actsParameter.get<Acts::eBoundTheta>(),
334 actsParameter.get<Acts::eBoundQOverP>() * 1_MeV, cylSurface,
cov);
339 return std::make_unique<Trk::AtaDisc>(
340 actsParameter.get<Acts::eBoundLoc0>(),
341 actsParameter.get<Acts::eBoundLoc1>(),
342 actsParameter.get<Acts::eBoundPhi>(),
343 actsParameter.get<Acts::eBoundTheta>(),
344 actsParameter.get<Acts::eBoundQOverP>() * 1_MeV, discSurface,
cov);
348 auto helperSurface = Acts::Surface::makeShared<Acts::PlaneSurface>(planeSurface.transform());
350 auto covpc = actsParameter.covariance().value();
352 Acts::FreeVector freePars = Acts::transformBoundToFreeParameters(actsSurface, gctx,
353 actsParameter.parameters());
356 Acts::BoundVector targetPars = Acts::transformFreeToBoundParameters(freePars,
357 *helperSurface, gctx).value();
359 Acts::FreeMatrix freeTransportJacobian{Acts::FreeMatrix::Identity()};
362 freeToPathDerivatives.head<3>() = freePars.segment<3>(Acts::eFreeDir0);
364 auto boundToFreeJacobian = actsSurface.boundToFreeJacobian(gctx, freePars.segment<3>(Acts::eFreePos0),
365 freePars.segment<3>(Acts::eFreeDir0));
367 Acts::BoundMatrix boundToBoundJac = Acts::detail::boundToBoundTransportJacobian(gctx, freePars,
368 boundToFreeJacobian, freeTransportJacobian, freeToPathDerivatives, *helperSurface);
370 Acts::BoundMatrix targetCov{boundToBoundJac * covpc * boundToBoundJac.transpose()};
372 auto pars = std::make_unique<Trk::AtaPlane>(
373 targetPars[Acts::eBoundLoc0], targetPars[Acts::eBoundLoc1],
374 targetPars[Acts::eBoundPhi], targetPars[Acts::eBoundTheta],
375 targetPars[Acts::eBoundQOverP] * 1_MeV, planeSurface,
376 targetCov.topLeftCorner<5, 5>());
379 ActsTrackParameterCheck(actsParameter, gctx, covpc, targetPars,
380 targetCov, &planeSurface);
385 throw std::domain_error(
"Acts::DiscSurface is not associated with ATLAS disc or plane surface");
388 }
case Acts::Surface::SurfaceType::Perigee: {
390 return std::make_unique<Trk::Perigee>(
391 actsParameter.get<Acts::eBoundLoc0>(),
392 actsParameter.get<Acts::eBoundLoc1>(),
393 actsParameter.get<Acts::eBoundPhi>(),
394 actsParameter.get<Acts::eBoundTheta>(),
395 actsParameter.get<Acts::eBoundQOverP>() * 1_MeV, perSurface,
cov);
398 return std::make_unique<Trk::AtaPlane>(
399 actsParameter.get<Acts::eBoundLoc0>(),
400 actsParameter.get<Acts::eBoundLoc1>(),
401 actsParameter.get<Acts::eBoundPhi>(),
402 actsParameter.get<Acts::eBoundTheta>(),
403 actsParameter.get<Acts::eBoundQOverP>() * 1_MeV, plaSurface,
cov);
406 return std::make_unique<Trk::AtaStraightLine>(
407 actsParameter.get<Acts::eBoundLoc0>(),
408 actsParameter.get<Acts::eBoundLoc1>(),
409 actsParameter.get<Acts::eBoundPhi>(),
410 actsParameter.get<Acts::eBoundTheta>(),
411 actsParameter.get<Acts::eBoundQOverP>() * 1_MeV, lineSurface,
cov);
413 return std::make_unique<Trk::CurvilinearParameters>(
414 actsParameter.position(gctx), actsParameter.get<Acts::eBoundPhi>(),
415 actsParameter.get<Acts::eBoundTheta>(),
416 actsParameter.get<Acts::eBoundQOverP>() * 1_MeV,
cov);
418 }
case Acts::Surface::SurfaceType::Other: {
422 throw std::domain_error(
"Surface type not found");
427 const Acts::GeometryContext & gctx)
const {
429 << trackColl.size() <<
" tracks.");
430 unsigned int trkCount = 0;
431 std::vector<Identifier> failedIds;
436 auto actsTrack = tc.getTrack(tc.addTrack());
437 auto& trackStateContainer = tc.trackStateContainer();
440 <<
" track states on surfaces.");
442 actsTrack.chi2() = trk->fitQuality()->chiSquared();
443 actsTrack.nDoF() = trk->fitQuality()->numberDoF();
447 bool first_tsos =
true;
448 int measurementsCount = 0;
453 if (tsos->measurementOnTrack()) {
454 mask |= Acts::TrackStatePropMask::Calibrated;
456 if (tsos->trackParameters()) {
457 mask |= Acts::TrackStatePropMask::Smoothed;
461 auto index = Acts::MultiTrajectoryTraits::kInvalid;
463 index = actsTrack.tipIndex();
465 auto actsTSOS = trackStateContainer.getTrackState(trackStateContainer.addTrackState(
mask,
index));
466 ATH_MSG_VERBOSE(
"TipIndex: " << actsTrack.tipIndex() <<
" TSOS index within trajectory: "<< actsTSOS.index());
467 actsTrack.tipIndex() = actsTSOS.index();
469 if (tsos->trackParameters()) {
479 failedIds.push_back(tsos->trackParameters()->associatedSurface().associatedDetectorElementIdentifier());
485 actsTrack.parameters() =
parameters.parameters();
486 actsTrack.covariance() = *
parameters.covariance();
487 actsTrack.setReferenceSurface(
parameters.referenceSurface().getSharedPtr());
490 actsTSOS.setReferenceSurface(
parameters.referenceSurface().getSharedPtr());
492 actsTSOS.smoothed() =
parameters.parameters();
493 actsTSOS.smoothedCovariance() = *
parameters.covariance();
496 if (!(actsTSOS.hasSmoothed() && actsTSOS.hasReferenceSurface())) {
498 << actsTSOS.hasSmoothed()
499 <<
"] or reference surface ["
500 << actsTSOS.hasReferenceSurface() <<
"].");
502 ATH_MSG_VERBOSE(
"TrackState has smoothed state and reference surface.");
506 ATH_MSG_ERROR(
"Unable to convert TrackParameter with exception ["<<
e.what()<<
"]. Will be missing from ACTS track."
507 <<(*tsos->trackParameters()));
510 if (tsos->measurementOnTrack()) {
511 auto &measurement = *(tsos->measurementOnTrack());
519 int dim = measurement.localParameters().dimension();
520 actsTSOS.allocateCalibrated(
dim);
522 actsTSOS.calibrated<1>() = measurement.localParameters();
523 actsTSOS.calibratedCovariance<1>() = measurement.localCovariance();
524 }
else if (
dim == 2) {
525 actsTSOS.calibrated<2>() = measurement.localParameters();
526 actsTSOS.calibratedCovariance<2>() = measurement.localCovariance();
528 throw std::domain_error(
"Cannot handle measurement dim>2");
534 actsTrack.nMeasurements() = measurementsCount;
536 <<
" track states on surfaces.");
538 ATH_MSG_VERBOSE(
"Finished converting " << trackColl.size() <<
" tracks.");
540 if (!failedIds.empty()){
541 ATH_MSG_WARNING(
"Failed to convert "<<failedIds.size()<<
" track parameters.");
542 for (
auto id : failedIds){
546 ATH_MSG_VERBOSE(
"ACTS Track container has " << tc.size() <<
" tracks.");
552 const Acts::GeometryContext &gctx)
const {
560 if ( (actsPos - trkparameters.
position()).mag() > 0.1) {
562 << actsPos <<
" vs Trk \n"
575 #pragma GCC diagnostic push
576 #pragma GCC diagnostic ignored "-Wunused-function"
577 static void ActsMeasurementCheck(
579 const Acts::Surface &surface,
const Acts::BoundVector &loc) {
586 if (bounds ==
nullptr) {
587 throw std::runtime_error{
"Annulus but not XY"};
596 if (
auto res = surface.globalToLocal(gctx,
global, Acts::Vector3{});
600 throw std::runtime_error{
"Global position not on target surface"};
606 Acts::Surface::makeShared<Acts::PlaneSurface>(surf.
transform());
607 Acts::BoundVector locxypar;
608 locxypar.head<2>() = locxy;
610 locxypar[3] = M_PI_2;
613 Acts::FreeVector globalxypar = Acts::transformBoundToFreeParameters(
614 *planeSurface, gctx, locxypar);
615 auto boundToFree = planeSurface->boundToFreeJacobian(
616 gctx, globalxypar.segment<3>(Acts::eFreePos0),
617 globalxypar.segment<3>(Acts::eFreeDir0));
618 Acts::ActsSquareMatrix<2> xyToXyzJac = boundToFree.topLeftCorner<2, 2>();
620 Acts::BoundVector locpcpar;
621 locpcpar.head<2>() = locpc;
623 locpcpar[3] = M_PI_2;
626 Acts::FreeVector globalpcpar = Acts::transformBoundToFreeParameters(
627 surface, gctx, locpcpar);
629 boundToFree = surface.boundToFreeJacobian(
630 gctx, globalpcpar.segment<3>(Acts::eFreePos0),
631 globalpcpar.segment<3>(Acts::eFreeDir0));
632 Acts::ActsSquareMatrix<2> pcToXyzJac = boundToFree.topLeftCorner<2, 2>();
633 Acts::ActsSquareMatrix<2> xyzToPcJac = pcToXyzJac.inverse();
636 Acts::ActsMatrix<2, 2> covpc = covxy;
637 covpc = xyToXyzJac * covpc * xyToXyzJac.transpose();
638 covpc = xyzToPcJac * covpc * xyzToPcJac.transpose();
640 std::mt19937
gen{42 + surface.geometryId().value()};
641 std::normal_distribution<double> normal{0, 1};
642 std::uniform_real_distribution<double>
uniform{-1, 1};
644 Acts::ActsMatrix<2, 2> lltxy = covxy.llt().matrixL();
645 Acts::ActsMatrix<2, 2> lltpc = covpc.llt().matrixL();
647 for (
size_t i = 0;
i < 1
e4;
i++) {
648 std::cout <<
"ANNULUS COV: ";
649 std::cout << surface.geometryId();
657 std::cout <<
"," << xy.x() <<
"," << xy.y();
658 std::cout <<
"," <<
xyz.x() <<
"," <<
xyz.y() <<
"," <<
xyz.z();
668 std::cout <<
"," << rt.x() <<
"," << rt.y();
669 std::cout <<
"," <<
xyz.x() <<
"," <<
xyz.y() <<
"," <<
xyz.z();
672 std::cout << std::endl;
675 #pragma GCC diagnostic pop
677 void ActsTrackParameterCheck(
678 const Acts::BoundTrackParameters &actsParameter,
679 const Acts::GeometryContext &gctx,
const Acts::BoundSquareMatrix &covpc,
680 const Acts::BoundVector &targetPars,
const Acts::BoundSquareMatrix &targetCov,
683 std::cout <<
"ANNULUS PAR COV: ";
684 std::cout << actsParameter.referenceSurface().geometryId();
685 for (
unsigned int i = 0;
i < 5;
i++) {
686 for (
unsigned int j = 0; j < 5; j++) {
687 std::cout <<
"," << covpc(
i, j);
690 for (
unsigned int i = 0;
i < 5;
i++) {
691 for (
unsigned int j = 0; j < 5; j++) {
692 std::cout <<
"," << targetCov(
i, j);
695 std::cout << std::endl;
697 std::mt19937
gen{4242 +
698 actsParameter.referenceSurface().geometryId().value()};
699 std::normal_distribution<double> normal{0, 1};
701 Acts::ActsMatrix<2, 2> lltxy =
702 targetCov.topLeftCorner<2, 2>().llt().matrixL();
703 Acts::ActsMatrix<2, 2> lltpc = covpc.topLeftCorner<2, 2>().llt().matrixL();
705 for (
size_t i = 0;
i < 1
e4;
i++) {
706 std::cout <<
"ANNULUS PAR: ";
707 std::cout << actsParameter.referenceSurface().geometryId();
709 Acts::ActsVector<2> rnd;
710 rnd << normal(
gen), normal(
gen);
714 Acts::ActsVector<2> xy =
715 lltxy.topLeftCorner<2, 2>() * rnd + targetPars.head<2>();
719 for (
unsigned int i = 0;
i < 2;
i++) {
720 std::cout <<
"," << xy[
i];
722 std::cout <<
"," <<
xyz.x() <<
"," <<
xyz.y() <<
"," <<
xyz.z();
726 Acts::ActsVector<2> rt = lltpc.topLeftCorner<2, 2>() * rnd +
727 actsParameter.parameters().head<2>();
729 gctx, Acts::Vector2{rt.head<2>()}, Acts::Vector3{});
731 for (
unsigned int i = 0;
i < 2;
i++) {
732 std::cout <<
"," << rt[
i];
734 std::cout <<
"," <<
xyz.x() <<
"," <<
xyz.y() <<
"," <<
xyz.z();
737 std::cout << std::endl;
743 TrackFitResult_t& fitResult,
749 if (not fitResult.ok()) {
758 const auto& acts_track = fitResult.value();
760 auto finalTrajectory = std::make_unique<Trk::TrackStates>();
762 unsigned int numberOfDeadPixel{0}, numberOfDeadSCT{0};
768 tracks.trackStateContainer().visitBackwards(acts_track.tipIndex(),
769 [&] (
const auto &state) ->
void {
771 const auto* associatedDetEl = dynamic_cast<const IDetectorElementBase*>(
772 state.referenceSurface().associatedDetectorElement());
774 if (not associatedDetEl) {
775 ATH_MSG_VERBOSE(
"State is not associated with a measurement sruface");
779 auto flag = state.typeFlags();
782 std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePattern;
783 std::unique_ptr<Trk::TrackParameters> measPars{};
784 std::unique_ptr<Trk::MeasurementBase> measState{};
787 if (
flag.test(Acts::TrackStateFlag::HoleFlag)){
788 const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
792 measPars = actsTrackParametersToTrkParameters(actsParam, gctx);
793 if (associatedDetEl->detectorType() == DetectorType::Pixel ||
794 associatedDetEl->detectorType() == DetectorType::Sct) {
795 ATH_MSG_VERBOSE(
"Check if this is a hole, a dead sensors or a state outside the sensor boundary");
796 switch (m_boundaryCheckTool->boundaryCheck(*measPars)) {
797 case Trk::BoundaryCheckResult::DeadElement:
798 numberOfDeadPixel += (associatedDetEl->detectorType() == DetectorType::Pixel);
799 numberOfDeadSCT+= (associatedDetEl->detectorType() == DetectorType::Sct);
801 case Trk::BoundaryCheckResult::Candidate:
810 else if (
flag.test(Acts::TrackStateFlag::MeasurementFlag)) {
811 Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
815 typePattern.set(Trk::TrackStateOnSurface::Measurement);
817 using enum detail::SourceLinkType;
819 measState = measCalib.unpack(state.getUncalibratedSourceLink())->uniqueClone();
822 measState = prdCalib.createROT(gctx, cctx, state.getUncalibratedSourceLink(), state);
824 case xAODUnCalibMeas:
825 ATH_MSG_WARNING(
"Uncalibrated measurement is not implemented");
828 ATH_MSG_WARNING(
"Invalid type enumaration parsed");
831 nDoF = state.calibratedSize();
836 std::move(measState),
837 std::move(measPars),
nullptr, typePattern);
839 ATH_MSG_VERBOSE(
"State succesfully creates, adding it to the trajectory");
840 finalTrajectory->insert(finalTrajectory->begin(), std::move(perState));
843 const Acts::BoundTrackParameters actsPer(acts_track.referenceSurface().getSharedPtr(),
844 acts_track.parameters(),
845 acts_track.covariance(),
846 acts_track.particleHypothesis());
847 std::unique_ptr<Trk::TrackParameters> per = actsTrackParametersToTrkParameters(actsPer, gctx);
848 std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePattern;
850 auto perState = std::make_unique<Trk::TrackStateOnSurface>(
nullptr, std::move(per),
nullptr, typePattern);
851 finalTrajectory->insert(finalTrajectory->begin(), std::move(perState));
855 auto newtrack = std::make_unique<Trk::Track>(newInfo, std::move(finalTrajectory),
nullptr);
858 if (!newtrack->trackSummary()) {
859 newtrack->setTrackSummary(std::make_unique<Trk::TrackSummary>());
863 m_trkSummaryTool->updateTrackSummary(ctx, *newtrack,
true);