File indexing completed on 2024-04-06 12:26:13
0001
0002
0003
0004
0005
0006
0007
0008 #include "ME0SegAlgoRU.h"
0009 #include "MuonSegFit.h"
0010 #include "Geometry/GEMGeometry/interface/ME0Layer.h"
0011 #include "DataFormats/GeometryVector/interface/GlobalPoint.h"
0012 #include "DataFormats/Math/interface/deltaPhi.h"
0013 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0014 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0015
0016 #include <algorithm>
0017 #include <cmath>
0018 #include <iostream>
0019 #include <string>
0020
0021 #include <Math/Functions.h>
0022 #include <Math/SVector.h>
0023 #include <Math/SMatrix.h>
0024
0025 ME0SegAlgoRU::ME0SegAlgoRU(const edm::ParameterSet& ps) : ME0SegmentAlgorithmBase(ps), myName("ME0SegAlgoRU") {
0026 allowWideSegments = ps.getParameter<bool>("allowWideSegments");
0027 doCollisions = ps.getParameter<bool>("doCollisions");
0028
0029 stdParameters.maxChi2Additional = ps.getParameter<double>("maxChi2Additional");
0030 stdParameters.maxChi2Prune = ps.getParameter<double>("maxChi2Prune");
0031 stdParameters.maxChi2GoodSeg = ps.getParameter<double>("maxChi2GoodSeg");
0032 stdParameters.maxPhiSeeds = ps.getParameter<double>("maxPhiSeeds");
0033 stdParameters.maxPhiAdditional = ps.getParameter<double>("maxPhiAdditional");
0034 stdParameters.maxETASeeds = ps.getParameter<double>("maxETASeeds");
0035 stdParameters.maxTOFDiff = ps.getParameter<double>("maxTOFDiff");
0036 stdParameters.requireCentralBX = ps.getParameter<bool>("requireCentralBX");
0037 stdParameters.minNumberOfHits = ps.getParameter<unsigned int>("minNumberOfHits");
0038 stdParameters.requireBeamConstr = true;
0039
0040 wideParameters = stdParameters;
0041 wideParameters.maxChi2Prune *= 2;
0042 wideParameters.maxChi2GoodSeg *= 2;
0043 wideParameters.maxPhiSeeds *= 2;
0044 wideParameters.maxPhiAdditional *= 2;
0045 wideParameters.minNumberOfHits += 1;
0046
0047 displacedParameters = stdParameters;
0048 displacedParameters.maxChi2Additional *= 2;
0049 displacedParameters.maxChi2Prune = 100;
0050 displacedParameters.maxChi2GoodSeg *= 5;
0051 displacedParameters.maxPhiSeeds *= 2;
0052 displacedParameters.maxPhiAdditional *= 2;
0053 displacedParameters.maxETASeeds *= 2;
0054 displacedParameters.requireBeamConstr = false;
0055
0056 LogDebug("ME0SegAlgoRU") << myName << " has algorithm cuts set to: \n"
0057 << "--------------------------------------------------------------------\n"
0058 << "allowWideSegments = " << allowWideSegments << "\n"
0059 << "doCollisions = " << doCollisions << "\n"
0060 << "maxChi2Additional = " << stdParameters.maxChi2Additional << "\n"
0061 << "maxChi2Prune = " << stdParameters.maxChi2Prune << "\n"
0062 << "maxChi2GoodSeg = " << stdParameters.maxChi2GoodSeg << "\n"
0063 << "maxPhiSeeds = " << stdParameters.maxPhiSeeds << "\n"
0064 << "maxPhiAdditional = " << stdParameters.maxPhiAdditional << "\n"
0065 << "maxETASeeds = " << stdParameters.maxETASeeds << "\n"
0066 << "maxTOFDiff = " << stdParameters.maxTOFDiff << "\n"
0067 << std::endl;
0068
0069 theChamber = nullptr;
0070 }
0071
0072 std::vector<ME0Segment> ME0SegAlgoRU::run(const ME0Chamber* chamber, const HitAndPositionContainer& rechits) {
0073 #ifdef EDM_ML_DEBUG
0074 ME0DetId chId(chamber->id());
0075 edm::LogVerbatim("ME0SegAlgoRU") << "[ME0SegmentAlgorithm::run] build segments in chamber " << chId
0076 << " which contains " << rechits.size() << " rechits";
0077 for (unsigned int iH = 0; iH < rechits.size(); ++iH) {
0078 auto me0id = rechits[iH].rh->me0Id();
0079 auto rhLP = rechits[iH].lp;
0080 edm::LogVerbatim("ME0SegAlgoRU") << "[RecHit :: Loc x = " << std::showpos << std::setw(9) << rhLP.x()
0081 << " Glb y = " << std::showpos << std::setw(9) << rhLP.y()
0082 << " Time = " << std::showpos << rechits[iH].rh->tof() << " -- " << me0id.rawId()
0083 << " = " << me0id << " ]" << std::endl;
0084 }
0085 #endif
0086
0087 if (rechits.size() < 3 || rechits.size() > 300) {
0088 return std::vector<ME0Segment>();
0089 }
0090
0091 theChamber = chamber;
0092
0093 std::vector<unsigned int> recHits_per_layer(6, 0);
0094 for (unsigned int iH = 0; iH < rechits.size(); ++iH) {
0095 recHits_per_layer[rechits[iH].layer - 1]++;
0096 }
0097
0098 BoolContainer used(rechits.size(), false);
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114 std::vector<ME0Segment> segments;
0115
0116 auto doStd = [&]() {
0117 for (unsigned int n_seg_min = 6u; n_seg_min >= stdParameters.minNumberOfHits; --n_seg_min)
0118 lookForSegments(stdParameters, n_seg_min, rechits, recHits_per_layer, used, segments);
0119 };
0120 auto doDisplaced = [&]() {
0121 for (unsigned int n_seg_min = 6u; n_seg_min >= displacedParameters.minNumberOfHits; --n_seg_min)
0122 lookForSegments(displacedParameters, n_seg_min, rechits, recHits_per_layer, used, segments);
0123 };
0124
0125
0126
0127
0128
0129 auto printSegments = [&] {
0130 #ifdef EDM_ML_DEBUG
0131 for (unsigned int iS = 0; iS < segments.size(); ++iS) {
0132 const auto& seg = segments[iS];
0133 ME0DetId chId(seg.me0DetId());
0134 const auto& rechits = seg.specificRecHits();
0135 edm::LogVerbatim("ME0SegAlgoRU") << "[ME0SegAlgoRU] segment in chamber " << chId << " which contains "
0136 << rechits.size() << " rechits and with specs: \n"
0137 << seg;
0138 for (auto rh = rechits.begin(); rh != rechits.end(); ++rh) {
0139 auto me0id = rh->me0Id();
0140 edm::LogVerbatim("ME0SegAlgoRU") << "[RecHit :: Loc x = " << std::showpos << std::setw(9)
0141 << rh->localPosition().x() << " Loc y = " << std::showpos << std::setw(9)
0142 << rh->localPosition().y() << " Time = " << std::showpos << rh->tof() << " -- "
0143 << me0id.rawId() << " = " << me0id << " ]";
0144 }
0145 }
0146 #endif
0147 };
0148
0149
0150 if (!doCollisions) {
0151 doDisplaced();
0152 printSegments();
0153 return segments;
0154 }
0155
0156
0157 doStd();
0158
0159 if (false) {
0160
0161
0162
0163
0164 if (!allowWideSegments || !segments.empty()) {
0165 doDisplaced();
0166 return segments;
0167 }
0168
0169 doDisplaced();
0170 }
0171 printSegments();
0172 return segments;
0173 }
0174
0175 void ME0SegAlgoRU::lookForSegments(const SegmentParameters& params,
0176 const unsigned int n_seg_min,
0177 const HitAndPositionContainer& rechits,
0178 const std::vector<unsigned int>& recHits_per_layer,
0179 BoolContainer& used,
0180 std::vector<ME0Segment>& segments) const {
0181 auto ib = rechits.begin();
0182 auto ie = rechits.end();
0183 std::vector<std::pair<float, HitAndPositionPtrContainer> > proto_segments;
0184
0185 for (auto i1 = ib; i1 != ie; ++i1) {
0186 const auto& h1 = *i1;
0187
0188
0189 if (used[h1.idx])
0190 continue;
0191 if (recHits_per_layer[h1.layer - 1] > 100)
0192 continue;
0193
0194
0195
0196 for (auto i2 = ie - 1; i2 != i1; --i2) {
0197
0198 const auto& h2 = *i2;
0199
0200
0201 if (used[h2.idx])
0202 continue;
0203 if (recHits_per_layer[h2.layer - 1] > 100)
0204 continue;
0205
0206
0207 if ((std::abs(int(h2.layer) - int(h1.layer)) + 1) < int(n_seg_min))
0208 break;
0209
0210 if (std::fabs(h1.rh->tof() - h2.rh->tof()) > params.maxTOFDiff + 1.0)
0211 continue;
0212 if (!areHitsCloseInEta(params.maxETASeeds, params.requireBeamConstr, h1.gp, h2.gp))
0213 continue;
0214 if (!areHitsCloseInGlobalPhi(params.maxPhiSeeds, abs(int(h2.layer) - int(h1.layer)), h1.gp, h2.gp))
0215 continue;
0216
0217 HitAndPositionPtrContainer current_proto_segment;
0218 std::unique_ptr<MuonSegFit> current_fit;
0219 current_fit = addHit(current_proto_segment, h1);
0220 current_fit = addHit(current_proto_segment, h2);
0221
0222 tryAddingHitsToSegment(params.maxTOFDiff,
0223 params.maxETASeeds,
0224 params.maxPhiAdditional,
0225 params.maxChi2Additional,
0226 current_fit,
0227 current_proto_segment,
0228 used,
0229 i1,
0230 i2);
0231
0232 if (current_proto_segment.size() > n_seg_min)
0233 pruneBadHits(params.maxChi2Prune, current_proto_segment, current_fit, n_seg_min);
0234
0235 edm::LogVerbatim("ME0SegAlgoRU") << "[ME0SegAlgoRU::lookForSegments] # of hits in segment "
0236 << current_proto_segment.size() << " min # " << n_seg_min << " => "
0237 << (current_proto_segment.size() >= n_seg_min) << " chi2/ndof "
0238 << current_fit->chi2() / current_fit->ndof() << " => "
0239 << (current_fit->chi2() / current_fit->ndof() < params.maxChi2GoodSeg)
0240 << std::endl;
0241
0242 if (current_proto_segment.size() < n_seg_min)
0243 continue;
0244 const float current_metric = current_fit->chi2() / current_fit->ndof();
0245 if (current_metric > params.maxChi2GoodSeg)
0246 continue;
0247
0248 if (params.requireCentralBX) {
0249 int nCentral = 0;
0250 int nNonCentral = 0;
0251 for (const auto* rh : current_proto_segment) {
0252 if (std::fabs(rh->rh->tof()) < 2)
0253 nCentral++;
0254 else
0255 nNonCentral++;
0256 }
0257 if (nNonCentral >= nCentral)
0258 continue;
0259 }
0260
0261
0262 proto_segments.emplace_back(current_metric, current_proto_segment);
0263 }
0264 }
0265 addUniqueSegments(proto_segments, segments, used);
0266 }
0267
0268 void ME0SegAlgoRU::addUniqueSegments(SegmentByMetricContainer& proto_segments,
0269 std::vector<ME0Segment>& segments,
0270 BoolContainer& used) const {
0271 std::sort(proto_segments.begin(),
0272 proto_segments.end(),
0273 [](const std::pair<float, HitAndPositionPtrContainer>& a,
0274 const std::pair<float, HitAndPositionPtrContainer>& b) { return a.first < b.first; });
0275
0276
0277 std::vector<unsigned int> usedHits;
0278 for (unsigned int iS = 0; iS < proto_segments.size(); ++iS) {
0279 HitAndPositionPtrContainer currentProtoSegment = proto_segments[iS].second;
0280
0281
0282 bool alreadyFilled = false;
0283 for (unsigned int iH = 0; iH < currentProtoSegment.size(); ++iH) {
0284 for (unsigned int iOH = 0; iOH < usedHits.size(); ++iOH) {
0285 if (usedHits[iOH] != currentProtoSegment[iH]->idx)
0286 continue;
0287 alreadyFilled = true;
0288 break;
0289 }
0290 }
0291 if (alreadyFilled)
0292 continue;
0293 for (const auto* h : currentProtoSegment) {
0294 usedHits.push_back(h->idx);
0295 used[h->idx] = true;
0296 }
0297
0298 std::unique_ptr<MuonSegFit> current_fit = makeFit(currentProtoSegment);
0299
0300
0301
0302
0303 float averageTime = 0.;
0304 for (const auto* h : currentProtoSegment) {
0305 averageTime += h->rh->tof();
0306 }
0307 averageTime /= float(currentProtoSegment.size());
0308 float timeUncrt = 0.;
0309 for (const auto* h : currentProtoSegment) {
0310 timeUncrt += (h->rh->tof() - averageTime) * (h->rh->tof() - averageTime);
0311 }
0312 timeUncrt = std::sqrt(timeUncrt / float(currentProtoSegment.size() - 1));
0313
0314 std::sort(currentProtoSegment.begin(),
0315 currentProtoSegment.end(),
0316 [](const HitAndPosition* a, const HitAndPosition* b) { return a->layer < b->layer; });
0317
0318 std::vector<const ME0RecHit*> bareRHs;
0319 bareRHs.reserve(currentProtoSegment.size());
0320 for (const auto* rh : currentProtoSegment)
0321 bareRHs.push_back(rh->rh);
0322 const float dPhi = theChamber->computeDeltaPhi(current_fit->intercept(), current_fit->localdir());
0323 ME0Segment temp(bareRHs,
0324 current_fit->intercept(),
0325 current_fit->localdir(),
0326 current_fit->covarianceMatrix(),
0327 current_fit->chi2(),
0328 averageTime,
0329 timeUncrt,
0330 dPhi);
0331 segments.push_back(temp);
0332 }
0333 }
0334
0335 void ME0SegAlgoRU::tryAddingHitsToSegment(const float maxTOF,
0336 const float maxETA,
0337 const float maxPhi,
0338 const float maxChi2,
0339 std::unique_ptr<MuonSegFit>& current_fit,
0340 HitAndPositionPtrContainer& proto_segment,
0341 const BoolContainer& used,
0342 HitAndPositionContainer::const_iterator i1,
0343 HitAndPositionContainer::const_iterator i2) const {
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356 for (auto iH = i1 + 1; iH != i2; ++iH) {
0357 if (iH->layer == i1->layer)
0358 continue;
0359 if (iH->layer == i2->layer)
0360 break;
0361 if (used[iH->idx])
0362 continue;
0363 if (!areHitsConsistentInTime(maxTOF, proto_segment, *iH))
0364 continue;
0365 if (!isHitNearSegment(maxETA, maxPhi, current_fit, proto_segment, *iH))
0366 continue;
0367 if (hasHitOnLayer(proto_segment, iH->layer))
0368 compareProtoSegment(current_fit, proto_segment, *iH);
0369 else
0370 increaseProtoSegment(maxChi2, current_fit, proto_segment, *iH);
0371 }
0372 }
0373
0374 bool ME0SegAlgoRU::areHitsCloseInEta(const float maxETA,
0375 const bool beamConst,
0376 const GlobalPoint& h1,
0377 const GlobalPoint& h2) const {
0378 float diff = std::fabs(h1.eta() - h2.eta());
0379 edm::LogVerbatim("ME0SegAlgoRU") << "[ME0SegAlgoRU::areHitsCloseInEta] gp1 = " << h1 << " in eta part = " << h1.eta()
0380 << " and gp2 = " << h2 << " in eta part = " << h2.eta() << " ==> dEta = " << diff
0381 << " ==> return " << (diff < 0.1) << std::endl;
0382
0383 return (diff < std::max(maxETA, 0.01f));
0384 }
0385
0386 bool ME0SegAlgoRU::areHitsCloseInGlobalPhi(const float maxPHI,
0387 const unsigned int nLayDisp,
0388 const GlobalPoint& h1,
0389 const GlobalPoint& h2) const {
0390 float dphi12 = deltaPhi(h1.barePhi(), h2.barePhi());
0391 edm::LogVerbatim("ME0SegAlgoRU") << "[ME0SegAlgoRU::areHitsCloseInGlobalPhi] gp1 = " << h1 << " and gp2 = " << h2
0392 << " ==> dPhi = " << dphi12 << " ==> return "
0393 << (fabs(dphi12) < std::max(maxPHI, 0.02f)) << std::endl;
0394 return fabs(dphi12) < std::max(maxPHI, float(float(nLayDisp) * 0.004));
0395 }
0396
0397 bool ME0SegAlgoRU::isHitNearSegment(const float maxETA,
0398 const float maxPHI,
0399 const std::unique_ptr<MuonSegFit>& fit,
0400 const HitAndPositionPtrContainer& proto_segment,
0401 const HitAndPosition& h) const {
0402
0403 const float avgETA = (proto_segment[1]->gp.eta() + proto_segment[0]->gp.eta()) / 2.;
0404
0405 if (std::fabs(h.gp.eta() - avgETA) > std::max(maxETA, 0.01f))
0406 return false;
0407
0408
0409 GlobalPoint globIntercept = globalAtZ(fit, h.lp.z());
0410 float dPhi = deltaPhi(h.gp.barePhi(), globIntercept.phi());
0411
0412
0413 return (std::fabs(dPhi) < std::max(maxPHI, 0.001f));
0414 }
0415
0416 bool ME0SegAlgoRU::areHitsConsistentInTime(const float maxTOF,
0417 const HitAndPositionPtrContainer& proto_segment,
0418 const HitAndPosition& h) const {
0419 std::vector<float> tofs;
0420 tofs.reserve(proto_segment.size() + 1);
0421 tofs.push_back(h.rh->tof());
0422 for (const auto* ih : proto_segment)
0423 tofs.push_back(ih->rh->tof());
0424 std::sort(tofs.begin(), tofs.end());
0425 if (std::fabs(tofs.front() - tofs.back()) < maxTOF + 1.0)
0426 return true;
0427 return false;
0428 }
0429
0430 GlobalPoint ME0SegAlgoRU::globalAtZ(const std::unique_ptr<MuonSegFit>& fit, float z) const {
0431 float x = fit->xfit(z);
0432 float y = fit->yfit(z);
0433 return theChamber->toGlobal(LocalPoint(x, y, z));
0434 }
0435
0436 std::unique_ptr<MuonSegFit> ME0SegAlgoRU::addHit(HitAndPositionPtrContainer& proto_segment,
0437 const HitAndPosition& aHit) const {
0438 proto_segment.push_back(&aHit);
0439
0440 return makeFit(proto_segment);
0441 }
0442
0443 std::unique_ptr<MuonSegFit> ME0SegAlgoRU::makeFit(const HitAndPositionPtrContainer& proto_segment) const {
0444
0445
0446 MuonSegFit::MuonRecHitContainer muonRecHits;
0447 for (auto rh = proto_segment.begin(); rh < proto_segment.end(); rh++) {
0448 ME0RecHit* newRH = (*rh)->rh->clone();
0449 newRH->setPosition((*rh)->lp);
0450 MuonSegFit::MuonRecHitPtr trkRecHit(newRH);
0451 muonRecHits.push_back(trkRecHit);
0452 }
0453 std::unique_ptr<MuonSegFit> currentFit(new MuonSegFit(muonRecHits));
0454 currentFit->fit();
0455 return currentFit;
0456 }
0457
0458 void ME0SegAlgoRU::pruneBadHits(const float maxChi2,
0459 HitAndPositionPtrContainer& proto_segment,
0460 std::unique_ptr<MuonSegFit>& fit,
0461 const unsigned int n_seg_min) const {
0462 while (proto_segment.size() > n_seg_min && fit->chi2() / fit->ndof() > maxChi2) {
0463 float maxDev = -1;
0464 HitAndPositionPtrContainer::iterator worstHit;
0465 for (auto it = proto_segment.begin(); it != proto_segment.end(); ++it) {
0466 const float dev = getHitSegChi2(fit, *(*it)->rh);
0467 if (dev < maxDev)
0468 continue;
0469 maxDev = dev;
0470 worstHit = it;
0471 }
0472 edm::LogVerbatim("ME0SegAlgoRU") << "[ME0SegAlgoRU::pruneBadHits] pruning one hit-> layer: " << (*worstHit)->layer
0473 << " eta: " << (*worstHit)->gp.eta() << " phi: " << (*worstHit)->gp.phi()
0474 << " old chi2/dof: " << fit->chi2() / fit->ndof() << std::endl;
0475 proto_segment.erase(worstHit);
0476 fit = makeFit(proto_segment);
0477 }
0478 }
0479
0480 float ME0SegAlgoRU::getHitSegChi2(const std::unique_ptr<MuonSegFit>& fit, const ME0RecHit& hit) const {
0481 const auto lp = hit.localPosition();
0482 const auto le = hit.localPositionError();
0483 const float du = fit->xdev(lp.x(), lp.z());
0484 const float dv = fit->ydev(lp.y(), lp.z());
0485
0486 ROOT::Math::SMatrix<double, 2, 2, ROOT::Math::MatRepSym<double, 2> > IC;
0487 IC(0, 0) = le.xx();
0488 IC(1, 0) = le.xy();
0489 IC(1, 1) = le.yy();
0490
0491
0492 IC.Invert();
0493 return du * du * IC(0, 0) + 2. * du * dv * IC(0, 1) + dv * dv * IC(1, 1);
0494 }
0495
0496 bool ME0SegAlgoRU::hasHitOnLayer(const HitAndPositionPtrContainer& proto_segment, const unsigned int layer) const {
0497 for (const auto* h : proto_segment)
0498 if (h->layer == layer)
0499 return true;
0500 return false;
0501 }
0502
0503 void ME0SegAlgoRU::compareProtoSegment(std::unique_ptr<MuonSegFit>& current_fit,
0504 HitAndPositionPtrContainer& current_proto_segment,
0505 const HitAndPosition& new_hit) const {
0506 const HitAndPosition* old_hit = nullptr;
0507 HitAndPositionPtrContainer new_proto_segment = current_proto_segment;
0508
0509 for (auto it = new_proto_segment.begin(); it != new_proto_segment.end();) {
0510 if ((*it)->layer == new_hit.layer) {
0511 old_hit = *it;
0512 it = new_proto_segment.erase(it);
0513 } else {
0514 ++it;
0515 }
0516 }
0517 if (old_hit == nullptr)
0518 return;
0519 auto new_fit = addHit(new_proto_segment, new_hit);
0520
0521
0522 bool useNew = false;
0523 if (old_hit->lp == new_hit.lp) {
0524 float avgtof = 0;
0525 for (const auto* h : current_proto_segment)
0526 if (old_hit != h)
0527 avgtof += h->rh->tof();
0528 avgtof /= float(current_proto_segment.size() - 1);
0529 if (std::abs(avgtof - new_hit.rh->tof()) < std::abs(avgtof - old_hit->rh->tof()))
0530 useNew = true;
0531 }
0532 else if (new_fit->chi2() < current_fit->chi2())
0533 useNew = true;
0534
0535 if (useNew) {
0536 current_proto_segment = new_proto_segment;
0537 current_fit = std::move(new_fit);
0538 }
0539 }
0540
0541 void ME0SegAlgoRU::increaseProtoSegment(const float maxChi2,
0542 std::unique_ptr<MuonSegFit>& current_fit,
0543 HitAndPositionPtrContainer& current_proto_segment,
0544 const HitAndPosition& new_hit) const {
0545 HitAndPositionPtrContainer new_proto_segment = current_proto_segment;
0546 auto new_fit = addHit(new_proto_segment, new_hit);
0547
0548 if (new_fit->chi2() / new_fit->ndof() < maxChi2) {
0549 current_proto_segment = new_proto_segment;
0550 current_fit = std::move(new_fit);
0551 }
0552 }