File indexing completed on 2023-03-17 11:23:28
0001 #ifndef RecoVertex_PrimaryVertexProducer_WeightedMeanFitter_h
0002 #define RecoVertex_PrimaryVertexProducer_WeightedMeanFitter_h
0003
0004 #include <vector>
0005 #include "TrackingTools/TransientTrack/interface/TransientTrack.h"
0006 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0007 #include "DataFormats/BeamSpot/interface/BeamSpot.h"
0008 #include "RecoVertex/VertexPrimitives/interface/TransientVertex.h"
0009
0010 namespace WeightedMeanFitter {
0011
0012 constexpr float startError = 20.0;
0013 constexpr float precision = 1e-24;
0014 constexpr float corr_x = 1.2;
0015 constexpr float corr_x_bs = 1.0;
0016 constexpr float corr_z = 1.4;
0017 constexpr int maxIterations = 50;
0018 constexpr float muSquare = 9.;
0019
0020 inline std::pair<GlobalPoint, double> nearestPoint(const GlobalPoint& vertex, reco::Track iclus) {
0021 double ox = iclus.vx();
0022 double oy = iclus.vy();
0023 double oz = iclus.vz();
0024
0025 double vx = iclus.px();
0026 double vy = iclus.py();
0027 double vz = iclus.pz();
0028
0029 double opx = vertex.x() - ox;
0030 double opy = vertex.y() - oy;
0031 double opz = vertex.z() - oz;
0032
0033 double vnorm2 = (vx * vx + vy * vy + vz * vz);
0034 double t = (vx * opx + vy * opy + vz * opz) / (vnorm2);
0035
0036 GlobalPoint p(ox + t * vx, oy + t * vy, oz + t * vz);
0037 return std::pair<GlobalPoint, double>(
0038 p,
0039 std::sqrt(std::pow(p.x() - vertex.x(), 2) + std::pow(p.y() - vertex.y(), 2) + std::pow(p.z() - vertex.z(), 2)));
0040 }
0041
0042 inline TransientVertex weightedMeanOutlierRejection(const std::vector<std::pair<GlobalPoint, GlobalPoint>>& points,
0043 std::vector<reco::TransientTrack> iclus) {
0044 float x = 0., y = 0., z = 0.;
0045 float s_wx = 0., s_wz = 0.;
0046 float s2_wx = 0., s2_wz = 0.;
0047 float wx = 0., wz = 0., chi2 = 0.;
0048 float ndof_x = 0.;
0049
0050 AlgebraicSymMatrix33 err;
0051 err(0, 0) = startError / 10 * startError / 10;
0052 err(1, 1) = startError / 10 * startError / 10;
0053 err(2, 2) = startError * startError;
0054 for (const auto& p : points) {
0055 wx = p.second.x() <= precision ? 1. / std::pow(precision, 2) : 1. / std::pow(p.second.x(), 2);
0056
0057 wz = p.second.z() <= precision ? 1. / std::pow(precision, 2) : 1. / std::pow(p.second.z(), 2);
0058
0059 x += p.first.x() * wx;
0060 y += p.first.y() * wx;
0061 z += p.first.z() * wz;
0062
0063 s_wx += wx;
0064 s_wz += wz;
0065 }
0066
0067 if (s_wx == 0. || s_wz == 0.) {
0068 edm::LogWarning("WeightedMeanFitter") << "Vertex fitting failed at beginning\n";
0069 return TransientVertex(GlobalPoint(0, 0, 0), err, iclus, 0, 0);
0070 }
0071
0072 x /= s_wx;
0073 y /= s_wx;
0074 z /= s_wz;
0075
0076 float old_x, old_y, old_z;
0077
0078 float xpull;
0079 int niter = 0;
0080
0081 float err_x, err_z;
0082
0083 err_x = 1. / s_wx;
0084 err_z = 1. / s_wz;
0085
0086 while ((niter++) < 2) {
0087 old_x = x;
0088 old_y = y;
0089 old_z = z;
0090 s_wx = 0;
0091 s_wz = 0;
0092 s2_wx = 0;
0093 s2_wz = 0;
0094 x = 0;
0095 y = 0;
0096 z = 0;
0097 ndof_x = 0;
0098
0099 for (unsigned int i = 0; i < (unsigned int)points.size(); i++) {
0100 std::pair<GlobalPoint, double> p = nearestPoint(GlobalPoint(old_x, old_y, old_z), (iclus)[i].track());
0101
0102 wx = points[i].second.x() <= precision ? std::pow(precision, 2) : std::pow(points[i].second.x(), 2);
0103 wz = points[i].second.z() <= precision ? std::pow(precision, 2) : std::pow(points[i].second.z(), 2);
0104
0105 xpull = 0.;
0106
0107 if (std::pow(p.first.x() - old_x, 2) / (wx + err_x) < muSquare &&
0108 std::pow(p.first.y() - old_y, 2) / (wx + err_x) < muSquare &&
0109 std::pow(p.first.z() - old_z, 2) / (wz + err_z) < muSquare)
0110 xpull = 1.;
0111
0112 ndof_x += xpull;
0113
0114 wx = xpull / wx;
0115 wz = xpull / wz;
0116
0117 x += wx * p.first.x();
0118 y += wx * p.first.y();
0119 z += wz * p.first.z();
0120
0121 s_wx += wx;
0122 s_wz += wz;
0123
0124 s2_wx += wx * xpull;
0125 s2_wz += wz * xpull;
0126 }
0127
0128 if (s_wx == 0. || s_wz == 0.) {
0129 edm::LogWarning("WeightedMeanFitter")
0130 << "Vertex fitting failed, either all tracks are outliers or they have a very large error\n";
0131 return TransientVertex(GlobalPoint(0, 0, 0), err, iclus, 0, 0);
0132 }
0133 x /= s_wx;
0134 y /= s_wx;
0135 z /= s_wz;
0136
0137 err_x = (s2_wx / std::pow(s_wx, 2));
0138 err_z = (s2_wz / std::pow(s_wz, 2));
0139
0140 if (std::abs(x - old_x) < (precision / 1.) && std::abs(y - old_y) < (precision / 1.) &&
0141 std::abs(z - old_z) < (precision / 1.)) {
0142 break;
0143 }
0144 }
0145
0146 err(0, 0) = err_x * corr_x * corr_x;
0147 err(1, 1) = err_x * corr_x * corr_x;
0148 err(2, 2) = err_z * corr_z * corr_z;
0149
0150 float dist = 0;
0151 for (const auto& p : points) {
0152 wx = p.second.x();
0153 wx = wx <= precision ? precision : wx;
0154
0155 wz = p.second.z();
0156 wz = wz <= precision ? precision : wz;
0157
0158 dist = std::pow(p.first.x() - x, 2) / (std::pow(wx, 2) + err(0, 0));
0159 dist += std::pow(p.first.y() - y, 2) / (std::pow(wx, 2) + err(1, 1));
0160 dist += std::pow(p.first.z() - z, 2) / (std::pow(wz, 2) + err(2, 2));
0161 chi2 += dist;
0162 }
0163 TransientVertex v(GlobalPoint(x, y, z), err, iclus, chi2, (int)ndof_x);
0164 return v;
0165 }
0166
0167 inline TransientVertex weightedMeanOutlierRejectionBeamSpot(
0168 const std::vector<std::pair<GlobalPoint, GlobalPoint>>& points,
0169 std::vector<reco::TransientTrack> iclus,
0170 const reco::BeamSpot& beamSpot) {
0171 float x = 0., y = 0., z = 0.;
0172 float s_wx = 0., s_wz = 0.;
0173 float s2_wx = 0., s2_wz = 0.;
0174 float wx = 0., wz = 0., chi2 = 0.;
0175 float wy = 0., s_wy = 0., s2_wy = 0.;
0176 float ndof_x = 0.;
0177
0178 AlgebraicSymMatrix33 err;
0179 err(0, 0) = startError / 10 * startError / 10;
0180 err(1, 1) = startError / 10 * startError / 10;
0181 err(2, 2) = startError * startError;
0182
0183 GlobalError bse(beamSpot.rotatedCovariance3D());
0184 GlobalPoint bsp(Basic3DVector<float>(beamSpot.position()));
0185
0186 for (const auto& p : points) {
0187 wx = p.second.x() <= precision ? 1. / std::pow(precision, 2) : 1. / std::pow(p.second.x(), 2);
0188 wy = p.second.y() <= precision ? 1. / std::pow(precision, 2) : 1. / std::pow(p.second.y(), 2);
0189
0190 wz = p.second.z() <= precision ? 1. / std::pow(precision, 2) : 1. / std::pow(p.second.z(), 2);
0191
0192 x += p.first.x() * wx;
0193 y += p.first.y() * wy;
0194 z += p.first.z() * wz;
0195
0196 s_wx += wx;
0197 s_wy += wy;
0198 s_wz += wz;
0199 }
0200
0201 if (s_wx == 0. || s_wy == 0. || s_wz == 0.) {
0202 edm::LogWarning("WeightedMeanFitter") << "Vertex fitting failed at beginning\n";
0203 return TransientVertex(GlobalPoint(0, 0, 0), err, iclus, 0, 0);
0204 }
0205
0206 wx = bse.cxx() <= precision ? 1. / std::pow(precision, 2) : 1. / std::pow(bse.cxx(), 2);
0207 wy = bse.cyy() <= precision ? 1. / std::pow(precision, 2) : 1. / std::pow(bse.cyy(), 2);
0208
0209 x += bsp.x() * wx;
0210 y += bsp.y() * wy;
0211
0212 x /= (s_wx + wx);
0213 y /= (s_wy + wy);
0214 z /= s_wz;
0215
0216 float old_x, old_y, old_z;
0217
0218 float xpull;
0219 int niter = 0;
0220
0221 float err_x, err_y, err_z;
0222
0223 err_x = 1. / s_wx;
0224 err_y = 1. / s_wy;
0225 err_z = 1. / s_wz;
0226
0227 while ((niter++) < 2) {
0228 old_x = x;
0229 old_y = y;
0230 old_z = z;
0231 s_wx = 0;
0232 s_wz = 0;
0233 s2_wx = 0;
0234 s2_wz = 0;
0235
0236 s_wy = 0;
0237 s2_wy = 0;
0238
0239 x = 0;
0240 y = 0;
0241 z = 0;
0242 ndof_x = 0;
0243
0244 for (unsigned int i = 0; i < (unsigned int)points.size(); i++) {
0245 std::pair<GlobalPoint, double> p = nearestPoint(GlobalPoint(old_x, old_y, old_z), (iclus)[i].track());
0246
0247 wx = points[i].second.x() <= precision ? std::pow(precision, 2) : std::pow(points[i].second.x(), 2);
0248 wy = points[i].second.y() <= precision ? std::pow(precision, 2) : std::pow(points[i].second.y(), 2);
0249
0250 wz = points[i].second.z() <= precision ? std::pow(precision, 2) : std::pow(points[i].second.z(), 2);
0251
0252 xpull = 0.;
0253 if (std::pow(p.first.x() - old_x, 2) / (wx + err_x) < muSquare &&
0254 std::pow(p.first.y() - old_y, 2) / (wy + err_y) < muSquare &&
0255 std::pow(p.first.z() - old_z, 2) / (wz + err_z) < muSquare)
0256 xpull = 1.;
0257
0258 ndof_x += xpull;
0259
0260 wx = xpull / wx;
0261 wy = xpull / wy;
0262 wz = xpull / wz;
0263
0264 x += wx * p.first.x();
0265 y += wy * p.first.y();
0266 z += wz * p.first.z();
0267
0268 s_wx += wx;
0269 s_wy += wy;
0270 s_wz += wz;
0271
0272 s2_wx += wx * xpull;
0273 s2_wy += wy * xpull;
0274 s2_wz += wz * xpull;
0275 }
0276
0277 if (s_wx == 0. || s_wy == 0. || s_wz == 0.) {
0278 edm::LogWarning("WeightedMeanFitter")
0279 << "Vertex fitting failed, either all tracks are outliers or they have a very large error\n";
0280 return TransientVertex(GlobalPoint(0, 0, 0), err, iclus, 0, 0);
0281 }
0282 wx = bse.cxx() <= std::pow(precision, 2) ? 1. / std::pow(precision, 2) : 1. / bse.cxx();
0283 wy = bse.cyy() <= std::pow(precision, 2) ? 1. / std::pow(precision, 2) : 1. / bse.cyy();
0284
0285 x += bsp.x() * wx;
0286 y += bsp.y() * wy;
0287 s_wx += wx;
0288 s2_wx += wx;
0289 s_wy += wy;
0290 s2_wy += wy;
0291
0292 x /= s_wx;
0293 y /= s_wy;
0294 z /= s_wz;
0295
0296 err_x = (s2_wx / std::pow(s_wx, 2));
0297 err_y = (s2_wy / std::pow(s_wy, 2));
0298 err_z = (s2_wz / std::pow(s_wz, 2));
0299
0300 if (std::abs(x - old_x) < (precision) && std::abs(y - old_y) < (precision) && std::abs(z - old_z) < (precision)) {
0301 break;
0302 }
0303 }
0304 err(0, 0) = err_x * corr_x_bs * corr_x_bs;
0305 err(1, 1) = err_y * corr_x_bs * corr_x_bs;
0306 err(2, 2) = err_z * corr_z * corr_z;
0307
0308 float dist = 0;
0309 for (const auto& p : points) {
0310 wx = p.second.x();
0311 wx = wx <= precision ? precision : wx;
0312
0313 wz = p.second.z();
0314 wz = wz <= precision ? precision : wz;
0315
0316 dist = std::pow(p.first.x() - x, 2) / (std::pow(wx, 2) + err(0, 0));
0317 dist += std::pow(p.first.y() - y, 2) / (std::pow(wx, 2) + err(1, 1));
0318 dist += std::pow(p.first.z() - z, 2) / (std::pow(wz, 2) + err(2, 2));
0319 chi2 += dist;
0320 }
0321 TransientVertex v(GlobalPoint(x, y, z), err, iclus, chi2, (int)ndof_x);
0322 return v;
0323 }
0324
0325 inline TransientVertex weightedMeanOutlierRejectionVarianceAsError(
0326 const std::vector<std::pair<GlobalPoint, GlobalPoint>>& points,
0327 std::vector<std::vector<reco::TransientTrack>>::const_iterator iclus) {
0328 float x = 0, y = 0, z = 0, s_wx = 0, s_wy = 0, s_wz = 0, wx = 0, wy = 0, wz = 0, chi2 = 0;
0329 float ndof_x = 0;
0330 AlgebraicSymMatrix33 err;
0331 err(2, 2) = startError * startError;
0332 err(0, 0) = err(1, 1) = err(2, 2) / 100.;
0333
0334 for (const auto& p : points) {
0335 wx = p.second.x();
0336 wx = wx <= precision ? 1. / std::pow(precision, 2) : 1. / std::pow(wx, 2);
0337
0338 wz = p.second.z();
0339 wz = wz <= precision ? 1. / std::pow(precision, 2) : 1. / std::pow(wz, 2);
0340
0341 x += p.first.x() * wx;
0342 y += p.first.y() * wx;
0343 z += p.first.z() * wz;
0344
0345 s_wx += wx;
0346 s_wz += wz;
0347 }
0348
0349 if (s_wx == 0. || s_wz == 0.) {
0350 edm::LogWarning("WeightedMeanFitter") << "Vertex fitting failed at beginning\n";
0351 return TransientVertex(GlobalPoint(0, 0, 0), err, *iclus, 0, 0);
0352 }
0353
0354 x /= s_wx;
0355 y /= s_wx;
0356 z /= s_wz;
0357
0358 float old_x, old_y, old_z;
0359 float xpull;
0360 int niter = 0;
0361 float err_x, err_y, err_z;
0362 err_x = 1. / s_wx;
0363 err_y = 1. / s_wx;
0364 err_z = 1. / s_wz;
0365 float s_err_x = 0., s_err_y = 0., s_err_z = 0.;
0366 while ((niter++) < maxIterations) {
0367 old_x = x;
0368 old_y = y;
0369 old_z = z;
0370 s_wx = 0;
0371 s_wy = 0;
0372 s_wz = 0;
0373 x = 0;
0374 y = 0;
0375 z = 0;
0376 s_err_x = 0.;
0377 s_err_y = 0.;
0378 s_err_z = 0.;
0379
0380 for (const auto& p : points) {
0381 wx = p.second.x();
0382 wx = wx <= precision ? precision : wx;
0383
0384 wy = wx * wx + err_y;
0385 wx = wx * wx + err_x;
0386
0387 wz = p.second.z();
0388 wz = wz <= precision ? precision : wz;
0389 wz = wz * wz + err_z;
0390
0391 xpull = std::pow((p.first.x() - old_x), 2) / wx;
0392 xpull += std::pow((p.first.y() - old_y), 2) / wy;
0393 xpull += std::pow((p.first.z() - old_z), 2) / wz;
0394 xpull = 1. / (1. + std::exp(-0.5 * ((muSquare)-xpull)));
0395 ndof_x += xpull;
0396
0397 wx = 1. / wx;
0398 wy = 1. / wy;
0399 wz = 1. / wz;
0400
0401 wx *= xpull;
0402 wy *= xpull;
0403 wz *= xpull;
0404
0405 x += wx * p.first.x();
0406 y += wy * p.first.y();
0407 z += wz * p.first.z();
0408
0409 s_wx += wx;
0410 s_wy += wy;
0411 s_wz += wz;
0412
0413 s_err_x += wx * pow(p.first.x() - old_x, 2);
0414 s_err_y += wy * pow(p.first.y() - old_y, 2);
0415 s_err_z += wz * pow(p.first.z() - old_z, 2);
0416 }
0417 if (s_wx == 0. || s_wy == 0. || s_wz == 0.) {
0418 edm::LogWarning("WeightedMeanFitter")
0419 << "Vertex fitting failed, either all tracks are outliers or they have a very large error\n";
0420 return TransientVertex(GlobalPoint(0, 0, 0), err, *iclus, 0, 0);
0421 }
0422 x /= s_wx;
0423 y /= s_wy;
0424 z /= s_wz;
0425
0426 err_x = s_err_x / s_wx;
0427 err_y = s_err_y / s_wy;
0428 err_z = s_err_z / s_wz;
0429
0430 if (std::abs(x - old_x) < (precision / 1.) && std::abs(y - old_y) < (precision / 1.) &&
0431 std::abs(z - old_z) < (precision / 1.))
0432 break;
0433 }
0434
0435 err(0, 0) = err_x;
0436 err(1, 1) = err_y;
0437 err(2, 2) = err_z;
0438
0439 float dist = 0.f;
0440 for (const auto& p : points) {
0441 wx = p.second.x();
0442 wx = wx <= precision ? precision : wx;
0443
0444 wz = p.second.z();
0445 wz = wz <= precision ? precision : wz;
0446
0447 dist = std::pow(p.first.x() - x, 2) / (std::pow(wx, 2) + std::pow(err(0, 0), 2));
0448 dist += std::pow(p.first.y() - y, 2) / (std::pow(wx, 2) + std::pow(err(1, 1), 2));
0449 dist += std::pow(p.first.z() - z, 2) / (std::pow(wz, 2) + std::pow(err(2, 2), 2));
0450 chi2 += dist;
0451 }
0452 TransientVertex v(GlobalPoint(x, y, z), err, *iclus, chi2, (int)ndof_x);
0453 return v;
0454 }
0455
0456 };
0457
0458 #endif