ATLAS Offline Software
Loading...
Searching...
No Matches
MmRdoToPrepDataToolMT.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
11
12// BS access
16using namespace MuonGM;
17using namespace Trk;
18
19namespace {
20 // Count hits with negative charge, which indicates bad calibration
21 std::atomic<bool> hitNegativeCharge{false};
22} // namespace
23
24namespace Muon{
25
27 ATH_MSG_DEBUG(" in initialize()");
28 ATH_CHECK(m_idHelperSvc.retrieve());
29 // check if the initialization of the data container is success
30 ATH_CHECK(m_writeKey.initialize());
31 ATH_CHECK(m_readKey.initialize());
32 ATH_CHECK(m_muDetMgrKey.initialize());
33 ATH_CHECK(m_calibTool.retrieve());
34 ATH_CHECK(m_updateKey.initialize(!m_updateKey.key().empty()));
35 ATH_CHECK(m_xAODKey.initialize(!m_xAODKey.empty()));
36 return StatusCode::SUCCESS;
37}
38
39StatusCode MmRdoToPrepDataToolMT::processCollection(const EventContext& ctx,
40 MMPrepDataContainer* mmPrepDataContainer,
41 xAOD::MMClusterContainer* xAODContainer,
42 const std::vector<IdentifierHash>& idsToDecode,
43 const MM_RawDataCollection* rdoColl) const {
44 ATH_MSG_DEBUG(" ***************** Start of process MM Collection");
45 const MmIdHelper& id_helper = m_idHelperSvc->mmIdHelper();
46 // protect for large splashes
47 bool merge = m_merge || rdoColl->size() > 100;
48
49 const IdentifierHash hash = rdoColl->identifierHash();
50
51 // check if we actually want to decode this RDO collection
52 if (!idsToDecode.empty() and std::find(idsToDecode.begin(), idsToDecode.end(),
53 hash) == idsToDecode.end()) {
54 ATH_MSG_DEBUG("Hash ID " << hash << " not in input list, ignore");
55 return StatusCode::SUCCESS;
56 } else
57 ATH_MSG_DEBUG("Going to decode " << hash);
58
59 // check if the collection already exists, otherwise add it
60 if (mmPrepDataContainer->indexFindPtr(hash) != nullptr) {
61
62 ATH_MSG_DEBUG("In processCollection: collection already contained in the MM PrepData container");
63 return StatusCode::SUCCESS;
64 }
65
66 // Get write handle for this collection
67 MMPrepDataContainer::IDC_WriteHandle lock = mmPrepDataContainer->getWriteHandle(hash);
68 // Check if collection already exists (via the cache, i.e. in online trigger
69 // mode)
71 ATH_MSG_DEBUG("In processCollection: collection already available in the MM PrepData container (via cache)");
72 return StatusCode::SUCCESS;
73 }
74 auto prdColl = std::make_unique<MMPrepDataCollection>(hash);
75
76 // set the offline identifier of the collection Id
77 IdContext context = id_helper.module_context();
78 Identifier moduleId{};
79 if (id_helper.get_id(hash, moduleId, &context) != 0) {
80 ATH_MSG_ERROR("Could not convert the hash Id: " << hash << " to identifier");
81 } else {
82 ATH_MSG_DEBUG(" dump moduleId " << moduleId);
83 prdColl->setIdentifier(moduleId);
84 }
85
86 // MuonDetectorManager from the conditions store
88 if (!MuonDetMgr.isValid()) {
89 ATH_MSG_ERROR("Null pointer to the read MuonDetectorManager conditions object");
90 return StatusCode::FAILURE;
91 }
92
93 std::vector<MMPrepData> MMprds;
94 // convert the RDO collection to a PRD collection
95 for (const MM_RawData* rdo : *rdoColl) {
96 ATH_MSG_DEBUG("Adding a new MM PrepRawData");
97
98 const Identifier rdoId = rdo->identify();
99 // ATH_MSG_ALWAYS(" dump rdo " << m_idHelperSvc->toString(rdoId) << " pdo " << rdo->charge()
100 // << " time " << rdo->time() << " relBCID " << rdo->relBcid());
101
102 int channel = rdo->channel();
103 std::vector<Identifier> rdoList;
104 Identifier prdId = id_helper.channelID(rdoId, id_helper.multilayer(rdoId), id_helper.gasGap(rdoId), channel);
105 ATH_MSG_DEBUG(" channel RDO " << channel << " channel from rdoID " << id_helper.channel(rdoId));
106 rdoList.push_back(prdId);
107
108 // get the local and global positions
109 const MuonGM::MMReadoutElement* detEl = MuonDetMgr->getMMReadoutElement(prdId);
110 Amg::Vector2D localPos{Amg::Vector2D::Zero()};
111
112 bool getLocalPos = detEl->stripPosition(prdId, localPos);
113 if (!getLocalPos) {
114 if (msgLvl(MSG::DEBUG)) { // We should still keep this a warning and fix it properly but silence it for now (ATLASRECTS-7520)
115 ATH_MSG_WARNING("Could not get the local strip position for "<< m_idHelperSvc->toString(prdId));
116 }
117 continue;
118 }
119
120 Amg::Vector3D globalPos{Amg::Vector3D::Zero()};
121 bool getGlobalPos = detEl->stripGlobalPosition(prdId, globalPos);
122 if (!getGlobalPos) {
123 ATH_MSG_WARNING("Could not get the global strip position for MM");
124 continue;
125 }
126 NSWCalib::CalibratedStrip calibStrip;
127 ATH_CHECK(m_calibTool->calibrateStrip(ctx, rdo, calibStrip));
128 if (calibStrip.charge < 0) {
129 if (!hitNegativeCharge || msgLvl(MSG::DEBUG)) {
130 ATH_MSG_DEBUG("One MM RDO or more, such as one with pdo = "<< rdo->charge()
131 << " counts, corresponds to a negative charge ("<< calibStrip.charge << "). Skipping these RDOs");
132 hitNegativeCharge = true;
133 }
134 continue;
135 }
136
137 Trk::LocalDirection localDir;
138 const Trk::PlaneSurface& psurf = detEl->surface(prdId);
139 Amg::Vector2D lpos{Amg::Vector2D::Zero()};
140 psurf.globalToLocal(globalPos, globalPos, lpos);
141 psurf.globalToLocalDirection(globalPos, localDir);
142
143 ATH_MSG_DEBUG(" Surface centre x " << Amg::toString(psurf.center()));
144 ATH_MSG_DEBUG(" localPos x " <<Amg::toString(localPos)<< " localPos y " << Amg::toString(lpos));
145
146 Amg::Vector3D gdir = psurf.transform().linear() * Amg::Vector3D::UnitY();
147 ATH_MSG_DEBUG(" MM detector surface direction phi "<< gdir.phi() << " global radius hit " << globalPos.perp()
148 << " phi pos " << globalPos.phi() << " global z "<< globalPos.z());
149
150 auto cov = Amg::MatrixX(2, 2);
151 cov.setIdentity();
152 (cov)(0, 0) = calibStrip.resTransDistDrift;
153 (cov)(1, 1) = calibStrip.resLongDistDrift;
154 localPos.x() += calibStrip.dx;
155
156 if (!merge) {
157 // storage will be handeled by Store Gate
158 auto mpd = std::make_unique<MMPrepData>(prdId, hash,
159 std::move(localPos), std::move(rdoList), std::move(cov),
160 detEl,
161 calibStrip.time, calibStrip.charge, calibStrip.distDrift);
163
164 prdColl->push_back(std::move(mpd));
165
166 } else {
167 if (calibStrip.charge < m_singleStripChargeCut) {
168 // ATH_MSG_ALWAYS("Strip with charge " << calibStrip.charge << " below the cut of " << m_singleStripChargeCut << ", skipping it");
169 continue;
170 }
171 // ATH_MSG_ALWAYS("producing prd with charge " << calibStrip.charge << " time " << calibStrip.time);
172 MMPrepData mpd(prdId, hash, std::move(localPos), std::move(rdoList),
173 std::move(cov), detEl, calibStrip.time, calibStrip.charge,
174 calibStrip.distDrift);
175 // set the hash of the MMPrepData such that it contains the correct value
176 // in case it gets used in SimpleMMClusterBuilderTool::getClusters
177 mpd.setHashAndIndex(hash, 0);
179 MMprds.push_back(std::move(mpd));
180 }
181 }
182
183 if (merge) {
184 std::vector<std::unique_ptr<MMPrepData>> clusters;
185
187 ATH_CHECK(m_clusterBuilderTool->getClusters(ctx, std::move(MMprds), clusters));
188
189 for (std::unique_ptr<MMPrepData>& prdN : clusters) {
190 prdN->setHashAndIndex(prdColl->identifyHash(), prdColl->size());
191 prdColl->push_back(std::move(prdN));
192 }
193 } // merge
194
195 if (xAODContainer) {
196 // Lambda to fill xprd from prd
197 std::vector<const MMPrepData*> sortMe{prdColl->begin(), prdColl->end()};
198 std::ranges::sort(sortMe, IdentifierByDetElSorter{m_idHelperSvc.get()});
199 for (const MMPrepData* prd : sortMe) {
200 xAOD::MMCluster* cluster{xAODContainer->push_back(std::make_unique<xAOD::MMCluster>())};
201 cluster->setIdentifier(prd->identify().get_compact());
202 cluster->setMeasurement(m_idHelperSvc->detElementHash(prd->identify()),
203 xAOD::MeasVector<1>{prd->localPosition().x()},
204 xAOD::MeasMatrix<1>{prd->localCovariance()(0, 0)});
205 cluster->setGasGap(id_helper.gasGap(prd->identify()));
206 cluster->setChannelNumber(id_helper.channel(prd->identify()));
207 cluster->setTime(prd->time());
208 cluster->setCharge(prd->charge());
209 cluster->setDriftDist(prd->driftDist());
210 cluster->setAngle(prd->angle());
211 cluster->setChiSqProb(prd->chisqProb());
212 cluster->setAuthor(prd->author());
213 cluster->setQuality(prd->quality());
214 cluster->setStripNumbers(prd->stripNumbers());
215 cluster->setStripTimes(prd->stripTimes());
216 cluster->setStripCharges(prd->stripCharges());
217 cluster->setStripDriftDist(prd->stripDriftDist());
218 cluster->setStripDriftErrors(prd->stripDriftErrors());
219 }
220 }
221 // now write the collection
222 ATH_CHECK(lock.addOrDelete(std::move(prdColl)));
223 ATH_MSG_DEBUG("PRD hash " << hash << " has been moved to container");
224
225 return StatusCode::SUCCESS;
226}
227
229 MmRdoToPrepDataToolMT::getRdoContainer(const EventContext& ctx) const {
230 auto rdoContainerHandle = SG::makeHandle(m_readKey, ctx);
231 if (rdoContainerHandle.isValid()) {
232 ATH_MSG_DEBUG("MM_getRdoContainer success");
233 return rdoContainerHandle.cptr();
234 }
235 ATH_MSG_WARNING("Retrieval of MM_RawDataContainer failed !");
236
237 return nullptr;
238}
239
240void MmRdoToPrepDataToolMT::processRDOContainer(const EventContext& ctx,
241 MMPrepDataContainer* mmPrepDataContainer,
242 xAOD::MMClusterContainer* xAODContainer,
243 const std::vector<IdentifierHash>& idsToDecode) const {
244 ATH_MSG_DEBUG("In processRDOContainer");
245 const MM_RawDataContainer* rdoContainer = getRdoContainer(ctx);
246 if (!rdoContainer) {
247 return;
248 }
249
250 for (const MM_RawDataCollection* rdoColl : *rdoContainer) {
251
252 if (rdoColl->empty()){
253 continue;
254 }
255 ATH_MSG_DEBUG("New RDO collection with " << rdoColl->size() << "MM Hits");
256
257 if (processCollection(ctx, mmPrepDataContainer, xAODContainer, idsToDecode, rdoColl).isFailure()) {
259 "processCsm returns a bad StatusCode - keep going for new data "
260 "collections in this event");
261 }
262 }
263}
264
265// methods for ROB-based decoding
266StatusCode MmRdoToPrepDataToolMT::decode(const EventContext& ctx,
267 const std::vector<IdentifierHash>& idVect) const {
268
269 // is idVect a right thing to use here? to be reviewed maybe
270 ATH_MSG_DEBUG("Size of the RDO container to be decoded: " << idVect.size());
271
272 MMPrepDataContainer* mmPrepDataContainer = setupMM_PrepDataContainer(ctx);
273
274 if (!mmPrepDataContainer) {
275 return StatusCode::FAILURE;
276 }
277
279 xAOD::MMClusterContainer* xAODContainer{nullptr};
280 if (!m_xAODKey.empty()) {
281 outputContainer = SG::WriteHandle{m_xAODKey, ctx};
282 ATH_CHECK(outputContainer.record(std::make_unique<xAOD::MMClusterContainer>(),
283 std::make_unique<xAOD::MMClusterAuxContainer>()));
284 xAODContainer = outputContainer.ptr();
285 }
286
287 processRDOContainer(ctx, mmPrepDataContainer, xAODContainer, idVect);
288
289 return StatusCode::SUCCESS;
290}
291
292StatusCode MmRdoToPrepDataToolMT::decode(const EventContext&,
293 const std::vector<uint32_t>&) const {
294 ATH_MSG_FATAL("ROB based decoding is not supported....");
295 return StatusCode::FAILURE;
296}
297StatusCode MmRdoToPrepDataToolMT::provideEmptyContainer(const EventContext& ctx) const {
298 if (!m_xAODKey.empty()) {
299 SG::WriteHandle writeHandle{m_xAODKey, ctx};
300 ATH_CHECK(writeHandle.record(std::make_unique<xAOD::MMClusterContainer>(),
301 std::make_unique<xAOD::MMClusterAuxContainer>()));
302 }
303
304 return setupMM_PrepDataContainer(ctx) ? StatusCode::SUCCESS
305 : StatusCode::FAILURE;
306}
307
310
311 SG::WriteHandle handle{m_writeKey, ctx};
312 if (m_updateKey.key().empty()) {
313 // No external cache, just record the container
314 StatusCode status =
315 handle.record(std::make_unique<MMPrepDataContainer>(
316 m_idHelperSvc->mmIdHelper().module_hash_max()));
317
318 if (status.isFailure() || !handle.isValid()) {
320 "Could not record container of MicroMega PrepData Container at "
321 << m_writeKey.key());
322 return nullptr;
323 }
324 } else {
325 // use the cache to get the container
326 SG::UpdateHandle update(m_updateKey, ctx);
327 if (!update.isValid()) {
328 ATH_MSG_FATAL("Invalid UpdateHandle " << m_updateKey.key());
329 return nullptr;
330 }
331 StatusCode status = handle.record(std::make_unique<MMPrepDataContainer>(update.ptr()));
332 if (status.isFailure() || !handle.isValid()) {
334 "Could not record container of MM PrepData Container using cache "
335 << m_updateKey.key() << " - "
336 << m_writeKey.key());
337 return nullptr;
338 }
339 ATH_MSG_DEBUG("Created container using cache for "
340 << m_updateKey.key());
341 }
342 return handle.ptr();
343}
344
345}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
value_type push_back(value_type pElem)
Add an element to the end of the collection.
size_type size() const noexcept
Returns the number of elements in the collection.
This class saves the "context" of an expanded identifier (ExpandedIdentifier) for compact or hash ver...
Definition IdContext.h:26
bool OnlineAndPresentInAnotherView()
This method is to avoid calling an expensive operation in the offline case.
StatusCode addOrDelete(std::unique_ptr< T > ptr)
IDC_WriteHandle getWriteHandle(IdentifierHash hash)
virtual const T * indexFindPtr(IdentifierHash hashId) const override final
return pointer on the found entry or null if out of range using hashed index - fast version,...
This is a "hash" representation of an Identifier.
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int gasGap, int channel) const
int channel(const Identifier &id) const override
int gasGap(const Identifier &id) const override
get the hashes
int multilayer(const Identifier &id) const
An MMReadoutElement corresponds to a single STGC module; therefore typicaly a barrel muon station con...
virtual bool stripPosition(const Identifier &id, Amg::Vector2D &pos) const override final
strip position – local or global If the strip number is outside the range of valid strips,...
bool stripGlobalPosition(const Identifier &id, Amg::Vector3D &gpos) const
virtual const Trk::PlaneSurface & surface() const override
access to chamber surface (phi orientation), uses the first gas gap
virtual int get_id(const IdentifierHash &hash_id, Identifier &id, const IdContext *context=0) const override
Create compact id from hash id (return == 0 for OK)
IdContext module_context() const
id for module
Class to represent MM measurements.
Definition MMPrepData.h:22
void setAuthor(Author author)
const IdentifierHash & identifierHash() const
Temporary class to hold the MM RDO.
Definition MM_RawData.h:20
SG::WriteHandleKey< Muon::MMPrepDataContainer > m_writeKey
MdtPrepRawData containers.
virtual StatusCode initialize() override
standard Athena-Algorithm method
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
const MM_RawDataContainer * getRdoContainer(const EventContext &ctx) const
SG::WriteHandleKey< xAOD::MMClusterContainer > m_xAODKey
ToolHandle< IMMClusterBuilderTool > m_clusterBuilderTool
StatusCode processCollection(const EventContext &ctx, Muon::MMPrepDataContainer *mmPrepDataContainer, xAOD::MMClusterContainer *xAODContainer, const std::vector< IdentifierHash > &idsToDecode, const MM_RawDataCollection *rdoColl) const
Gaudi::Property< float > m_singleStripChargeCut
ToolHandle< INSWCalibTool > m_calibTool
virtual StatusCode decode(const EventContext &ctx, const std::vector< IdentifierHash > &idVect) const override
Decode method - declared in Muon::IMuonRdoToPrepDataTool.
SG::UpdateHandleKey< MMPrepDataCollection_Cache > m_updateKey
This is the key for the cache for the MM PRD containers, can be empty.
SG::ReadHandleKey< MM_RawDataContainer > m_readKey
Gaudi::Property< bool > m_merge
SG::ReadCondHandleKey< MuonGM::MuonDetectorManager > m_muDetMgrKey
void processRDOContainer(const EventContext &ctx, Muon::MMPrepDataContainer *mmPrepDataContainer, xAOD::MMClusterContainer *xAODContainer, const std::vector< IdentifierHash > &idsToDecode) const
virtual StatusCode provideEmptyContainer(const EventContext &ctx) const override
Muon::MMPrepDataContainer * setupMM_PrepDataContainer(const EventContext &ctx) const
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
pointer_type ptr()
Dereference the pointer.
represents the three-dimensional global direction with respect to a planar surface frame.
Class for a planaer rectangular or trapezoidal surface in the ATLAS detector.
virtual bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const override final
Specified for PlaneSurface: GlobalToLocal method without dynamic memory allocation - boolean checks i...
void globalToLocalDirection(const Amg::Vector3D &glodir, Trk::LocalDirection &locdir) const
This method transforms the global direction to a local direction wrt the plane.
void setHashAndIndex(unsigned short collHash, unsigned short objIndex)
TEMP for testing: might make some classes friends later ...
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
const Amg::Vector3D & center() const
Returns the center position of the Surface.
void setDriftDist(float value)
Sets the drift distance.
void setStripDriftDist(const std::vector< float > &stripDriftDist)
void setStripDriftErrors(const std::vector< DriftCov_t > &stripDriftErrors)
void setStripNumbers(const std::vector< uint16_t > &stripNumbers)
void setStripCharges(const std::vector< int > &stripCharges)
void setAuthor(Author author)
void setChiSqProb(float value)
Sets the microTPC chisq probability.
void setTime(uint16_t value)
Sets the TDC counts.
void setAngle(float value)
Sets the microTPC angle.
void setQuality(Quality quality)
void setStripTimes(const std::vector< int16_t > &stripTimes)
void setChannelNumber(uint16_t strip)
void setGasGap(uint8_t gap)
void setCharge(uint32_t value)
Sets the calibrated charge.
void setMeasurement(const DetectorIDHashType idHash, MeasVector< N > locPos, MeasMatrix< N > locCov)
Sets IdentifierHash, local position and local covariance of the measurement.
void setIdentifier(const DetectorIdentType measId)
Sets the full Identifier of the measurement.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
Ensure that the Athena extensions are properly loaded.
Definition GeoMuonHits.h:27
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
MuonPrepDataContainerT< MMPrepData > MMPrepDataContainer
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
Ensure that the ATLAS eigen extensions are properly loaded.
Definition merge.py:1
MMClusterContainer_v1 MMClusterContainer
Eigen::Matrix< float, N, N > MeasMatrix
Eigen::Matrix< float, N, 1 > MeasVector
Abrivation of the Matrix & Covariance definitions.
MMCluster_v1 MMCluster