ATLAS Offline Software
Loading...
Searching...
No Matches
MuonR4::xAODSegmentCnvTool Class Reference

The xAODSegmentCnvTool takes a MuonR4::Segment and converts it into a xAOD::MuonSegment. More...

#include <xAODSegmentCnvTool.h>

Inheritance diagram for MuonR4::xAODSegmentCnvTool:
Collaboration diagram for MuonR4::xAODSegmentCnvTool:

Classes

struct  Counter
 Helper struct to keep track of the number of precision, trigger phi and trigger eta hits. More...

Public Member Functions

 ~xAODSegmentCnvTool ()=default
StatusCode initialize () override
xAOD::MuonSegmentconvertSegment (const EventContext &ctx, const MuonR4::Segment &inSegment, DataShip &ship) const override
 Convert a MuonR4::Segment to an xAOD::MuonSegment and decorate it with the necessary information.

Private Member Functions

StatusCode linkMeasurements (const Acts::GeometryContext &tgContext, const Segment &inSegment, xAOD::MuonSegment &targetSegment, DataShip &ship) const
 Decorate the prd links onto the output muon segment.
void evaluateSummary (const EventContext &ctx, xAOD::MuonSegment &segment) const
 Calculate the number of hits, outliers and holes on the segment and set the hit summary fields of the passed segment.
void findHoles (const EventContext &ctx, const Acts::BoundTrackParameters &startPars, const Acts::Surface *target, const std::unordered_set< Identifier > &geoIdsWithHits, Counter &holeCounter) const
 Find potential sensitive surfaces crossed by the segment but without contributing measurements.

Private Attributes

ServiceHandle< Muon::IMuonIdHelperSvcm_idHelperSvc
 IdHelperSvc for Identifier printing & manipulation.
ActsTrk::AuxiliaryMeasurementHandler m_auxMeasProv {this}
 Handler to parse the auxiliary beam spot constaint.
ServiceHandle< ActsTrk::ITrackingGeometrySvcm_trackingGeometrySvc {this, "TrackingGeometrySvc", "ActsTrackingGeometrySvc"}
 Tracking geometry tool to search for holes.
ToolHandle< ActsTrk::IExtrapolationToolm_extrapolationTool {this, "ExtrapolationTool", ""}
 Acts extrapolation tool to search for holes.
ActsTrk::ContextUtility m_ctxProvider {this}
 Context provider for geometry, magnetic field and calibration contexts.
Gaudi::Property< bool > m_estimateHoles {this, "estimateHoles", true}
 Flag to tell whether the hole summary shall be written.
Gaudi::Property< double > m_extraHolePath {this, "extraHolePath", 20.*Gaudi::Units::cm}
 Extra path length for the propagation after the last surface was crossed.

Detailed Description

The xAODSegmentCnvTool takes a MuonR4::Segment and converts it into a xAOD::MuonSegment.

The segments carry the global segment position and direction, the fit quality in terms of chi2 & nDoF, and the hit, outlier and hole hit count summary. For the latter, the algortihm optionally launches a hole search using the Acts::TrackingGeometry. Further, the local parameters and covariance from the fit are decorated onto the segment. Finally, the ElementLinks to the contributing measurements are attached. Prds from the uncombined space points (mainly Mdt, Mm, BI-RPC, sTGC pad) are directly appended to the list. The eta & phi measurements of Rpc/Tgc/sTgc which are within the same gasgap are combined in a CombindMuonStrip object which itself is then appended to the list. Optionally, the conversion alg can also convert the beamspot measurement into a xAOD::UncalibratedMeasurement. For each measurement, the flag whether it was an outlier or not is also stored.

Definition at line 18 of file xAODSegmentCnvTool.h.

Constructor & Destructor Documentation

◆ ~xAODSegmentCnvTool()

MuonR4::xAODSegmentCnvTool::~xAODSegmentCnvTool ( )
default

Member Function Documentation

◆ convertSegment()

xAOD::MuonSegment * MuonR4::xAODSegmentCnvTool::convertSegment ( const EventContext & ctx,
const MuonR4::Segment & inSegment,
DataShip & ship ) const
override

Convert a MuonR4::Segment to an xAOD::MuonSegment and decorate it with the necessary information.

Parameters
ctxThe event context
inSegmentThe input segment
shipThe data ship
Returns
: The converted segment

Definition at line 33 of file xAODSegmentCnvTool.cxx.

