8 #include "GaudiKernel/SystemOfUnits.h"
12 m_stgcIdHelper(idHelper),
13 m_errorCalibData{errorCalibData}
19 std::array<std::vector<Muon::sTgcPrepData>, 8>
23 std::array<std::vector<Muon::sTgcPrepData>, 8> stgcPrdsPerLayer;
26 int layer = 4 * (m_stgcIdHelper.multilayer(
id) - 1) + (m_stgcIdHelper.gasGap(
id) - 1);
27 ATH_MSG_DEBUG(
"Sorting PRD into layer, layer: " <<
layer <<
" gas_gap: " << m_stgcIdHelper.gasGap(
id)
28 <<
"multilayer: " << m_stgcIdHelper.multilayer(
id));
29 stgcPrdsPerLayer.at(
layer).push_back(std::move(prd));
33 for (
unsigned int i_layer = 0; i_layer < stgcPrdsPerLayer.size(); i_layer++) {
34 std::sort(stgcPrdsPerLayer.at(i_layer).begin(), stgcPrdsPerLayer.at(i_layer).end(),
36 return m_stgcIdHelper.channel(a.identify()) < m_stgcIdHelper.channel(b.identify());
39 return stgcPrdsPerLayer;
45 const int maxMissingStrip)
const {
46 std::vector<std::vector<Muon::sTgcPrepData>>
clusters;
51 const Identifier& firstStripId = strips.front().identify();
57 clusters.back().push_back(std::move(prd));
62 if (m_stgcIdHelper.multilayerID(firstStripId) != m_stgcIdHelper.multilayerID(prd_id) ||
63 m_stgcIdHelper.gasGap(firstStripId) != m_stgcIdHelper.gasGap(prd_id) ||
64 m_stgcIdHelper.channelType(firstStripId) != m_stgcIdHelper.channelType(prd_id)) {
65 ATH_MSG_WARNING(
"Strips must be separated by layer before attempting to build clusters,"
66 <<
" but found strips from different chambers");
71 if (std::abs(m_stgcIdHelper.channel(prd.identify()) -
72 m_stgcIdHelper.channel(
clusters.back().back().identify())) > maxMissingStrip + 1) {
75 clusters.back().push_back(std::move(prd));
84 const std::vector<Muon::sTgcPrepData>& cluster,
89 if (cluster.empty()) {
94 double weightedPosX{0.0}, maxCharge{-1.0}, sumWeight{0.0}, sigmaSq{0.0};
98 ATH_MSG_DEBUG(
"Running weighted average method on a cluster with " << cluster.size() <<
" strips");
101 if (prd.charge() < 0)
continue;
106 weightedPosX += prd.localPosition().x()*
weight;
110 ATH_MSG_DEBUG(
"Channel local position and charge: " << prd.localPosition().x() <<
" " << prd.charge() );
114 clusterId = prd.identify();
115 }
else if (prd.charge() > maxCharge) {
116 maxCharge = prd.charge();
117 clusterId = prd.identify();
129 double reconstructedPosX = weightedPosX / sumWeight;
130 sigmaSq /= sumWeight;
133 errorCalibIn.
stripId = clusterId;
135 errorCalibIn.locPhi = clusDir.phi();
136 errorCalibIn.locTheta = clusDir.theta();
138 errorCalibIn.clusterSize = cluster.size();
140 const double localUncertainty = m_errorCalibData.clusterUncertainty(errorCalibIn);
143 <<
" cluster Id: " << m_stgcIdHelper.print_to_string(clusterId)
146 <<
", mean position = " << reconstructedPosX
147 <<
", uncertainty = " << localUncertainty
148 <<
", sigmaSQ: "<<sigmaSq);
150 return std::make_optional<Muon::STgcClusterPosition>(clusterId, reconstructedPosX, localUncertainty*localUncertainty);
156 const std::vector<sTgcPrepData>& cluster,
157 const double positionResolution,
158 const double angularResolution,
163 std::vector<int> charges;
164 charges.reserve(cluster.size());
165 std::vector<double> stripPositions;
166 stripPositions.reserve(cluster.size());
167 bool isStairUp{
true}, isStairDown{
true};
168 int multiplicity = 0;
169 for (
unsigned int j = 0; j < cluster.size(); ++j){
170 int stripCharge = cluster.at(j).charge();
171 if (stripCharge > 0) {
173 charges.push_back(stripCharge);
174 stripPositions.push_back(cluster.at(j).localPosition().x());
177 int prevStripCharge = cluster.at(j-1).charge();
178 if (isStairUp && (stripCharge - prevStripCharge < 0))
180 if (isStairDown && (prevStripCharge > 0) && (stripCharge - prevStripCharge > 0))
187 if (multiplicity < 3 || isStairUp || isStairDown) {
189 std::stringstream sstr{};
191 sstr << m_stgcIdHelper.print_to_string(prd.identify())
192 <<
", local pos: ("<< prd.localPosition().x() <<
"," << prd.localPosition().y()
193 <<
"), charge: " << prd.charge() <<
", time: " <<
static_cast<int>(prd.time())
196 ATH_MSG_VERBOSE(
"Reject cluster incompatible with the Caruana method..." << std::endl << sstr.str());
203 for (
int i=0;
i<3;
i++) {
204 for (
int j=0; j<=
i; j++) elementPosMatrix.fillSymmetric(
i, j, 0);
210 float clusterCenter = 0;
211 for (
size_t i_strip = 0; i_strip < stripPositions.size(); i_strip++) {
212 clusterCenter += stripPositions.at(i_strip);
214 clusterCenter = clusterCenter / stripPositions.size();
216 std::vector<double> stripPositions_shifted = {};
217 for (
size_t i_strip = 0; i_strip < stripPositions.size(); i_strip++) {
218 stripPositions_shifted.push_back(stripPositions.at(i_strip)-clusterCenter);
222 for (
size_t i_element = 0; i_element < stripPositions_shifted.size(); i_element++) {
223 elementPosMatrix.fillSymmetric(0, 0, elementPosMatrix(0,0) + 1);
224 elementPosMatrix.fillSymmetric(0, 1, elementPosMatrix(0,1) + stripPositions_shifted.at(i_element));
225 elementPosMatrix.fillSymmetric(0, 2, elementPosMatrix(0,2) +
std::pow(stripPositions_shifted.at(i_element), 2));
226 elementPosMatrix.fillSymmetric(1, 2, elementPosMatrix(1,2) +
std::pow(stripPositions_shifted.at(i_element), 3));
227 elementPosMatrix.fillSymmetric(2, 2, elementPosMatrix(2,2) +
std::pow(stripPositions_shifted.at(i_element), 4));
228 const double log_charge =
std::log(charges.at(i_element));
229 chargeVector(0) += log_charge;
230 chargeVector(1) += stripPositions_shifted.at(i_element) * log_charge;
231 chargeVector(2) +=
std::pow(stripPositions_shifted.at(i_element), 2) * log_charge;
233 elementPosMatrix(1,1) = elementPosMatrix(0,2);
236 if (elementPosMatrix.determinant() == 0) {
238 std::stringstream sstr{};
240 sstr << m_stgcIdHelper.print_to_string(prd.identify())
241 <<
", local pos: ("<< prd.localPosition().x() <<
"," << prd.localPosition().y()
242 <<
"), charge: " << prd.charge() <<
", time: " <<
static_cast<int>(prd.time())
245 ATH_MSG_VERBOSE(
"Failed to compute the position of the cluster..." << std::endl << sstr.str());
251 Amg::Vector3D caruanaPars = (elementPosMatrix.inverse()) * chargeVector;
256 double reconstructedPosX{0.};
257 if (caruanaPars(2) < -0.005) {
258 reconstructedPosX = clusterCenter - caruanaPars(1) / (2*caruanaPars(2));
261 std::stringstream sstr{};
263 sstr << m_stgcIdHelper.print_to_string(prd.identify())
264 <<
", local pos: ("<< prd.localPosition().x() <<
"," << prd.localPosition().y()
265 <<
"), charge: " << prd.charge() <<
", time: " <<
static_cast<int>(prd.time())
268 ATH_MSG_VERBOSE(
"Reject cluster with large standard deviation..." << std::endl << sstr.str());
274 double minCenterDistance = 9999.99;
275 int channelIndex = 0;
276 for (
size_t i_elem = 0; i_elem < cluster.size(); i_elem++) {
277 double strip_localPos = cluster.at(i_elem).localPosition().x();
278 if (minCenterDistance > abs(strip_localPos - reconstructedPosX)) {
279 minCenterDistance = abs(strip_localPos - reconstructedPosX);
280 channelIndex = i_elem;
283 const Identifier clusterId = cluster.at(channelIndex).identify();
287 const double stripPitch = detEl->
channelPitch(clusterId);
291 if (minCenterDistance > stripPitch) {
293 std::stringstream sstr{};
295 sstr << m_stgcIdHelper.print_to_string(prd.identify())
296 <<
", local pos: ("<< prd.localPosition().x() <<
"," << prd.localPosition().y()
297 <<
"), charge: " << prd.charge() <<
", time: " <<
static_cast<int>(prd.time())
300 ATH_MSG_VERBOSE(
"Reject cluster since its position is more than " << stripPitch <<
" mm too far from the nearest strip..."
301 << std::endl << sstr.str());
310 for (
size_t i_strip = 0; i_strip < stripPositions_shifted.size(); i_strip++) {
312 gamma2 +=
std::pow(stripPositions_shifted.at(i_strip), 2);
313 gamma4 +=
std::pow(stripPositions_shifted.at(i_strip), 4);
319 double tan_theta = std::hypot(globPos.x(), globPos.y()) / globPos.z();
320 double spreadFactor = std::hypot(positionResolution, angularResolution * tan_theta);
322 double sigma_b = spreadFactor / std::sqrt(gamma2);
323 double sigma_c = spreadFactor * std::sqrt(gamma0 / (gamma0 * gamma4 - gamma2 * gamma2));
326 double sigmaSq =
std::pow((1 / (2 * caruanaPars(2))) * sigma_b, 2) +
327 std::pow((caruanaPars(1) / (2 * caruanaPars(2) * caruanaPars(2))) * sigma_c, 2);
332 std::stringstream sstr{};
334 sstr << m_stgcIdHelper.print_to_string(prd.identify())
335 <<
", local pos: ("<< prd.localPosition().x() <<
"," << prd.localPosition().y()
336 <<
"), charge: " << prd.charge() <<
", time: " <<
static_cast<int>(prd.time())
339 ATH_MSG_VERBOSE(
"Reject cluster with large error on the mean position..." << std::endl << sstr.str());
349 errorCalibIn.
stripId = clusterId;
351 errorCalibIn.clusterError = std::sqrt(sigmaSq);
352 errorCalibIn.locPhi = clusDir.phi();
353 errorCalibIn.locTheta = clusDir.theta();
355 errorCalibIn.clusterSize = cluster.size();
357 const double localUncertainty = m_errorCalibData.clusterUncertainty(errorCalibIn);
359 ATH_MSG_DEBUG(
"Reconstructed a cluster using the Caruana method,"
360 <<
" cluster Id: " << m_stgcIdHelper.print_to_string(clusterId)
361 <<
", mean position = " << reconstructedPosX
362 <<
", uncertainty = " << std::sqrt(sigmaSq));
364 return std::make_optional<Muon::STgcClusterPosition>(clusterId, reconstructedPosX, localUncertainty*localUncertainty);