ATLAS Offline Software
Loading...
Searching...
No Matches
SegmentFinder.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <algorithm>
8#include <iostream>
9#include <iterator>
10
18
19namespace TrkDriftCircleMath {
20
22 : m_fitter (std::make_shared<DCSLFitter>())
23 {
24 // update the cached directions
26 }
27
28 SegmentFinder::SegmentFinder(double roadWidth, double deltaCut, bool fullScan) :
29 m_deltaCut{deltaCut}, m_roadWidth{roadWidth},
30 m_fitter (std::make_shared<DCSLFitter>()),
32 {
33 // update the cached directions
35 }
36
38 if (m_debugLevel > 0) {
39 std::lock_guard<std::mutex> lock(m_mutex);
40 std::cout << " drop summary " << std::endl;
41 for (unsigned int i = 0; i < m_dropDepthMax + 1; ++i) { std::cout << " Accepted " << m_dropDepthAcceptCounts[i] << std::endl; }
42 for (unsigned int i = 0; i < m_dropDepthMax; ++i) { std::cout << " Rejected " << m_dropDepthRejectCounts[i] << std::endl; }
43 }
44 }
45
48 std::lock_guard<std::mutex> lock(m_mutex);
49 m_dropDepthAcceptCounts.clear();
50 m_dropDepthAcceptCounts.resize(max + 1, 0);
51 m_dropDepthRejectCounts.clear();
52 m_dropDepthRejectCounts.resize(max + 1, 0);
53 }
54
55 void SegmentFinder::setRecoverMDT(bool doRecover) { m_recoverMdtHits = doRecover; }
56
57 void SegmentFinder::setSortSegmentsUsingAllHits(bool doAllHitsSort) { m_doAllHitSort = doAllHitsSort; }
58
59 void SegmentFinder::setResidualCutT0(double resCut) { m_resCutT0 = resCut; }
60
61 void SegmentFinder::setDeltaCutT0(double deltaCut) { m_deltaCutT0 = deltaCut; }
62
64
65 void SegmentFinder::setUseChamberPhi(bool useChamberPhi) { m_useChamberPhi = useChamberPhi; }
66
67 void SegmentFinder::setCurvedSegmentFinder(bool doCurvedSegmentFinder) { m_doCurvedSegmentFinder = doCurvedSegmentFinder; }
68
69 void SegmentFinder::setRemoveSingleOutliers(bool removeSingleOutliers) { m_removeSingleOutliers = removeSingleOutliers; }
70
71 void SegmentFinder::setTGCPullCut(double cut) { m_tgcPullCut = cut; }
72
73 void SegmentFinder::setRPCPullCut(double cut) { m_rpcPullCut = cut; }
74
75 void SegmentFinder::setDropHits(bool doDrop) { m_doDrop = doDrop; }
76
77 void SegmentFinder::setSeedCleaning(bool doCleanup) { m_seedCleaning = doCleanup; }
78
80
81 void SegmentFinder::setDeltaCut(double cut) { m_deltaCut = cut; }
82
84
85 void SegmentFinder::setRatioEmptyTubesCut(double ratioEmptyTubesCut) { m_ratioEmptyTubesCut = ratioEmptyTubesCut; }
86
87 void SegmentFinder::setPhiRoad(double phiRoad, double phiChamber, double sinPhiCut, bool useRoadPhi, bool useChamberPhi) {
88 // set road
89 m_phiRoad = phiRoad;
90
91 // set phi chamber
92 m_phiChamber = phiChamber;
93
94 // set road cut
95 m_phiDifCut = sinPhiCut;
96
97 m_useRoadPhi = useRoadPhi;
98 m_useChamberPhi = useChamberPhi;
99
100 // update the cached directions
102 }
103
105 m_roadDir = LocVec2D(std::cos(m_phiRoad), std::sin(m_phiRoad));
106 m_chamberDir = LocVec2D(std::cos(m_phiChamber), std::sin(m_phiChamber));
107
108 // set road cut
109 m_phiDifCut = std::cos(m_phiDifCut);
110
111 Line roadLine(LocVec2D(0., 0.), m_roadDir);
112 if (roadLine.phi() != m_phiRoad) {
113 if (m_debugLevel >= 1) std::cout << " bad phi for road: road " << m_phiRoad << " dir phi " << roadLine.phi() << std::endl;
114 }
115 Line chamberLine(LocVec2D(0., 0.), m_chamberDir);
116 if (chamberLine.phi() != m_phiChamber) {
117 if (m_debugLevel >= 1)
118 std::cout << " bad phi for chamber: chamber " << m_phiChamber << " dir phi " << chamberLine.phi() << std::endl;
119 }
120 }
121
123 CLVec clusters;
124 return findSegments(dcsIn, clusters);
125 }
126
128 std::cout << " SegmentFinder::setting: " << std::endl
129 << " Road width " << m_roadWidth << " Pull cuts: MDT " << m_deltaCut << " RPC " << m_rpcPullCut << " TGC "
130 << m_tgcPullCut << std::endl
131 << " Phi seed " << m_phiRoad;
132
133 if (m_useChamberPhi) std::cout << " chamberCut";
134 if (m_useRoadPhi) std::cout << " roadCut";
135
136 if (m_useChamberPhi || m_useRoadPhi) std::cout << " phi cut " << m_phiDifCut << std::endl;
137
138 std::cout << " Empty tube ratio cut " << m_ratioEmptyTubesCut << " chi2 drop cut " << m_chi2Cut << std::endl;
139 std::cout << " Options: ";
140 if (m_fullScan) std::cout << " -- full scan ";
141 if (m_singleMultiLayerScan) std::cout << " -- single multilayer scan ";
142 if (m_seedCleaning) std::cout << " -- seed cleaning ";
143 if (m_doDrop) std::cout << " -- drop hits ";
144 if (m_doAllHitSort) std::cout << " -- sort with all hits ";
145 if (m_doCurvedSegmentFinder) std::cout << " -- curved segment finder ";
146 if (m_mdtGeometry) std::cout << " -- using geometry ";
147 std::cout << std::endl;
148 }
149
150 void SegmentFinder::handleHits(const DCVec& dcsIn, const CLVec& clsIn,
152 DCVec dcs = dcsIn;
153
154 if (m_debugLevel >= 1) {
155 std::cout << "In handleHits: dcs " << dcsIn.size() << " clusters " << clsIn.size() << std::endl;
157 }
158 // sort input drift circles
159 std::stable_sort(dcs.begin(), dcs.end(), SortDcsByY());
160
161 SegVec preSelSegs;
162 if (!m_fullScan) {
163 // find seeds in multilayer
164 std::pair<DCVec, DCVec> dcsPerMl = splitInMulitlayers(dcs);
165
166 DCVec seedsMl1;
167 DCVec seedsMl2;
168
169 if (m_seedCleaning) {
170 // remove triples or larger ranges per layer
171 selectSeeds(dcsPerMl.first, 3).swap(seedsMl1);
172 selectSeeds(dcsPerMl.second, 3).swap(seedsMl2);
173 } else {
174 seedsMl1 = dcsPerMl.first;
175 seedsMl2 = dcsPerMl.second;
176 }
177
178 // search for segments crossing both multilayers
179 twoMultiLayerScan(seedsMl1, seedsMl2, dcs, clsIn, segments);
180
181 if (m_debugLevel >= 1) {
182 std::cout << " two layer scan " << std::endl;
183 for (const auto & it : segments.data()) { std::cout << " " << it << std::endl; }
184 }
185
186 // reset segments so it contains only the cleaned segments
187 cleanSegments(segments.data()).swap(preSelSegs);
188 segments.set(preSelSegs);
189
190 if (m_debugLevel >= 1) {
191 std::cout << " after cleaning " << std::endl;
192 for (const auto & it : segments.data()) { std::cout << " " << it << std::endl; }
193 }
194
195 unsigned int usedHits(0);
196 for (const auto & it : segments.data()) { usedHits += it.hitsOnTrack(); }
197
198 // if remaining dcs not associated with selected track smaller then 2 no additional segments can be formed
199 // thus no further search in single multi layers is needed
200 if ((usedHits >= dcs.size() - 2 && !m_doCurvedSegmentFinder) || !m_singleMultiLayerScan) {
201 } else {
202 // full combinatorics in single ml
203 fullScan(seedsMl1, dcsPerMl.first, clsIn, segments);
204
205 if (m_debugLevel >= 1) {
206 std::cout << " segments after scan multilayer 1 " << std::endl;
207 for (const auto & it : segments.data()) { std::cout << " " << it << std::endl; }
208 }
209
210 fullScan(seedsMl2, dcsPerMl.second, clsIn, segments);
211
212 if (m_debugLevel >= 1) {
213 std::cout << " segments after scan multilayer 2 " << std::endl;
214 for (const auto & it : segments.data()) { std::cout << " " << it << std::endl; }
215 }
216 }
217
218 } else {
219 // remove triples or larger ranges per layer
220 DCVec seeds = selectSeeds(dcs, 3);
221 fullScan(seeds, dcs, clsIn, segments);
222 }
223 }
224
225 SegVec SegmentFinder::findSegments(const DCVec& dcsIn, const CLVec& clsIn) const {
226 // prepare segment collection
228
229 // find segments
230 handleHits(dcsIn, clsIn, segments);
231
232 // Curved Segment finder
234 CurvedSegmentFinder CurvedSegFinder(m_debugLevel);
235 CurvedSegFinder.curvedSegments(*m_mdtGeometry, segments.data());
236 } else if (m_debugLevel >= 5 && m_doCurvedSegmentFinder)
237 std::cout << "CurvedSegmentFinder was passed a NULL pointer to the ChamberGeometry" << std::endl;
238
239 SegVec selectedSegments;
240
241 // final cleaning of segments
242 cleanSegments(segments.data()).swap(selectedSegments);
243
244 // redo cluster association with final tracks
245 associateClusters(selectedSegments, clsIn);
246
247 if (m_debugLevel >= 1) {
248 std::cout << " final segments " << std::endl;
249 for (auto & selectedSegment : selectedSegments) { std::cout << selectedSegment << std::endl; }
250 }
251
252 return selectedSegments;
253 }
254
255 std::pair<DCVec, DCVec> SegmentFinder::splitInMulitlayers(const DCVec& dcs) {
256 DCVec ml1, ml2;
257 ml1.reserve(dcs.size());
258 ml2.reserve(dcs.size());
259 for (const DriftCircle& circ : dcs) {
260 if (circ.id().ml() == 0)
261 ml1.emplace_back(circ);
262 else
263 ml2.emplace_back(circ);
264 }
265 return std::make_pair(std::move(ml1), std::move(ml2));
266 }
267
268 DCVec SegmentFinder::selectSeeds(const DCVec& dcs, int maxSerie) {
269 // this algorithm assumes a sorted collection!!
270 if (dcs.size() <= 2) return dcs;
271
272 DCVec seeds;
273
274 NeighbourTube isNeighbour;
275
276 DCCit it_start_serie;
277 DCCit it = dcs.begin();
278 DCCit it_end = dcs.end() - 1;
279
280 while (it <= it_end) {
281 // mark first entry as start serie
282 it_start_serie = it;
283
284 // loop over next entries until an entry is no neighbour or we reached the end of the data set
285 while (it != it_end && isNeighbour(*it, *(it + 1))) { ++it; }
286
287 // if less then 2 neighbours found, add hits to seeds
288 if (std::distance(it_start_serie, it + 1) < maxSerie) {
289 // add new seeds
290 for (; it_start_serie != it + 1; ++it_start_serie) {
291 // only fill hits that are "in time"
292 if (it_start_serie->driftState() == DriftCircle::InTime) { seeds.push_back(*it_start_serie); }
293 }
294 }
295 // all other combinations are not taken into account
296
297 // if we reached the end of the data set quit loop
298 if (it == dcs.end()) break;
299 ++it;
300 }
301
302 return seeds;
303 }
304
306 // no segments found return empty segment vector
307 if (segs.empty()) return segs;
308
309 MatchDCWithLine matchWithLine;
310
311 SegVec segments;
312 segments.reserve(segs.size());
313
314 if (m_debugLevel >= 3) { std::cout << " refitting segments " << std::endl; }
315
317 for (const Segment& inSegment : segs) {
318 // keep all curved segments
319 if (inSegment.hasCurvatureParameters()) {
320 segments.emplace_back(inSegment);
321 continue;
322 }
324 Segment resultSeg{inSegment};
325
326 // drop hits is switched on
327 bool goodSeg{true}, hasDroppedHit{false};
328 unsigned int dropDepth = 0;
329 if (m_doDrop) goodSeg = dropHits(resultSeg, hasDroppedHit, dropDepth);
330
331 if (goodSeg) {
332 if (!hasDroppedHit && !m_removeSingleOutliers) {
333 // if the segment was accepted without dropping we still have to refit it
334
335 // find all hits within cut-off
336 matchWithLine.set(inSegment.line(), m_deltaCut, MatchDCWithLine::Pull, tubeRadius());
337 bool usePrecise = resultSeg.hasT0Shift();
338 const DCOnTrackVec& hitsOnLine = matchWithLine.match(inSegment.dcs(), nullptr, m_recoverMdtHits, usePrecise);
339
340 if (matchWithLine.matchDifference() > 0) {
341 if (m_debugLevel >= 4) {
342 std::cout << " -- " << inSegment;
343 std::cout << " -- new DCS " << hitsOnLine.size() << std::endl;
344 for (const DCOnTrack& cit : hitsOnLine) { std::cout << " " << cit << std::endl; }
345 }
346
347 // reject segment if less then 3 hits remain
348 if (matchWithLine.hitsOnTrack() <= 2) { continue; }
349
350 // refit segment
351 Segment result(Line(0., 0., 0.), DCOnTrackVec());
352 if (inSegment.hasT0Shift()) {
353 if (!m_fitter->fit(result, inSegment.line(), hitsOnLine, m_hitSelector.selectHitsOnTrack(hitsOnLine),
354 inSegment.t0Shift())) {
355 if (m_debugLevel >= 4) std::cout << " failed fit " << std::endl;
356 continue;
357 }
358 } else {
359 if (!m_fitter->fit(result, inSegment.line(), hitsOnLine, m_hitSelector.selectHitsOnTrack(hitsOnLine))) {
360 if (m_debugLevel >= 4) std::cout << " failed fit " << std::endl;
361 continue;
362 }
363 }
364 if (m_debugLevel >= 4) {
365 std::cout << " after fit " << std::endl;
366 std::cout << result << std::endl;
367 }
368 resultSeg = result;
369
370 // update match parameters
371 updateMatch(resultSeg, matchWithLine);
372
373 // keep close hits from initial road as information is not available anymore and shouldn't change to much
374 resultSeg.showerHits(inSegment.showerHits()); // copy showerHits of initial road
375
376 // keep clusters
377 resultSeg.clusters(inSegment.clusters()); // copy clusters of initial road
378
379 // update crossed tubes
380 crossedTubes(resultSeg);
381
382 // check hit ratio
383 if (!goodHitRatio(resultSeg)) continue;
384
385 // once more do dropping
386 if (m_doDrop) goodSeg = dropHits(resultSeg, hasDroppedHit, dropDepth);
387
388 if (!goodSeg) {
389 if (m_debugLevel >= 2) { std::cout << " segment lossed after refit and dropping " << resultSeg << std::endl; }
390 continue;
391 }
392 }
393 }
394
395 // update segment parameters
396 segments.emplace_back(std::move(resultSeg));
397 if (m_debugLevel >= 2) {
398 std::cout << " new segment added " << segments.size() << std::endl;
399 std::cout << segments.back() << std::endl;
400 }
401 } else {
402 if (m_debugLevel >= 2) std::cout << " segment lost during hit dropping " << std::endl;
403 }
404 }
405
406 return segments;
407 }
408
409 bool SegmentFinder::dropHits(Segment& segment, bool& hasDroppedHit, unsigned int& dropDepth) const {
410 if (dropDepth > m_dropDepthMax) {
411 if (m_debugLevel >= 5) {
412 std::cout << " dropDepth too large keeping segment " << segment << std::endl;
413 std::cout << " dropDepth " << dropDepth << std::endl;
414 for (const DCOnTrack& hit : segment.dcs()) {
415 if (segment.hasT0Shift()) {
416 std::cout << " t0 fit residual " << hit.residual() << std::endl;
417 } else {
418 std::cout << " NO t0 fit residual " << hit.residual() << std::endl;
419 }
420 }
421 }
422 if (m_debugLevel > 0) {
423 std::lock_guard<std::mutex> lock(m_mutex);
424 ++m_dropDepthAcceptCounts[dropDepth];
425 }
426 return true;
427 }
428 ++dropDepth;
429
430 if (m_debugLevel >= 5) std::cout << " dropDepth " << dropDepth << " " << segment << std::endl;
431
432 // discard all segments with less then 3 hits
433 if (segment.ndof() <= 0) {
434 --dropDepth;
435 if (m_debugLevel > 0) {
436 std::lock_guard<std::mutex> lock(m_mutex);
437 ++m_dropDepthRejectCounts[dropDepth];
438 }
439 return false;
440 }
441
442 // if chi2/ndof of segment smaller than cut-off:
443 // do dropping for t0 reffited segments if residual > 1 mm or 5 sigma precise errors
444 // for NOT refitted if residual > 3 mm
445 if (segment.chi2() / segment.ndof() < m_chi2Cut) {
446 bool hasBadHit = false;
448 for (const DCOnTrack& hit : segment.dcs()) {
449 if (segment.hasT0Shift()) {
450 double res = std::abs(hit.residual());
451 if (hit.state() == DCOnTrack::OnTrack && (res > m_resCutT0 || res / hit.drPrecise() > m_deltaCutT0)) {
452 hasBadHit = true;
453 break;
454 }
455 } else {
456 if (hit.state() == DCOnTrack::OnTrack && (std::abs(hit.residual()) > m_deltaCut * hit.dr())) {
457 hasBadHit = true;
458 break;
459 }
460 }
461 }
462 }
463
464 if (!hasBadHit) {
465 if (m_debugLevel >= 5) std::cout << " keeping candidate " << segment << std::endl;
466 --dropDepth;
467 if (m_debugLevel > 0) {
468 std::lock_guard<std::mutex> lock(m_mutex);
469 ++m_dropDepthAcceptCounts[dropDepth];
470 }
471 return true;
472 }
473 }
474
475 if (m_debugLevel >= 5) std::cout << " dropHits " << segment << std::endl;
476
477 // if segment has 3 hots and fails cut discard segment
478 if (segment.hitsOnTrack() <= 3) {
479 --dropDepth;
480 if (m_debugLevel > 0) {
481 std::lock_guard<std::mutex> lock(m_mutex);
482 ++m_dropDepthRejectCounts[dropDepth];
483 }
484 return false;
485 }
486
487 // create selection hits for segment
488 HitSelection selection = m_hitSelector.selectHitsOnTrack(segment.dcs());
489
490 // vector to hold results refit
491 SegVec segs;
492 segs.reserve(segment.hitsOnTrack());
493
494 double bestChi2(1e9);
495 int indexBest(-1);
496
497 MatchDCWithLine matchWithLine;
498
499 // loop over selection and refit without hit
500 for (unsigned int i = 0; i < selection.size(); ++i) {
501 // if this is a hot
502 if (selection[i] == 0) {
503 // unselect hit
504 selection[i] = 1;
505
506 // refit segment
507 Segment result(Line(0., 0., 0.), DCOnTrackVec());
508 if (!m_fitter->fit(result, segment.line(), segment.dcs(), selection)) {
509 if (m_debugLevel >= 5) std::cout << " failed fit (dropHits) " << std::endl;
510 } else {
511 if (m_debugLevel >= 5) std::cout << " dropping hit " << i << " " << segment.dcs()[i] << std::endl;
512
513 // add segment to vector
514 segs.push_back(std::move(result));
515 Segment& newSegment = segs.back();
516
517 // find all hits within cut-off
518 matchWithLine.set(newSegment.line(), 0.7 * m_deltaCut, MatchDCWithLine::Pull, tubeRadius());
519 bool usePrecise = newSegment.hasT0Shift();
520 DCOnTrackVec hitsOnLine = matchWithLine.match(newSegment.dcs(), &selection, m_recoverMdtHits, usePrecise);
521
522 // if less then three hits left drop segment
523 if (matchWithLine.hitsOnTrack() <= 2) {
524 // reset flag
525 selection[i] = 0;
526 segs.pop_back(); // remove segment from vector
527 continue;
528 }
529
530 // reset DCOnTracks
531 newSegment.dcs(hitsOnLine);
532
533 // check if number of hits used in fit equal to number of hits within 5 sigma of fit result
534 if (matchWithLine.matchDifference() > 0) {
535 if (m_debugLevel >= 5) {
536 std::cout << " Hits on track content changed after match, redoing fit " << matchWithLine.hitsOnTrack()
537 << std::endl;
538 std::cout << " fit result " << newSegment << std::endl;
539 }
540 // redo refit using new prediction
541 if (!m_fitter->fit(result, newSegment.line(), newSegment.dcs(),
542 m_hitSelector.selectHitsOnTrack(newSegment.dcs()))) {
543 if (m_debugLevel >= 5) std::cout << " failed fit (dropHits2) " << std::endl;
544 // reset flag
545 selection[i] = 0;
546 segs.pop_back(); // remove segment from vector
547 continue;
548 } else {
549 matchWithLine.set(result.line(), 0.7 * m_deltaCut, MatchDCWithLine::Pull, tubeRadius());
550 usePrecise = result.hasT0Shift();
551 hitsOnLine = matchWithLine.match(result.dcs(), &selection, m_recoverMdtHits, usePrecise);
552 newSegment = result;
553 // reset DCOnTracks
554 newSegment.dcs(hitsOnLine);
555 if (m_debugLevel >= 5) std::cout << " redid refit " << newSegment << std::endl;
556 }
557 }
558
559 // update match parameters
560 updateMatch(segs.back(), matchWithLine);
561
562 // keep close hits from initial road as information is not available anymore and shouldn't change to much
563 segs.back().showerHits(segment.showerHits()); // copy showerHits of initial road
564
565 // keep clusters
566 segs.back().clusters(segment.clusters()); // copy clusters of initial road
567 segs.back().clusterLayers(segment.clusterLayers());
568
569 // update crossed tubes
570 crossedTubes(segs.back());
571
572 // remove segments with bad onTrack/emptyTube ratio
573 if (!goodHitRatio(segs.back())) {
574 // reset flag
575 selection[i] = 0;
576 continue;
577 }
578
579 // flag best candidate
580 double chi2 = segs.back().chi2();
581 if (m_useSegmentQuality) chi2 += 5.1 * (segs.back().hitsOutOfTime() + segs.back().emptyTubes().size());
582 if (segs.empty() || bestChi2 > chi2) {
583 bestChi2 = chi2;
584 indexBest = segs.size() - 1;
585 }
586
587 if (m_debugLevel >= 5) std::cout << " fit result " << segs.back() << std::endl;
588 }
589
590 // reset flag
591 selection[i] = 0;
592 }
593 }
594
595 // if we get here we performed hit dropping
596 hasDroppedHit = true;
597
598 if (indexBest == -1) {
599 if (m_debugLevel >= 5) std::cout << " not good candidate found " << std::endl;
600 --dropDepth;
601 if (m_debugLevel > 0) {
602 std::lock_guard<std::mutex> lock(m_mutex);
603 ++m_dropDepthRejectCounts[dropDepth];
604 }
605 return false;
606 }
607
608 segment = segs[indexBest];
609 if (m_debugLevel >= 5) std::cout << " best candidate " << segment << std::endl;
610
611 bool drop = dropHits(segment, hasDroppedHit, dropDepth);
612 --dropDepth;
613 return drop;
614 }
615
617 SegVec segments = refitSegments(segs);
618
619 // no segments found return empty segment vector
620 // if only one segment found no further processing needed
621 if (segments.size() <= 1) return segments;
622
623 // vector to hold clean segments
624 SegVec selectedSegments;
625
626 // sort segments
627 if (m_doAllHitSort)
628 std::stable_sort(segments.begin(), segments.end(), SortSegByNumberOfHitsAndChi2());
629 else
630 std::stable_sort(segments.begin(), segments.end(), SortSegByNumberOfMDTHitsAndChi2());
631
632 if (m_debugLevel >= 3) {
633 std::cout << " sorting segments " << std::endl;
634 for (auto & segment : segments) { std::cout << segment << std::endl; }
635 }
636 // first segment is automatically accepted
637 selectedSegments.push_back(segments.front());
638
639 // function object to count number of shared hits between segments
640 SharedHitsSegments sharedHits(false);
641
642 // discard all segments that share hits with the best segment(s)
643 SegIt it = segments.begin() + 1;
644 SegIt it_end = segments.end();
645 for (; it != it_end; ++it) {
646 unsigned int shareHits(0);
647 bool addSeg(true);
648 for (auto & selectedSegment : selectedSegments) {
649 // count number of shared hits
650 shareHits = sharedHits(*it, selectedSegment);
651 if (shareHits != 0) {
652 unsigned int nmdtHitsIt = it->hitsOnTrack();
653 unsigned int nmdtHitsSit = selectedSegment.hitsOnTrack();
654
655 // deal with curved segments
656 if (it->hasCurvatureParameters()) {
657 if (selectedSegment.hasCurvatureParameters()) continue;
658 if (shareHits == it->hitsOnTrack()) {
659 if ((selectedSegment.chi2() < it->chi2()) || (std::abs(it->deltaAlpha()) < 0.01)) {
660 addSeg = false;
661 break;
662 }
663 } else if (selectedSegment.hasCurvatureParameters()) {
664 if (std::abs(it->line().phi() - selectedSegment.line().phi()) < 0.05 &&
665 std::abs(it->deltaAlpha() - selectedSegment.deltaAlpha()) < 0.01) {
666 ResidualWithLine resWithLine(it->line());
667 if (std::abs(resWithLine.residual(selectedSegment.line().position())) < 0.1) {
668 addSeg = false;
669 break;
670 }
671 }
672 } else {
673 // if the curved segment has unique hits, keep both
674 selectedSegment.ambigue(2);
675 continue;
676 }
677 }
678
679 // reject segment if it containes less hits on track
680 if (nmdtHitsSit > nmdtHitsIt) {
681 addSeg = false;
682 break;
683 }
684
685 // reject segment if slected has clusters and current doesn't
686 if (!selectedSegment.clusters().empty() && it->clusters().empty()) {
687 addSeg = false;
688 break;
689 }
690 if (std::abs(it->chi2() - selectedSegment.chi2()) > selectedSegment.hitsOnTrack()) {
691 addSeg = false;
692 break;
693 }
694
695 // if number of hits the same reject if difference in angle smaller 0.05 and distance between lines small 0.1 mm
696 if (std::abs(it->line().phi() - selectedSegment.line().phi()) < 0.05) {
697 ResidualWithLine resWithLine(it->line());
698 if (std::abs(resWithLine.residual(selectedSegment.line().position())) < 0.1) {
699 addSeg = false;
700 break;
701 }
702 }
703
704 // mark segment as ambiguous
705 selectedSegment.ambigue(2);
706 }
707 }
708 if (addSeg) {
709 selectedSegments.push_back(*it);
710 // set number of ambiguities
711 if (shareHits != 0) selectedSegments.back().ambigue(2);
712 }
713 }
714
715 return selectedSegments;
716 }
717
718 void SegmentFinder::handleSeedPair(const DriftCircle& seed1, const DriftCircle& seed2, const DCVec& dcs, const CLVec& cls,
719 MatchDCWithLine& matchWithLine,
721 // create tangent lines
723
724 // loop over tangent lines match dcs with line
725 for (const auto & line : lines) {
726 // only accept segments with reasonable angle
727 if (!directionCheck(line.direction())) {
728 if (m_debugLevel >= 19) {
729 std::cout << " failed direction cut " << line.direction() * m_roadDir << " line: " << line.phi() << " road "
730 << atan2(m_roadDir.y(), m_roadDir.x()) << " chamber " << atan2(m_chamberDir.y(), m_chamberDir.x())
731 << std::endl;
732 }
733 continue;
734 }
735 matchWithLine.set(line, m_roadWidth, MatchDCWithLine::Road, tubeRadius());
736 const DCOnTrackVec& hitsOnLine = matchWithLine.match(dcs);
737
738 if (matchWithLine.hitsOnTrack() <= 2) {
739 if (m_debugLevel >= 19) { std::cout << " too few hits associated " << matchWithLine.hitsOnTrack() << std::endl; }
740 continue;
741 }
742 if (matchWithLine.hitsOutOfTime() + matchWithLine.deltas() >= matchWithLine.hitsOnTrack()) {
743 if (m_debugLevel >= 19) {
744 std::cout << " too many outliers: hoo " << matchWithLine.hitsOutOfTime() << " delta " << matchWithLine.deltas()
745 << " hot " << matchWithLine.hitsOnTrack() << std::endl;
746 }
747 continue;
748 }
749
750 Segment result(Line(0., 0., 0.), DCOnTrackVec());
751 if (!m_fitter->fit(result, line, hitsOnLine, m_hitSelector.selectHitsOnTrack(hitsOnLine))) {
752 if (m_debugLevel >= 3) std::cout << " failed fit " << std::endl;
753 continue;
754 }
755
756 // also apply direction cuts on output
757 if (!directionCheck(result.line().direction())) {
758 if (m_debugLevel >= 19) {
759 std::cout << " failed direction cut (2) " << result.line().direction() * m_roadDir << " line: " << result.line().phi()
760 << " road " << atan2(m_roadDir.y(), m_roadDir.x()) << " chamber " << atan2(m_chamberDir.y(), m_chamberDir.x())
761 << std::endl;
762 }
763 continue;
764 }
765 Segment seg = result;
766
767 // update match parameters
768 updateMatch(seg, matchWithLine);
769
770 // add shower hits
771 seg.showerHits(matchWithLine.showerHits());
772
773 // associate clusters with segment
774
775 // hack for avoiding bad alloc problem (bug 45261), should be properly fixed!
776 if (cls.size() < 500) { associateClusters(seg, cls); }
777 // calculate crossed tubes
778 crossedTubes(seg);
779
780 // remove segments with bad onTrack/emptyTube ratio
781 if (!goodHitRatio(seg)) {
782 if (m_debugLevel >= 3) std::cout << " candidate dropped due to hit ratio " << seg << std::endl;
783 continue;
784 }
785
786 if (m_debugLevel >= 3) { std::cout << " new segment candidate " << seg << std::endl; }
787
788 // add segment to collection
789 segments.insert(seg);
790 }
791 }
792
794 if (m_mdtGeometry) {
795 // calculated number of passed tubes
796
797 const DCVec ct = m_mdtGeometry->tubesPassedByLine(seg.line());
798 const MatchResult result = m_matchCrossed(seg.dcs(), ct);
799 unsigned int tubesMl1 {0}, tubesMl2 {0};
800 DCOnTrackCit doit = result.first.begin();
801 DCOnTrackCit doit_end = result.first.end();
802 for (; doit != doit_end; ++doit) {
803 if (doit->state() == DCOnTrack::CloseDC) continue;
804
805 if (doit->id().ml() == 0)
806 ++tubesMl1;
807 else
808 ++tubesMl2;
809 }
810
811 DCCit dcit = ct.begin();
812 DCCit dcit_end = ct.end();
813 for (; dcit != dcit_end; ++dcit) {
814 if (dcit->id().ml() == 0)
815 ++tubesMl1;
816 else
817 ++tubesMl2;
818 }
819
820 if (tubesMl1 + tubesMl2 != ct.size() + result.first.size()) {
821 if (m_debugLevel >= 1)
822 std::cout << " ERROR in empty tube calculation: ml1 " << tubesMl1 << " ml2 " << tubesMl2 << " tot "
823 << ct.size() + result.first.size() << std::endl;
824 }
825
826 seg.crossedTubes(tubesMl1, tubesMl2);
827
828 seg.emptyTubes(result.second);
829 if (m_debugLevel >= 1) {
830 if (seg.crossedTubes() != seg.hitsOnTrack() + seg.deltas() + seg.hitsOutOfTime() + seg.emptyTubes().size()) {
831 std::cout << " ---- mismatch!!! " << std::endl;
832 DCCit eit = result.second.begin();
833 DCCit eit_end = result.second.end();
834 for (; eit != eit_end; ++eit) { std::cout << " match result " << *eit << std::endl; }
835 std::cout << seg << std::endl;
836 }
837 }
838 }
839 }
840
842 seg.deltas(matchWithLine.deltas());
843 seg.hitsOutOfTime(matchWithLine.hitsOutOfTime());
844 seg.hitsOnTrack(matchWithLine.hitsOnTrack());
845 seg.hitsPerMl(matchWithLine.hitsMl1(), matchWithLine.hitsMl2());
846 seg.closeHits(matchWithLine.closeHits());
847 }
848
849 void SegmentFinder::twoMultiLayerScan(const DCVec& seeds_ml1, const DCVec& seeds_ml2, const DCVec& dcs, const CLVec& cls,
851 MatchDCWithLine matchWithLine;
852
853 // hack for bug #45261, should be properly fixed!
854 if (seeds_ml1.size() * seeds_ml2.size() > 2500) return;
855
856 // combine a dc from the first set with a dc from the second set
857 for (const auto & it1 : seeds_ml1) {
858 for (DCVec::const_reverse_iterator it2 = seeds_ml2.rbegin(); it2 != seeds_ml2.rend(); ++it2) {
859 // find segments using the two seeds
860 handleSeedPair(it1, *it2, dcs, cls, matchWithLine, segments);
861 }
862 }
863 }
864
865 void SegmentFinder::fullScan(const DCVec& seeds, const DCVec& dcs, const CLVec& cls,
867 MatchDCWithLine matchWithLine;
868
869 // use all combinations of segments as seed
870
871 // hack for bug #45261, should be properly fixed!
872 if (seeds.size() > 50) return;
873
874 for (DCCit it = seeds.begin(); it != seeds.end(); ++it) {
875 for (DCVec::const_reverse_iterator rit = seeds.rbegin(); rit != seeds.rend(); ++rit) {
876 // break of inner loop when *it == *rit
877 if (std::distance(seeds.begin(), it) >= std::distance(rit, seeds.rend() - 1)) break;
878
879 // hits in the same ml are not combined
880 if (std::abs(it->position().y() - rit->position().y()) < 1.) break;
881
882 // find segments using the two seeds
883 handleSeedPair(*it, *rit, dcs, cls, matchWithLine, segments);
884 }
885 }
886 }
887
889 if (segs.empty()) return dcs;
890
891 DCVec newdcs;
892
893 SameTube sameTube;
894
895 DCCit dit = dcs.begin();
896 DCCit dit_end = dcs.end();
897
898 for (; dit != dit_end; ++dit) {
899 bool found(false);
900 for (const auto & seg : segs) {
901 DCOnTrackCit pos = std::lower_bound(seg.dcs().begin(), seg.dcs().end(), *dit, SortDcsByY());
902 if (pos != seg.dcs().end() && pos->state() != DCOnTrack::CloseDC && sameTube(*pos, *dit)) {
903 found = true;
904 break;
905 }
906 }
907 if (!found) { newdcs.push_back(*dit); }
908 }
909
910 return newdcs;
911 }
912
913 void SegmentFinder::associateClusters(SegVec& segs, const CLVec& cls) const {
914 // loop over all segments pass to associateClusters
915 SegIt sit = segs.begin();
916 SegIt sit_end = segs.end();
917 for (; sit != sit_end; ++sit) { associateClusters(*sit, cls); }
918 }
919 void SegmentFinder::associateClusters(Segment& seg, const CLVec& cls) const {
920 // calculate residuals with line
921 ResidualWithSegment resSeg(seg);
922
923 // store associated clusters
924 CLVec assCls;
925
926 bool hasClustersBefore = false;
927 bool hasClustersAfter = false;
928
929 CLCit cit = cls.begin();
930 CLCit cit_end = cls.end();
931 for (; cit != cit_end; ++cit) {
932 // always assign phi hits
933 if (cit->id().measuresPhi() == 1) {
934 if (m_debugLevel >= 1)
935 std::cout << " phi hit, not associated: id " << cit->id().id() << " pos " << cit->position() << std::endl;
936 continue;
937 }
938
939 // calculate residual
940 double res = resSeg.residual(*cit);
941 double error = std::sqrt(cit->err() * cit->err() + resSeg.trackError2(*cit));
942 double pull = res / error;
943
944 if (m_debugLevel >= 4)
945 std::cout << " handling cluster " << cit->id() << " res " << res << " pull " << pull << " hit error " << cit->err()
946 << " track error " << sqrt(resSeg.trackError2(*cit)) << " pos " << cit->position();
947
948 double pullCut = cit->id().isTgc() ? m_tgcPullCut : m_rpcPullCut;
949
950 // spatial associate
951 if (std::abs(pull) < pullCut) {
952 assCls.push_back(*cit);
953 if (cit->position().y() < 0.) hasClustersBefore = true;
954 if (cit->position().y() > 0.) hasClustersAfter = true;
955 if (m_debugLevel >= 4) std::cout << " associated" << std::endl;
956 } else {
957 if (m_debugLevel >= 4) std::cout << " dropped" << std::endl;
958 }
959 }
960
961 if (assCls.empty()) return;
962
963 seg.clusters(assCls);
964 unsigned int ncl = 0;
965 if (hasClustersBefore) ++ncl;
966 if (hasClustersAfter) ++ncl;
967 seg.clusterLayers(ncl);
968 }
969
971 if (!m_mdtGeometry) return true;
972 bool good = (double)(seg.crossedTubes() - seg.hitsOnTrack()) < m_ratioEmptyTubesCut * seg.hitsOnTrack();
973 if (!good) {
974 if (seg.hitsMl1() == 0) {
975 good = (double)(seg.crossedTubesMl2() - seg.hitsMl2()) < m_ratioEmptyTubesCut * seg.hitsMl2();
976 } else if (seg.hitsMl2() == 0) {
977 good = (double)(seg.crossedTubesMl1() - seg.hitsMl1()) < m_ratioEmptyTubesCut * seg.hitsMl1();
978 }
979 }
980 return good;
981 }
982
983} // namespace TrkDriftCircleMath
std::pair< std::vector< unsigned int >, bool > res
#define max(a, b)
Definition cfImp.cxx:41
void curvedSegments(const ChamberGeometry &mdtGeo, SegVec &Segs) const
class representing a drift circle meaurement on segment
Definition DCOnTrack.h:16
@ CloseDC
too large drift time
Definition DCOnTrack.h:23
This class represents a drift time measurement.
Definition DriftCircle.h:22
@ InTime
drift time too small to be compatible with drift spectrum
Definition DriftCircle.h:27
double phi() const
Definition Line.h:62
Implementation of 2 dimensional vector class.
Definition LocVec2D.h:16
const DCOnTrackVec & match(const DCVec &dcs)
unsigned int matchDifference() const
returns the number of DCOnTrack that have a different status after the match, returns 0 if used with ...
void set(const Line &l, double deltaCut, MatchStrategy strategy, double tubeRadius)
double residual(const LocVec2D &pos) const
class to calculate residual of a hit with a segment and calculate the local track errors
double trackError2(const DriftCircle &dc) const
calculate the track error at the position of a drift circle
void setDeltaCutT0(double deltaCut)
void fullScan(const DCVec &seeds, const DCVec &dcs, const CLVec &cls, ResolvedCollection< Segment, IsSubsetSegment< SortDcsByY > > &segments) const
void printSettings() const
print settings
std::shared_ptr< const DCSLFitter > m_fitter
void associateClusters(SegVec &segs, const CLVec &cls) const
bool dropHits(Segment &segment, bool &hasDroppedHit, unsigned int &dropDepth) const
SegVec findSegments(const DCVec &dcs) const
static DCVec selectSeeds(const DCVec &dcs, int maxSerie)
void setRemoveSingleOutliers(bool removeSingleOutliers)
void handleSeedPair(const DriftCircle &seed1, const DriftCircle &seeds2, const DCVec &dcs, const CLVec &cls, MatchDCWithLine &matchWithLine, ResolvedCollection< Segment, IsSubsetSegment< SortDcsByY > > &segments) const
void setPhiRoad(double phiRoad, double phiChamber, double sinPhiCut=0.2, bool useRoadPhi=true, bool useChamberPhi=true)
void setRatioEmptyTubesCut(double ratioEmptyTubesCut)
void setUseChamberPhi(bool useChamberPhi)
static std::pair< DCVec, DCVec > splitInMulitlayers(const DCVec &dcs)
bool goodHitRatio(Segment &seg) const
void handleHits(const DCVec &dcs, const CLVec &clusters, ResolvedCollection< Segment, IsSubsetSegment< SortDcsByY > > &segments) const
static void updateMatch(Segment &seg, MatchDCWithLine &matchWithLine)
void setSeedCleaning(bool doCleanup)
void updateDirections()
update the cached values for the phi road and chamber road
bool directionCheck(const LocVec2D &LocVec2D) const
void twoMultiLayerScan(const DCVec &seeds_ml1, const DCVec &seeds_ml2, const DCVec &dcs, const CLVec &cls, ResolvedCollection< Segment, IsSubsetSegment< SortDcsByY > > &segments) const
void setSortSegmentsUsingAllHits(bool doAllHitsSort)
const ChamberGeometry * m_mdtGeometry
SegVec cleanSegments(const SegVec &segments) const
SegVec refitSegments(const SegVec &segs) const
static DCVec removeDCOnSegments(const DCVec &dcs, const SegVec &segs)
void setCurvedSegmentFinder(bool doCurvedSegmentFinder)
void crossedTubes(Segment &seg) const
void setSingleMultiLayerScan(bool doScan)
void crossedTubes(unsigned int crossedTubesMl1, unsigned int crossedTubesMl2)
static LineVec tangentLines(const DriftCircle &dc1, const DriftCircle &dc2)
double chi2(TH1 *h0, TH1 *h1)
const std::string selection
Function object to check whether two Segments are sub/super sets or different.
DCOnTrackVec::const_iterator DCOnTrackCit
Definition DCOnTrack.h:61
std::pair< DCOnTrackVec, DCVec > MatchResult
counts the number of hits shared by the two segments
std::vector< bool > HitSelection
Definition HitSelection.h:9
DCVec::const_iterator DCCit
std::vector< DriftCircle > DCVec
std::vector< DCOnTrack > DCOnTrackVec
Definition DCOnTrack.h:59
STL namespace.
void stable_sort(DataModel_detail::iterator< DVL > beg, DataModel_detail::iterator< DVL > end)
Specialization of stable_sort for DataVector/List.
counts the number of hits shared by the two segments