35 {
36
37 const Acts::GeometryContext tgContext = m_ctxProvider.getGeometryContext(ctx);
38 const MuonGMR4::SpectrometerSector* sector = inSegment.msSector();
39
40 xAOD::MuonSegment* convertedSeg = ship.segmentContainer->push_back(std::make_unique<xAOD::MuonSegment>());
41
42 const Amg::Vector3D& pos{inSegment.position()};
43 const Amg::Vector3D& dir{inSegment.direction()};
44 convertedSeg->setPosition(pos.x(), pos.y(), pos.z());
45 convertedSeg->setDirection(dir.x(), dir.y(), dir.z());
46
47 convertedSeg->setIdentifier(sector->sector(), sector->chamberIndex(),
48 sector->side(), inSegment.technology());
49 convertedSeg->setFitQuality(inSegment.chi2(), inSegment.nDoF());
50
51 using enum SegmentFit::ParamDefs;
52 convertedSeg->setT0Error(inSegment.segementT0(),
53 Amg::error(inSegment.covariance(), Acts::toUnderlying(t0)));
54
55 if (ship.dec_localSegPars) {
56 using SegPars_t = xAOD::PosAccessor<Acts::toUnderlying(SegmentFit::ParamDefs::nPars)>::element_type;
57 SegPars_t& localPars{ship.dec_localSegPars(*convertedSeg)};
58
59 const Amg::Transform3D globToLoc{sector->globalToLocalTransform(tgContext)};
60 const Amg::Vector3D locPos{globToLoc * pos};
61 const Amg::Vector3D locDir{globToLoc.linear() * dir};
62
63 localPars[Acts::toUnderlying(x0)] = locPos.x();
64 localPars[Acts::toUnderlying(y0)] = locPos.y();
65 localPars[Acts::toUnderlying(theta)] = locDir.theta();
66 localPars[Acts::toUnderlying(phi)] = locDir.phi();
67 localPars[Acts::toUnderlying(t0)] = inSegment.segementT0();
68 }
69
70 if (ship.dec_localSegCov) {
71 using SegCov_t = xAOD::PosAccessor<Acts::sumUpToN(Acts::toUnderlying(SegmentFit::ParamDefs::nPars))>::element_type;
72 SegCov_t& localCov{ship.dec_localSegCov(*convertedSeg)};
73 constexpr std::size_t n = Acts::toUnderlying(SegmentFit::ParamDefs::nPars);
74 for (std::size_t p = 1; p < n; ++p) {
75 for (std::size_t p1 = 0 ; p1 <=p;++p1) {
76 localCov[Acts::vecIdxFromSymMat<n>(p,p1)] = inSegment.covariance()(p, p1);
77 }
78 }
79 }
80
81 if (linkMeasurements(tgContext, inSegment, *convertedSeg, ship) != StatusCode::SUCCESS) {
82 ATH_MSG_ERROR("Failed to link measurements");
83 ship.segmentContainer->pop_back();
84 return nullptr;
85 }
86 evaluateSummary(ctx, *convertedSeg);
87 return convertedSeg;
88 }
Scalar phi() const
phi method
Scalar theta() const
theta method
#define ATH_MSG_ERROR(x,...)
static Double_t t0
int8_t side() const
Returns the side of the MS-sector 1 -> A side ; -1 -> C side.
Amg::Transform3D globalToLocalTransform(const ActsTrk::GeometryContext &gctx) const
Returns the global -> local transformation from the ATLAS global.
int sector() const
Returns the sector of the MS-sector.
Muon::MuonStationIndex::ChIndex chamberIndex() const
Returns the chamber index scheme.
double segementT0() const
Returns the fitted segment time, if there's any.
unsigned int nDoF() const
Returns the number of degrees of freedom.
const SegmentFit::Covariance & covariance() const
Returns the uncertainties of the defining parameters.
const MuonGMR4::SpectrometerSector * msSector() const
Returns the associated MS sector.
Muon::MuonStationIndex::TechnologyIndex technology() const
Returns the technology index of the first precision hit.
const Amg::Vector3D & position() const
Returns the global segment position.
const Amg::Vector3D & direction() const
Returns the global segment direction.
void evaluateSummary(const EventContext &ctx, xAOD::MuonSegment &segment) const
Calculate the number of hits, outliers and holes on the segment and set the hit summary fields of the...
ActsTrk::ContextUtility m_ctxProvider
Context provider for geometry, magnetic field and calibration contexts.
StatusCode linkMeasurements(const Acts::GeometryContext &tgContext, const Segment &inSegment, xAOD::MuonSegment &targetSegment, DataShip &ship) const
Decorate the prd links onto the output muon segment.
void setDirection(float px, float py, float pz)
Sets the direction.
void setFitQuality(float chiSquared, float numberDoF)
Set the 'Fit Quality' information.
void setT0Error(float t0, float t0Error)
Sets the time error.
void setPosition(float x, float y, float z)
Sets the global position.
void setIdentifier(const std::uint8_t sector, const ::Muon::MuonStationIndex::ChIndex chamberIndex, const std::int8_t etaIndex, const ::Muon::MuonStationIndex::TechnologyIndex technology)
Set the Identifier fields of the Segment.
double error(const Amg::MatrixX &mat, int index)
return diagonal error of the matrix caller should ensure the matrix is symmetric and the index is in ...
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
SeedingAux::FitParIndex ParamDefs
Use the same parameter indices as used by the CompSpacePointAuxiliaries.
xAOD::PosAccessor< Acts::toUnderlying(ParamDefs::nPars)>::element_type SegPars_t
SG::AuxElement::Accessor< std::array< float, N > > PosAccessor
xAOD Accessor to the position
MuonSegment_v1 MuonSegment
Reference the current persistent version:

