ATLAS Offline Software
Loading...
Searching...
No Matches
MuonSystemExtensionTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
17
18namespace{
19 template <class T>
20 std::string to_string(const std::vector<T>& v) {
21 std::stringstream ostr{};
22 ostr<<"{";
23 for (auto x: v)ostr<<x<<", ";
24 ostr<<"}";
25 return ostr.str();
26 }
28 double pathAlongPars(const Trk::TrackParameters& pars, const Amg::Vector3D& pos) {
29 const Amg::Vector3D parDir{pars.momentum().unit()};
30 return (pars.position().dot(parDir) > 0 ? 1 : -1) * (parDir.dot(pos));
31 }
32}
33namespace Muon {
34
37 ATH_CHECK(m_extrapolator.retrieve());
38 ATH_CHECK(m_idHelperSvc.retrieve());
39 if (!initializeGeometry()) return StatusCode::FAILURE;
40
41 return StatusCode::SUCCESS;
42 }
43
45 // initialize reference surfaces hash vectors per region and sector
46
47 // first build the barrel, we need different reference planes for all sectors
48 ATH_MSG_DEBUG("Initializing barrel ");
49 for (unsigned int sector = 1; sector <= 16; ++sector) {
50 // get rotation into sector frame
51 double sectorPhi = m_sectorMapping.sectorPhi(sector);
52 const Amg::Transform3D sectorRotation(Amg::getRotateZ3D(sectorPhi));
53 if (!initializeGeometryBarrel(sector, sectorRotation)) return false;
54 if (!initializeGeometryEndcap(sector, DetRegIdx::EndcapA, sectorRotation)) return false;
55 if (!initializeGeometryEndcap(sector, DetRegIdx::EndcapC, sectorRotation)) return false;
56 }
57
58 return true;
59 }
60
62 const Amg::Transform3D& sectorRotation) {
63 using namespace MuonStationIndex;
64 ATH_MSG_DEBUG("Initializing endcap: sector " << sector << " " << regionName(regionIndex));
65
66 SurfaceVec& surfaces = m_referenceSurfaces[toInt(regionIndex)][sector - 1];
67 MuonChamberLayerDescription chamberLayerDescription;
68
69 static constexpr std::array<StIndex, 4> layers{StIndex::EI, StIndex::EE, StIndex::EM, StIndex::EO};
70
71 for (const StIndex stLayer : layers) {
72 // calculate reference position from radial position of the layer
73 LayerIndex layer = toLayerIndex(stLayer);
74 MuonChamberLayerDescriptor layerDescriptor = chamberLayerDescription.getDescriptor(sector, regionIndex, layer);
75 // reference transform + surface
76 Amg::Transform3D trans{Amg::getTranslateZ3D(layerDescriptor.referencePosition) *sectorRotation}; //*Amg::AngleAxis3D(xToZRotation,Amg::Vector3D(0.,1.,0.)
77 std::unique_ptr<Trk::PlaneSurface> surface = std::make_unique<Trk::PlaneSurface>(trans);
78 // sanity checks
79
80 ATH_MSG_VERBOSE("initializeGeometryEndcap() -- sector " << sector << " layer " << layerName(layer)
81 << " surface "<<Amg::toString(surface->transform())
82 << " center " << Amg::toString(surface->center()) << " theta " << surface->normal().theta()
83 << " normal: " <<Amg::toString(surface->normal()));
84
85 MuonLayerSurface data(std::move(surface), sector, regionIndex, layer);
86 surfaces.push_back(std::move(data));
87
88
89 }
90 ATH_MSG_VERBOSE(" Total number of surfaces " << surfaces.size());
91 return true;
92 }
93
95 MuonChamberLayerDescription chamberLayerDescription;
96
97 using namespace MuonStationIndex;
98 SurfaceVec& surfaces = m_referenceSurfaces[toInt(DetectorRegionIndex::Barrel)][sector - 1];
99 constexpr double xToZRotation = -M_PI_2;
100
101 for (const StIndex stationLayer : {StIndex::BI, StIndex::BM, StIndex::BO, StIndex::BE}) {
102 // skip BEE if in small sectors, not installed
103 if (stationLayer == StIndex::BE && m_sectorMapping.isSmall(sector)) continue;
104
105 // calculate reference position from radial position of the laeyr
106 LayerIndex layer = toLayerIndex(stationLayer);
107 MuonChamberLayerDescriptor layerDescriptor = chamberLayerDescription.getDescriptor(sector, DetectorRegionIndex::Barrel, layer);
108 Amg::Vector3D positionInSector(layerDescriptor.referencePosition, 0., 0.);
109 Amg::Vector3D globalPosition = sectorRotation * positionInSector;
110
111 // reference transform + surface
112 Amg::Transform3D trans(sectorRotation * Amg::getRotateY3D(xToZRotation));
113 trans.pretranslate(globalPosition);
114 std::unique_ptr<Trk::PlaneSurface> surface = std::make_unique<Trk::PlaneSurface>(trans);
115 // sanity checks
116 if (msgLvl(MSG::VERBOSE)) {
117 double sectorPhi = m_sectorMapping.sectorPhi(sector);
118 ATH_MSG_VERBOSE(" sector " << sector << " layer " << MuonStationIndex::layerName(layer) << " phi " << sectorPhi
119 << " ref theta " << globalPosition.theta() << " phi " << globalPosition.phi() << " r "
120 << globalPosition.perp() << " pos " << Amg::toString(globalPosition)
121 << " lpos3d " << Amg::toString(surface->transform().inverse() * globalPosition)
122 << " normal: " << Amg::toString(surface->normal()));
123 }
124 MuonLayerSurface data{std::move(surface), sector, DetectorRegionIndex::Barrel, layer};
125 surfaces.push_back(std::move(data));
126 }
127 return true;
128 }
129
130 bool MuonSystemExtensionTool::muonSystemExtension(const EventContext& ctx, SystemExtensionCache& cache) const {
132 if (!cache.candidate->getCaloExtension()) {
133 if (!cache.extensionContainer) {
134 std::unique_ptr<Trk::CaloExtension> caloExtension =
135 m_caloExtensionTool->caloExtension(ctx, cache.candidate->indetTrackParticle());
136 if (!caloExtension || !caloExtension->muonEntryLayerIntersection()) {
137 ATH_MSG_VERBOSE("Failed to create the calo extension for "<<cache.candidate->toString());
138 return false;
139 }
140 cache.candidate->setExtension(caloExtension);
141 } else {
142 const Trk::CaloExtension* caloExtension = m_caloExtensionTool->caloExtension(cache.candidate->indetTrackParticle(),
143 *cache.extensionContainer);
144 if (!caloExtension || !caloExtension->muonEntryLayerIntersection()) {
145 ATH_MSG_VERBOSE("Failed to create the calo extension for "<<cache.candidate->toString());
146 return false;
147 }
148 cache.candidate->setExtension(caloExtension);
149 }
150 }
151
152 if (!cache.createSystemExtension) {
153 ATH_MSG_VERBOSE("No system extension is required for "<<cache.candidate->toString());
154 return true;
155 }
156 // get entry parameters, use it as current parameter for the extrapolation
157 const Trk::TrackParameters* currentPars = cache.candidate->getCaloExtension()->muonEntryLayerIntersection();
158
159 // get reference surfaces
160 ATH_MSG_VERBOSE(" getSurfacesForIntersection " << currentPars);
161 SurfaceVec surfaces = getSurfacesForIntersection(*currentPars, cache);
162
163 // store intersections
164 std::vector<MuonSystemExtension::Intersection> intersections;
165
166 // garbage collection
167 std::vector<std::shared_ptr<Trk::TrackParameters> > trackParametersVec;
168
169 // loop over reference surfaces
170 for (const MuonLayerSurface& it : surfaces) {
171 // extrapolate to next layer
172 const Trk::Surface& surface = *it.surfacePtr;
173 ATH_MSG_VERBOSE(" startPars: "<<m_printer->print(*currentPars));
174 ATH_MSG_VERBOSE(" destination: sector " << it.sector << " " << MuonStationIndex::regionName(it.regionIndex) << " "
175 << MuonStationIndex::layerName(it.layerIndex) << " phi " << surface.center().phi()
176 << " r " << surface.center().perp() << " z " << surface.center().z());
177
178 std::unique_ptr<Trk::TrackParameters> exPars{m_extrapolator->extrapolate(ctx, *currentPars, surface,
180 if (!exPars) {
181 ATH_MSG_VERBOSE("extrapolation failed, trying next layer ");
182 continue;
183 }
184 ATH_MSG_DEBUG("Extrapolated in event "<<ctx.eventID().event_number()<<" track @ "<<m_printer->print(*exPars));
185
186 // reject intersections with very big uncertainties (parallel to surface)
187 const double sigma_lx = Amg::error(*exPars->covariance(), Trk::locX);
188 const double sigma_ly = Amg::error(*exPars->covariance(), Trk::locY);
189 if (!Amg::hasPositiveDiagElems(*exPars->covariance()) || std::max(sigma_lx, sigma_ly) > 1. * Gaudi::Units::meter){
190 ATH_MSG_DEBUG("Reject bad extrapolation "<<m_printer->print(*exPars));
191 continue;
192 }
193
194 // create shared pointer and add to garbage collection
195 std::shared_ptr<Trk::TrackParameters> sharedPtr{std::move(exPars)};
196 trackParametersVec.emplace_back(sharedPtr);
197
198 intersections.emplace_back(sharedPtr, it);
199 constexpr double TenCm = 10. * Gaudi::Units::cm;
200 if(std::hypot(sigma_lx, sigma_ly) < std::max(TenCm, 10. * std::hypot(Amg::error(*currentPars->covariance(), Trk::locX),
201 Amg::error(*currentPars->covariance(), Trk::locY)))) {
202 // only update the parameters if errors don't blow up
203 currentPars = sharedPtr.get();
204 } else {
205 ATH_MSG_DEBUG("Extrapolation reached at "<<m_printer->print(*sharedPtr)<<" has larger uncertainties than "<<
206 m_printer->print(*currentPars));
207 }
208 }
209 ATH_MSG_DEBUG("Completed extrapolation: destinations " << surfaces.size() << " intersections " << intersections.size());
210 if (intersections.empty()){
211 ATH_MSG_DEBUG("No system extensions are made for "<<cache.candidate->toString()
212 <<" will accept the candidate: "<< (!cache.requireSystemExtension ? "si": "no"));
213 return !cache.requireSystemExtension;
214 }
215 cache.candidate->setExtension(std::make_unique<MuonSystemExtension>(cache.candidate->getCaloExtension()->muonEntryLayerIntersection(),
216 std::move(intersections)));
217 return true;
218 }
220 const SystemExtensionCache& cache) const {
221 using namespace MuonStationIndex;
222 // if in endcaps pick endcap surfaces
223 const double eta = muonEntryPars.position().eta();
224 DetectorRegionIndex regionIndex = DetectorRegionIndex::Barrel;
225 if (eta < -1.05) regionIndex = DetectorRegionIndex::EndcapC;
226 if (eta > 1.05) regionIndex = DetectorRegionIndex::EndcapA;
227
228 // in barrel pick primary sector
229 const double phi = muonEntryPars.position().phi();
230 std::vector<int> sectors;
231 m_sectorMapping.getSectors(phi, sectors);
232 SurfaceVec surfaces;
234 if (cache.useHitSectors) {
235 const auto map_itr = cache.sectorsWithHits->find(regionIndex);
236 if (map_itr == cache.sectorsWithHits->end()) {
237 ATH_MSG_DEBUG("No hits in detector region " << regionName(regionIndex));
238 return surfaces;
239 }
240 std::vector<int>::const_iterator sec_itr = std::find_if(
241 sectors.begin(), sectors.end(), [&map_itr](const int sector) -> bool { return map_itr->second.count(sector); });
242 if (sec_itr == sectors.end()) {
243 ATH_MSG_DEBUG("No hits found for sector " << m_sectorMapping.getSector(phi)
244 << " in MuonStation " << regionName(regionIndex));
245 return surfaces;
246 }
247 }
248
249 for (const int sector : sectors) {
250 const SurfaceVec& toInsert{m_referenceSurfaces[toInt(regionIndex)][sector - 1]};
251 surfaces.insert(surfaces.end(), toInsert.begin(), toInsert.end());
252 }
253 std::stable_sort(surfaces.begin(), surfaces.end(),
254 [&muonEntryPars](const MuonLayerSurface& s1, const MuonLayerSurface& s2) {
255 return std::abs(pathAlongPars(muonEntryPars,s1.surfacePtr->center())) <
256 std::abs(pathAlongPars(muonEntryPars,s2.surfacePtr->center()));
257
258 });
259 if (msgLvl(MSG::VERBOSE)) {
260 for (auto& s1 : surfaces) {
261 ATH_MSG_VERBOSE("Surface "<<layerName(s1.layerIndex)
262 <<", center: "<<Amg::toString(s1.surfacePtr->center())
263 <<", pathAlongPars "<<pathAlongPars(muonEntryPars,s1.surfacePtr->center())
264 <<std::endl<<(*s1.surfacePtr));
265
266 }
267 }
268 return surfaces;
269 }
271 const MuonCombined::TagBase& cmbTag,
272 SystemExtensionCache& cache) const{
273
274 const Trk::Track* cmbTrk = cmbTag.primaryTrack();
275 if (!cmbTrk){
276 ATH_MSG_WARNING("A combined tag without any track? Please check "<<cmbTag.toString());
277 return false;
278 }
280 const Trk::TrackParameters* entryPars = cache.candidate->getCaloExtension()->muonEntryLayerIntersection();
281 std::vector<const Trk::TrackStateOnSurface*> cmbParVec{};
282
283 ATH_MSG_VERBOSE("Calo entry parameters "<<m_printer->print(*entryPars));
284 std::vector<MuonSystemExtension::Intersection> intersections{};
285 MuonLayerSurface lastSurf{};
286
287 const Trk::TrackStates::const_iterator end_itr = cmbTrk->trackStateOnSurfaces()->end();
288 for (Trk::TrackStates::const_iterator itr = cmbTrk->trackStateOnSurfaces()->begin(); itr != end_itr; ++itr) {
289 const Trk::TrackStateOnSurface* msTSOS{*itr};
290 ATH_MSG_VERBOSE("Track state "<<m_printer->print(*msTSOS));
291
292 if (!msTSOS->measurementOnTrack()) {
293 continue;
294 }
295 const Identifier measId = m_edmHelperSvc->getIdentifier(*msTSOS->measurementOnTrack());
296 const Trk::TrackParameters& msPars{*msTSOS->trackParameters()};
298 if (!m_idHelperSvc->isMuon(measId) || pathAlongPars(msPars, msPars.position() - entryPars->position())< 0.){
299 continue;
300 }
301
302
303 using namespace MuonStationIndex;
304 DetectorRegionIndex regionIdx = m_idHelperSvc->regionIndex(measId);
305 LayerIndex layerIdx = m_idHelperSvc->layerIndex(measId);
306 if (layerIdx == LayerIndex::BarrelExtended) {
307 regionIdx = DetectorRegionIndex::Barrel;
308 layerIdx = LayerIndex::Inner;
309 }
310
311 const int sector = m_sectorMapping.getSector(msTSOS->measurementOnTrack()->associatedSurface().center().phi());
312
314 if (lastSurf.layerIndex == layerIdx && lastSurf.regionIndex == regionIdx && lastSurf.sector == sector) {
315 continue;
316 }
317 const SurfaceVec& refSurfaces = m_referenceSurfaces[toInt(regionIdx)][sector - 1];
318 SurfaceVec::const_iterator surfItr = std::find_if(refSurfaces.begin(), refSurfaces.end(),
319 [&layerIdx](const MuonLayerSurface& surf){
320 return surf.layerIndex == layerIdx;
321 });
322 if (surfItr == refSurfaces.end()) {
323 ATH_MSG_WARNING("Failed to find a reference surface matching to combined parameters "<<m_printer->print(*msTSOS)
324 <<", sector: "<<sector <<", layer: "<<layerName(layerIdx)
325 <<", region index: "<<regionName(regionIdx));
326 continue;
327 }
328 lastSurf = (*surfItr);
329 const Trk::Surface& target{*lastSurf.surfacePtr};
330
332 for (Trk::TrackStates::const_iterator closePars = itr+1; closePars != end_itr; ++closePars) {
333 const Trk::TrackStateOnSurface * tsosInChamb{*closePars};
334 if (!tsosInChamb->measurementOnTrack()) continue;
335
336 const Trk::TrackParameters& chPars{*tsosInChamb->trackParameters()};
337 if (std::abs(pathAlongPars(chPars, chPars.position() - target.center())) >
338 std::abs(pathAlongPars(*msTSOS->trackParameters(),
339 msTSOS->trackParameters()->position() - target.center()))) {
340 break;
341 }
342 itr = closePars -1;
343 msTSOS = *itr;
344 }
345
346 std::unique_ptr<Trk::TrackParameters> exPars{m_extrapolator->extrapolate(ctx, *msTSOS->trackParameters(),
347 target, Trk::anyDirection, false, Trk::muon)};
348 if (!exPars) {
349 ATH_MSG_VERBOSE(__LINE__<<" - Failed to extrapolate track @ "<<m_printer->print(*msTSOS)
350 <<", sector: "<<sector <<", layer: "<<layerName(layerIdx)
351 <<", region index: "<<regionName(regionIdx) <<" to surface "<<std::endl<<target<<std::endl
352 <<", sector: "<<lastSurf.sector <<", layer: "<<layerName(lastSurf.layerIndex)
353 <<", region index: "<<regionName(lastSurf.regionIndex)
354 <<" pathAlongPars "<<pathAlongPars(*msTSOS->trackParameters(), target.center())
355 <<", dir: "<<Amg::toString(msTSOS->trackParameters()->momentum().unit()));
356 continue;
357 }
358 intersections.emplace_back(std::move(exPars), lastSurf);
359
360 }
361
362 ATH_MSG_VERBOSE("Selected "<<intersections.size()<<" intersections");
363
364 if (intersections.empty()) {
365 ATH_MSG_DEBUG("Failed to find the intersections for the combined track");
366 return false;
367 }
368 cache.candidate->setExtension(std::make_unique<MuonSystemExtension>(entryPars, std::move(intersections)));
369
370 return true;
371 }
372} // namespace Muon
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
static std::string to_string(const std::vector< T > &v)
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
#define x
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
const_iterator end() const noexcept
Return a const_iterator pointing past the end of the collection.
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
base-class for combined reconstruction output Provides access to MuonType and Author
Definition TagBase.h:48
virtual const Trk::Track * primaryTrack() const
access to primary muon system track, zero if non available
Definition TagBase.h:89
virtual std::string toString() const =0
print content to string
class managing geometry of the chamber layers
MuonChamberLayerDescriptor getDescriptor(int sector, DetRegIdx region, LayerIdx layer) const
std::vector< MuonLayerSurface > SurfaceVec
ToolHandle< Trk::IParticleCaloExtensionTool > m_caloExtensionTool
MuonSectorMapping m_sectorMapping
sector mapping helper
MuonStationIndex::DetectorRegionIndex DetRegIdx
reference surfaces per region and sector
ToolHandle< Trk::IExtrapolator > m_extrapolator
ServiceHandle< IMuonIdHelperSvc > m_idHelperSvc
bool initializeGeometryBarrel(int sector, const Amg::Transform3D &sectorRotation)
bool muonLayerInterSections(const EventContext &ctx, const MuonCombined::TagBase &cmb_tag, SystemExtensionCache &cache) const override
bool muonSystemExtension(const EventContext &ctx, SystemExtensionCache &cache) const override
get muon system extension
std::array< std::array< SurfaceVec, 16 >, MuonStationIndex::toInt(DetRegIdx::DetectorRegionIndexMax)> m_referenceSurfaces
bool initializeGeometry()
initialize geometry
SurfaceVec getSurfacesForIntersection(const Trk::TrackParameters &muonEntryPars, const SystemExtensionCache &cache) const
get surfaces to be intersected for a given start parameters
ServiceHandle< IMuonEDMHelperSvc > m_edmHelperSvc
PublicToolHandle< MuonEDMPrinterTool > m_printer
bool initializeGeometryEndcap(int sector, MuonStationIndex::DetectorRegionIndex regionIndex, const Amg::Transform3D &sectorRotation)
Tracking class to hold the extrapolation through calorimeter Layers Both the caloEntryLayerIntersecti...
const TrackParameters * muonEntryLayerIntersection() const
access to intersection with the muon entry layer return nullptr if the intersection failed
virtual const Surface & associatedSurface() const =0
Interface method to get the associated Surface.
const Amg::Vector3D & momentum() const
Access method for the momentum.
const Amg::Vector3D & position() const
Access method for the position.
Abstract Base Class for tracking surfaces.
const Amg::Vector3D & center() const
Returns the center position of the Surface.
represents the track state (measurement, material, fit parameters and quality) at a surface.
const MeasurementBase * measurementOnTrack() const
returns MeasurementBase const overload
const TrackParameters * trackParameters() const
return ptr to trackparameters const overload
const Trk::TrackStates * trackStateOnSurfaces() const
return a pointer to a const DataVector of const TrackStateOnSurfaces.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Amg::Transform3D getTranslateZ3D(const double Z)
: Returns a shift transformation along the z-axis
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 ...
Amg::Transform3D getRotateZ3D(double angle)
get a rotation transformation around Z-axis
Eigen::Affine3d Transform3D
bool hasPositiveDiagElems(const AmgSymMatrix(N) &mat)
Returns true if all diagonal elements of the covariance matrix are finite aka sane in the above defin...
Eigen::Matrix< double, 3, 1 > Vector3D
Amg::Transform3D getRotateY3D(double angle)
get a rotation transformation around Y-axis
StIndex
enum to classify the different station layers in the muon spectrometer
const std::string & layerName(LayerIndex index)
convert LayerIndex into a string
DetectorRegionIndex
enum to classify the different layers in the muon spectrometer
constexpr int toInt(const EnumType enumVal)
const std::string & regionName(DetectorRegionIndex index)
convert DetectorRegionIndex into a string
LayerIndex toLayerIndex(ChIndex index)
convert ChIndex into LayerIndex
LayerIndex
enum to classify the different layers in the muon spectrometer
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
@ alongMomentum
@ anyDirection
@ locY
local cartesian
Definition ParamDefs.h:38
@ locX
Definition ParamDefs.h:37
ParametersBase< TrackParametersDim, Charged > TrackParameters
void stable_sort(DataModel_detail::iterator< DVL > beg, DataModel_detail::iterator< DVL > end)
Specialization of stable_sort for DataVector/List.
struct containing all information to build a Hough transform for a given chamber index