84 const std::vector<Muon::sTgcPrepData>& cluster,
85 const double resolution,
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;
103 double weight = isStrip ? prd.charge() : 1.0;
104 ATH_MSG_DEBUG(
"isStrip: " << isStrip <<
" weight: " << weight);
106 weightedPosX += prd.localPosition().x()*weight;
108 sigmaSq += weight*weight*resolution*resolution;
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();
140 const double localUncertainty =
m_errorCalibData.clusterUncertainty(errorCalibIn);
145 <<
", theta: "<<clusDir.theta() / Gaudi::Units::deg
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) {
188 if (
msgLvl(MSG::VERBOSE)) {
189 std::stringstream sstr{};
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) {
237 if (
msgLvl(MSG::VERBOSE)) {
238 std::stringstream sstr{};
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));
260 if (
msgLvl(MSG::VERBOSE)) {
261 std::stringstream sstr{};
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) {
292 if (
msgLvl(MSG::VERBOSE)) {
293 std::stringstream sstr{};
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);
331 if (
msgLvl(MSG::VERBOSE)) {
332 std::stringstream sstr{};
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;
352 errorCalibIn.
locPhi = clusDir.phi();
353 errorCalibIn.
locTheta = clusDir.theta();
357 const double localUncertainty =
m_errorCalibData.clusterUncertainty(errorCalibIn);
359 ATH_MSG_DEBUG(
"Reconstructed a cluster using the Caruana method,"
361 <<
", mean position = " << reconstructedPosX
362 <<
", uncertainty = " << std::sqrt(sigmaSq));
364 return std::make_optional<Muon::STgcClusterPosition>(clusterId, reconstructedPosX, localUncertainty*localUncertainty);