44 using CandidateToDuplicate = std::vector<std::pair<int, int>>;
53 bool checkForOverlappingTracks(
62 bool useForestFromDB_;
91 unsigned int overlapCheckMaxHits_;
93 unsigned int overlapCheckMaxMissingLayers_;
95 double overlapCheckMinCosT_;
132 desc.
add<
double>(
"minDeltaR3d", -4.0);
133 desc.add<
double>(
"minBDTG", -0.1);
134 desc.add<
double>(
"minpT", 0.2);
135 desc.add<
double>(
"minP", 0.4);
136 desc.add<
double>(
"maxDCA", 30.0);
137 desc.add<
double>(
"maxDPhi", 0.30);
138 desc.add<
double>(
"maxDLambda", 0.30);
139 desc.add<
double>(
"maxDdsz", 10.0);
140 desc.add<
double>(
"maxDdxy", 10.0);
141 desc.add<
double>(
"maxDQoP", 0.25);
142 desc.add<
unsigned>(
"overlapCheckMaxHits", 4);
143 desc.add<
unsigned>(
"overlapCheckMaxMissingLayers", 1);
144 desc.add<
double>(
"overlapCheckMinCosT", 0.99);
145 desc.add<
std::string>(
"forestLabel",
"MVADuplicate");
147 desc.add<
bool>(
"useInnermostState",
true);
148 desc.add<
std::string>(
"ttrhBuilderName",
"WithAngleAndTemplate");
149 desc.add<
std::string>(
"propagatorName",
"PropagatorWithMaterial");
150 desc.add<
std::string>(
"chi2EstimatorName",
"DuplicateTrackMergerChi2Est");
151 descriptions.add(
"DuplicateTrackMerger", desc);
154 DuplicateTrackMerger::DuplicateTrackMerger(
const edm::ParameterSet &iPara) : forest_(nullptr), merger_(iPara) {
156 minDeltaR3d2_ = iPara.
getParameter<
double>(
"minDeltaR3d");
157 minDeltaR3d2_ *=
std::abs(minDeltaR3d2_);
163 maxDCA2_ *= maxDCA2_;
169 overlapCheckMaxHits_ = iPara.
getParameter<
unsigned>(
"overlapCheckMaxHits");
170 overlapCheckMaxMissingLayers_ = iPara.
getParameter<
unsigned>(
"overlapCheckMaxMissingLayers");
171 overlapCheckMinCosT_ = iPara.
getParameter<
double>(
"overlapCheckMinCosT");
173 produces<std::vector<TrackCandidate>>(
"candidates");
174 produces<CandidateToDuplicate>(
"candidateMap");
179 useForestFromDB_ = dbFileName_.empty();
199 DuplicateTrackMerger::~DuplicateTrackMerger() {
200 if (!useForestFromDB_)
206 Stat() : maxCos(1.1), nCand(0), nLoop0(0) {}
207 ~Stat() {
std::cout <<
"Stats " << nCand <<
' ' << nLoop0 <<
' ' << maxCos << std::endl; }
208 std::atomic<float> maxCos;
209 std::atomic<int> nCand, nLoop0;
214 template <
typename T>
215 void update_maximum(std::atomic<T> &maximum_value,
T const &
value) noexcept {
216 T prev_value = maximum_value;
217 while (prev_value <
value && !maximum_value.compare_exchange_weak(prev_value,
value))
221 template <
typename T>
222 void update_minimum(std::atomic<T> &minimum_value,
T const &
value) noexcept {
223 T prev_value = minimum_value;
224 while (prev_value >
value && !minimum_value.compare_exchange_weak(prev_value,
value))
229 merger_.init(iSetup);
232 if (useForestFromDB_) {
235 forest_ = forestHandle.
product();
237 TFile gbrfile(dbFileName_.c_str());
238 forest_ = dynamic_cast<const GBRForest *>(gbrfile.Get(forestLabel_.c_str()));
249 magfield_ = hmagfield.
product();
261 propagator_ = hpropagator.
product();
265 chi2Estimator_ = hestimator.
product();
268 auto out_duplicateCandidates = std::make_unique<std::vector<TrackCandidate>>();
270 auto out_candidateMap = std::make_unique<CandidateToDuplicate>();
271 LogDebug(
"DuplicateTrackMerger") <<
"Number of tracks to be checked for merging: " <<
tracks.size();
275 const auto ev =
iEvent.id().event();
276 const auto aOriAlgo =
a->originalAlgo();
277 const auto bOriAlgo =
b->originalAlgo();
278 const auto aSeed =
a->seedRef().key();
279 const auto bSeed =
b->seedRef().key();
280 return ((
ev == 6903 && ((aOriAlgo == 23 && aSeed == 695 && bOriAlgo == 5 && bSeed == 652) ||
281 (aOriAlgo == 23 && aSeed == 400 && bOriAlgo == 7 && bSeed == 156) ||
282 (aOriAlgo == 4 && aSeed == 914 && bOriAlgo == 22 && bSeed == 503) ||
283 (aOriAlgo == 5 && aSeed == 809 && bOriAlgo == 4 && bSeed == 1030) ||
284 (aOriAlgo == 23 && aSeed == 749 && bOriAlgo == 5 && bSeed == 659) ||
285 (aOriAlgo == 4 && aSeed == 1053 && bOriAlgo == 23 && bSeed == 1035) ||
286 (aOriAlgo == 4 && aSeed == 810 && bOriAlgo == 5 && bSeed == 666) ||
287 (aOriAlgo == 4 && aSeed == 974 && bOriAlgo == 5 && bSeed == 778))) ||
288 (
ev == 6904 && ((aOriAlgo == 23 && aSeed == 526 && bOriAlgo == 5 && bSeed == 307) ||
289 (aOriAlgo == 4 && aSeed == 559 && bOriAlgo == 22 && bSeed == 472))) ||
290 (
ev == 6902 && ((aOriAlgo == 4 && aSeed == 750 && bOriAlgo == 22 && bSeed == 340) ||
291 (aOriAlgo == 4 && aSeed == 906 && bOriAlgo == 5 && bSeed == 609) ||
292 (aOriAlgo == 4 && aSeed == 724 && bOriAlgo == 5 && bSeed == 528) ||
293 (aOriAlgo == 4 && aSeed == 943 && bOriAlgo == 23 && bSeed == 739) ||
294 (aOriAlgo == 8 && aSeed == 2 && bOriAlgo == 9 && bSeed == 2282) ||
295 (aOriAlgo == 23 && aSeed == 827 && bOriAlgo == 5 && bSeed == 656) ||
296 (aOriAlgo == 22 && aSeed == 667 && bOriAlgo == 7 && bSeed == 516))));
322 if (
test(rt1, rt2) ||
test(rt2, rt1)) {
336 auto cosT = (*rt1).momentum().Dot((*rt2).momentum());
337 IfLogTrace(debug_,
"DuplicateTrackMerger") <<
" cosT " << cosT;
340 cosT /=
std::sqrt((*rt1).momentum().Mag2() * (*rt2).momentum().Mag2());
343 unsigned int nhv1, nhv2;
346 nhv1 = nValidHits[
i];
348 nhv2 = nValidHits[
j];
351 nhv1 = nValidHits[
j];
353 nhv2 = nValidHits[
i];
355 auto deltaR3d2 = (
t1->outerPosition() -
t2->innerPosition()).
mag2();
357 if (
t1->outerPosition().perp2() >
t2->innerPosition().perp2())
360 <<
" deltaR3d2 " << deltaR3d2 <<
" t1.outerPos2 " <<
t1->outerPosition().perp2() <<
" t2.innerPos2 "
361 <<
t2->innerPosition().perp2();
363 bool compatible =
false;
365 if (deltaR3d2 >= minDeltaR3d2_) {
366 compatible = checkForDisjointTracks(
t1,
t2, tscpBuilder);
369 compatible = checkForOverlappingTracks(
t1,
t2, nhv1, nhv2, cosT);
375 IfLogTrace(debug_,
"DuplicateTrackMerger") <<
" marking as duplicates" << oriIndex[
i] <<
',' << oriIndex[
j];
376 out_duplicateCandidates->push_back(merger_.merge(*
t1, *
t2, duplType));
377 out_candidateMap->emplace_back(oriIndex[
i], oriIndex[
j]);
383 update_minimum(
stat.maxCos,
float(cosT));
393 bool DuplicateTrackMerger::checkForDisjointTracks(
const reco::Track *
t1,
396 IfLogTrace(debug_,
"DuplicateTrackMerger") <<
" Checking for disjoint duplicates";
400 GlobalPoint avgPoint((
t1->outerPosition().x() +
t2->innerPosition().x()) * 0.5,
401 (
t1->outerPosition().y() +
t2->innerPosition().y()) * 0.5,
402 (
t1->outerPosition().z() +
t2->innerPosition().z()) * 0.5);
406 <<
" TSCP1.isValid " << TSCP1.
isValid() <<
" TSCP2.isValid " << TSCP2.
isValid();
421 float tmva_dqoverp_ = qoverp1 - qoverp2;
422 IfLogTrace(debug_,
"DuplicateTrackMerger") <<
" dqoverp " << tmva_dqoverp_;
423 if (
std::abs(tmva_dqoverp_) > maxDQoP_)
431 IfLogTrace(debug_,
"DuplicateTrackMerger") <<
" dlambda " << tmva_dlambda_;
432 if (
std::abs(tmva_dlambda_) > maxDLambda_)
437 float tmva_dphi_ = phi1 - phi2;
440 IfLogTrace(debug_,
"DuplicateTrackMerger") <<
" dphi " << tmva_dphi_;
441 if (
std::abs(tmva_dphi_) > maxDPhi_)
448 float tmva_ddxy_ = dxy1 - dxy2;
449 IfLogTrace(debug_,
"DuplicateTrackMerger") <<
" ddxy " << tmva_ddxy_;
450 if (
std::abs(tmva_ddxy_) > maxDdxy_)
459 float tmva_ddsz_ = dsz1 - dsz2;
460 IfLogTrace(debug_,
"DuplicateTrackMerger") <<
" ddsz " << tmva_ddsz_;
461 if (
std::abs(tmva_ddsz_) > maxDdsz_)
464 float tmva_d3dr_ = avgPoint.perp();
465 float tmva_d3dz_ = avgPoint.z();
470 gbrVals_[0] = tmva_ddsz_;
471 gbrVals_[1] = tmva_ddxy_;
472 gbrVals_[2] = tmva_dphi_;
473 gbrVals_[3] = tmva_dlambda_;
474 gbrVals_[4] = tmva_dqoverp_;
475 gbrVals_[5] = tmva_d3dr_;
476 gbrVals_[6] = tmva_d3dz_;
477 gbrVals_[7] = tmva_outer_nMissingInner_;
478 gbrVals_[8] = tmva_inner_nMissingOuter_;
480 auto mvaBDTG = forest_->GetClassifier(gbrVals_);
481 IfLogTrace(debug_,
"DuplicateTrackMerger") <<
" mvaBDTG " << mvaBDTG;
482 if (mvaBDTG < minBDTG_)
489 bool DuplicateTrackMerger::checkForOverlappingTracks(
498 <<
" Checking for overlapping duplicates, cosT " << cosT <<
" t1 hits " << nvh1;
499 if (cosT < overlapCheckMinCosT_)
501 if (nvh1 > overlapCheckMaxHits_)
506 const auto hitDet = hit1->geographicalId().det();
507 const auto hitSubdet = hit1->geographicalId().subdetId();
508 const auto hitLayer = ttopo_->layer(hit1->geographicalId());
509 return std::find_if(
t2->recHitsBegin(),
t2->recHitsEnd(), [&](
const TrackingRecHit *hit2) {
510 const auto &detId = hit2->geographicalId();
511 return (detId.det() == hitDet && detId.subdetId() == hitSubdet && ttopo_->layer(detId) == hitLayer);
515 auto t1HitIter =
t1->recHitsBegin();
516 if (!(*t1HitIter)->isValid()) {
517 IfLogTrace(debug_,
"DuplicateTrackMerger") <<
" first t1 hit invalid";
520 auto t2HitIter = findHitOnT2(*t1HitIter);
521 if (t2HitIter ==
t2->recHitsEnd()) {
525 assert(t1HitIter !=
t1->recHitsEnd());
527 if (!(*t1HitIter)->isValid()) {
528 IfLogTrace(debug_,
"DuplicateTrackMerger") <<
" second t1 hit invalid";
531 t2HitIter = findHitOnT2(*t1HitIter);
532 if (t2HitIter ==
t2->recHitsEnd())
536 <<
" starting overlap check from t1 hit " <<
std::distance(
t1->recHitsBegin(), t1HitIter) <<
" t2 hit "
539 auto prevSubdet = (*t1HitIter)->geographicalId().subdetId();
544 unsigned int missedLayers = 0;
545 while (t1HitIter !=
t1->recHitsEnd() && t2HitIter !=
t2->recHitsEnd()) {
550 <<
" t1 hit " <<
std::distance(
t1->recHitsBegin(), t1HitIter) <<
" t2 hit "
551 <<
std::distance(
t2->recHitsBegin(), t2HitIter) <<
" either is invalid, types t1 "
552 << (*t1HitIter)->getType() <<
" t2 " << (*t2HitIter)->getType();
556 const auto &t1DetId = (*t1HitIter)->geographicalId();
557 const auto &t2DetId = (*t2HitIter)->geographicalId();
559 const auto t1Det = t1DetId.det();
560 const auto t2Det = t2DetId.det();
564 <<
" either not from Tracker, dets t1 " << t1Det <<
" t2 " << t2Det;
568 const auto t1Subdet = t1DetId.subdetId();
569 const auto t1Layer = ttopo_->layer(t1DetId);
572 if (t1DetId == t2DetId) {
575 <<
" t1 hit " <<
std::distance(
t1->recHitsBegin(), t1HitIter) <<
" t2 hit "
576 <<
std::distance(
t2->recHitsBegin(), t2HitIter) <<
" same DetId (" << t1DetId.rawId()
577 <<
") but do not share all input";
581 const auto t2Subdet = t2DetId.subdetId();
582 const auto t2Layer = ttopo_->layer(t2DetId);
585 if (t1Subdet != t2Subdet || t1Layer != t2Layer) {
586 bool recovered =
false;
588 if (t1Subdet == prevSubdet && t2Subdet != prevSubdet) {
592 }
else if (t1Subdet != prevSubdet && t2Subdet == prevSubdet) {
596 }
else if (t1Subdet == t2Subdet) {
597 prevSubdet = t1Subdet;
599 if (t2Layer > t1Layer) {
603 }
else if (t1Layer > t2Layer) {
611 if (missedLayers > overlapCheckMaxMissingLayers_) {
612 IfLogTrace(debug_,
"DuplicateTrackMerger") <<
" max number of missed layers exceeded";
619 <<
" t1 hit " <<
std::distance(
t1->recHitsBegin(), t1HitIter) <<
" t2 hit "
620 <<
std::distance(
t2->recHitsBegin(), t2HitIter) <<
" are on different layers (subdet, layer) t1 "
621 << t1Subdet <<
"," << t1Layer <<
" t2 " << t2Subdet <<
"," << t2Layer;
627 <<
" t1 hit " <<
std::distance(
t1->recHitsBegin(), t1HitIter) <<
" t2 hit "
628 <<
std::distance(
t2->recHitsBegin(), t2HitIter) <<
" are on same layer, but in non-pixel detector (det "
629 << t1Det <<
" subdet " << t1Subdet <<
" layer " << t1Layer <<
")";
636 if (!tsosPropagated.
isValid()) {
638 <<
" t1 hit " <<
std::distance(
t1->recHitsBegin(), t1HitIter) <<
" t2 hit "
642 auto passChi2Pair = chi2Estimator_->estimate(tsosPropagated, **t1HitIter);
643 if (!passChi2Pair.first) {
645 <<
" t1 hit " <<
std::distance(
t1->recHitsBegin(), t1HitIter) <<
" t2 hit "
646 <<
std::distance(
t2->recHitsBegin(), t2HitIter) <<
" hit chi2 compatibility failed with chi2 "
647 << passChi2Pair.second;
651 prevSubdet = t1Subdet;
655 if (t1HitIter !=
t1->recHitsEnd()) {
656 IfLogTrace(debug_,
"DuplicateTrackMerger") <<
" hits on t2 ended before hits on t1";
660 IfLogTrace(debug_,
"DuplicateTrackMerger") <<
" all hits on t2 are on layers whre t1 has also a hit";