ATLAS Offline Software
Loading...
Searching...
No Matches
ClusterTimeProjectionMMClusterBuilderTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
5
6#include <algorithm>
7#include <numeric>
8
10#include "GaudiKernel/PhysicalConstants.h"
11#include "GaudiKernel/SystemOfUnits.h"
12
13#define DEFINE_VECTOR(dType, varName, nEles) \
14 std::vector<dType> varName{}; \
15 varName.reserve(nEles);
16
17namespace {
18 constexpr double halfGapWidth = 2.52;
19}
20namespace Muon{
22
24 const std::string& n,
25 const IInterface* p) :
26 AthAlgTool(t, n, p) {
27 declareInterface<IMMClusterBuilderTool>(this);
28}
29
31 ATH_CHECK(m_idHelperSvc.retrieve());
32 ATH_CHECK(m_uncertCalibKey.initialize());
33 return StatusCode::SUCCESS;
34}
35
37 std::vector<MMPrepData>&& MMprds,
38 std::vector<std::unique_ptr<MMPrepData>>& clustersVec) const {
39 LaySortedPrds prdsPerLayer = sortHitsToLayer(std::move(MMprds));
40
41
42 for (std::vector<MMPrepData>& prdsOfLayer : prdsPerLayer) {
43 if (prdsOfLayer.size() < 2) continue; // require at least two strips per layer
44
45 std::vector<std::vector<uint>> idxClusters = clusterLayer(prdsOfLayer);
46
47 for (std::vector<uint>& clustIds : idxClusters) {
48 DEFINE_VECTOR(MMPrepData, clustConstituents, clustIds.size());
49 DEFINE_VECTOR(NSWCalib::CalibratedStrip, stripFeatures, clustIds.size());
50
51 Amg::Vector3D clustDir{Amg::Vector3D::Zero()};
52 for (unsigned idx : clustIds) {
53 MMPrepData& toMerge{prdsOfLayer[idx]};
54
55 const Amg::Vector3D lDir{NswClustering::toLocal(toMerge)};
56 const double q = toMerge.charge();
57
58 clustDir += q * lDir;
60 clusFeat.identifier = toMerge.identify();
61 clusFeat.locPos = toMerge.localPosition();
62 clusFeat.distDrift = toMerge.driftDist();
63 clusFeat.resTransDistDrift = toMerge.localCovariance()(0, 0);
64 clusFeat.resLongDistDrift = toMerge.localCovariance()(1, 1);
65 clusFeat.charge = q;
66
67 stripFeatures.emplace_back(std::move(clusFeat));
68 clustConstituents.emplace_back(std::move(toMerge));
69 }
70
72 if (!errorCalibDB.isValid()) {
73 ATH_MSG_FATAL("Failed to retrieve the parameterized errors "<<m_uncertCalibKey.fullKey());
74 return StatusCode::FAILURE;
75 }
76
77 constexpr uint8_t toolAuthor = static_cast<uint8_t>(MMPrepData::Author::ClusterTimeProjectionClusterBuilder);
78 std::pair<double, double> posAndErrorSq = getClusterPositionPRD(**errorCalibDB,
79 toolAuthor,
80 stripFeatures,
81 clustDir.unit());
82
83 ATH_CHECK(writeClusterPrd(ctx, clustConstituents, posAndErrorSq.first, posAndErrorSq.second, clustersVec));
84
85 }
86 }
87 return StatusCode::SUCCESS;
88}
89
91 ClusterTimeProjectionMMClusterBuilderTool::sortHitsToLayer(std::vector<MMPrepData>&& MMprds) const {
92
93 LaySortedPrds prdsPerLayer{};
94 const MmIdHelper& idHelper{m_idHelperSvc->mmIdHelper()};
95 // sorting hits by gas gap
96 for (MMPrepData& prd : MMprds) {
97 const Identifier id = prd.identify();
98 int layer = 4 * (idHelper.multilayer(id) - 1) + (idHelper.gasGap(id) - 1);
99 prdsPerLayer.at(layer).push_back(std::move(prd));
100 }
101 ATH_MSG_DEBUG("sorted hist");
102 // sort MMPrds by channel
103 for (std::vector<MMPrepData>& prdsInLay : prdsPerLayer) {
104 std::sort(prdsInLay.begin(), prdsInLay.end(), [&idHelper](const MMPrepData& a, const MMPrepData& b) {
105 return idHelper.channel(a.identify()) <
106 idHelper.channel(b.identify());
107 });
108 }
109 return prdsPerLayer;
110}
111
112 std::vector<std::vector<uint>>
113 ClusterTimeProjectionMMClusterBuilderTool::clusterLayer(const std::vector<MMPrepData>& MMPrdsPerLayer) const {
114
115 const MmIdHelper& idHelper{m_idHelperSvc->mmIdHelper()};
116 // get gas gap for later correction of the sign of the slope
117 int gasGap = idHelper.gasGap(MMPrdsPerLayer.at(0).identify());
118
119 ATH_MSG_DEBUG("Scanning gas gap " << gasGap);
120 if (msgLvl(MSG::VERBOSE)) {
121 for (const auto& prd : MMPrdsPerLayer) {
122 ATH_MSG_DEBUG("Hit channel " << " " << m_idHelperSvc->toStringDetEl(prd.identify())
123 << " local positionX " << prd.localPosition().x() << " time " << prd.time()
124 << " corrected time " << prd.time() << " angle to IP "<< prd.globalPosition().theta() << " "
125 << prd.globalPosition().theta() / Gaudi::Units::degree);
126 }
127 }
128 std::vector<std::vector<uint>> idxClusters{};
129 // simple grouping of strips using the fact that the strips where ordered by channel
130 idxClusters.push_back(std::vector<uint>{0}); // assumes that mmPrdsPerLayer always has at least one strip
131 for (uint i_strip = 1; i_strip < MMPrdsPerLayer.size(); i_strip++) {
132 if (channel(MMPrdsPerLayer.at(i_strip)) - channel(MMPrdsPerLayer.at(i_strip - 1)) <= m_maxHoleSize + 1) {
133 idxClusters.back().push_back(i_strip);
134 } else {
135 idxClusters.push_back(std::vector<uint>{i_strip});
136 }
137 }
138 if (msgLvl(MSG::VERBOSE)) {
139 ATH_MSG_DEBUG("Found " << idxClusters.size() << " clusters");
140 for (const auto& idxCluster : idxClusters) { ATH_MSG_DEBUG("cluster: " << idxCluster); }
141 }
142 return idxClusters;
143} // end of cluster layer
144
145std::pair<double, double>
147 uint8_t author,
148 const std::vector<NSWCalib::CalibratedStrip>& constituents,
149 const Amg::Vector3D& dirEstimate) const {
150
151
152 double clusterPosition{0}, clusterPositionErrorSq{0.};
153
154 double qtot{0}, meanDriftDist{0.}, meanDriftDistError{0.};
155 double meanPosX{0.}, meanPosXError{0.};
156
157 for (const NSWCalib::CalibratedStrip& clustFeat : constituents) {
158 const double driftDist = clustFeat.distDrift;
160 const double charge = clustFeat.charge * Gaudi::Units::perThousand;
161 const double chargeSq = std::pow(charge, 2);
162 qtot += charge;
163 meanPosX += clustFeat.locPos.x() * charge;
164 meanPosXError += clustFeat.resLongDistDrift * chargeSq;
165 meanDriftDist += driftDist * charge;
166 meanDriftDistError += clustFeat.resTransDistDrift * chargeSq;
167 ATH_MSG_VERBOSE("Strip:"<<m_idHelperSvc->toString(clustFeat.identifier)
168 << " drift dist " << driftDist << " +- " << std::sqrt(clustFeat.resTransDistDrift)
169 << " xpos: "<< clustFeat.locPos.x() << " +- " << std::sqrt(clustFeat.resLongDistDrift)
170 << " xMeanPos " << meanPosX / qtot << " +- " << std::sqrt(meanPosXError) / qtot
171 << " meanPosXError " << meanPosXError << " meanDriftDist " << meanDriftDist / qtot
172 << " meanDriftDist Error " << std::sqrt(meanDriftDistError) / qtot
173 << " charge " << charge << " qtot " << qtot);
174 }
175 meanPosX /= qtot;
176 double meanPosXErrorSq = meanPosXError / (qtot * qtot);
177 meanDriftDist /= qtot;
178 double meanDriftDistErrorSq = meanDriftDistError / (qtot * qtot);
179
180 const double tanTheta = std::tan(dirEstimate.theta());
181 double correction = tanTheta * (meanDriftDist - halfGapWidth);
182 if (m_idHelperSvc->mmIdHelper().gasGap(constituents[0].identifier) % 2 == 0) {
183 correction = -1. * correction; // take care of inverted drif direction for even gaps
184 }
185 double correctionErrorSq = tanTheta * tanTheta * meanDriftDistErrorSq;
186
187 clusterPosition = meanPosX + correction;
188 clusterPositionErrorSq = correctionErrorSq + meanPosXErrorSq;
189
190
191 NswErrorCalibData::Input errorCalibIn{};
192 errorCalibIn.stripId = constituents[0].identifier;
193 errorCalibIn.clusterAuthor = author;
194 errorCalibIn.locPhi = dirEstimate.phi();
195 errorCalibIn.locTheta = dirEstimate.theta();
196 errorCalibIn.localPos = Amg::Vector2D{clusterPosition, 0.};
197 errorCalibIn.clusterSize = constituents.size();
198
199 const double localUncertainty = errorCalibDB.clusterUncertainty(errorCalibIn);
200
201 ATH_MSG_DEBUG("Cluster Properties"
202 << " meanX " << meanPosX << " +-" << std::sqrt(meanPosXErrorSq) << " mean drift dist " << meanDriftDist << " +- "
203 << std::sqrt(meanDriftDistErrorSq) << " correction " << correction << " +- " << std::sqrt(correctionErrorSq)
204 << " final position " << clusterPosition << " +- " << std::sqrt(clusterPositionErrorSq));
205 return std::make_pair(clusterPosition, localUncertainty*localUncertainty);
206}
207
209 const std::vector<Muon::MMPrepData>& constituents,
210 const double clusterPosition,
211 const double clusterPositionErrorSq,
212 std::vector<std::unique_ptr<Muon::MMPrepData>>& mergedClust) const {
213
214 DEFINE_VECTOR(Identifier, rdoList, constituents.size());
215 DEFINE_VECTOR(int, stripCharges, constituents.size());
216 DEFINE_VECTOR(short int, stripTimes, constituents.size());
217 DEFINE_VECTOR(uint16_t, stripNumbers, constituents.size());
218 DEFINE_VECTOR(float, stripDriftDists, constituents.size());
219 DEFINE_VECTOR(AmgVector(2), stripDriftDistErrors, constituents.size());
220
221 int totalCharge{0};
222 for (const Muon::MMPrepData& clustFeat : constituents) {
223 rdoList.push_back(clustFeat.identify());
224 stripNumbers.push_back(channel(clustFeat));
225 stripTimes.push_back(clustFeat.time());
226 stripCharges.push_back(clustFeat.charge());
227 stripDriftDists.push_back(clustFeat.driftDist());
228 const Amg::MatrixX cov{clustFeat.localCovariance()};
229 stripDriftDistErrors.emplace_back(cov(0,0), cov(1,1));
230 totalCharge += clustFeat.charge();
231 }
232 if (!m_writeStripProperties) { stripNumbers.clear(); }
233
234 auto covN = Amg::MatrixX(1, 1);
235 covN.coeffRef(0, 0) = clusterPositionErrorSq;
236 Amg::Vector2D localClusterPositionV(clusterPosition, constituents[0].localPosition().y());
237 Identifier idStrip0 = constituents[0].identify();
238
239 std::unique_ptr<MMPrepData> prdN = std::make_unique<MMPrepData>(idStrip0,
240 constituents[0].collectionHash(),
241 std::move(localClusterPositionV),
242 std::move(rdoList),
243 std::move(covN),
244 constituents[0].detectorElement(),
245 0, // drift dist
246 totalCharge,
247 0.0 /*drift dist*/,
248 std::move(stripNumbers),
249 std::move(stripTimes),
250 std::move(stripCharges));
251
252 prdN->setDriftDist(std::move(stripDriftDists), std::move(stripDriftDistErrors));
254
255 mergedClust.push_back(std::move(prdN));
256 return StatusCode::SUCCESS;
257}
258
260 const std::vector<NSWCalib::CalibratedStrip>& calibratedStrips,
261 const Amg::Vector3D& directionEstimate,
262 Amg::Vector2D& clusterLocalPosition,
263 Amg::MatrixX& covMatrix) const{
264
266 if (!errorCalibDB.isValid()) {
267 ATH_MSG_FATAL("Failed to retrieve the parameterized errors "<<m_uncertCalibKey.fullKey());
268 return RIO_Author::unKnownAuthor;
269 }
270
271 constexpr uint8_t toolAuthor = static_cast<uint8_t>(RIO_Author::ClusterTimeProjectionClusterBuilder);
272 std::pair<double, double> posAndErrorSq = getClusterPositionPRD(*errorCalibDB.cptr(), toolAuthor, calibratedStrips, directionEstimate);
273
274 clusterLocalPosition[Trk::locX] = posAndErrorSq.first;
275 Amg::MatrixX covN(1, 1);
276 covN.coeffRef(0, 0) = posAndErrorSq.second;
277 covMatrix = covN;
278
279 return RIO_Author::ClusterTimeProjectionClusterBuilder;
280}
281}
282#undef DEFINE_VECTOR
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_FATAL(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
double charge(const T &p)
Definition AtlasPID.h:997
#define DEFINE_VECTOR(dType, varName, nEles)
#define AmgVector(rows)
unsigned int uint
static Double_t a
#define y
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
bool msgLvl(const MSG::Level lvl) const
int gasGap(const Identifier &id) const override
get the hashes
int multilayer(const Identifier &id) const
std::array< std::vector< Muon::MMPrepData >, 8 > LaySortedPrds
StatusCode writeClusterPrd(const EventContext &ctx, const std::vector< Muon::MMPrepData > &constituents, const double clustersPosition, const double clustersPositionErrorSq, std::vector< std::unique_ptr< Muon::MMPrepData > > &mergedClust) const
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
Muon Detector Descriptor.
ClusterTimeProjectionMMClusterBuilderTool(const std::string &, const std::string &, const IInterface *)
std::vector< std::vector< uint > > clusterLayer(const std::vector< Muon::MMPrepData > &MMPrdsPerLayer) const
LaySortedPrds sortHitsToLayer(std::vector< Muon::MMPrepData > &&MMprds) const
StatusCode getClusters(const EventContext &ctx, std::vector< Muon::MMPrepData > &&stripsVect, std::vector< std::unique_ptr< Muon::MMPrepData > > &clustersVect) const override
Standard Interface to produce Micromega clusters from raw Input hits without external contstaint.
virtual RIO_Author getCalibratedClusterPosition(const EventContext &ctx, const std::vector< NSWCalib::CalibratedStrip > &calibratedStrips, const Amg::Vector3D &directionEstimate, Amg::Vector2D &clusterLocalPosition, Amg::MatrixX &covMatrix) const override
std::pair< double, double > getClusterPositionPRD(const NswErrorCalibData &errorCalibDB, uint8_t author, const std::vector< NSWCalib::CalibratedStrip > &features, const Amg::Vector3D &thetaEstimate) const
MMClusterOnTrack::Author RIO_Author
Refinement of the cluster position after the cluster calibration loop is ran with a complete external...
Class to represent MM measurements.
Definition MMPrepData.h:22
float driftDist() const
Returns the Drift Distance.
Definition MMPrepData.h:232
int charge() const
Returns the AD.
Definition MMPrepData.h:227
double clusterUncertainty(const Input &clustInfo) const
const_pointer_type cptr()
const Amg::Vector2D & localPosition() const
return the local position reference
Identifier identify() const
return the identifier
const Amg::MatrixX & localCovariance() const
return const ref to the error matrix
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
Amg::Vector3D toLocal(const Amg::Transform3D &toLocalTrans, const Amg::Vector3D &dir)
Rotates a direction vector into a local frame: x-axis : Parallell to the radial direction of the dete...
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
IMMClusterBuilderTool::RIO_Author RIO_Author
@ locX
Definition ParamDefs.h:37
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
Helper struct to be parsed to the object to derive the specific error of the cluster.
unsigned int clusterSize
Cluster size.
double locTheta
Direction of the muon in the local coordinate frame.
Amg::Vector2D localPos
Local position on the surface.
Identifier stripId
Identifier of the strip.
uint8_t clusterAuthor
Author of the cluster.
double locPhi
Azimuthal angle in the local frame.