◆ evaluateSummary()

void MuonR4::xAODSegmentCnvTool::evaluateSummary ( const EventContext & ctx,
xAOD::MuonSegment & segment ) const
private

Calculate the number of hits, outliers and holes on the segment and set the hit summary fields of the passed segment.

Parameters
ctxEventContext to access conditions data and to propagate
segmentThe segment for which the hit summary shall be evaluated

Instantiate one counter for hits, outliers, holes

Also write down the geometryIdentifiers of the segment measurements

Calculate the segment start parameters

Definition at line 238 of file xAODSegmentCnvTool.cxx.

239 {
240
242 Counter hits{}, outliers{}, holes{};
244 std::unordered_set<Identifier> crossedSurfaces{};
245 const std::size_t nMeas = nMeasurements(segment);
246
247 const Acts::Surface* startSurface{}, *lastSurface{};
248 const Acts::TrackingGeometry* trackingGeo = m_estimateHoles ? m_trackingGeometrySvc->trackingGeometry().get() : nullptr;
249
250 ATH_MSG_DEBUG(__func__<<"() "<<__LINE__<<" - Loop over "<<nMeas<<" measurements.");
251 for (std::size_t m = 0 ; m < nMeas; ++m) {
252 const xAOD::UncalibratedMeasurement* meas = getMeasurement(segment, m);
253 // Skip auxiliary constraints from summary, such as the beam spot (technically this should not happen because the beam spot is not considered as measurement here, but just in case )
254 if (meas->type() == xAOD::UncalibMeasType::Other) {
255 ATH_MSG_VERBOSE(__func__ << "() " << __LINE__
256 << " - Skip auxiliary measurement in segment summary");
257 continue;
258 }
259
260 const bool isOutlier = isOutlierMeasurement(segment, m);
261 Counter& increment = {isOutlier ? outliers: hits};
262
263 increment.precision += xAOD::isPrecisionHit(meas);
264 const auto* muonMeas = static_cast<const xAOD::MuonMeasurement*>(meas);
265
266 increment.triggerPhi += (muonMeas->measuresPhi() ||
267 //RPC BI / MDT twin or sTGC strip + pad hits
268 muonMeas->numDimensions() == 2);
269 increment.triggerEta += !xAOD::isPrecisionHit(muonMeas) && (
270 // 0D for combined strip + X measurements
271 (muonMeas->numDimensions() == 0 ) ||
272 // 1D strip/wire/pad (RPC,TGC, sTGC) cases
273 (muonMeas->numDimensions() == 1 && !muonMeas->measuresPhi() ) ||
274 //RPC BI for which measuresPhi = 0 as the phi is extracted from time information
275 (muonMeas->numDimensions() == 2));
276 // Count measurement holes of the trigger hits
277 if (!isOutlier && meas->numDimensions() == 1) {
279 //coverity[FORWARD_NULL]
280 const auto* re = static_cast<const MuonGMR4::RpcReadoutElement*>(muonMeas->readoutElement());
281 if (!muonMeas->measuresPhi() && re->nPhiStrips()) {
282 ++holes.triggerPhi;
283 } else if (muonMeas->measuresPhi()) {
284 ++holes.triggerEta;
285 }
286 } else if (meas->type() == xAOD::UncalibMeasType::TgcStripType) {
287 //coverity[FORWARD_NULL]
288 const auto* re = static_cast<const MuonGMR4::TgcReadoutElement*>(muonMeas->readoutElement());
289 if (!muonMeas->measuresPhi() && re->numStrips(muonMeas->layerHash())) {
290 ++holes.triggerPhi;
291 } else if (muonMeas->measuresPhi() && re->numWireGangs(muonMeas->layerHash())) {
292 ++holes.triggerEta;
293 }
294 } else if (meas->type() == xAOD::UncalibMeasType::sTgcStripType) {
295 if (!xAOD::isPrecisionHit(meas)) {
296 ++holes.precision;
297 } else {
298 ++holes.triggerPhi;
299 }
300 }
301 }
302
303 if (!m_estimateHoles) {
304 continue;
305 }
306 const Acts::Surface& surface = xAOD::muonSurface(meas);
307 if (!muonMeas){
308 continue;
309 }
310 crossedSurfaces.insert( muonMeas->type() != xAOD::UncalibMeasType::MdtDriftCircleType ?
311 m_idHelperSvc->gasGapId(muonMeas->identify()) :
312 muonMeas->identify());
313 const auto* volume = MuonGMR4::highestAlignable(trackingGeo->findVolume(volumeId(surface)));
314 assert(volume != nullptr);
315 if (!startSurface) {
316 startSurface = MuonGMR4::bottomBoundary(*volume);
317 } else if (m +1 == nMeas) {
318 lastSurface = MuonGMR4::topBoundary(*volume);
319 }
320 }
322 if (m_estimateHoles) {
323 const Acts::GeometryContext tgContext = m_ctxProvider.getGeometryContext(ctx);
324 std::shared_ptr<const Acts::Surface> startSurfPtr = startSurface->getSharedPtr();
325 auto atSurface = startSurface->intersect(tgContext, segment.position(), segment.direction(),
326 Acts::BoundaryTolerance::Infinite()).closest();
327
328 const auto locPos = startSurface->globalToLocal(tgContext, atSurface.position(), segment.direction());
329 if (!locPos.ok()) {
330 ATH_MSG_WARNING(__func__<<"() "<<__LINE__<<" - Intersection "<<Amg::toString(atSurface.position())
331 <<" is not on surface "<<startSurface->geometryId());
332 return;
333 }
334 if (!startSurface->insideBounds(*locPos)) {
335 const auto* volume = MuonGMR4::highestAlignable(trackingGeo->highestTrackingVolume()->
336 lowestTrackingVolume(tgContext, atSurface.position()));
337 ATH_MSG_DEBUG(__func__<<"() "<<__LINE__<<" - Intersection "<<Amg::toString(atSurface.position())
338 <<" is outside surface: "<<startSurface->geometryId()<<", "<<startSurface->bounds()<<". "
339 <<" Switch to volume "<<volume->geometryId()<<", bounds: "<<volume->volumeBounds());
340
341 if (volume->isAlignable()) {
342 startSurfPtr = MuonGMR4::bottomBoundary(*volume)->getSharedPtr();
343 atSurface = startSurfPtr->intersect(tgContext, segment.position(), segment.direction(),
344 Acts::BoundaryTolerance::Infinite()).closest();
345 } else {
346 startSurfPtr = Acts::Surface::makeShared<Acts::PlaneSurface>(startSurfPtr->localToGlobalTransform(tgContext));
347 }
348 }
349 auto startPars = Acts::BoundTrackParameters::create(tgContext, startSurfPtr,
350 ActsTrk::convertPosToActs(atSurface.position()),
351 segment.direction(), 1./ 5._TeV, std::nullopt,
352 Acts::ParticleHypothesis::muon());
353 if (startPars.ok()) {
354 findHoles(ctx, *startPars, lastSurface, crossedSurfaces, holes);
355 } else {
356 ATH_MSG_WARNING(__func__<<"() "<<__LINE__<<" - Start parameters not defined.");
357 }
358 }
359 segment.setNHits(hits.precision, hits.triggerPhi, hits.triggerEta);
360 segment.setNOutliers(outliers.precision, outliers.triggerPhi, outliers.triggerEta);
361 segment.setNHoles(holes.precision, holes.triggerPhi, holes.triggerEta);
362 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" Updated summary: "<<hits);
363 }
const std::regex re(r_e)
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
IdHelperSvc for Identifier printing & manipulation.
Gaudi::Property< bool > m_estimateHoles
Flag to tell whether the hole summary shall be written.
ServiceHandle< ActsTrk::ITrackingGeometrySvc > m_trackingGeometrySvc
Tracking geometry tool to search for holes.
void findHoles(const EventContext &ctx, const Acts::BoundTrackParameters &startPars, const Acts::Surface *target, const std::unordered_set< Identifier > &geoIdsWithHits, Counter &holeCounter) const
Find potential sensitive surfaces crossed by the segment but without contributing measurements.
Amg::Vector3D direction() const
Returns the direction as Amg::Vector.
void setNHits(const std::uint8_t nPrecisionHits, const std::uint8_t nPhiLayers, const std::uint8_t nTrigEtaLayers)
Assign the segment hit summary.
void setNOutliers(const std::uint8_t nPrecOutliers, const std::uint8_t nTrigPhiOutliers, const std::uint8_t nTrigEtaOutliers)
Assign the number of hits with a large pull per hit category.
void setNHoles(const std::uint8_t nPrecHoles, const std::uint8_t nTrigPhiHoles, const std::uint8_t nTrigEtaHoles)
Assign the number of expected but missing hits.
Amg::Vector3D position() const
Returns the position as Amg::Vector.
virtual unsigned int numDimensions() const =0
Returns the number of dimensions of the measurement.
virtual xAOD::UncalibMeasType type() const =0
Returns the type of the measurement type as a simple enumeration.
Acts::Vector4 convertPosToActs(const Amg::Vector3D &athenaPos, const double athenaTime=0.)
Converts a position vector & time from Athena units into Acts units.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
const Acts::Surface * bottomBoundary(const Acts::TrackingVolume &volume)
Returns the boundary surface parallel to the x-y plane at negative local z.
const Acts::TrackingVolume * highestAlignable(const Acts::TrackingVolume *volume)
Returns the highest parent volume that is alignable.
const Acts::Surface * topBoundary(const Acts::TrackingVolume &volume)
Returns the boundary surface parallel to the x-y plane at positive local z.
const xAOD::UncalibratedMeasurement * getMeasurement(const xAOD::MuonSegment &segment, const std::size_t n)
Returns the n-th uncalibrated measurement.
std::size_t nMeasurements(const xAOD::MuonSegment &segment)
Returns the number of associated Uncalibrated measurements.
Acts::GeometryIdentifier volumeId(const Acts::Surface &surface)
Returns the identifier of the volume in which the surface is embedded.
bool isOutlierMeasurement(const xAOD::MuonSegment &segment, const std::size_t n)
Returns whether the n-the uncalibrated measurement is an outlier.
UncalibratedMeasurement_v1 UncalibratedMeasurement
Define the version of the uncalibrated measurement class.
MuonMeasurement_v1 MuonMeasurement
bool isPrecisionHit(const UncalibratedMeasurement *meas)
Returns whether the measurement is a precision hit.
const Acts::Surface & muonSurface(const UncalibratedMeasurement *meas)
Returns the associated Acts surface to the measurement.
Helper struct to keep track of the number of precision, trigger phi and trigger eta hits.

