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)
LayerIndex
enum to classify the different layers in the muon spectrometer
const std::string & regionName(DetectorRegionIndex index)
convert DetectorRegionIndex into a string
LayerIndex toLayerIndex(ChIndex index)
convert ChIndex into LayerIndex
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