ATLAS Offline Software
AlignmentErrorTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
9 
10 #include "AlignmentErrorTool.h"
11 
12 #include <boost/functional/hash.hpp>
13 #include <fstream>
14 #include <sstream>
15 #include <unordered_map>
16 
24 #include "TrkTrack/Track.h"
25 
26 namespace MuonAlign {
27 
28 AlignmentErrorTool::AlignmentErrorTool(const std::string& t, const std::string& n, const IInterface* p) : AthAlgTool(t, n, p) {
29  declareInterface<Trk::ITrkAlignmentDeviationTool>(this);
30 }
31 
33  ATH_MSG_INFO("*****************************************");
34  ATH_MSG_INFO("AlignmentErrorTool::initialize()");
35 
36  ATH_CHECK(m_idTool.retrieve());
37  ATH_CHECK(m_idHelperSvc.retrieve());
39 
40  return StatusCode::SUCCESS;
41 }
42 
43 void AlignmentErrorTool::makeAlignmentDeviations(const Trk::Track& track, std::vector<Trk::AlignmentDeviation*>& deviations) const {
44  ATH_MSG_DEBUG("AlignmentErrorTool::makeAlignmentDeviations()");
45 
47  const MuonAlignmentErrorData* readCdo{*readHandle};
48  if (!readCdo) {
49  ATH_MSG_ERROR("nullptr to the read conditions object");
50  return;
51  }
52  const auto& deviationVec = readCdo->getAlignmentErrorRules();
53  std::vector<deviationSummary_t> devSumVec;
54  devSumVec.reserve(deviationVec.size());
55  deviationSummary_t aDevSumm;
56  for (const auto & i : deviationVec) {
57  aDevSumm.translation = i.translation;
58  aDevSumm.rotation = i.rotation;
59  aDevSumm.stationName = i.stationName;
60  aDevSumm.multilayer = i.multilayer;
61  devSumVec.emplace_back(std::move(aDevSumm));
62  }
63 
64  const auto& MuonAlignmentErrorRuleCacheVec = readCdo->getMuonAlignmentErrorRuleCache();
65  const auto& map_struct = MuonAlignmentErrorRuleCacheVec[0];
66 
67  typedef Trk::TrackStates tsosc_t;
68  const tsosc_t* tsosc = track.trackStateOnSurfaces();
69 
70  // LOOP ON HITS ON TRACK //
71  unsigned int nPrecisionHits = 0;
72  for (const auto *tsos : *tsosc) {
73  if (!tsos->type(Trk::TrackStateOnSurface::Measurement)) {
74  continue;
75  }
76  const Trk::MeasurementBase* meas = tsos->measurementOnTrack();
77  const auto* rot = dynamic_cast<const Trk::RIO_OnTrack*>(meas);
78 
79  if (!rot) {
80  const auto* crot = dynamic_cast<const Trk::CompetingRIOsOnTrack*>(meas);
81  if (crot) {
82  unsigned int index = crot->indexOfMaxAssignProb();
83  rot = &(crot->rioOnTrack(index));
84  }
85  }
86  if (!rot) continue;
87 
88  Identifier channelId = rot->identify();
89  if (!m_idHelperSvc->isMuon(channelId)) {
90  // the RIO_OnTrack Identifiers could also come from ID or Calo, but this tool is only interested in MS hits
91  ATH_MSG_VERBOSE("Given Identifier " << channelId.get_compact() << " is not a muon Identifier, continuing");
92  continue;
93  }
94 
95  // Keep only the precision coordinate hits
96  if (m_idHelperSvc->isRpc(channelId)
97  || m_idHelperSvc->isTgc(channelId)
98  || (m_idHelperSvc->isCsc(channelId) && m_idHelperSvc->cscIdHelper().measuresPhi(channelId) == 1)
99  || (m_idHelperSvc->issTgc(channelId) && m_idHelperSvc->stgcIdHelper().channelType(channelId) != sTgcIdHelper::sTgcChannelTypes::Strip)) {
100  continue;
101  }
102 
103  // To maintain backward compatibility with the old error CLOBs, activate
104  // the NSW hits only if specified in the CLOB, else disccard them
105  if (!readCdo->hasNswHits()
106  && (m_idHelperSvc->issTgc(channelId) || m_idHelperSvc->isMM(channelId))) {
107  continue;
108  }
109 
110  MuonCalib::MuonFixedLongId calibId = m_idTool->idToFixedLongId(channelId);
111  if (!calibId.isValid()) continue;
112 
113  ATH_MSG_DEBUG("Hit is in station " << calibId << " (MuonFixedLongId)");
114  ++nPrecisionHits;
115 
116  // Compute deviationSummary_t building blocks
117  const Trk::PrepRawData* prd = rot->prepRawData();
118  const Trk::Surface& sur = prd->detectorElement()->surface(prd->identify());
119 
120  double w2 = 1.0 / (rot->localCovariance()(Trk::loc1, Trk::loc1));
121  Amg::Vector3D hitP = tsos->trackParameters()->position();
122  Amg::Vector3D hitU = tsos->trackParameters()->momentum().unit();
123 
124  // Wire direction for MDT, strip direction for MM or sTGC
125  int icol = (calibId.is_mdt()||calibId.is_csc()) ? 2 : 1;
126  Amg::Vector3D hitV = sur.transform().rotation().col(icol);
127 
128  // Enforce orientation of the V vectors
129  static const Amg::Vector3D zATLAS(0., 0., 1.);
130  if (hitP.cross(zATLAS).dot(hitV)<0.0) {
131  hitV *= -1.0;
132  }
133 
134  // FOR CROSS-CHECK
135  bool is_matched = false;
136 
137  // Construct detector element identifier from channelId, remaining only chamber name and multilayer information
138  int multilayer = 1;
139  if (calibId.is_mdt()) {
140  multilayer = calibId.mdtMultilayer();
141  } else if (calibId.is_mmg()) {
142  multilayer = calibId.mmgMultilayer();
143  } else if (calibId.is_stg()) {
144  multilayer = calibId.stgMultilayer();
145  }
146 
147  Identifier key_id{};
148  if (m_idHelperSvc->isMdt(channelId)){
149  key_id = m_idHelperSvc->mdtIdHelper().channelID(channelId, multilayer, 1, 1);
150  }
151  if (m_idHelperSvc->isRpc(channelId)){
152  key_id = m_idHelperSvc->rpcIdHelper().elementID(channelId);
153  }
154  if (m_idHelperSvc->isMM(channelId)){
155  key_id = m_idHelperSvc->mmIdHelper().channelID(channelId, multilayer, 1, 1);
156  }
157  if (m_idHelperSvc->issTgc(channelId)){
158  key_id = m_idHelperSvc->stgcIdHelper().channelID(channelId, multilayer, 1, 0, 1);
159  }
160  if (m_idHelperSvc->isCsc(channelId)){
161  key_id = m_idHelperSvc->cscIdHelper().elementID(channelId);
162  }
163  if (m_idHelperSvc->isTgc(channelId)){
164  key_id = m_idHelperSvc->tgcIdHelper().elementID(channelId);
165  }
166 
167  // Find deviation (pointer) for current detector element
168  auto range = map_struct.id_rule_map.equal_range(key_id);
169  for (auto i = range.first; i != range.second; ++i){
171 
172  // ASSOCIATE EACH NUISANCE TO A LIST OF HITS
173  devSumVec[rule_idx].hits.push_back(rot);
174 
175  devSumVec[rule_idx].sumW2 += w2;
176  devSumVec[rule_idx].sumP += w2 * hitP;
177  devSumVec[rule_idx].sumU += w2 * hitU;
178  devSumVec[rule_idx].sumV += w2 * hitV;
179 
180  // FOR CROSS-CHECK
181  is_matched = true;
182 
183 
184  } // LOOP ON DEVIATIONS
185 
186  if (!is_matched) {
187  ATH_MSG_WARNING("The hits in the station " << calibId << " (MuonFixedLongId)"
188  << " couldn't be matched to any deviation regexp in the list.");
189  }
190 
191  } // LOOP ON TSOS
192 
193  // Nuisance parameters covering the complete track are not wanted. (MS/ID
194  // error treated differently for now). Removing the deviations covering the
195  // full track in further processing.
196  for (auto& dev : devSumVec) {
197  if (dev.hits.size() == nPrecisionHits) {
198  dev.hits.clear();
199  }
200  }
201 
202  // GET RID OF PERFECT OVERLAPS BY COMBINING ERRORS
203  std::vector<const Trk::RIO_OnTrack*> v1, v2;
204  for (auto iti = devSumVec.begin(); iti != devSumVec.end(); ++iti) {
205 
206  v1 = iti->hits;
207  if (v1.empty()) {
208  continue;
209  }
210 
211  std::stable_sort(v1.begin(), v1.end());
212 
213  for (auto itj = iti+1; itj != devSumVec.end(); ++itj) {
214 
215  if (iti->hits.size() != itj->hits.size()) {
216  continue;
217  }
218 
219  v2 = itj->hits;
220  std::stable_sort(v2.begin(), v2.end());
221 
222  if (v1 == v2) {
223  auto iDev = std::distance(devSumVec.begin(), iti);
224  auto jDev = std::distance(devSumVec.begin(), itj);
225  ATH_MSG_DEBUG("Found deviations " << iDev << " and " << jDev << " related to the same list of hits. Merging...");
226  ATH_MSG_DEBUG("old (translation, rotation) systematic uncertainties for "
227  << iDev << ": " << iti->translation << ", " << iti->rotation);
228  ATH_MSG_DEBUG("old (translation, rotation) systematic uncertainties for "
229  << jDev << ": " << itj->translation << ", " << itj->rotation);
230 
231  // MERGE THE TWO DEVIATIONS ASSOCIATED TO THE SAME LIST OF HITS //
232  double new_translation = std::hypot(iti->translation, itj->translation);
233  double new_rotation = std::hypot(iti->rotation, itj->rotation);
234 
235  // NOW PREPARE TO ERASE ONE OF THE TWO COPIES //
236  itj->hits.clear();
237 
238  // ASSIGN NEW TRASLATION/ROTATION TO THE REMAINING COPY //
239  iti->translation = new_translation;
240  iti->rotation = new_rotation;
241  ATH_MSG_DEBUG("New combined (translation, rotation) systematic uncertainties: " << new_translation << ", " << new_rotation);
242 
243  } // FIND AN OVERLAP IN THE HITS LISTS
244  } // SECOND LOOP ON DEVIATIONS
245  } // FIRST LOOP ON DEVIATIONS
246 
247 
248  // NOW BUILD THE DEVIATIONS
249  deviations.clear();
250  ATH_MSG_DEBUG("************************************");
251  ATH_MSG_DEBUG("FINAL LIST OF DEVIATIONS");
252  for (const auto & iDev : devSumVec) {
253  if (iDev.hits.empty()) {
254  continue;
255  }
256 
257  double rotation = iDev.rotation;
258  double translation = iDev.translation;
259 
260  Amg::Vector3D sumP = iDev.sumP;
261  Amg::Vector3D sumU = iDev.sumU;
262  Amg::Vector3D sumV = iDev.sumV;
263  double sumW2 = iDev.sumW2;
264 
265  sumP *= (1. / sumW2);
266  sumU *= (1. / sumW2);
267  sumV *= (1. / sumW2);
268 
269  if (translation >= 0.001 * Gaudi::Units::mm) {
270  std::size_t hitshash = 0;
271  for (const auto *it : iDev.hits) {
272  boost::hash_combine(hitshash, (it->identify()).get_compact());
273  }
274  deviations.push_back(
275  new AlignmentTranslationDeviation(sumU.cross(sumV), translation * Gaudi::Units::mm, iDev.hits));
276  deviations.back()->setHashOfHits(hitshash);
277 
278  ATH_MSG_DEBUG("A translation along ("
279  << sumU.x() << ", " << sumU.y() << ", " << sumU.z() << ") with sigma=" << translation * Gaudi::Units::mm
280  << " mm was applied to " << iDev.hits.size()
281  << " hits matching the station: " << iDev.stationName.str() << " and the multilayer "
282  << iDev.multilayer.str());
283  }
284  if (rotation >= 0.000001 * Gaudi::Units::rad) {
285  std::size_t hitshash = 0;
286  for (const auto *it : iDev.hits) {
287  boost::hash_combine(hitshash, (it->identify()).get_compact());
288  }
289  deviations.push_back(new AlignmentRotationDeviation(sumP, sumV, rotation * Gaudi::Units::rad, iDev.hits));
290  deviations.back()->setHashOfHits(hitshash);
291 
292  ATH_MSG_DEBUG("A rotation around the center = (" << sumP.x() << ", " << sumP.y() << ", " << sumP.z() << ") and axis = ("
293  << sumV.x() << ", " << sumV.y() << ", " << sumV.z()
294  << ") with sigma=" << rotation / Gaudi::Units::mrad << " mrad was applied to "
295  << iDev.hits.size() << " hits matching the station "
296  << iDev.stationName.str() << " and the multilayer "
297  << iDev.multilayer.str());
298  }
299 
300  } // LOOP ON NUISANCES
301 
302  ATH_MSG_DEBUG("******************************");
303  ATH_MSG_DEBUG("FINAL CHECKUP");
304  ATH_MSG_DEBUG("Found " << deviations.size() << " nuisances after duplicates merging");
305  ATH_MSG_DEBUG("******************************");
306 }
307 
308 } // namespace MuonAlign
MuonCalib::MuonFixedLongId::mmgMultilayer
int mmgMultilayer() const
Mmg specific:
Definition: MuonFixedLongId.h:1451
MuonCalib::MuonFixedLongId::is_mdt
bool is_mdt() const
Definition: MuonFixedLongId.h:774
MuonAlign::AlignmentErrorTool::AlignmentErrorTool
AlignmentErrorTool(const std::string &, const std::string &, const IInterface *)
Definition: AlignmentErrorTool.cxx:28
MuonAlign::AlignmentRotationDeviation
Definition: AlignmentRotationDeviation.h:11
MuonAlign::AlignmentErrorTool::deviationSummary_t::rotation
double rotation
Definition: AlignmentErrorTool.h:49
SG::ReadCondHandle
Definition: ReadCondHandle.h:44
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
AthMsgStreamMacros.h
CompetingRIOsOnTrack.h
Trk::Track
The ATLAS Track class.
Definition: Tracking/TrkEvent/TrkTrack/TrkTrack/Track.h:73
MuonAlign::AlignmentErrorTool::deviationSummary_t
Definition: AlignmentErrorTool.h:46
index
Definition: index.py:1
skel.it
it
Definition: skel.GENtoEVGEN.py:396
MuonCalib::MuonFixedLongId::isValid
bool isValid() const
check validity of the identifier.
Definition: MuonFixedLongId.h:770
MuonCalib::MuonFixedLongId::is_mmg
bool is_mmg() const
Definition: MuonFixedLongId.h:790
Trk::RIO_OnTrack
Definition: RIO_OnTrack.h:70
MuonAlign::AlignmentErrorTool::m_idTool
ToolHandle< MuonCalib::IIdToFixedIdTool > m_idTool
Definition: AlignmentErrorTool.h:42
MuonCalib::MuonFixedLongId::is_stg
bool is_stg() const
Definition: MuonFixedLongId.h:794
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
python.SystemOfUnits.mrad
int mrad
Definition: SystemOfUnits.py:112
PrepRawData.h
MuonAlign::AlignmentErrorTool::deviationSummary_t::stationName
boost::regex stationName
Definition: AlignmentErrorTool.h:51
atlasStyleMacro.icol
int icol
Definition: atlasStyleMacro.py:13
MuonAlign::AlignmentErrorTool::m_readKey
SG::ReadCondHandleKey< MuonAlignmentErrorData > m_readKey
Definition: AlignmentErrorTool.h:62
AlignmentTranslationDeviation.h
Track.h
MuonCalib::MuonFixedLongId::stgMultilayer
int stgMultilayer() const
Stg specific:
Definition: MuonFixedLongId.h:1516
MuonAlign::AlignmentErrorTool::deviationSummary_t::translation
double translation
Definition: AlignmentErrorTool.h:48
GeoPrimitives.h
MuonCalib::MuonFixedLongId
Definition: MuonFixedLongId.h:50
MuonAlignmentErrorData
MuonAlignmentErrorData is condition data which is derived and recorded by MuonAlignmentErrorDbAlg.
Definition: MuonAlignmentErrorData.h:21
MuonAlign
Definition: AlignmentRotationDeviation.h:10
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
MuonAlign::AlignmentErrorTool::initialize
StatusCode initialize() override
Definition: AlignmentErrorTool.cxx:32
MuonAlign::AlignmentTranslationDeviation
Definition: AlignmentTranslationDeviation.h:11
lumiFormat.i
int i
Definition: lumiFormat.py:85
beamspotman.n
n
Definition: beamspotman.py:731
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
xAOD::rotation
rotation
Definition: TrackSurface_v1.cxx:15
Trk::CompetingRIOsOnTrack
Base class for all CompetingRIOsOnTack implementations, extends the common MeasurementBase.
Definition: CompetingRIOsOnTrack.h:64
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:195
Trk::TrkDetElementBase::surface
virtual const Surface & surface() const =0
Return surface associated with this detector element.
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
CaloCondBlobAlgs_fillNoiseFromASCII.channelId
channelId
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:122
DataVector< const Trk::TrackStateOnSurface >
MuonCalib::MuonFixedLongId::is_csc
bool is_csc() const
Definition: MuonFixedLongId.h:782
MuonAlign::AlignmentErrorTool::m_idHelperSvc
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
Definition: AlignmentErrorTool.h:43
Trk::PrepRawData
Definition: PrepRawData.h:62
Trk::MeasurementBase
Definition: MeasurementBase.h:58
Trk::PrepRawData::identify
Identifier identify() const
return the identifier
MuonAlign::AlignmentErrorTool::deviationSummary_t::multilayer
boost::regex multilayer
Definition: AlignmentErrorTool.h:52
RIO_OnTrack.h
MuonAlignmentErrorData::MuonAlignmentErrorRuleIndex
size_t MuonAlignmentErrorRuleIndex
Definition: MuonAlignmentErrorData.h:31
SG::CondHandleKey::initialize
StatusCode initialize(bool used=true)
AlignmentErrorTool.h
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
AlignmentRotationDeviation.h
python.SystemOfUnits.mm
int mm
Definition: SystemOfUnits.py:83
ReadCellNoiseFromCoolCompare.v2
v2
Definition: ReadCellNoiseFromCoolCompare.py:364
MuonAlign::AlignmentErrorTool::makeAlignmentDeviations
void makeAlignmentDeviations(const Trk::Track &track, std::vector< Trk::AlignmentDeviation * > &deviations) const override
Compute alignment deviations, given a track as input.
Definition: AlignmentErrorTool.cxx:43
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
MuonCalib::MuonFixedLongId::mdtMultilayer
int mdtMultilayer() const
Mdt specific:
Definition: MuonFixedLongId.h:1070
xAOD::track
@ track
Definition: TrackingPrimitives.h:512
AthAlgTool
Definition: AthAlgTool.h:26
Trk::loc1
@ loc1
Definition: ParamDefs.h:34
Trk::Surface
Definition: Tracking/TrkDetDescr/TrkSurfaces/TrkSurfaces/Surface.h:75
Amg::distance
float distance(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the distance between two point in 3D space
Definition: GeoPrimitivesHelpers.h:54
Trk::Surface::transform
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
Trk::TrackStateOnSurface::Measurement
@ Measurement
This is a measurement, and will at least contain a Trk::MeasurementBase.
Definition: TrackStateOnSurface.h:101
python.SystemOfUnits.rad
int rad
Definition: SystemOfUnits.py:111
Trk::PrepRawData::detectorElement
virtual const TrkDetElementBase * detectorElement() const =0
return the detector element corresponding to this PRD The pointer will be zero if the det el is not d...
Identifier
Definition: IdentifierFieldParser.cxx:14