◆ findHoles()

void MuonR4::xAODSegmentCnvTool::findHoles ( const EventContext & ctx,
const Acts::BoundTrackParameters & startPars,
const Acts::Surface * target,
const std::unordered_set< Identifier > & geoIdsWithHits,
Counter & holeCounter ) const
private

Find potential sensitive surfaces crossed by the segment but without contributing measurements.

The segment line is propagated from the startPars to the target surface + some margin using the Acts::Propagator. The propaator records every surface crossing. The associated SurfacePlacements are then used to determine the ATLAS identifier and then to assign whether there's a hole or not.

Parameters
ctxEventContext to be passed to the extrapolation tool
startParsThe start parameters from which the propagation starts. The surface is the bottom boundary surface of the volume where's the first segment measurement.
targetThe top boundary surface of the volume with the last segment measurement.
geoIdsWithHitsThe list of ATLAS identifiers with segmen measurements (outlier + hit)
holeCounterMutable reference to the segment hole counter.

Surface is already part of the measurement pool

We expect at least one hit in the same sector to avoid that hits in the sector-overlap from the adjacent chamber are marked as holes. While they are not part of the segment by construction

Definition at line 364 of file xAODSegmentCnvTool.cxx.

368 {
369
370
371 using SurfaceRecordOptions = ActsTrk::IExtrapolationTool::SurfaceRecordOptions;
372 SurfaceRecordOptions propOpts{target, m_extraHolePath};
373 propOpts.recordMaterial = false;
374 propOpts.recordPassive = false;
375 propOpts.recordSensitive = true;
376
377
378 auto propResult = m_extrapolationTool->propagateAndRecord(ctx, startPars, propOpts);
379 if (!propResult.ok()) {
380 return;
381 }
382
383 /* Loop over the track record to filter out the holes*/
384 for (Acts::BoundTrackParameters& record : (*propResult)) {
385 const auto* placement = dynamic_cast<const ActsTrk::SurfacePlacement*>(record.referenceSurface().surfacePlacement());
386 assert(placement != nullptr);
387 const auto* detEl = static_cast<const MuonGMR4::MuonReadoutElement*>(placement->detectorElement());
388 using enum ActsTrk::DetectorType;
390 if (layersWithHits.count(placement->identify())) {
391 continue;
392 }
397 if(std::ranges::none_of(layersWithHits,[&](const Identifier& recorded){
398 return m_idHelperSvc->chamberIndex(recorded) == detEl->chamberIndex() &&
399 m_idHelperSvc->stationPhi(recorded) == detEl->stationPhi();
400 })) {
401 ATH_MSG_DEBUG(__func__<<"() "<<__LINE__<<" - Surface "
402 <<m_idHelperSvc->toStringGasGap(placement->identify())<<" is not in the same sector");
403 continue;
404 }
405 switch (placement->detectorType()) {
406 case Mm:
407 case Mdt: {
408 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Precision hole detected "
409 <<m_idHelperSvc->toString(placement->identify()));
410 ++holeCounter.precision;
411 break;
412 } case Rpc: {
413 const auto* re = static_cast<const MuonGMR4::RpcReadoutElement*>(placement->detectorElement());
414 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Rpc hole detected "
415 <<m_idHelperSvc->toStringGasGap(placement->identify())<<".");
416 ++holeCounter.triggerEta;
417 holeCounter.triggerPhi += (re->nPhiStrips() > 0);
418 break;
419 } case Tgc: {
420 const auto* re = static_cast<const MuonGMR4::TgcReadoutElement*>(placement->detectorElement());
421 holeCounter.triggerEta += (re->numWireGangs(placement->hash())>0);
422 holeCounter.triggerPhi += (re->numStrips(placement->hash())>0);
423 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Tgc hole detected "
424 <<m_idHelperSvc->toStringGasGap(placement->identify())<<".");
425 break;
426 } case sTgc: {
427 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Precision hole detected "
428 <<m_idHelperSvc->toString(placement->identify()));
429 ++holeCounter.precision;
430 ++holeCounter.triggerPhi;
431 break;
432 } default:
433 ATH_MSG_WARNING(__func__<<"() "<<__LINE__<<" - Unknown detector type "
434 <<placement->detectorType());
435 break;
436 }
437 }
438 }
Gaudi::Property< double > m_extraHolePath
Extra path length for the propagation after the last surface was crossed.
ToolHandle< ActsTrk::IExtrapolationTool > m_extrapolationTool
Acts extrapolation tool to search for holes.
DetectorType
Simple enum to Identify the Type of the ACTS sub detector.
@ Mm
Maybe not needed in the migration.
@ Tgc
Resitive Plate Chambers.
@ sTgc
Micromegas (NSW).
@ Rpc
Monitored Drift Tubes.
@ Mdt
MuonSpectrometer.

◆ initialize()

StatusCode MuonR4::xAODSegmentCnvTool::initialize ( )
override

Definition at line 23 of file xAODSegmentCnvTool.cxx.

23 {
24 ATH_CHECK(m_idHelperSvc.retrieve());
25 ATH_CHECK(m_ctxProvider.initialize());
26 if (m_estimateHoles) {
28 }
29 ATH_CHECK(m_extrapolationTool.retrieve(EnableTool{m_estimateHoles}));
30 return StatusCode::SUCCESS;
31 }
#define ATH_CHECK
Evaluate an expression and check for errors.

◆ linkMeasurements()

StatusCode MuonR4::xAODSegmentCnvTool::linkMeasurements ( const Acts::GeometryContext & tgContext,
const Segment & inSegment,
xAOD::MuonSegment & targetSegment,
DataShip & ship ) const
private

Decorate the prd links onto the output muon segment.

Eta & phi measurements are absorbed converted into a CombinedMuonStrip which is a source link linke object carrying a link to both prds. In this way, only one track state is generated later in the track fit from the two measurements. Two assumptions are made for the linking

  • There's exclusivley one eta & one phi measurement @maximum on the segment
  • The measurements are sorted along the segment trajectory.
    Parameters
    tgContextThe geometry context to construct the local segment parameters
    inSegmentThe segment from which the space points are collected
    targetSegmentThe xAOD segment onto which all the links are decorated
    shipReference to the auxiliary ship carrying all the write decor handles needed for the linking

Combine the two prds from the space point to a combined muonstrip and link the latter to the segment.

Size of the bounds purely for visualization purposes

It might be that the segment has anoher 1D-measurement in the same gas gap

The first measurement should always be the eta measurement

Definition at line 90 of file xAODSegmentCnvTool.cxx.

93 {
94 if (!ship.dec_prdLinks || !ship.dec_prdStates || !ship.prdCombContainer.hasHandle()) {
95 ATH_MSG_DEBUG("Decorators for the prd links and states are not initialized");
96 return StatusCode::SUCCESS;
97 }
98
100 // Cache all measurements that can be combined to two measurements in a single gas gap
101 std::vector< std::tuple<const xAOD::MuonMeasurement*, State, std::size_t>> combineMap{};
102 std::vector< std::tuple<const xAOD::UncalibratedMeasurement*, State, std::size_t>> linkMap{};
103
104 using PrdLinkVec_t = std::vector<ElementLink<xAOD::UncalibratedMeasurementContainer>>;
105 PrdLinkVec_t& links = ship.dec_prdLinks(targetSegment);
106 std::vector<char>& linkStates = ship.dec_prdStates(targetSegment);
107 links.reserve(2*inSegment.measurements().size());
108 linkStates.reserve(2*inSegment.measurements().size());
109
112 auto combine = [&](const xAOD::MuonMeasurement* m1,
113 const xAOD::MuonMeasurement* m2) {
114 auto cmbMeas = ship.prdCombContainer->push_back(std::make_unique<xAOD::CombinedMuonStrip>());
115
116 cmbMeas->setPrimaryStrip(m1);
117 cmbMeas->setSecondaryStrip(m2);
118 const auto [locPos, locCov] = xAOD::positionAndCovariance(m1, m2);
119 cmbMeas->localCovariance<2>() = xAOD::toStorage(locCov);
120 cmbMeas->localPosition<2>() = xAOD::toStorage(locPos);
121 const Identifier id1{m1->identify()}, id2{m2->identify()};
122 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Combine "<<m_idHelperSvc->toString(id1)
123 <<" & "<<m_idHelperSvc->toString(id2));
124 if ((m1->type() != xAOD::UncalibMeasType::sTgcStripType ||
125 m_idHelperSvc->stgcIdHelper().channelType(id1) ==
126 m_idHelperSvc->stgcIdHelper().channelType(id2))&&
127 m_idHelperSvc->measuresPhi(id1) == m_idHelperSvc->measuresPhi(id2)) {
128 THROW_EXCEPTION("Cannot combine "<<m_idHelperSvc->toString(id1)
129 <<" & "<<m_idHelperSvc->toString(id2));
130 }
131 return cmbMeas;
132 };
133 // Loop over the measurements
134 for (const auto [segIdx, meas] : Acts::enumerate(inSegment.measurements())) {
135 const SpacePoint* sp = meas->spacePoint();
136 if (!sp) {
137 if (!ship.beamSpotMeasCreator.ok()) {
138 continue;
139 }
140 // Up to now, there's no variety on the beamspot across the segments
141 if (!ship.beamSpot) {
142 if (!ship.beamSpotMeasCreator.ok()) {
143 ATH_MSG_ERROR("Cannot create a beamspot measurement");
144 return StatusCode::FAILURE;
145 }
146
147 const Amg::Vector3D beamSpot = inSegment.msSector()->localToGlobalTransform(tgContext) *
148 meas->localPosition();
149 AmgSymMatrix(2) covariance{AmgSymMatrix(2)::Identity()};
150 using CovIdx = SpacePoint::CovIdx;
151 using ProjectorType = xAOD::AuxiliaryMeasurement::ProjectorType;
152 covariance(0,0) = meas->covariance()[Acts::toUnderlying(CovIdx::etaCov)];
153 covariance(1,1) = meas->covariance()[Acts::toUnderlying(CovIdx::phiCov)];
155 auto surf = Acts::Surface::makeShared<Acts::StrawSurface>(Amg::getTranslate3D(beamSpot),
156 std::make_shared<Acts::LineBounds>(std::sqrt(covariance(0,0)), 20._m));
157
158 ship.beamSpot = ship.beamSpotMeasCreator->newMeasurement<2>(surf, ProjectorType::e2DimNoTime, covariance);
159 ATH_MSG_DEBUG(__func__<<"() "<<__LINE__<<" - Created beamspot measurement "<<(*meas)<<", "
160 <<surf->toString(tgContext));
161 }
162 linkMap.emplace_back(ship.beamSpot, meas->fitState(), segIdx);
163 continue;
164 }
165 switch (sp->type()) {
166 using enum xAOD::UncalibMeasType;
167 // Mdt & micromegas are never combined
169 case MMClusterType: {
170 linkMap.emplace_back(sp->primaryMeasurement(), meas->fitState(), segIdx);
171 break;
172 } case RpcStripType:
173 case TgcStripType:
174 case sTgcStripType: {
175 if (sp->primaryMeasurement() && sp->secondaryMeasurement()) {
176 if (sp->primaryMeasurement() != sp->secondaryMeasurement()) {
177 linkMap.emplace_back(combine(sp->primaryMeasurement(),
178 sp->secondaryMeasurement()),
179 meas->fitState(), segIdx);
180 } else { // BI - RPC measurements
181 linkMap.emplace_back(sp->primaryMeasurement(), meas->fitState(), segIdx);
182 }
183 } else {
186 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Append for later combination "<<(*meas));
187 combineMap.emplace_back(sp->primaryMeasurement(), meas->fitState(), segIdx);
188 }
189 break;
190 } default:
191 break;
192 }
193 }
194
195 // Finally we need to check whether there're measurements left to combine
196 for (std::size_t cmbIdx = 0; cmbIdx < combineMap.size(); ++cmbIdx){
197 const xAOD::MuonMeasurement* m1{std::get<0>(combineMap[cmbIdx])};
198 const State s1{std::get<1>(combineMap[cmbIdx])};
199 const std::size_t segIdx1{std::get<2>(combineMap[cmbIdx])};
200 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Find another measurement to combine with "
201 <<m_idHelperSvc->toString(m1->identify()));
202 if (cmbIdx +1 < combineMap.size()) {
203 const xAOD::MuonMeasurement* m2{std::get<0>(combineMap[cmbIdx +1])};
204 const State s2{std::get<1>(combineMap[cmbIdx+1])};
205 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - Check whether "<<m_idHelperSvc->toString(m2->identify())
206 <<" is a good candidate");
207 // Ensure that they point to the same detector element, are within the same
208 // layer and have also the same state
209 if (m1->type() == m2->type() && m1->identifierHash() == m2->identifierHash() &&
210 m1->layerHash() == m2->layerHash() && s1 == s2) {
212 ATH_MSG_VERBOSE(__func__<<"() "<<__LINE__<<" - They match");
213 if (m1->measuresPhi()) {
214 linkMap.emplace_back(combine(m2, m1), s2, segIdx1);
215 } else {
216 linkMap.emplace_back(combine(m1, m2), s1, segIdx1);
217 }
218 ++cmbIdx; // skip the next measurement as it's absorbed here
219 continue;
220 }
221 }
222 ATH_MSG_VERBOSE("No match found");
223 linkMap.emplace_back(m1, s1, segIdx1);
224 }
225
226 std::ranges::sort(linkMap, [](const auto& a, const auto& b){
227 return std::get<2>(a) < std::get<2>(b);
228 });
229
230 for (const auto& [prd, state, segIdx]: linkMap) {
231 links.emplace_back(*static_cast<const xAOD::UncalibratedMeasurementContainer*>(prd->container()),
232 prd->index());
233 linkStates.emplace_back(Acts::toUnderlying(state));
234 }
235 return StatusCode::SUCCESS;
236 }
#define AmgSymMatrix(dim)
static Double_t sp
static Double_t a
State
State flag to distinguish different space point states.
ActsTrk::detail::MeasurementCalibratorBase::ProjectorType ProjectorType
Use the calibration projector.
Amg::Transform3D getTranslate3D(const double X, const double Y, const double Z)
: Returns a shift transformation along an arbitrary axis
size_t combine(size_t lhs, size_t rhs)
Definition hash.h:22
CalibratedSpacePoint::State State
std::vector< PrdLink_t > PrdLinkVec_t
AthConfigFlags beamSpot(AthConfigFlags flags, str instanceName, str recoMode)
MeasVector< N > toStorage(const AmgVector(N)&amgVec)
Converts the double precision of the AmgVector into the floating point storage precision of the MeasV...
UncalibMeasType
Define the type of the uncalibrated measurement.
std::pair< Amg::Vector2D, AmgSymMatrix(2)> positionAndCovariance(const MuonMeasurement *oneDimMeas)
Returns the 1D position of the uncalibrated measurement expressed in the coordinate system of the mea...
UncalibratedMeasurementContainer_v1 UncalibratedMeasurementContainer
Define the version of the uncalibrated measurement container.
#define THROW_EXCEPTION(MESSAGE)
Definition throwExcept.h:10

Member Data Documentation

◆ m_auxMeasProv

ActsTrk::AuxiliaryMeasurementHandler MuonR4::xAODSegmentCnvTool::m_auxMeasProv {this}
private

Handler to parse the auxiliary beam spot constaint.

Definition at line 86 of file xAODSegmentCnvTool.h.

86{this};

◆ m_ctxProvider

ActsTrk::ContextUtility MuonR4::xAODSegmentCnvTool::m_ctxProvider {this}
private

Context provider for geometry, magnetic field and calibration contexts.

Definition at line 92 of file xAODSegmentCnvTool.h.

92{this};

◆ m_estimateHoles

Gaudi::Property<bool> MuonR4::xAODSegmentCnvTool::m_estimateHoles {this, "estimateHoles", true}
private

Flag to tell whether the hole summary shall be written.

Definition at line 95 of file xAODSegmentCnvTool.h.

95{this, "estimateHoles", true};

◆ m_extraHolePath

Gaudi::Property<double> MuonR4::xAODSegmentCnvTool::m_extraHolePath {this, "extraHolePath", 20.*Gaudi::Units::cm}
private

Extra path length for the propagation after the last surface was crossed.

Definition at line 97 of file xAODSegmentCnvTool.h.

97{this, "extraHolePath", 20.*Gaudi::Units::cm};

◆ m_extrapolationTool

ToolHandle<ActsTrk::IExtrapolationTool> MuonR4::xAODSegmentCnvTool::m_extrapolationTool {this, "ExtrapolationTool", ""}
private

Acts extrapolation tool to search for holes.

Definition at line 90 of file xAODSegmentCnvTool.h.

90{this, "ExtrapolationTool", ""};

◆ m_idHelperSvc

ServiceHandle<Muon::IMuonIdHelperSvc> MuonR4::xAODSegmentCnvTool::m_idHelperSvc
private
Initial value:
{this, "MuonIdHelperSvc",
"Muon::MuonIdHelperSvc/MuonIdHelperSvc"}

IdHelperSvc for Identifier printing & manipulation.

Definition at line 83 of file xAODSegmentCnvTool.h.

83 {this, "MuonIdHelperSvc",
84 "Muon::MuonIdHelperSvc/MuonIdHelperSvc"};

◆ m_trackingGeometrySvc

ServiceHandle<ActsTrk::ITrackingGeometrySvc> MuonR4::xAODSegmentCnvTool::m_trackingGeometrySvc {this, "TrackingGeometrySvc", "ActsTrackingGeometrySvc"}
private

Tracking geometry tool to search for holes.

Definition at line 88 of file xAODSegmentCnvTool.h.

88{this, "TrackingGeometrySvc", "ActsTrackingGeometrySvc"};

The documentation for this class was generated from the following files: