ATLAS Offline Software
Loading...
Searching...
No Matches
CscSegmentUtilTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <cmath>
8#include <iostream>
9
22#include "TMath.h" // for TMath::Landau()
29
37
38namespace {
39 std::string station_name(const int station) {
40 if (station == 1)
41 return "CSS";
42 else if (station == 2)
43 return "CSL";
44 else
45 return "UNKNOWN_STATION";
46 }
47
48 std::string measphi_name(const bool measphi) {
49 if (measphi)
50 return "phi";
51 else
52 return "eta";
53 }
54
55 double alignConst(const bool measphi, const int wlay) {
56 if (measphi) return 0.;
57 const double aConst[4] = {0, -0.2289, -0.620181, -0.6534445};
58 return aConst[wlay - 1];
59 }
60
61 bool enoughHitLayers(const ICscSegmentFinder::ChamberTrkClusters& eta_clus, const ICscSegmentFinder::ChamberTrkClusters& phi_clus) {
62 int nHitLayer_eta = 0;
63 int nHitLayer_phi = 0;
64 for (int i = 0; i < 4; ++i) {
65 if (!eta_clus[i].empty()) ++nHitLayer_eta;
66 if (!phi_clus[i].empty()) ++nHitLayer_phi;
67 }
68 return nHitLayer_eta >= 2 || nHitLayer_phi >= 2;
69 }
70
71 bool IsUnspoiled(const Muon::CscClusterStatus status) {
73 }
74} // namespace
75
76//******************************************************************************
77// Constructor.
78CscSegmentUtilTool::CscSegmentUtilTool(const std::string& type, const std::string& name, const IInterface* parent) :
79 AthAlgTool(type, name, parent) {
80 declareInterface<ICscSegmentUtilTool>(this);
81}
82
83/*********************************/
85 ATH_MSG_DEBUG("Initializing " << name());
86 ATH_MSG_DEBUG(" Max chi-square: " << m_max_chisquare);
87 ATH_MSG_DEBUG(" chi-square tight: " << m_max_chisquare_tight);
88 ATH_MSG_DEBUG(" chi-square loose: " << m_max_chisquare_loose);
89 ATH_MSG_DEBUG(" Max r:phi slope: " << m_max_slope_r << " : " << m_max_slope_phi);
90 ATH_MSG_DEBUG(" Max segments/chamber: " << m_max_seg_per_chamber);
91 ATH_MSG_DEBUG(" ROT tan(theta) tolerance: " << m_fitsegment_tantheta_tolerance);
92 ATH_MSG_DEBUG(" cluster_error_scaler " << m_cluster_error_scaler);
93 ATH_MSG_DEBUG(" ROT creator: " << m_rotCreator.typeAndName());
94
95 if (m_TightenChi2) m_IPerror = 2.;
96 if (m_TightenChi2) ATH_MSG_DEBUG(" Chi2 cuts are tightened and m_IPerror is: " << m_IPerror);
97
98 if (m_x5data) ATH_MSG_DEBUG(" Things for X5Data analysis is applied such as alignment ");
99
100 ATH_CHECK(m_rotCreator.retrieve());
101
102 ATH_CHECK(m_readKey.initialize());
103
104 ATH_CHECK(m_DetectorManagerKey.initialize());
105
106 ATH_CHECK(m_idHelperSvc.retrieve());
107
108 ATH_CHECK(m_eventInfo.initialize());
109
110 return StatusCode::SUCCESS;
111}
112
114// Note: this code was required for old MuGirl but is not used by the current reconstruction
115// Leaving it in place for backwards compatibility
116std::unique_ptr<std::vector<std::unique_ptr<MuonSegment> > > CscSegmentUtilTool::getMuonSegments(
118 const Amg::Vector3D& lpos000, const EventContext& ctx) const {
119 if (!enoughHitLayers(eta_clus, phi_clus)) {
120 ATH_MSG_DEBUG(" Could not find at least two individual layer hits! ");
121 std::unique_ptr<std::vector<std::unique_ptr<MuonSegment> > > segments;
122 return segments;
123 }
124
125 for (int i = 0; i < 4; ++i)
126 ATH_MSG_DEBUG("getMuonSegments2: No of clusters in layer " << i << " " << eta_clus[i].size() << " " << phi_clus[i].size());
127
128 ATH_MSG_DEBUG("getMuonSegments called get2dMuonSegmentCombination");
129 std::unique_ptr<MuonSegmentCombination> Muon2dSegComb(get2dMuonSegmentCombination(eta_id, phi_id, eta_clus, phi_clus, lpos000, ctx));
130
131 ATH_MSG_DEBUG("getMuonSegments called get4dMuonSegmentCombination");
132 std::unique_ptr<MuonSegmentCombination> Muon4dSegComb(get4dMuonSegmentCombination(Muon2dSegComb.get(), ctx));
133
134 std::unique_ptr<std::vector<std::unique_ptr<MuonSegment> > > segments_clone(new std::vector<std::unique_ptr<MuonSegment> >);
135
136 if (Muon4dSegComb) {
137 std::vector<std::unique_ptr<MuonSegment> >* segments = Muon4dSegComb->stationSegments(0);
138
139 if (!segments->empty()) {
140 for (unsigned int i = 0; i < segments->size(); ++i) { segments_clone->push_back(std::move(segments->at(i))); }
141 }
142 }
143
144 return segments_clone;
145}
146
151 const Amg::Vector3D& lpos000, const EventContext& ctx, int etaStat,
152 int phiStat) const {
153 int nGoodEta = 0, nGoodPhi = 0;
154 for (int i = 0; i < 4; ++i) {
155 ATH_MSG_DEBUG("get2dMuonSegmentCombination2: No of clusters in layer " << i << " " << eta_clus[i].size() << " "
156 << phi_clus[i].size());
157 if ((etaStat % (int)std::pow(10, i + 1)) / (int)std::pow(10, i) == 0) nGoodEta++;
158 if ((phiStat % (int)std::pow(10, i + 1)) / (int)std::pow(10, i) == 0) nGoodPhi++;
159 }
160
161 if (nGoodEta < 2 && nGoodPhi < 2) {
162 ATH_MSG_DEBUG(" Not enough hits in either eta or phi to form a segment");
163 MuonSegmentCombination* pcol = nullptr;
164 return pcol;
165 }
166
168 pcol->setNGoodCscLayers(nGoodEta, nGoodPhi);
169 // Find 2D segments.
172
173 // get2dSegments does : find_2dsegments -> find_2dseg3hit -> add_2dsegments
174 get2dSegments(eta_id, phi_id, eta_clus, phi_clus, eta_segs, phi_segs, lpos000, ctx, etaStat, phiStat);
175 std::unique_ptr<MuonSegmentCombination::SegmentVec> psegs(new MuonSegmentCombination::SegmentVec);
176 for (ICscSegmentFinder::Segments::const_iterator iseg = eta_segs.begin(); iseg != eta_segs.end(); ++iseg) {
177 std::unique_ptr<MuonSegment> pseg(build_segment(*iseg, false, eta_id, nGoodEta == 2, ctx)); // build_segment does getRios
178 if (pseg) {
179 ATH_MSG_DEBUG(" =============================> get2dMuonSegmentCombination:: MuonSegment time (eta) from build_segment is "
180 << pseg->time());
181 psegs->push_back(std::move(pseg));
182 }
183 }
184 ATH_MSG_DEBUG("added " << psegs->size() << " eta segments");
185 pcol->addSegments(std::move(psegs));
186
187 // Insert phi-segments.
188 std::unique_ptr<MuonSegmentCombination::SegmentVec> phisegs(new MuonSegmentCombination::SegmentVec);
189 for (ICscSegmentFinder::Segments::const_iterator iseg = phi_segs.begin(); iseg != phi_segs.end(); ++iseg) {
190 std::unique_ptr<MuonSegment> pseg(build_segment(*iseg, true, phi_id, nGoodPhi == 2, ctx));
191 if (pseg) {
192 ATH_MSG_DEBUG(" get2dMuonSegmentCombination:: MuonSegment time (phi) from build_segment is " << pseg->time());
193 phisegs->push_back(std::move(pseg));
194 }
195 }
196 ATH_MSG_DEBUG("added " << phisegs->size() << " phi segments");
197 pcol->addSegments(std::move(phisegs));
198
199 // Add to SG container.
200 ATH_MSG_DEBUG("Added " << eta_segs.size() << " r-segments and " << phi_segs.size() << " phi-segments.");
201
202 return pcol;
203}
204
205/**********************************************/
206// Fit a segment using a list of clusters.
207// Filling is least squares with the usual 1/d**2 weighting.
208// local z = -38.51 -12.82 12.87 38.56
209void CscSegmentUtilTool::fit_segment(const ICscSegmentFinder::TrkClusters& clus, const Amg::Vector3D& lpos000, double& s0, double& s1,
210 double& d0, double& d1, double& d01, double& chsq, double& time, double& dtime, double& zshift,
211 const EventContext& ctx, int outlierHitLayer) const {
212 ATH_MSG_DEBUG(" fit_segment called ");
213
214 bool measphi = false;
215 fit_detailCalcPart1(clus, lpos000, s0, s1, d0, d1, d01, chsq, measphi, time, dtime, zshift, false, outlierHitLayer,
216 ctx); // IsSlopeGiven should be false
217
218 if (measphi) return; // No need to do the second try
219 fit_detailCalcPart1(clus, lpos000, s0, s1, d0, d1, d01, chsq, measphi, time, dtime, zshift, true, outlierHitLayer,
220 ctx); }
221
223// if outlierid == iclu... error should be blown out in case of precision measurements..
224// if IsSlopeGiven true, then.... error is recalculated.....
225
227 double& s1, double& d0, double& d1, double& d01, double& chsq, bool& measphi, double& time,
228 double& dtime, double& zshift, bool IsSlopeGiven, int outlierHitLayer,
229 const EventContext& ctx) const {
230 // if (IsSlopeGiven)
231 // measure zshift
232
233 double q0 = 0.0;
234 double q1 = 0.0;
235 for (ICscSegmentFinder::TrkClusters::const_iterator iclu = clus.begin(); iclu != clus.end(); ++iclu) {
236 const ICscSegmentFinder::Cluster& cl = *iclu;
237 const CscClusterOnTrack* clu = cl.cl;
238 const CscPrepData* prd = clu->prepRawData();
239 Identifier id = clu->identify();
240
241 measphi = m_idHelperSvc->cscIdHelper().measuresPhi(id);
242 // Cluster position.
243 double y = cl.locY();
244 if (m_x5data) { y = y - alignConst(measphi, m_idHelperSvc->cscIdHelper().wireLayer(id)); }
245 double x = cl.locX();
246
247 bool isunspoiled = IsUnspoiled(prd->status());
248
249 // Error in cluster position.
250 // Slope is given and Unspoiled Status..... then error should be recalculated depending on slope...
251 // Outlier treatment is only working in case of unspoiled...
252 double d = Amg::error(clu->localCovariance(), Trk::locX);
253 if (isunspoiled) {
254 if (IsSlopeGiven && outlierHitLayer != (iclu - clus.begin()))
255 d = m_rotCreator->GetICscClusterFitter()->getCorrectedError(prd, s1);
256 }
257
258 d *= m_cluster_error_scaler; // This is for error scaler for cosmic!!!
259 double w = 1.0 / (d * d);
260 q0 += w;
261 q1 += w * x;
262 }
263 zshift = 0.0;
264 if (q0 > 0.) zshift = q1 / q0;
265 if (!m_zshift) zshift = 0.0;
266
267 ATH_MSG_VERBOSE(" fit_detailCalcPart1 zshift " << zshift);
268
269 q0 = 0.0;
270 q1 = 0.0;
271 double q2 = 0.0;
272 double q01 = 0.0;
273 double q11 = 0.0;
274 double q02 = 0.0;
275
276 if (m_IPconstraint) {
277 double x = lpos000.z();
278 double y = measphi ? lpos000.x() : lpos000.y();
279
280 ATH_MSG_DEBUG(" constraint x " << x << " y " << y << " error " << m_IPerror);
281
282 double d = m_IPerror;
283 double w = 1.0 / (d * d);
284 q0 += w;
285 q1 += w * (x - zshift);
286 q2 += w * (x - zshift) * (x - zshift);
287 q01 += w * y;
288 q11 += w * (x - zshift) * y;
289 q02 += w * y * y;
290 }
291
292 int cntSuccessHit = 0;
293 double sumHitTimes = 0.;
294 double sumHitTimeSquares = 0.;
295
296 int cntLateHit = 0;
297 int cntEarlyHit = 0;
298 float latestEarlyTime = -9999;
299 float earliestLateTime = 9999;
300 for (ICscSegmentFinder::TrkClusters::const_iterator iclu = clus.begin(); iclu != clus.end(); ++iclu) {
301 const ICscSegmentFinder::Cluster& cl = *iclu;
302 const CscClusterOnTrack* clu = cl.cl;
303 const CscPrepData* prd = clu->prepRawData();
304 Identifier id = clu->identify();
305
306 measphi = m_idHelperSvc->cscIdHelper().measuresPhi(id);
307 // Cluster position.
308 double y = cl.locY();
309 if (m_x5data) { y = y - alignConst(measphi, m_idHelperSvc->cscIdHelper().wireLayer(id)); }
310 double x = cl.locX();
311
312 bool isunspoiled = IsUnspoiled(prd->status());
313
314 // Error in cluster position.
315 // Slope is given and Unspoiled Status..... then error should be recalculated depending on slope...
316 // Outlier treatment is only working in case of unspoiled...
317 double d = Amg::error(clu->localCovariance(), Trk::locX);
318 if (isunspoiled) {
319 if (IsSlopeGiven) d = m_rotCreator->GetICscClusterFitter()->getCorrectedError(prd, s1);
320 if (outlierHitLayer == (iclu - clus.begin())) d = getDefaultError(id, measphi, prd, ctx);
321 }
322 d *= m_cluster_error_scaler; // This is for error scaler for cosmic!!!
323 ATH_MSG_VERBOSE(" +++fit_segment() x/y/d = " << x << " " << y << " " << d);
324
325 double w = 1.0 / (d * d);
326 q0 += w;
327 q1 += w * (x - zshift);
328 q2 += w * (x - zshift) * (x - zshift);
329 q01 += w * y;
330 q11 += w * (x - zshift) * y;
331 q02 += w * y * y;
332
333 if (prd->timeStatus() == Muon::CscTimeSuccess) {
334 ++cntSuccessHit;
335 sumHitTimes += prd->time();
336 sumHitTimeSquares += std::pow(prd->time(), 2);
337 }
338
339 if (prd->timeStatus() == Muon::CscTimeEarly) {
340 ++cntEarlyHit;
341 if (latestEarlyTime < prd->time()) latestEarlyTime = prd->time();
342 }
343
344 if (prd->timeStatus() == Muon::CscTimeLate) {
345 ++cntLateHit;
346 if (earliestLateTime > prd->time()) earliestLateTime = prd->time();
347 }
348 }
349
350 ATH_MSG_DEBUG(" Time Calculation!!! " << cntSuccessHit << " " << cntEarlyHit << " " << cntLateHit << " " << sumHitTimes << " "
351 << latestEarlyTime << " " << earliestLateTime);
352
353 if (cntSuccessHit > 0) {
354 time = sumHitTimes / float(cntSuccessHit);
355 float timeSquare = sumHitTimeSquares / float(cntSuccessHit);
356 dtime = timeSquare - time * time;
357 if (dtime < 0.0)
358 dtime = 0.0;
359 else
360 dtime = std::sqrt(dtime);
361 } else {
362 if (cntEarlyHit > 0 && cntLateHit > 0) {
363 time = 99999;
364 dtime = 99999;
365 ATH_MSG_DEBUG("Segment has nonzero earlyHits and nonzero lateHits. This should be backgrounds!!");
366 } else if (cntEarlyHit > 0) {
367 time = latestEarlyTime;
368 dtime = std::abs(latestEarlyTime);
369 } else if (cntLateHit > 0) {
370 time = earliestLateTime;
371 dtime = earliestLateTime;
372 } else {
373 time = 99999;
374 dtime = 99999;
375 ATH_MSG_DEBUG("Every Hit is CscTimeUnavailable or CscTimeStatusUndefined!!! Should be investigated");
376 }
377 }
378
379 ATH_MSG_DEBUG(" calc result " << time << " " << dtime);
380
381 // IsSlopeGiven (true) means 2nd try and somehow denominator is zero
382 // then return only available calc..
383 if (IsSlopeGiven && q2 * q0 - q1 * q1 == 0.0) return;
384
385 fit_detailCalcPart2(q0, q1, q2, q01, q11, q02, s0, s1, d0, d1, d01, chsq);
386}
387
388//******************************************************************************
389//
391 double& returned_chsq, const EventContext& ctx) const {
392 int nunspoil = 0;
393
394 double chsq_reference = 10000;
395 int remclu_ind = -1;
396 ATH_MSG_VERBOSE(" find_outlier_cluster clus size " << clus.size());
397
398 // check all four cases of outlier ... found the best chsq!!!
399 for (unsigned int ire = 0; ire < clus.size(); ire++) {
401 bool isunspoiled = IsUnspoiled(clus[ire].cl->status());
402 if (isunspoiled) ++nunspoil;
403
404 for (unsigned int itr = 0; itr < clus.size(); itr++)
405 if (ire != itr) fitclus.push_back(clus[itr]);
406
407 ATH_MSG_VERBOSE(" find_outlier_cluster drop ire " << ire << " fitclus size " << fitclus.size());
408
409 double s0, s1, d0, d1, d01, chsq, time, dtime, zshift;
410 fit_segment(fitclus, lpos000, s0, s1, d0, d1, d01, chsq, time, dtime, zshift, ctx);
411 if (chsq < chsq_reference && isunspoiled) { // require outlier should be precision measurement
412 chsq_reference = chsq;
413 remclu_ind = ire;
414 }
415
416 if (remclu_ind >= 0) ATH_MSG_VERBOSE(" new chsq " << ire << " " << chsq << " @" << remclu_ind);
417 }
418
419 // If nunspoil clusters are only 2 or less, we don't want to treat this segment outlier removal process!!
420 // So, set remclu_ind = -1 meaning no outlier is found...
421 if (nunspoil < m_nunspoil) {
422 ATH_MSG_VERBOSE(" Number of unspoiled cluster is " << nunspoil << " which is not enough!! At least 3 unspoiled hits required!! ");
423 remclu_ind = -1;
424 }
425
426 returned_chsq = 99999;
427 if (remclu_ind >= 0) {
428 ICscSegmentFinder::TrkClusters fitclus; // Muon::CscClusterOnTrack!!
429 // loading clusters into fitclus with outlier error blown up ....
430 for (unsigned int ire = 0; ire < clus.size(); ire++) fitclus.push_back(clus[ire]);
431
432 ATH_MSG_VERBOSE(" final fit outlier_cluster drop cluster index " << remclu_ind << " fitclus.size " << fitclus.size());
433
434 double s0, s1, d0, d1, d01, chsq, time, dtime, zshift;
435 fit_segment(fitclus, lpos000, s0, s1, d0, d1, d01, chsq, time, dtime, zshift, ctx, remclu_ind);
436 returned_chsq = chsq;
437 }
438
439 return remclu_ind;
440}
441
442//******************************************************************************
443
444// Fit a segment residual with a list of clusters.
445// Segment is fit excluding cluster irclu and then the residual is calculated
446// as the difference between the cluster position and that predicted by
447// the segment. The error in the residual includes those of the segment and the
448// excluded cluster.
449
450void CscSegmentUtilTool::fit_residual(const ICscSegmentFinder::TrkClusters& clus, const Amg::Vector3D& lpos000, unsigned int irclu,
451 double& res, double& dres, const EventContext& ctx) const {
452 ATH_MSG_DEBUG("CscSegmentUtilTool::fit_residual called ");
453
455 for (unsigned int iclu = 0; iclu < clus.size(); ++iclu) {
456 if (iclu != irclu) fitclus.push_back(clus[iclu]);
457 }
458 // Fit cluster.
459 double s0, s1, d0, d1, d01, chsq, time, dtime, zshift;
460 fit_segment(fitclus, lpos000, s0, s1, d0, d1, d01, chsq, time, dtime, zshift, ctx);
461
462 // Extract excluded cluster paramters.
463 const CscClusterOnTrack* cot = clus[irclu].cl;
464
466 double y = clus[irclu].locY();
467 if (m_x5data) {
468 const Identifier& id = cot->identify();
469 y = y - alignConst(m_idHelperSvc->cscIdHelper().measuresPhi(id), m_idHelperSvc->cscIdHelper().wireLayer(id));
470 }
471 double x = clus[irclu].locX();
472 // Error in cluster position.
473 double d = Amg::error(cot->localCovariance(), ierr) * m_cluster_error_scaler;
474
475 // This is for CscClusterCollection
476 if (d0 < 0 || d1 < 0) {
477 res = -99.;
478 dres = -9.;
479 } else {
480 // Calculate predicted position and error.
481 double seg_y = s0 + s1 * x;
482 double seg_dsquare = d0 * d0 + 2.0 * x * d01 + d1 * d1 * x * x;
483 // Calculate residual and error.
484 res = y - seg_y;
485 dres = d * d + seg_dsquare;
486
487 ATH_MSG_VERBOSE(" fit_residual d0:d01:d1 :: seg_dsquare:dres " << d0 << " " << d01 << " " << d1 << " :: " << seg_dsquare << " "
488 << dres);
489
490 if (dres < 0)
491 dres = -1.0 * std::sqrt(-1.0 * dres);
492 else if (dres >= 0)
493 dres = std::sqrt(dres);
494 else // in case of nan
495 dres = -9.;
496 }
497}
498
499//******************************************************************************
500
501// Fit a segment using a list of RIO's.
502// Filling is least squares with the usual 1/d**2 weighting.
503
504void CscSegmentUtilTool::fit_rio_segment(const Trk::PlaneSurface& ssrf, bool /*dump*/, const ICscSegmentFinder::RioList& rios, double& s0,
505 double& s1, double& d0, double& d1, double& d01, double& chsq, double& zshift) const {
506 ATH_MSG_DEBUG("CscSegmentUtilTool::fit_rio_segment called: ");
507
508 // measure zshift
509
510 double q0 = 0.0;
511 double q1 = 0.0;
512 for (ICscSegmentFinder::RioList::const_iterator irio = rios.begin(); irio != rios.end(); ++irio) {
513 const RIO_OnTrack& rio = **irio;
514 // Fetch the measurement.
516 const Trk::LocalParameters& msmt = rio.localParameters();
517 double y = msmt[iloc];
518 if (m_x5data) {
519 y = y - alignConst(m_idHelperSvc->cscIdHelper().measuresPhi(rio.identify()),
520 m_idHelperSvc->cscIdHelper().wireLayer(rio.identify()));
521 }
522 // Fetch the measurement error.
523 const Amg::MatrixX& cov = rio.localCovariance();
524 int dim = cov.rows();
525 Trk::ParamDefs ierr = dim == 1 ? Trk::loc1 : iloc;
526 double d = Amg::error(cov, ierr);
527 // Fetch the position of the measurement coordinate.
528 const Amg::Vector3D& gpos = rio.globalPosition();
529 Amg::Vector3D lpos = ssrf.transform().inverse() * gpos;
530 double x = lpos.z();
531 if (msgLvl(MSG::VERBOSE)) {
532 ATH_MSG_VERBOSE(" RIO global pos: " << gpos.x() << " " << gpos.y() << " " << gpos.z());
533 ATH_MSG_VERBOSE(" RIO local pos: " << lpos.x() << " " << lpos.y() << " " << lpos.z());
534 }
535 ATH_MSG_DEBUG(" RIO: " << x << " " << y << " " << d);
536
537 // Update least-square sums.
538 double w = 1.0 / (d * d);
539 q0 += w;
540 q1 += w * x;
541 }
542
543 zshift = 0.0;
544 if (q0 > 0) zshift = q1 / q0;
545 if (!m_zshift) zshift = 0.0;
546 ATH_MSG_VERBOSE(" fit_rio_segment: zshift " << zshift);
547 // Initialize least-square sums.
548
549 q0 = 0.;
550 q1 = 0.;
551 double q2 = 0.0;
552 double q01 = 0.0;
553 double q11 = 0.0;
554 double q02 = 0.0;
555 for (ICscSegmentFinder::RioList::const_iterator irio = rios.begin(); irio != rios.end(); ++irio) {
556 const RIO_OnTrack& rio = **irio;
557 // Fetch the measurement.
559 const Trk::LocalParameters& msmt = rio.localParameters();
560 double y = msmt[iloc];
561 if (m_x5data) {
562 y = y - alignConst(m_idHelperSvc->cscIdHelper().measuresPhi(rio.identify()),
563 m_idHelperSvc->cscIdHelper().wireLayer(rio.identify()));
564 }
565 // Fetch the measurement error.
566 // Fetch the measurement error.
567 const Amg::MatrixX& cov = rio.localCovariance();
568 int dim = cov.rows();
569 Trk::ParamDefs ierr = dim == 1 ? Trk::loc1 : iloc;
570 double d = Amg::error(cov, ierr);
571 // Fetch the position of the measurement coordinate.
572 const Amg::Vector3D& gpos = rio.globalPosition();
573 Amg::Vector3D lpos = ssrf.transform().inverse() * gpos;
574 double x = lpos.z();
575 if (msgLvl(MSG::VERBOSE)) {
576 ATH_MSG_VERBOSE(" RIO global pos: " << gpos.x() << " " << gpos.y() << " " << gpos.z());
577 ATH_MSG_VERBOSE(" RIO local pos: " << lpos.x() << " " << lpos.y() << " " << lpos.z());
578 }
579 ATH_MSG_DEBUG(" RIO: " << x << " " << y << " " << d);
580
581 // Update least-square sums.
582 double w = 1.0 / (d * d);
583 q0 += w;
584 q1 += w * (x - zshift);
585 q2 += w * (x - zshift) * (x - zshift);
586 q01 += w * y;
587 q11 += w * (x - zshift) * y;
588 q02 += w * y * y;
589 }
590
591 // detailed calc part2
592 fit_detailCalcPart2(q0, q1, q2, q01, q11, q02, s0, s1, d0, d1, d01, chsq);
593}
594
595//******************************************************************************
596
597// Fit a RIO segment residual with a list of clusters.
598// Segment is fit excluding RIO irio and then the residual is calculated
599// as the difference between the cluster position and that predicted by
600// the segment. The error in the residual includes those of the segment and the
601// excluded cluster.
602
604 unsigned int irrio, double& res, double& dres, double& rs, double& drs) const {
605 ATH_MSG_DEBUG("CscSegmentUtilTool::fit_rio_segment called ");
606
609 for (unsigned int irio = 0; irio < rios.size(); ++irio) {
610 if (irio != irrio) fitrios.push_back(rios[irio]);
611 // For three point method.... 0 x 2; 1 x 3;
612 if ((irrio == 1) && (irio == 0 || irio == 2)) fitrios3pt.push_back(rios[irio]);
613 if ((irrio == 2) && (irio == 1 || irio == 3)) fitrios3pt.push_back(rios[irio]);
614 }
615 // Fit cluster.
616 double s0, s1, d0, d1, d01, chsq, zshift;
617 fit_rio_segment(ssrf, dump, fitrios, s0, s1, d0, d1, d01, chsq, zshift);
618
619 // Extract excluded cluster paramters (see fit_rio_segment).
620 const RIO_OnTrack& rio = *rios[irrio];
622 const Trk::LocalParameters& msmt = rio.localParameters();
623 double y = msmt[iloc];
624 if (m_x5data) {
625 y = y -
626 alignConst(m_idHelperSvc->cscIdHelper().measuresPhi(rio.identify()), m_idHelperSvc->cscIdHelper().wireLayer(rio.identify()));
627 }
628 const Amg::MatrixX& cov = rio.localCovariance();
629 int dim = cov.rows();
630 Trk::ParamDefs ierr = dim == 1 ? Trk::loc1 : iloc;
631 double d = Amg::error(cov, ierr);
632 const Amg::Vector3D& gpos = rio.globalPosition();
633 Amg::Vector3D lpos = ssrf.transform().inverse() * gpos;
634 double x = lpos.z();
635 ATH_MSG_VERBOSE(" excluded RIO: " << x << " " << y << " " << d);
636
637 // Calculate predicted position and error.
638 double seg_y = s0 + s1 * x;
639 double seg_dsquare = d0 * d0 + 2.0 * x * d01 + d1 * d1 * x * x;
640 // Calculate residual and error.
641 res = y - seg_y;
642 dres = d * d + seg_dsquare;
643
644 ATH_MSG_VERBOSE(" fit_residual d0:d01:d1 :: seg_dsquare:dres " << d0 << " " << d01 << " " << d1 << " :: " << seg_dsquare << " "
645 << dres);
646
647 if (dres < 0)
648 dres = -1.0 * std::sqrt(-1.0 * dres);
649 else if (dres >= 0)
650 dres = std::sqrt(dres);
651 else // in case of nan
652 dres = -9.;
653
654 // 3pt method
655 // Calculate predicted position and error.
656 if (irrio == 1 || irrio == 2) {
657 // For 3 point method
658 double s0_3pt, s1_3pt, d0_3pt, d1_3pt, d01_3pt, chsq_3pt, zshift_3pt;
659 fit_rio_segment(ssrf, dump, fitrios3pt, s0_3pt, s1_3pt, d0_3pt, d1_3pt, d01_3pt, chsq_3pt, zshift_3pt);
660
661 if (d0_3pt < 0 || d1_3pt < 0) {
662 rs = -99.;
663 drs = -9.;
664 } else {
665 seg_y = s0_3pt + s1_3pt * x;
666 seg_dsquare = d0_3pt * d0_3pt + 2.0 * x * d01_3pt + d1_3pt * d1_3pt * x * x;
667 // Calculate residual and error.
668 rs = y - seg_y;
669 drs = d * d + seg_dsquare;
670
671 ATH_MSG_VERBOSE(" fit_rio_residual d0:d01:d1 :: seg_dsquare:dres " << d0_3pt << " " << d01_3pt << " " << d1_3pt
672 << " :: " << seg_dsquare << " " << drs);
673
674 if (drs < 0)
675 drs = -1.0 * std::sqrt(-1.0 * drs);
676 else if (drs >= 0)
677 drs = std::sqrt(drs);
678 else // in case of nan
679 drs = -999.;
680 }
681 } else {
682 rs = -99.;
683 drs = -9.;
684 }
685
686 ATH_MSG_DEBUG("Residual " << irrio << ": " << res << " " << dres);
687}
688
689//******************************************************************************
690
691// Extract then numbers of spoiled and unspoiled measurements from a list
692// of RIO's.
693
694void CscSegmentUtilTool::spoiled_count(const ICscSegmentFinder::RioList& rios, double threshold, int& nspoil, int& nunspoil) {
695 nspoil = 0;
696 nunspoil = 0;
697 for (ICscSegmentFinder::RioList::const_iterator irio = rios.begin(); irio != rios.end(); ++irio) {
698 const RIO_OnTrack& rio = **irio;
699 // Fetch the measurement.
701 const Amg::MatrixX& cov = rio.localCovariance();
702 int dim = cov.rows();
703 Trk::ParamDefs ierr = dim == 1 ? Trk::loc1 : iloc;
704 double d = Amg::error(cov, ierr);
705 if (d < threshold)
706 ++nunspoil;
707 else
708 ++nspoil;
709 }
710}
711
712void CscSegmentUtilTool::spoiled_count(const ICscSegmentFinder::RioList& rios, int& nspoil, int& nunspoil) {
713 nspoil = 0;
714 nunspoil = 0;
715 for (ICscSegmentFinder::RioList::const_iterator irio = rios.begin(); irio != rios.end(); ++irio) {
716 const RIO_OnTrack& rio = **irio;
717 const CscPrepData* pclu = dynamic_cast<const CscPrepData*>(rio.prepRawData());
718
719 if (pclu) {
720 if (IsUnspoiled(pclu->status()))
721 ++nunspoil;
722 else
723 ++nspoil;
724 } else {
725 ATH_MSG_WARNING(" Could not find CscPrepData from RIO_OnTrack ");
726 }
727 }
728}
729
730void CscSegmentUtilTool::spoiled_count(const ICscSegmentFinder::RioList& rios, int& nspoil, int& nunspoil, int& spoilmap) {
731 nspoil = 0;
732 nunspoil = 0;
733 spoilmap = 0;
734
735 for (ICscSegmentFinder::RioList::const_iterator irio = rios.begin(); irio != rios.end(); ++irio) {
736 const RIO_OnTrack& rio = **irio;
737 const CscPrepData* pclu = dynamic_cast<const CscPrepData*>(rio.prepRawData());
738 if (pclu) {
739 if (IsUnspoiled(pclu->status()))
740 ++nunspoil;
741 else {
742 int wlay = m_idHelperSvc->cscIdHelper().wireLayer(pclu->identify());
743 ++nspoil;
744 spoilmap += int(std::pow(2, wlay - 1));
745 }
746 } else {
747 ATH_MSG_WARNING(" Could not find CscPrepData from RIO_OnTrack ");
748 }
749 }
750}
751
752//******************************************************************************
753// Build an ATLAS segment.
754// Using the muon convention that x is normal to the plane of measurement:
755// My r segment: (z, dz/dx)
756// My phi segment: (y, dy/dx)
757// ATLAS segment: (u, v, atan(dx/du), atan(dx/dv)) = (y, z, axu, axv)
758// d(axy)/d(dx/dy) = -1/(1+(dx/dy)**2)
759// where u is the measured coordinate.
760// Use 0+/-1000 for the missing position and pi/2+/-1 for the missing direction.
761
763 const EventContext& ctx) const {
764 // chid from any last cluster in given chamber
765
766 ATH_MSG_DEBUG("Building csc segment.");
767
769 const MuonGM::MuonDetectorManager* MuonDetMgr{*DetectorManagerHandle};
770 if (MuonDetMgr == nullptr) {
771 ATH_MSG_ERROR("Null pointer to the read MuonDetectorManager conditions object");
772 return nullptr;
773 }
774 const CscReadoutElement* pro = MuonDetMgr->getCscReadoutElement(chid);
776 Amg::Vector3D lpos000 = gToLocal * Amg::Vector3D(0.0, 0.0, 0.0);
777 Amg::Transform3D lToGlobal = gToLocal.inverse();
778
779 // Surface.
780 // Position is the local origin transformed to the global coordinate system.
781 // We cannot use chamber position because it is at the first plane, not the
782 // origin of the local coordinate system!
783 ATH_MSG_VERBOSE(" build_segment: zshift " << seg.zshift);
784 Amg::Vector3D locp(0.0, 0.0, seg.zshift);
785 Amg::Vector3D glop = lToGlobal * locp;
786 // Use chamber rotation.
788 xf = pro->transform(chid).rotation();
789 xf.pretranslate(glop);
790 // Use chamber bounds.
791 Trk::SurfaceBounds* pbnd = pro->bounds(chid).clone();
792 Trk::TrapezoidBounds* pbnd_trap = dynamic_cast<Trk::TrapezoidBounds*>(pbnd);
793 Trk::RotatedTrapezoidBounds* pbnd_rtrap = dynamic_cast<Trk::RotatedTrapezoidBounds*>(pbnd);
794 Trk::PlaneSurface* psrf = nullptr;
795
796 ATH_MSG_VERBOSE(" Surface: ");
797 if (pbnd_trap) {
798 psrf = new Trk::PlaneSurface(xf, std::shared_ptr<Trk::TrapezoidBounds> (pbnd_trap));
799 ATH_MSG_VERBOSE("trapezoid");
800 } else if (pbnd_rtrap) {
801 psrf = new Trk::PlaneSurface(xf, std::shared_ptr<Trk::RotatedTrapezoidBounds>(pbnd_rtrap));
802 ATH_MSG_VERBOSE("rotated trapezoid");
803 } else {
804 ATH_MSG_FATAL(" Invalid boundary: " << *pbnd);
805 abort();
806 }
807 ATH_MSG_VERBOSE(" Segment surface: " << *psrf);
808
809 Amg::Transform3D gToSurf = psrf->transform().inverse();
810 double lx = measphi ? seg.s0 : 0.;
811 double ly = measphi ? 0. : seg.s0;
812 double lz = seg.zshift;
813 double dlx = measphi ? seg.s1 : 0.;
814 double dly = measphi ? 0. : seg.s1;
815 double dlz = 1.;
816 Amg::Vector3D lposAMDB(lx, ly, lz);
817 Amg::Vector3D gpos = lToGlobal * lposAMDB;
818 Amg::Vector3D lposRef = gToSurf * gpos;
819 Amg::Vector3D ldirAMDB(dlx, dly, dlz);
820 Amg::Vector3D gdir = lToGlobal.linear() * ldirAMDB;
821 Amg::Vector3D ldirRef = gToSurf.linear() * gdir;
822 Amg::Vector3D lposRefShift = lposRef - ldirRef * lposRef.z();
823
824 ATH_MSG_VERBOSE(" extrapolation to lposRef.z() " << lposRef.z());
825 double s0 = lposRefShift.x();
826 ATH_MSG_VERBOSE(" Input position, slope: " << s0 << " " << seg.s1);
827 ATH_MSG_VERBOSE(" Error: " << seg.d0 << " " << seg.d1 << " " << seg.d01);
828
829 // Build list of RIO on track objects.
830 auto prios = ICscSegmentFinder::MbaseList{};
831 getRios(seg, &prios, measphi, ctx); // if hit is in outlier, error is estimated in width/sqrt(12)
832
833 // Fit quality.
834 int ndof = int(prios.size()) - 2;
835 if (m_IPconstraint) ndof = ndof + 1;
836 if (use2Lay) ndof = 1;
837 Trk::FitQuality* pfq = new Trk::FitQuality(seg.chsq, ndof);
838 // Build segment.
839 // Build position vector.
840 Amg::Vector2D pos(s0, 0.0);
841 // Build direction vector.
842 double ameas = std::atan2(1.0, seg.s1);
843 Trk::LocalDirection pdir(ameas, M_PI_2);
844 // Error matrix.
845 double dfac = -1.0 / (1 + seg.s1 * seg.s1);
846 double e_pos_pos = seg.d0 * seg.d0;
847 double e_pos_dir = seg.d01 * dfac;
848 const double e_dir_dir = seg.d1 * seg.d1 * dfac * dfac;
849 Amg::MatrixX cov(4, 4);
850 cov.setIdentity();
851 cov(0, 0) = e_pos_pos;
852 cov(0, 2) = e_pos_dir;
853 cov(2, 0) = cov(0, 2);
854 cov(2, 2) = e_dir_dir;
855 cov(1, 1) = 1000000.0;
856 cov(1, 3) = 0.0;
857 cov(3, 1) = cov(1, 3);
858 cov(3, 3) = 1.0;
859 MuonSegment* pseg_ref = new MuonSegment(pos,
860 pdir,
861 std::move(cov),
862 psrf,
863 std::move(prios),
864 pfq,
866 pseg_ref->setT0Error(float(seg.time), float(seg.dtime));
867
868 ATH_MSG_DEBUG(" build_segment:: right after ctor* " << pseg_ref->time());
869
870 Amg::Transform3D globalToLocal = pro->transform(chid).inverse();
871 Amg::Vector3D d(globalToLocal.linear() * pseg_ref->globalDirection());
872
873 double tantheta = 0;
874 if (d.z() == 0) {
875 ATH_MSG_WARNING("build_segment() - segment z is 0, set tantheta=0");
876 } else
877 tantheta = d.x() / d.z(); // is equal to seg.s1
878
879 ATH_MSG_VERBOSE(" Position: " << pos[Trk::loc1] << " " << pos[Trk::loc2]);
880 ATH_MSG_VERBOSE("seg.s1 : ameas " << seg.s1 << " " << ameas);
881 ATH_MSG_VERBOSE(" Direction: " << pdir.angleXZ() << " " << pdir.angleYZ());
882 ATH_MSG_VERBOSE(" d.x : d.z : tantheta " << d.x() << " " << d.z() << " " << tantheta);
883 ATH_MSG_VERBOSE(resetiosflags(std::ios_base::floatfield));
884
885 MuonSegment* pseg = pseg_ref->clone();
886 ATH_MSG_DEBUG(" build_segment:: right after copying * " << pseg->time());
887
888 const double initialDiffTanTheta = 99;
889 double diff_tantheta = initialDiffTanTheta;
890 const unsigned int nTrials = 10;
891 unsigned int n_update = 0;
892 while (diff_tantheta > m_fitsegment_tantheta_tolerance && n_update < nTrials) {
893 // Loop over collections in the container.
894 auto prios_new = ICscSegmentFinder::MbaseList{};
897 for (unsigned int irot = 0; irot < pseg_ref->numberOfContainedROTs(); irot++) oldrios.push_back(pseg_ref->rioOnTrack(irot));
898
899 int cnt = 0;
900 for (ICscSegmentFinder::RioList::size_type irio = 0; irio < pseg_ref->numberOfContainedROTs(); ++irio) {
901 const Trk::RIO_OnTrack* pold = oldrios[irio];
902 const Trk::RIO_OnTrack* cot =
903 (seg.outlierid == cnt)
904 ? pold->clone() // No update for outlier owing to error blown up
905 : m_rotCreator->createRIO_OnTrack(*pold->prepRawData(), pold->globalPosition(), pseg->globalDirection());
906 if (!cot) {
907 ATH_MSG_WARNING("Failed to create CscClusterOnTrack");
908 continue;
909 }
910 const CscClusterOnTrack* pcl = dynamic_cast<const CscClusterOnTrack*>(cot);
911 if (!pcl) {
912 ATH_MSG_WARNING("Failed to cast to CscClusterOnTrack");
913 delete cot;
914 continue;
915 }
916 prios_new.push_back(cot);
917
918 // Create new calibrated hit to put into fitclus
919 const CscPrepData* prd = pcl->prepRawData();
920 Amg::Vector3D lpos = gToLocal * pcl->globalPosition();
921
922 ATH_MSG_DEBUG(" ---+++----> build_segment each rios time " << pcl->time() << " " << prd->time());
923
924 ATH_MSG_VERBOSE(cnt << " " << n_update << " error ");
925 if (seg.outlierid == cnt)
926 ATH_MSG_VERBOSE(" !! outlier !! ");
927 else
928 ATH_MSG_VERBOSE(" !! !! ");
930
931 fitclus.emplace_back(lpos, pcl, measphi);
932 cnt++;
933 }
934
935 ICscSegmentFinder::Segment seg_new; // Reconstruct segment in 2nd try with re-calibrated cluster position error
936 seg_new.outlierid = seg.outlierid;
937
938 fit_segment(fitclus, lpos000, seg_new.s0, seg_new.s1, seg_new.d0, seg_new.d1, seg_new.d01, seg_new.chsq, seg_new.time,
939 seg_new.dtime, seg_new.zshift, ctx, seg.outlierid);
940 ATH_MSG_DEBUG("build_segments:: " << seg_new.time << " " << seg_new.dtime << " fitclus size " << fitclus.size());
941
942 if (seg.outlierid >= 0) ATH_MSG_VERBOSE(n_update << " outlierid =" << seg.outlierid << " new chsq ==> " << seg_new.chsq);
943
944 Trk::FitQuality* pfq_new = new Trk::FitQuality(seg_new.chsq, ndof);
945
946 double lx = measphi ? seg_new.s0 : 0.;
947 double ly = measphi ? 0. : seg_new.s0;
948 double lz = seg_new.zshift;
949 double dlx = measphi ? seg_new.s1 : 0.;
950 double dly = measphi ? 0. : seg_new.s1;
951 double dlz = 1.;
952 Amg::Vector3D lposAMDB(lx, ly, lz);
953 Amg::Vector3D gpos = lToGlobal * lposAMDB;
954 Amg::Vector3D lposRef = gToSurf * gpos;
955 Amg::Vector3D ldirAMDB(dlx, dly, dlz);
956 Amg::Vector3D gdir = lToGlobal.linear() * ldirAMDB;
957 Amg::Vector3D ldirRef = gToSurf.linear() * gdir;
958 Amg::Vector3D lposRefShift = lposRef - ldirRef * lposRef.z();
959 double s0 = lposRefShift.x();
960
961 Amg::Vector2D pos_new(s0, 0.0);
962 // Build direction vector.
963 double ameas_new = atan2(1.0, seg_new.s1);
964 Trk::LocalDirection pdir_new(ameas_new, M_PI_2);
965 // Error matrix.
966 double dfac_new = -1.0 / (1 + seg_new.s1 * seg_new.s1);
967 double e_pos_pos_new = seg_new.d0 * seg_new.d0;
968 double e_pos_dir_new = seg_new.d01 * dfac_new;
969 const double e_dir_dir_new = seg_new.d1 * seg_new.d1 * dfac_new * dfac_new;
970 Amg::MatrixX cov(4, 4);
971 cov.setIdentity();
972 cov(0, 0) = e_pos_pos_new;
973 cov(0, 2) = e_pos_dir_new;
974 cov(2, 2) = e_dir_dir_new;
975 cov(1, 1) = 1000000.0;
976 cov(1, 3) = 0.0;
977 cov(3, 3) = 1.0;
978
979 MuonSegment* pseg_new =
980 new MuonSegment(pos_new,
981 pdir_new,
982 std::move(cov),
983 pseg->associatedSurface().clone(),
984 std::move(prios_new),
985 pfq_new,
987 pseg_new->setT0Error(float(seg_new.time), float(seg_new.dtime));
988 ATH_MSG_DEBUG(" build_segment:: right after recreating * " << pseg_new->time());
989
990 Amg::Vector3D dnew(globalToLocal.linear() * pseg->globalDirection());
991 double tanthetanew = 0;
992 if (dnew.z() == 0) {
993 ATH_MSG_WARNING("build_segment() - new segment z is 0, staying with old segment and continue loop");
994 // we need to delete the new segment we just created
995 delete pseg_new;
996 // we set diff_tantheta again to its initial value and continue the loop
997 diff_tantheta = initialDiffTanTheta;
998 // if nTrials is reached anyway in the next iteration, break
999 if (n_update == (nTrials - 1)) break;
1000 continue;
1001 } else
1002 tanthetanew = dnew.x() / dnew.z();
1003
1004 // this gets only called if the new segment did not have tanthetanew=0
1005 delete pseg;
1006 pseg = pseg_new;
1007 ATH_MSG_DEBUG(" build_segment:: right after new assigning and resetting * " << pseg->time());
1008
1009 if (tantheta == 0) {
1010 ATH_MSG_WARNING("build_segment() - tantheta=0 but tanthetanew=" << tanthetanew << ", set diff_tantheta=tanthetanew");
1011 diff_tantheta = tanthetanew;
1012 } else {
1013 // both tanthetanew and tantheta are not 0
1014 diff_tantheta = std::abs(tanthetanew - tantheta) / tantheta;
1015 }
1016
1017 ATH_MSG_VERBOSE(" tantheta change in segment: " << tantheta << " ==> " << tanthetanew << " -ratio- " << diff_tantheta);
1018
1019 tantheta = tanthetanew;
1020 n_update++;
1021 }
1022 ATH_MSG_VERBOSE(" chisq " << (pseg->fitQuality())->chiSquared());
1023
1024 if ((pseg->fitQuality())->chiSquared() > m_max_chisquare) {
1025 ATH_MSG_DEBUG(" Segment dropped chisq " << (pseg->fitQuality())->chiSquared() << " cut value " << m_max_chisquare);
1026 delete pseg;
1027 delete pseg_ref;
1028 return nullptr;
1029 }
1030
1031 const Trk::LocalParameters& l = pseg->localParameters();
1032 ATH_MSG_VERBOSE(" Seg local key: " << l.parameterKey());
1033 ATH_MSG_VERBOSE(" Seg local params: " << l[Trk::loc1] << " " << l[Trk::loc2] << " " << l[Trk::phi] << " " << l[Trk::theta]);
1034 const Trk::LocalDirection& dr = pseg->localDirection();
1035 ATH_MSG_VERBOSE(" Seg local dir: " << dr.angleXZ() << " " << dr.angleYZ());
1036 const Amg::Vector3D& g = pseg->globalPosition();
1037 ATH_MSG_VERBOSE(" Seg global pos: " << g.x() << " " << g.y() << " " << g.z());
1038
1039 delete pseg_ref;
1040
1041 ATH_MSG_DEBUG(" build_segment:: right just before returning * " << pseg->time());
1042 return pseg;
1043}
1044
1045/**************************************************************/
1046void CscSegmentUtilTool::find_2dsegments(bool measphi, int station, int eta, int phi, const ICscSegmentFinder::ChamberTrkClusters& chclus,
1047 const Amg::Vector3D& lpos000, ICscSegmentFinder::Segments& segs, double lpos, double lslope,
1048 const EventContext& ctx) const {
1049 if (msgLvl(MSG::DEBUG)) {
1050 ATH_MSG_DEBUG("find_2dsegments called!! ID: " << measphi_name(measphi) << " " << std::showpos << eta << " "
1051 << station_name(station) << " " << phi << " ");
1052 ATH_MSG_DEBUG(" Counts: " << chclus[0].size() << " " << chclus[1].size() << " " << chclus[2].size() << " " << chclus[3].size());
1053 }
1054
1055 const ICscSegmentFinder::TrkClusters& clus1 = chclus[0];
1056 const ICscSegmentFinder::TrkClusters& clus2 = chclus[1];
1057 const ICscSegmentFinder::TrkClusters& clus3 = chclus[2];
1058 const ICscSegmentFinder::TrkClusters& clus4 = chclus[3];
1060 fitclus.reserve(4);
1062
1063 // Loop over clusters in each layer and find all combinatoric segments.
1064 for (ICscSegmentFinder::TrkClusters::const_iterator icl1 = clus1.begin(); icl1 != clus1.end(); ++icl1) {
1065 for (ICscSegmentFinder::TrkClusters::const_iterator icl2 = clus2.begin(); icl2 != clus2.end(); ++icl2) {
1066 for (ICscSegmentFinder::TrkClusters::const_iterator icl3 = clus3.begin(); icl3 != clus3.end(); ++icl3) {
1067 for (ICscSegmentFinder::TrkClusters::const_iterator icl4 = clus4.begin(); icl4 != clus4.end(); ++icl4) {
1068 fitclus = {*icl1, *icl2, *icl3, *icl4};
1069
1071 ATH_MSG_VERBOSE(" +++++++ find_2dsegments ++ Errors " << Amg::error((*icl1).cl->localCovariance(), ierr) << " "
1072 << Amg::error((*icl2).cl->localCovariance(), ierr) << " "
1073 << Amg::error((*icl3).cl->localCovariance(), ierr) << " "
1074 << Amg::error((*icl4).cl->localCovariance(), ierr) << " ");
1075
1076 seg.s0 = lpos;
1077 seg.s1 = lslope;
1078 fit_segment(fitclus, lpos000, seg.s0, seg.s1, seg.d0, seg.d1, seg.d01, seg.chsq, seg.time, seg.dtime, seg.zshift, ctx);
1079 seg.clus[0] = *icl1;
1080 seg.clus[1] = *icl2;
1081 seg.clus[2] = *icl3;
1082 seg.clus[3] = *icl4;
1083
1084 int nunspoil = 0;
1085 for (int i = 0; i < 4; ++i) {
1086 if (IsUnspoiled(seg.clus[i].cl->status())) ++nunspoil;
1087 ATH_MSG_DEBUG("Status of HIT #" << i << " " << seg.clus[i].cl->status());
1088 }
1089
1090 seg.nunspoil = nunspoil;
1091 seg.outlierid = -1;
1092 seg.nclus = 4;
1093
1094 double local_max_chi = 0.;
1095 if (nunspoil > 2)
1096 local_max_chi = m_max_chisquare_loose;
1097 else
1098 local_max_chi = m_max_chisquare;
1099
1100 bool keep = true;
1101 if (seg.chsq > m_max_chisquare_tight) keep = false;
1102
1103 ATH_MSG_VERBOSE(" find_2dsegments:: nunspoil and local_max_chi " << nunspoil << " " << local_max_chi << " " << keep
1104 << " " << m_max_chisquare_tight << " " << seg.chsq);
1105
1106 if (!keep) {
1107 // chi2 after outlier removal on 4 hit segments.
1108 double outlierRemoved_chsq;
1109 int ioutlierid = find_outlier_cluster(seg.clus, lpos000, outlierRemoved_chsq, ctx);
1110 if (ioutlierid > 0 && outlierRemoved_chsq < m_max_chisquare_tight) {
1111 keep = true;
1112 seg.chsq = outlierRemoved_chsq;
1113 seg.outlierid = ioutlierid;
1114 ATH_MSG_DEBUG("find_2dsegments: keep outlier ");
1115 } else {
1116 ATH_MSG_DEBUG("find_2dsegments: reject segment bad chi2 ");
1117 }
1118 }
1119 ATH_MSG_DEBUG("find_2dsegments:: " << seg.time << " " << seg.dtime);
1120
1121 // reject segments with slope of 0 (should only apply to NCB segments)
1122 if (seg.s1 == 0 && !m_IPconstraint) {
1123 ATH_MSG_DEBUG("slope too small, rejecting");
1124 keep = false;
1125 }
1126
1127 if (keep) segs.push_back(seg);
1128
1129 ATH_MSG_VERBOSE(" nunspoil and local_max_chi " << nunspoil << " " << local_max_chi << " " << keep << " " << seg.s1
1130 << " >< " << m_max_slope_r << " + " << seg.d1);
1131
1132 ATH_MSG_VERBOSE(" Segment measphi? " << measphi << " chsq:" << seg.chsq << " abs(seg.s1) " << std::abs(seg.s1)
1133 << " req eta:phi " << m_max_slope_r + seg.d1 << " : " << m_max_slope_phi + seg.d1
1134 << " keep? " << keep);
1135 }
1136 }
1137 }
1138 }
1139
1140 // Sort segments by nunspoil then chi-square.
1141 std::sort(segs.begin(), segs.end(), ICscSegmentFinder::sortByNunspoilAndChsq());
1142}
1143
1145
1147 // Limit number of segments
1148
1149 if (segs4.empty() and segs3.empty()) return;
1150
1151 ATH_MSG_DEBUG(" Total Input seg4 segment size " << segs4.size());
1152 ATH_MSG_DEBUG(" Total Input seg3 segment size " << segs3.size());
1153
1154 std::vector<int> isegs4OK(segs4.size(), 1);
1155 std::vector<int> isegs3OK(segs3.size(), 1);
1156 ICscSegmentFinder::Segments segs4All{segs4};
1157
1158 ICscSegmentFinder::Segments::const_iterator iseg;
1159 ICscSegmentFinder::Segments::const_iterator iseg2;
1160
1161 segs4.clear();
1162
1163
1164
1165 int iiseg = -1;
1166 for (iseg = segs4All.begin(); iseg != segs4All.end(); ++iseg) {
1167 iiseg++;
1168 int iiseg2 = iiseg;
1169 for (iseg2 = iseg + 1; iseg2 != segs4All.end(); ++iseg2) {
1170 int nhits_common = 0;
1171 iiseg2++;
1172 for (int iclus = 0; iclus < iseg->nclus; iclus++) {
1173 const Muon::CscClusterOnTrack* cot = iseg->clus[iclus].cl;
1174 for (int iclus2 = 0; iclus2 < iseg2->nclus; iclus2++) {
1175 const Muon::CscClusterOnTrack* cot2 = iseg2->clus[iclus2].cl;
1176 if (cot->identify() == cot2->identify()) nhits_common++;
1177 }
1178 }
1179 if (nhits_common > 0 && m_remove4Overlap) {
1180 isegs4OK[iiseg2] = 0;
1181 ATH_MSG_DEBUG(" seg4 segment nr " << iiseg2 << " dropped with nhits_common " << nhits_common);
1182 }
1183 }
1184 }
1185
1186 iiseg = -1;
1187 for (iseg = segs4All.begin(); iseg != segs4All.end(); ++iseg) {
1188 iiseg++;
1189 const Muon::CscClusterOnTrack* cot = iseg->clus[0].cl;
1190 Identifier id = cot->identify();
1191 if (!m_idHelperSvc->cscIdHelper().measuresPhi(id) && iseg->nunspoil < m_nunspoil) {
1192 ATH_MSG_DEBUG(" seg4 eta segment rejected with nclusters too few unspoiled hits " << iseg->nclus << " chi2 " << iseg->chsq
1193 << " unspoiled " << iseg->nunspoil);
1194 isegs4OK[iiseg] = 0;
1195 }
1196 if (isegs4OK[iiseg] == 1 && segs4.size() < m_max_seg_per_chamber) {
1197 segs4.push_back(*iseg);
1198 ATH_MSG_DEBUG(" seg4 segment accepted with nclusters " << iseg->nclus << " chi2 " << iseg->chsq << " unspoiled "
1199 << iseg->nunspoil << " measuresPhi "
1200 << m_idHelperSvc->cscIdHelper().measuresPhi(id));
1201 } else {
1202 ATH_MSG_DEBUG(" seg4 segment rejected with nclusters " << iseg->nclus << " chi2 " << iseg->chsq << " unspoiled "
1203 << iseg->nunspoil << " measuresPhi "
1204 << m_idHelperSvc->cscIdHelper().measuresPhi(id));
1205 }
1206 }
1207 int segs4Size = segs4.size();
1208 ATH_MSG_DEBUG(" Total seg4 segment accepted size " << segs4Size);
1209
1210 if (segs4.size() == m_max_seg_per_chamber) { return; }
1211
1212 for (iseg = segs4.begin(); iseg != segs4.end(); ++iseg) {
1213 int iiseg2 = -1;
1214 for (iseg2 = segs3.begin(); iseg2 != segs3.end(); ++iseg2) {
1215 iiseg2++;
1216 int nhits_common = 0;
1217 for (int iclus = 0; iclus < iseg->nclus; iclus++) {
1218 const Muon::CscClusterOnTrack* cot = iseg->clus[iclus].cl;
1219 for (int iclus2 = 0; iclus2 < iseg2->nclus; iclus2++) {
1220 const Muon::CscClusterOnTrack* cot2 = iseg2->clus[iclus2].cl;
1221 if (cot->identify() == cot2->identify()) nhits_common++;
1222 }
1223 }
1224 if (nhits_common > 0 && m_remove3Overlap) {
1225 isegs3OK[iiseg2] = 0;
1226 ATH_MSG_DEBUG(" seg3 segment nr " << iiseg2 << " dropped with nhits_common " << nhits_common);
1227 }
1228 }
1229 }
1230
1231 iiseg = -1;
1232 for (iseg = segs3.begin(); iseg != segs3.end(); ++iseg) {
1233 iiseg++;
1234 int iiseg2 = iiseg;
1235 for (iseg2 = iseg + 1; iseg2 != segs3.end(); ++iseg2) {
1236 iiseg2++;
1237 int nhits_common = 0;
1238 for (int iclus = 0; iclus < iseg->nclus; iclus++) {
1239 const Muon::CscClusterOnTrack* cot = iseg->clus[iclus].cl;
1240 for (int iclus2 = 0; iclus2 < iseg2->nclus; iclus2++) {
1241 const Muon::CscClusterOnTrack* cot2 = iseg2->clus[iclus2].cl;
1242 if (cot->identify() == cot2->identify()) nhits_common++;
1243 }
1244 }
1245 if (nhits_common > 0 && m_remove3Overlap) {
1246 isegs3OK[iiseg2] = 0;
1247 ATH_MSG_DEBUG(" seg3 segment nr " << iiseg2 << " dropped with nhits_common " << nhits_common);
1248 }
1249 }
1250 }
1251
1252 // As long as we don't exceed max size, add segments from segs3 to end of segs4
1253 iiseg = -1;
1254 for (iseg = segs3.begin(); iseg != segs3.end(); ++iseg) {
1255 iiseg++;
1256 const Muon::CscClusterOnTrack* cot = iseg->clus[0].cl;
1257 Identifier id = cot->identify();
1258 if (!m_idHelperSvc->cscIdHelper().measuresPhi(id) && iseg->nunspoil < m_nunspoil) {
1259 ATH_MSG_DEBUG(" seg3 eta segment rejected with nclusters too few unspoiled hits " << iseg->nclus << " chi2 " << iseg->chsq
1260 << " unspoiled " << iseg->nunspoil);
1261 isegs3OK[iiseg] = 0;
1262 }
1263 if (isegs3OK[iiseg] == 1 && segs4.size() < m_max_seg_per_chamber) {
1264 segs4.push_back(*iseg);
1265 ATH_MSG_DEBUG(" seg3 segment accepted with nclusters " << iseg->nclus << " chi2 " << iseg->chsq << " unspoiled "
1266 << iseg->nunspoil << " measuresPhi "
1267 << m_idHelperSvc->cscIdHelper().measuresPhi(id));
1268 } else {
1269 ATH_MSG_DEBUG(" seg3 segment rejected with nclusters " << iseg->nclus << " chi2 " << iseg->chsq << " unspoiled "
1270 << iseg->nunspoil << " measuresPhi "
1271 << m_idHelperSvc->cscIdHelper().measuresPhi(id));
1272 }
1273 }
1274 ATH_MSG_DEBUG(" Total seg3 segment size " << segs4.size() - segs4Size);
1275}
1276
1278// stores 2-hit segments
1280 if (segs2.empty()) return;
1281 ATH_MSG_DEBUG(" Total Input 2-layer segment size " << segs2.size());
1282
1283 int lay0 = -1, lay1 = -1;
1284 for (int i = 0; i < 4; i++) {
1285 if ((layStat % (int)std::pow(10, i + 1)) / (int)std::pow(10, i) == 0) {
1286 if (lay0 == -1)
1287 lay0 = i;
1288 else if (lay1 == -1)
1289 lay1 = i;
1290 }
1291 }
1292 bool checkCrossTalk = false;
1293 if (std::abs(lay0 - lay1) == 1 && lay0 + lay1 != 3)
1294 checkCrossTalk = true; // if we have layers 0 and 1 or 2 and 3 there could be cross-talk creating fake 2-layer segments
1295
1296 std::vector<int> isegs2OK(segs2.size(), 1);
1297 ICscSegmentFinder::Segments::const_iterator iseg;
1298 ICscSegmentFinder::Segments::const_iterator iseg2;
1299 ICscSegmentFinder::Segments segsAll{segs};
1300
1301 segs.clear();
1302
1303 int iiseg = -1;
1304 for (iseg = segs2.begin(); iseg != segs2.end(); ++iseg) {
1305 iiseg++;
1306 if (!isegs2OK[iiseg]) continue;
1307 int iiseg2 = iiseg;
1308 for (iseg2 = iseg + 1; iseg2 != segs2.end(); ++iseg2) {
1309 int nhits_common = 0;
1310 iiseg2++;
1311 if (!isegs2OK[iiseg2]) continue;
1312 double charges[2] = {0, 0};
1313 for (int iclus = 0; iclus < iseg->nclus; iclus++) {
1314 const Muon::CscClusterOnTrack* cot = iseg->clus[iclus].cl;
1315 if (checkCrossTalk) {
1316 const Muon::CscPrepData* prep = cot->prepRawData();
1317 std::vector<const Muon::CscStripPrepData*> strips = m_rotCreator->GetICscClusterUtilTool()->getStrips(prep);
1318 std::vector<double> stripCharges;
1319 for (unsigned int s = 0; s < strips.size(); ++s) {
1321 sfit = m_rotCreator->GetICscStripFitter()->fit(*strips[s]);
1322 stripCharges.push_back(sfit.charge);
1323 }
1324 double maxCharge = 0, centCharge = 0;
1325 for (unsigned int s = 0; s < stripCharges.size(); s++) {
1326 if (stripCharges[s] > maxCharge) {
1327 maxCharge = stripCharges[s];
1328 centCharge = stripCharges[s];
1329 if (s > 0) centCharge += stripCharges[s - 1];
1330 if (s < stripCharges.size() - 1) centCharge += stripCharges[s + 1];
1331 }
1332 }
1333 charges[iclus] = centCharge;
1334 if (iclus == 1) {
1335 float chargeRatio = charges[0] / charges[1];
1336 if (charges[0] > charges[1]) chargeRatio = charges[1] / charges[0];
1337 if (chargeRatio < .01) {
1338 nhits_common = -1;
1339 break;
1340 } // ratio this small means crosstalk, kill this segment
1341 }
1342 }
1343 for (int iclus2 = 0; iclus2 < iseg2->nclus; iclus2++) {
1344 const Muon::CscClusterOnTrack* cot2 = iseg2->clus[iclus2].cl;
1345 if (cot->identify() == cot2->identify()) nhits_common++;
1346 }
1347 }
1348 if (nhits_common != 0) { //>0, overlap; <0, cross-talk
1349 isegs2OK[iiseg2] = 0;
1350 ATH_MSG_DEBUG(" seg2 segment nr " << iiseg2 << " dropped with nhits_common " << nhits_common);
1351 }
1352 }
1353 }
1354 iiseg = -1;
1355 for (iseg = segsAll.begin(); iseg != segsAll.end(); ++iseg) {
1356 iiseg++;
1357 int iiseg2 = -1;
1358 for (iseg2 = segs2.begin(); iseg2 != segs2.end(); ++iseg2) {
1359 int nhits_common = 0;
1360 iiseg2++;
1361 if (isegs2OK[iiseg2] == 0) continue; // already rejected this segment
1362 for (int iclus = 0; iclus < iseg->nclus; iclus++) {
1363 const Muon::CscClusterOnTrack* cot = iseg->clus[iclus].cl;
1364 int wlay = m_idHelperSvc->cscIdHelper().wireLayer(cot->identify());
1365 if ((layStat % (int)std::pow(10, wlay + 1)) / (int)std::pow(10, wlay) ==
1366 1) { // this 3-layer segment has a hit in a bad layer: dump it
1367 nhits_common = -1;
1368 break;
1369 }
1370 for (int iclus2 = 0; iclus2 < iseg2->nclus; iclus2++) {
1371 const Muon::CscClusterOnTrack* cot2 = iseg2->clus[iclus2].cl;
1372 if (cot->identify() == cot2->identify()) nhits_common++;
1373 }
1374 }
1375 if (nhits_common > 0) {
1376 isegs2OK[iiseg2] = 0;
1377 ATH_MSG_DEBUG(" seg2 segment nr " << iiseg2 << " dropped with nhits_common " << nhits_common);
1378 if (iseg2 == segs2.begin()) segs.push_back(*iseg); // no hits in bad layers, add this segment (but only once)
1379 } else if (nhits_common == 0) {
1380 if (iseg2 == segs2.begin()) segs.push_back(*iseg); // no hits in bad layers, add this segment (but only once)
1381 } else if (nhits_common == -1)
1382 break; // this segment has a hit in a bad layer, skip to the next one
1383 }
1384 }
1385 iiseg = -1;
1386 for (iseg = segs2.begin(); iseg != segs2.end(); ++iseg) {
1387 iiseg++;
1388 const Muon::CscClusterOnTrack* cot = iseg->clus[0].cl;
1389 Identifier id = cot->identify();
1390 if (isegs2OK[iiseg] == 1 && segs.size() < m_max_seg_per_chamber) {
1391 segs.push_back(*iseg);
1392 ATH_MSG_DEBUG(" seg2 accepted, nclusters " << iseg->nclus << " chi2 " << iseg->chsq << " unspoiled " << iseg->nunspoil
1393 << " mPhi " << m_idHelperSvc->cscIdHelper().measuresPhi(id));
1394 } else {
1395 ATH_MSG_DEBUG(" seg2 rejected, nclusters " << iseg->nclus << " chi2 " << iseg->chsq << " unspoiled " << iseg->nunspoil
1396 << " mPhi " << m_idHelperSvc->cscIdHelper().measuresPhi(id));
1397 }
1398 }
1399 ATH_MSG_DEBUG(" Total seg2 accepted: " << segs.size());
1400}
1401
1403void CscSegmentUtilTool::find_2dseg3hit(bool measphi, int station, int eta, int phi, const ICscSegmentFinder::ChamberTrkClusters& chclus,
1404 const Amg::Vector3D& lpos000, ICscSegmentFinder::Segments& segs,
1405 ICscSegmentFinder::Segments& segs4hit, double lpos, double lslope, const EventContext& ctx) const {
1406 ATH_MSG_DEBUG("find_2dseg3hit called");
1407
1408 // List of possible combinations for three hits.
1409 constexpr int maxcomb = 4;
1410 constexpr std::array<int, maxcomb> layAcomb{1, 2, 3, 0};
1411 constexpr std::array<int, maxcomb> layBcomb{2, 3, 0, 1};
1412 constexpr std::array<int, maxcomb> layCcomb{3, 0, 1, 2};
1413
1414 ATH_MSG_VERBOSE("station " << station << " eta " << eta << " phi " << phi);
1415
1416 // Maximum number of hits per segment
1417 constexpr int maxhits = 3;
1419 fitclus.reserve(3);
1421
1422 // Loop over four possible combinations of clusters for three segments.
1423 for (int icomb = 0; icomb < maxcomb; icomb++) {
1424 // iterator over clusters
1425 ICscSegmentFinder::TrkClusters::const_iterator icl[maxhits];
1426 auto & pCluster1 = icl[0];
1427 auto & pCluster2 = icl[1];
1428 auto & pCluster3 = icl[2];
1429 // Select appropriate layer for first layer
1430 const ICscSegmentFinder::TrkClusters& clus1 = chclus[layAcomb[icomb]];
1431 for (pCluster1 = clus1.begin(); pCluster1 != clus1.end(); ++pCluster1) {
1432 // Select appropriate layer for second layer
1433 const ICscSegmentFinder::TrkClusters& clus2 = chclus[layBcomb[icomb]];
1434 for (pCluster2 = clus2.begin(); pCluster2 != clus2.end(); ++pCluster2) {
1435 // Select appropriate layer for third layer
1436 const ICscSegmentFinder::TrkClusters& clus3 = chclus[layCcomb[icomb]];
1437 for (pCluster3 = clus3.begin(); pCluster3 != clus3.end(); ++pCluster3) {
1438 // Use these three clusters as a segment.
1439 fitclus = {*pCluster1, *pCluster2, *pCluster3};
1440
1441 // Check if these hits are used by any other segments
1442 if (!unique_hits(fitclus, segs4hit)) {
1443 ATH_MSG_VERBOSE(" hits already used by other segments ");
1444 continue;
1445 }
1446 // Calculate chi2 for this segment.
1447 seg.s0 = lpos;
1448 seg.s1 = lslope;
1449 fit_segment(fitclus, lpos000, seg.s0, seg.s1, seg.d0, seg.d1, seg.d01, seg.chsq, seg.time, seg.dtime, seg.zshift, ctx);
1450
1451 // Count number of unspoiled clusters
1452 int nunspoil = 0;
1453 for (int i = 0; i < maxhits; i++) {
1454 seg.clus[i] = *(icl[i]);
1455 if (IsUnspoiled(seg.clus[i].cl->status())) ++nunspoil;
1456 }
1457
1458 seg.nunspoil = nunspoil;
1459 seg.outlierid = -1;
1460 seg.nclus = 3;
1461
1462 // Cut on chi2
1463 double local_max_chi = 0.;
1464 if (nunspoil > 2)
1465 local_max_chi = m_max_chisquare_loose;
1466 else
1467 local_max_chi = m_max_chisquare;
1468
1469 // tighten chi2 cut
1470 if (m_TightenChi2) local_max_chi = (2./3.) * m_max_chisquare ;
1471
1472 bool keep = true;
1473 if (seg.chsq > local_max_chi) keep = false;
1474
1475 ATH_MSG_VERBOSE(" nunspoil and local_max_chi " << nunspoil << " " << local_max_chi << " " << keep);
1476 ATH_MSG_DEBUG("find_2dseg3hit:: " << seg.time << " " << seg.dtime);
1477
1478 if (!keep) {
1479 // chi2 after outlier removal on 3 hit segments.
1480 double outlierRemoved_chsq;
1481 int ioutlierid = find_outlier_cluster(fitclus, lpos000, outlierRemoved_chsq, ctx);
1482 if (ioutlierid > -1 && outlierRemoved_chsq < m_max_chisquare_tight) {
1483 keep = true;
1484 seg.chsq = outlierRemoved_chsq;
1485 seg.outlierid = ioutlierid;
1486 ATH_MSG_DEBUG("find_2dseg3hit: keep outlier ");
1487 } else {
1488 ATH_MSG_DEBUG("find_2dseg3hit: reject segment bad chi2");
1489 }
1490 }
1491 // Add to segment list.
1492 if (keep) segs.push_back(seg);
1493
1494 ATH_MSG_VERBOSE(" Segment measphi? " << measphi << " chsq:" << seg.chsq << " abs(seg.s1) " << std::abs(seg.s1)
1495 << " keep? " << keep);
1496 }
1497 }
1498 }
1499 }
1500
1501 // Sort segments by nunspoil then chi-square.
1502 std::sort(segs.begin(), segs.end(), ICscSegmentFinder::sortByNunspoilAndChsq());
1503}
1504void CscSegmentUtilTool::find_2dseg2hit(bool measphi, int station, int eta, int phi, int layStat,
1505 const ICscSegmentFinder::ChamberTrkClusters& chclus, const Amg::Vector3D& lpos000,
1506 ICscSegmentFinder::Segments& segs, double lpos, double lslope, const EventContext& ctx) const {
1507 ATH_MSG_DEBUG("find_2dseg2hit called");
1508 // List of possible combinations for three hits.
1509
1510 ATH_MSG_VERBOSE("station " << station << " eta " << eta << " phi " << phi);
1511
1512 int lay0 = -1, lay1 = -1;
1513 for (int i = 0; i < 4; i++) {
1514 if ((layStat % (int)std::pow(10, i + 1)) / (int)std::pow(10, i) == 0) {
1515 if (lay0 == -1)
1516 lay0 = i;
1517 else if (lay1 == -1)
1518 lay1 = i;
1519 else {
1520 ATH_MSG_WARNING("can't do 2-layer segment finding, more than 2 layers marked as good");
1521 return;
1522 }
1523 }
1524 }
1525 if (lay0 == -1 || lay1 == -1) {
1526 ATH_MSG_WARNING("can't do 2-layer segment finding, fewer than 2 layers marked as good");
1527 return;
1528 }
1529 // Maximum number of hits per segment
1530 const int maxhits = 2;
1531
1532 // iterator over clusters
1533 ICscSegmentFinder::TrkClusters::const_iterator icl[maxhits] {};
1534
1535 // Select appropriate layer for first layer
1536 const ICscSegmentFinder::TrkClusters& clus1 = chclus[lay0];
1537 for (icl[0] = clus1.begin(); icl[0] != clus1.end(); ++icl[0]) {
1538 // Select appropriate layer for second layer
1539 const ICscSegmentFinder::TrkClusters& clus2 = chclus[lay1];
1540 for (icl[1] = clus2.begin(); icl[1] != clus2.end(); ++icl[1]) {
1541 // Use these two clusters as a segment.
1542 ATH_MSG_DEBUG("got 2 clusters for segment");
1543
1545 for (int i = 0; i < maxhits; i++) { fitclus.push_back(*(icl[i])); }
1546
1547 // Calculate chi2 for this segment.
1549 seg.s0 = lpos;
1550 seg.s1 = lslope;
1551 fit_segment(fitclus, lpos000, seg.s0, seg.s1, seg.d0, seg.d1, seg.d01, seg.chsq, seg.time, seg.dtime, seg.zshift, ctx);
1552
1553 // Count number of unspoiled clusters
1554 int nunspoil = 0;
1555 for (int i = 0; i < maxhits; i++) {
1556 seg.clus[i] = *(icl[i]);
1557 if (IsUnspoiled(seg.clus[i].cl->status())) ++nunspoil;
1558 }
1559 seg.nunspoil = nunspoil;
1560 seg.outlierid = -1;
1561 seg.nclus = 2;
1562
1563 // Cut on chi2
1564 double local_max_chi = 0.;
1565 if (nunspoil > 2)
1566 local_max_chi = m_max_chisquare_loose;
1567 else
1568 local_max_chi = m_max_chisquare;
1569 // tighten chi2 cut
1570 if (m_TightenChi2) local_max_chi = 1. * m_max_chisquare / 3.;
1571
1572 bool keep = true;
1573 if (seg.chsq > local_max_chi) keep = false;
1574 ATH_MSG_VERBOSE(" nunspoil, chi2, and local_max_chi " << nunspoil << " " << seg.chsq << " " << local_max_chi << " " << keep);
1575 ATH_MSG_DEBUG("find_2dseg2hit:: " << seg.time << " " << seg.dtime);
1576 // No outlier done on 3 hit segments.
1577
1578 ATH_MSG_VERBOSE(seg.s1 << " >< " << m_max_slope_r << " + " << seg.d1);
1579
1580 // Add to segment list.
1581 if (keep) {
1582 ATH_MSG_DEBUG("good segment found");
1583 segs.push_back(seg);
1584 } else
1585 ATH_MSG_DEBUG("bad segment, not keeping");
1586
1587 ATH_MSG_VERBOSE(" Segment measphi? " << measphi << " chsq:" << seg.chsq << " abs(seg.s1) " << std::abs(seg.s1)
1588 << " req eta:phi " << m_max_slope_r + seg.d1 << " : " << m_max_slope_phi + seg.d1
1589 << " keep? " << keep);
1590 }
1591 }
1592
1593 // Sort segments by nunspoil then chi-square.
1594 std::sort(segs.begin(), segs.end(), ICscSegmentFinder::sortByNunspoilAndChsq());
1595}
1596
1597void CscSegmentUtilTool::fit_detailCalcPart2(double q0, double q1, double q2, double q01, double q11, double q02, double& s0, double& s1,
1598 double& d0, double& d1, double& d01, double& chsq) const {
1599 ATH_MSG_VERBOSE(" q1 " << q1);
1600
1601 if (q2 * q0 - q1 * q1 == 0.0) {
1602 s0 = -999;
1603 s1 = -999;
1604 d0 = -99;
1605 d1 = -99;
1606 d01 = -99;
1607 chsq = 999;
1608 return;
1609 }
1610
1611 double r00 = q2 / (q2 * q0 - q1 * q1);
1612 double r01 = q1 / (q1 * q1 - q2 * q0);
1613 double r10 = q1 / (q1 * q1 - q0 * q2);
1614 double r11 = q0 / (q0 * q2 - q1 * q1);
1615 s0 = r01 * q11 + r00 * q01;
1616 s1 = r11 * q11 + r10 * q01;
1617 d0 = r01 * r01 * q2 + 2.0 * r00 * r01 * q1 + r00 * r00 * q0;
1618 if (d0 < 0)
1619 d0 = -1.0 * std::sqrt(-1.0 * d0);
1620 else
1621 d0 = std::sqrt(d0);
1622
1623 d1 = r11 * r11 * q2 + 2.0 * r10 * r11 * q1 + r10 * r10 * q0;
1624 if (d1 < 0)
1625 d1 = -1.0 * std::sqrt(-1.0 * d1);
1626 else
1627 d1 = std::sqrt(d1);
1628 d01 = r01 * r11 * q2 + (r01 * r10 + r00 * r11) * q1 + r00 * r10 * q0;
1629 chsq = q02 + s1 * s1 * q2 + 2 * s0 * s1 * q1 + s0 * s0 * q0 - 2 * s0 * q01 - 2 * s1 * q11;
1630
1631 ATH_MSG_VERBOSE(" details s0 = " << s0 << " " << d0 << " => " << r00);
1632 ATH_MSG_VERBOSE(" details s1 = " << s1 << " " << d1 << " " << d01 << " => " << r11 << " " << r10 << "chsq = " << chsq);
1633}
1634
1636 const EventContext& ctx) const {
1637 ATH_MSG_DEBUG("get4dMuonSegmentCombination called");
1638 const ICscSegmentFinder::SegmentVec& rsegs = *insegs->stationSegments(0);
1639 const ICscSegmentFinder::SegmentVec& phisegs = *insegs->stationSegments(1);
1640
1641 MuonSegmentCombination* pcol = nullptr;
1642
1643 ATH_MSG_DEBUG(" Combination has r/phi segments " << rsegs.size() << " / " << phisegs.size());
1644 ATH_MSG_DEBUG("chamber has " << insegs->getNGoodCscLayers(1) << " good eta layers and " << insegs->getNGoodCscLayers(0)
1645 << " good phi layers");
1646
1647 if ((rsegs.empty() && insegs->useStripsInSegment(1)) || (phisegs.empty() && insegs->useStripsInSegment(0))) {
1648 ATH_MSG_DEBUG(" Station does not have a r/phi segment, cannot make 4d segment ");
1649 return pcol;
1650 }
1651
1653
1654 std::unique_ptr<ICscSegmentFinder::SegmentVec> pnewsegs(new ICscSegmentFinder::SegmentVec);
1655 if (insegs->useStripsInSegment(1) && insegs->useStripsInSegment(0)) {
1656 for (ICscSegmentFinder::SegmentVec::const_iterator irsg = rsegs.begin(); irsg != rsegs.end(); ++irsg) {
1657 for (ICscSegmentFinder::SegmentVec::const_iterator ipsg = phisegs.begin(); ipsg != phisegs.end(); ++ipsg) {
1658 // If there are too many segments, we break from the inner loop.
1659 // There will be one additional message for each remaining entry in
1660 // the outer loop.
1661 if (pnewsegs->size() >= m_max_seg_per_chamber) {
1662 ATH_MSG_DEBUG("Too many segments: Discarding segments m_max_seg_per_chamber=" << m_max_seg_per_chamber);
1663 break;
1664 }
1665 const MuonSegment& rsg = **irsg;
1666 const MuonSegment& psg = **ipsg;
1667 const Trk::FitQuality& rfq = *rsg.fitQuality();
1668 ATH_MSG_DEBUG("got fit quality for r segment");
1669 const Trk::FitQuality& phifq = *psg.fitQuality();
1670 ATH_MSG_DEBUG("and phi segment");
1671 // Fit quality.
1672 double chsq = rfq.chiSquared() + phifq.chiSquared();
1673 ATH_MSG_DEBUG("total chi2=" << chsq);
1674 if (chsq > m_max_chisquare) {
1675 ATH_MSG_DEBUG("Segment rejected too large chsq: " << chsq);
1676 continue;
1677 }
1678 // ECC - require good x-y matching.
1679 // - a better way would be to calculate this value for all segments,
1680 // sort the segments (best to worst) and keep only the top N best ones.
1681 double xylike = matchLikelihood(rsg, psg);
1682 ATH_MSG_DEBUG("xy likelihood: " << xylike << " min: " << m_min_xylike);
1683 if (xylike < m_min_xylike) {
1684 ATH_MSG_DEBUG("Segment rejected too low likelihood: " << xylike);
1685 continue;
1686 }
1687 // if don't use phi, make segments from eta only; if don't use eta, make segments from phi only; else make segments from
1688 // both
1689 std::unique_ptr<MuonSegment> pseg(make_4dMuonSegment(rsg, psg, insegs->use2LayerSegments(1), insegs->use2LayerSegments(0)));
1690 if (pseg) {
1691 ATH_MSG_DEBUG("created new 4d segment");
1692 pnewsegs->push_back(std::move(pseg));
1693 }
1694 } // for phisegs
1695 } // for rsegs
1696 } else if (!insegs->useStripsInSegment(0)) {
1697 for (ICscSegmentFinder::SegmentVec::const_iterator irsg = rsegs.begin(); irsg != rsegs.end(); ++irsg) {
1698 const MuonSegment& rsg = **irsg;
1699 unsigned int nMinRIOs = 3;
1700 if (insegs->use2LayerSegments(1)) nMinRIOs = 2;
1701 if (rsg.numberOfContainedROTs() < nMinRIOs) {
1702 ATH_MSG_DEBUG("only " << rsg.numberOfContainedROTs()
1703 << ", RIO's, insufficient to build the 4d segment from a single eta segment");
1704 continue;
1705 }
1706 std::unique_ptr<MuonSegment> pseg(new MuonSegment(rsg));
1707 ATH_MSG_DEBUG("created new 4d segment from eta hits only");
1708 pnewsegs->push_back(std::move(pseg));
1709 }
1710 } else if (!insegs->useStripsInSegment(1)) {
1711 for (ICscSegmentFinder::SegmentVec::const_iterator ipsg = phisegs.begin(); ipsg != phisegs.end(); ++ipsg) {
1712 const MuonSegment& psg = **ipsg;
1713 unsigned int nMinRIOs = 3;
1714 if (insegs->use2LayerSegments(0)) nMinRIOs = 2;
1715 if (psg.numberOfContainedROTs() < nMinRIOs) {
1716 ATH_MSG_DEBUG("only " << psg.numberOfContainedROTs()
1717 << ", RIO's, insufficient to build the 4d segment from a single phi segment");
1718 continue;
1719 }
1720 std::unique_ptr<MuonSegment> pseg(new MuonSegment(psg));
1721 ATH_MSG_DEBUG("created new 4d segment from phi hits only");
1722 pnewsegs->push_back(std::move(pseg));
1723 }
1724 }
1725
1726 if (pnewsegs->empty()) {
1727 return pcol;
1728 } else
1729 ATH_MSG_DEBUG("created " << pnewsegs->size() << " new 4d segments");
1730
1731 pcol = new MuonSegmentCombination;
1732 pcol->addSegments(std::move(pnewsegs));
1733
1734 return pcol;
1735}
1736
1741 const Amg::Vector3D& lpos000, const EventContext& ctx) const {
1742 ATH_MSG_DEBUG(" get4dMuonSegmentCombination called ");
1743
1744 MuonSegmentCombination* Muon2dSegComb = get2dMuonSegmentCombination(eta_id, phi_id, eta_clus, phi_clus, lpos000, ctx);
1745
1746 MuonSegmentCombination* Muon4dSegComb = get4dMuonSegmentCombination(Muon2dSegComb, ctx);
1747
1748 delete Muon2dSegComb;
1749
1750 return Muon4dSegComb;
1751}
1752
1753/*************** PRIVATE FUNCTION *******************/
1755 bool use2LaySegsPhi) const {
1756 ATH_MSG_DEBUG("make_4dMuonSegment called");
1757
1758 double rpos = rsg.localParameters()[Trk::locX];
1759 double rdir = rsg.localDirection().angleXZ();
1760 double rtime = rsg.time();
1761 double rerrorTime = rsg.errorTime();
1762
1763 const Amg::MatrixX& rcov = rsg.localCovariance();
1764 const Trk::PlaneSurface& etasrf = rsg.associatedSurface();
1766 for (unsigned int irot = 0; irot < rsg.numberOfContainedROTs(); irot++) etarios.push_back(rsg.rioOnTrack(irot));
1767 const Trk::FitQuality& rfq = *rsg.fitQuality();
1768
1769 const Trk::FitQuality& phifq = *psg.fitQuality();
1770 double phipos = psg.localParameters()[Trk::locX];
1771 double phidir = psg.localDirection().angleXZ();
1772 const Amg::MatrixX& phicov = psg.localCovariance();
1773 const Trk::PlaneSurface& phisrf = psg.associatedSurface();
1775 for (unsigned int irot = 0; irot < psg.numberOfContainedROTs(); irot++) phirios.push_back(psg.rioOnTrack(irot));
1776
1777 // Fit quality.
1778 double chsq = rfq.chiSquared() + phifq.chiSquared();
1779
1780 Amg::MatrixX cov(4, 4);
1781 cov.setIdentity();
1782 // Local position and direction.
1783 Trk::LocalDirection pdir(phidir, rdir);
1784 // Error matrix.
1785 cov(0, 0) = phicov(0, 0);
1786 cov(2, 2) = phicov(2, 2);
1787 cov(0, 2) = phicov(0, 2);
1788 cov(2, 0) = cov(0, 2);
1789 cov(1, 1) = rcov(0, 0);
1790 cov(3, 3) = rcov(2, 2);
1791 cov(1, 3) = rcov(0, 2);
1792 cov(3, 1) = rcov(1, 3);
1793 ATH_MSG_VERBOSE("Error matrix is " << cov.cols() << "D");
1794 ATH_MSG_VERBOSE("( " << cov(0, 0) << " " << cov(0, 1) << " " << cov(0, 2) << " " << cov(0, 3));
1795 ATH_MSG_VERBOSE("( " << cov(1, 0) << " " << cov(1, 1) << " " << cov(1, 2) << " " << cov(1, 3));
1796 ATH_MSG_VERBOSE("( " << cov(2, 0) << " " << cov(2, 1) << " " << cov(2, 2) << " " << cov(2, 3));
1797 ATH_MSG_VERBOSE("( " << cov(3, 0) << " " << cov(3, 1) << " " << cov(3, 2) << " " << cov(3, 3));
1798
1799 // Surface -- for rotations use phi surface for positions use eta surface
1800
1801 Trk::SurfaceBounds* bnd = phisrf.bounds().clone();
1802 Trk::TrapezoidBounds* bnd_trap = dynamic_cast<Trk::TrapezoidBounds*>(bnd);
1803 Trk::RotatedTrapezoidBounds* bnd_rtrap = dynamic_cast<Trk::RotatedTrapezoidBounds*>(bnd);
1804 Amg::Vector3D glop = etasrf.transform().translation();
1805 Amg::Transform3D xf(phisrf.transform().rotation());
1806 xf.pretranslate(glop);
1807 Trk::PlaneSurface* psrf = nullptr;
1808 if (bnd_trap) {
1809 psrf = new Trk::PlaneSurface(xf, std::shared_ptr<Trk::TrapezoidBounds>(bnd_trap));
1810 } else if (bnd_rtrap) {
1811 psrf = new Trk::PlaneSurface(xf, std::shared_ptr<Trk::RotatedTrapezoidBounds>(bnd_rtrap));
1812 } else {
1813 ATH_MSG_WARNING(" no SurfaceBounds bounds for 4D segment found keep old bound ");
1814 psrf = new Trk::PlaneSurface(phisrf);
1815 }
1816
1817 Amg::Vector3D philpos(phipos, 0., 0.);
1818 Amg::Vector3D phigpos = phisrf.transform() * philpos;
1819
1820 Amg::Vector3D phietalpos = psrf->transform().inverse() * phigpos;
1821
1822 ATH_MSG_VERBOSE(" positions in NEW Eta frame for phi measurement x " << phietalpos.x() << " y " << phietalpos.y() << " z shift "
1823 << phietalpos.z() << " angleXZ " << phidir);
1824 double phiposNew = phietalpos.x() - phidir * phietalpos.z();
1825
1826 ATH_MSG_VERBOSE(" positions old z " << phipos << " New frame " << phietalpos.x() << " corrected " << phiposNew);
1827
1828 Amg::Vector2D pos(phiposNew, rpos);
1829
1830 // List of RIO's.
1831 auto rios = ICscSegmentFinder::MbaseList();
1832 // If each orientation has four RIOS's (as expected) then order the
1833 // RIO's eta1 phi1 eta2 .... to make fitting easier.
1834
1835 // ECC - allow for 3-hit segments.
1836 unsigned int nMinRIOsEta = 3, nMinRIOsPhi = 3;
1837 if (use2LaySegsEta) nMinRIOsEta = 2;
1838 if (use2LaySegsPhi) nMinRIOsPhi = 2;
1839 if (etarios.size() >= nMinRIOsEta && phirios.size() >= nMinRIOsPhi) {
1840 ATH_MSG_DEBUG("Using new RIO order.");
1841 ATH_MSG_DEBUG(" eta/phi segment sizes: " << etarios.size() << " " << phirios.size());
1842 // ECC - try to match eta and phi layers
1843 // for ( RioList::size_type irio=0; irio<4; ++irio ) {
1844 int maxeta = etarios.size();
1845 int maxphi = phirios.size();
1846
1847 // This is used to determine whether any hits are left unmatched.
1848 int eta_matchcode = 6;
1849 int phi_matchcode = 6;
1850 if (maxeta == 3) eta_matchcode = 3;
1851 if (maxphi == 3) phi_matchcode = 3;
1852 int eta_match = 0, phi_match = 0;
1853
1854 ATH_MSG_DEBUG("make_4dMuonSegment:: r/phi seg time " << rsg.time() << " " << psg.time());
1855 // Loop over all hits in eta and then in phi
1856 for (int ieta = 0; ieta < maxeta; ieta++) {
1857 for (int iphi = 0; iphi < maxphi; iphi++) {
1858 // Get RIO_OnTrack
1859 const Trk::RIO_OnTrack* etapold = etarios[ieta];
1860 const Trk::RIO_OnTrack* phipold = phirios[iphi];
1861 // ECC figure out wire layer.
1862 Identifier id_eta = etapold->identify();
1863 Identifier id_phi = phipold->identify();
1864 int iw_eta = m_idHelperSvc->cscIdHelper().wireLayer(id_eta);
1865 int iw_phi = m_idHelperSvc->cscIdHelper().wireLayer(id_phi);
1866
1867 // Check to see if these are the same layers.
1868 if (iw_eta != iw_phi) { continue; }
1869 ATH_MSG_DEBUG(" id_eta: " << m_idHelperSvc->toString(id_eta) << " "
1870 << " id_phi: " << m_idHelperSvc->toString(id_phi));
1871
1872 // get the reference surface of the eta hit
1873 const Trk::Surface& surf = etapold->associatedSurface();
1874
1875 // transform the global position of the phi hit into the reference frame of the eta hit
1876 std::optional<Amg::Vector2D> lpos = surf.globalToLocal(phipold->globalPosition());
1877
1878 // calculate the 2D space point
1879 if (!lpos) {
1880 Amg::Vector3D locPos = surf.transform().inverse() * phipold->globalPosition();
1881 Amg::Vector3D locPosS = surf.transform().inverse() * phipold->associatedSurface().center();
1882 Amg::Vector3D locNorm = surf.transform().inverse().linear() * phipold->associatedSurface().normal();
1883 Amg::Vector2D lpn(locPos.x(), locPos.y());
1884 ATH_MSG_WARNING("phipold->globalPosition() not on surface!"
1885 << std::endl
1886 << std::setprecision(9) << " etapos: r " << etapold->globalPosition().perp() << " z "
1887 << etapold->globalPosition().z() << " surfz " << surf.center().z() << std::endl
1888 << surf << std::endl
1889 << " phipos: r " << phipold->globalPosition().perp() << " z " << phipold->globalPosition().z()
1890 << " surfz " << phipold->associatedSurface().center().z() << std::endl
1891 << phipold->associatedSurface() << std::endl
1892 << " locpos " << locPos.x() << " " << locPos.y() << " " << locPos.z() << " locposS " << locPosS.x()
1893 << " " << locPosS.y() << " " << locPosS.z() << " inbounds " << surf.insideBounds(lpn) << " normals "
1894 << std::setprecision(9) << surf.normal().dot(phipold->associatedSurface().normal()) << " locN "
1895 << locNorm.x() << " " << locNorm.y() << " " << locNorm.z());
1896 continue;
1897 }
1898
1899 // Keep track of matched hits.
1900 phi_match++;
1901 eta_match++;
1902 eta_matchcode -= ieta;
1903 phi_matchcode -= iphi;
1904
1905 Amg::Vector2D lposnew(etapold->localParameters()[Trk::locX], (*lpos)[Trk::locY]);
1906
1907 // calculate the corresponding global position
1908 const Amg::Vector3D gposnew = surf.localToGlobal(lposnew);
1909 const Amg::Vector3D& gdirnew = rsg.globalDirection();
1910
1911 // create the new rots using the ROT creator
1912 const Trk::RIO_OnTrack* etaRot = m_rotCreator->createRIO_OnTrack(*etapold->prepRawData(), gposnew, gdirnew);
1913 rios.push_back(etaRot);
1914
1915 const Trk::RIO_OnTrack* phiRot = m_rotCreator->createRIO_OnTrack(*phipold->prepRawData(), gposnew);
1916 rios.push_back(phiRot);
1917
1918 // debug output, to be removed
1919 const Trk::Surface& surfPhi = phipold->associatedSurface();
1920 std::optional<Amg::Vector2D> lposEta = surf.globalToLocal(etaRot->globalPosition());
1921 std::optional<Amg::Vector2D> lposPhi = surfPhi.globalToLocal(phiRot->globalPosition());
1922 ATH_MSG_VERBOSE(" eta gp " << etapold->globalPosition() << " new " << etaRot->globalPosition() << " loc " << *lposEta);
1923 ATH_MSG_VERBOSE(" phi gp " << phipold->globalPosition() << " new " << phiRot->globalPosition() << " loc " << *lposPhi);
1924
1925 } // end loop over phi
1926 } // end loop over eta
1927
1928 // Handle unmatched hits here.
1929 int eta_single = maxeta - eta_match;
1930 int phi_single = maxphi - phi_match;
1931
1932 ATH_MSG_DEBUG(" eta_single, phi_single: " << eta_single << " " << phi_single << " eta_matchcode, phi_matchcode: " << eta_matchcode
1933 << " " << phi_matchcode);
1934
1935 // Add unmatched eta hit to the segment.
1936 if (maxeta > 2) { // only if there are at least 3 hits, if it's a 2-layer segment require both hits to be matched
1937 if (eta_single == 1) {
1938 if (eta_matchcode >= 0 && eta_matchcode < 4) {
1939 const Trk::RIO_OnTrack* pold = etarios[eta_matchcode];
1940 Trk::RIO_OnTrack* pnew = pold->clone();
1941 rios.push_back(pnew);
1942 }
1943 }
1944 // This should never happen
1945 else if (eta_single > 1) {
1946 ATH_MSG_WARNING("More than one unmatched eta hit: " << eta_single);
1947 }
1948 } else {
1949 if (eta_single != 0) {
1950 ATH_MSG_DEBUG("eta hit in a 2-layer segment not matched, bailing");
1951 delete psrf;
1952 return nullptr;
1953 }
1954 }
1955
1956 // Add unmatched phi hit to the segment.
1957 if (maxphi > 2) {
1958 if (phi_single == 1) {
1959 if (phi_matchcode >= 0 && phi_matchcode < 4) {
1960 const Trk::RIO_OnTrack* pold = phirios[phi_matchcode];
1961 Trk::RIO_OnTrack* pnew = pold->clone();
1962 rios.push_back(pnew);
1963 }
1964 }
1965 // This should never happen
1966 else if (phi_single > 1) {
1967 ATH_MSG_WARNING("More than one unmatched phi hit: " << phi_single);
1968 }
1969 } else {
1970 if (phi_single != 0) {
1971 ATH_MSG_DEBUG("phi hit in a 2-layer segment not matched, bailing");
1972 delete psrf;
1973 return nullptr;
1974 }
1975 }
1976 } else { // We should never get here!
1977 ATH_MSG_WARNING("Unexpected input RIO counts: " << etarios.size() << " " << phirios.size());
1978 for (ICscSegmentFinder::RioList::const_iterator irio = etarios.begin(); irio != etarios.end(); ++irio) {
1979 const Trk::RIO_OnTrack* pold = *irio;
1980 Trk::RIO_OnTrack* pnew = pold->clone();
1981 rios.push_back(pnew);
1982 }
1983 for (ICscSegmentFinder::RioList::const_iterator irio = phirios.begin(); irio != phirios.end(); ++irio) {
1984 const Trk::RIO_OnTrack* pold = *irio;
1985 Trk::RIO_OnTrack* pnew = pold->clone();
1986 rios.push_back(pnew);
1987 }
1988 }
1989
1990 unsigned int nMinRIOsTot = 5;
1991 if (use2LaySegsEta || use2LaySegsPhi) nMinRIOsTot = 4;
1992 if (rios.size() < nMinRIOsTot) {
1993 ATH_MSG_WARNING("too few CSC hits collected, not making segment: rios " << rios.size());
1994 delete psrf;
1995 return nullptr;
1996 }
1997 int ndof = rfq.numberDoF() + phifq.numberDoF();
1998 Trk::FitQuality* pfq = new Trk::FitQuality(chsq, ndof);
1999 // Build 4D segment.
2000
2001 ATH_MSG_DEBUG("Segment " << rios.size() << " : ");
2002 MuonSegment* pseg = new MuonSegment(pos,
2003 pdir,
2004 std::move(cov),
2005 psrf,
2006 std::move(rios),
2007 pfq,
2009 pseg->setT0Error(rtime, rerrorTime);
2010
2011 return pseg;
2012}
2013
2017 ICscSegmentFinder::Segments& phi_segs, const Amg::Vector3D& lpos000, const EventContext& ctx,
2018 int etaStat, int phiStat) const {
2019 if (!eta_id.is_valid() && !phi_id.is_valid()) {
2020 ATH_MSG_WARNING("in get2dSegments: got two invalid identifiers");
2021 return;
2022 }
2023 // check whether Id is valid
2024 Identifier chId = eta_id.is_valid() ? eta_id : phi_id;
2025 int col_station = m_idHelperSvc->cscIdHelper().stationName(chId) - 49;
2026 int col_eta = m_idHelperSvc->cscIdHelper().stationEta(chId);
2027 int col_phisec = m_idHelperSvc->cscIdHelper().stationPhi(chId);
2028
2029 ATH_MSG_DEBUG("get2dSegments called " << eta_id << " " << phi_id << " " << col_station << " " << col_eta << " " << col_phisec
2030 << " " << etaStat << " " << phiStat << " "
2031 << " Counts: " << eta_clus[0].size() << " " << eta_clus[1].size() << " " << eta_clus[2].size()
2032 << " " << eta_clus[3].size());
2033
2034 ICscSegmentFinder::Segments eta_segs3hit, phi_segs3hit;
2035
2036 double pos_eta = -999;
2037 double slope_eta = -999;
2038 double pos_phi = -999;
2039 double slope_phi = -999;
2040
2041 // Find 2D segments.
2042 find_2dsegments(false, col_station, col_eta, col_phisec, eta_clus, lpos000, eta_segs, pos_eta, slope_eta, ctx);
2043 find_2dsegments(true, col_station, col_eta, col_phisec, phi_clus, lpos000, phi_segs, pos_phi, slope_phi, ctx);
2044
2045 // Find 3-hit 2D segments.
2046 find_2dseg3hit(false, col_station, col_eta, col_phisec, eta_clus, lpos000, eta_segs3hit, eta_segs, pos_eta, slope_eta, ctx);
2047 find_2dseg3hit(true, col_station, col_eta, col_phisec, phi_clus, lpos000, phi_segs3hit, phi_segs, pos_phi, slope_phi, ctx);
2048
2049 // Add 3-hit segments to 4-hit segments.
2050 add_2dsegments(eta_segs, eta_segs3hit);
2051 add_2dsegments(phi_segs, phi_segs3hit);
2052
2053 int nGoodEta = 0, nGoodPhi = 0;
2054 for (int i = 0; i < 4; ++i) {
2055 if ((etaStat % (int)std::pow(10, i + 1)) / (int)std::pow(10, i) == 0) nGoodEta++;
2056 if ((phiStat % (int)std::pow(10, i + 1)) / (int)std::pow(10, i) == 0) nGoodPhi++;
2057 }
2058 if (nGoodEta == 2) {
2059 // Find 2-hit 2D segments for eta.
2060 ICscSegmentFinder::Segments eta_segs2hit;
2061
2062 ATH_MSG_VERBOSE(" start find_2dseg2hit eta ");
2063 find_2dseg2hit(false, col_station, col_eta, col_phisec, etaStat, eta_clus, lpos000, eta_segs2hit, pos_eta, slope_eta, ctx);
2064
2065 // store 2-hit segments
2066 ATH_MSG_VERBOSE(" store 2hit eta segments");
2067 add_2dseg2hits(eta_segs, eta_segs2hit, etaStat);
2068 }
2069 if (nGoodPhi == 2) {
2070 // Find 2-hit 2D segments for eta.
2071 ICscSegmentFinder::Segments phi_segs2hit;
2072 ATH_MSG_VERBOSE(" start find_2dseg2hit phi ");
2073 find_2dseg2hit(true, col_station, col_eta, col_phisec, phiStat, phi_clus, lpos000, phi_segs2hit, pos_phi, slope_phi, ctx);
2074 ATH_MSG_VERBOSE(" store 2hit phi segments");
2075 add_2dseg2hits(phi_segs, phi_segs2hit, phiStat);
2076 }
2077}
2078
2079//***********************************************************************
2080// By Elliott
2083 ICscSegmentFinder::Segments& segs) const { // segs => 4hitsegs...
2084
2085 int nclus = fitclus.size();
2086 ATH_MSG_VERBOSE(" unique_hits nclus " << nclus << " segs size " << segs.size());
2087 // Loop over segments
2088 ICscSegmentFinder::Segments::const_iterator iseg;
2089 for (iseg = segs.begin(); iseg != segs.end(); ++iseg) {
2090 int nhits_common = 0;
2091 // Loop over hits in the 4-hit segment
2092 for (int iclus = 0; iclus < iseg->nclus; iclus++) {
2093 // Loop over hits in fitclus
2094 ICscSegmentFinder::TrkClusters::const_iterator ihit;
2095 for (ihit = fitclus.begin(); ihit != fitclus.end(); ++ihit) {
2096 // Increment number of common hits if the ids are the same.
2097 const Muon::CscClusterOnTrack* cot = iseg->clus[iclus].cl;
2098 const Muon::CscClusterOnTrack* hit = ihit->cl;
2099 if (cot->identify() == hit->identify()) nhits_common++;
2100 }
2101 // if (nhits_common == nclus) return false;
2102 if (nhits_common == nclus || (nclus >= 2 && nhits_common > m_max_3hitseg_sharehit)) return false; // WP 4/5/10
2103 }
2104 }
2105 // If we get here, then the hits from the 3-hit segment are unique.
2106 return true;
2107}
2108
2110// if hit is in outlier, error is estimated in width/sqrt(12)
2112 const EventContext& ctx) const {
2113 // Getting CscPrepData
2114 for (int iclu = 0; iclu < seg.nclus; ++iclu) {
2115 const CscClusterOnTrack* pclu = seg.clus[iclu].cl;
2116
2117 if (pclu != nullptr) {
2118 // if this cluster is picked up as outlier cluster
2119 if (seg.outlierid == iclu) {
2120 Identifier id = pclu->identify();
2121
2122 // get prep raw data.
2123 const CscPrepData* prd = pclu->prepRawData();
2124 double err = getDefaultError(id, measphi, prd, ctx);
2125
2126 Amg::MatrixX cov(1, 1);
2127 cov(0, 0) = err * err;
2128
2129 // Create new calibrated hit with new error matrix.
2130 Amg::Vector2D lpos = prd->localPosition();
2131 Trk::DefinedParameter locPar(lpos.x(), Trk::locX);
2132 Trk::LocalParameters ppars(locPar);
2133
2134 Trk::RIO_OnTrack* pclu2 = new CscClusterOnTrack(prd, std::move(ppars), std::move(cov), 0.0, prd->status(), prd->timeStatus(), prd->time());
2135 prios->push_back(pclu2);
2136 }
2137 // Just put into list of RIO_OnTrack
2138 else {
2139 Trk::RIO_OnTrack* pclu2 = pclu->clone();
2140 prios->push_back(pclu2);
2141 }
2142 }
2143 }
2144}
2145
2147double CscSegmentUtilTool::getDefaultError(Identifier id, bool measphi, const CscPrepData* prd, const EventContext& ctx) const {
2148 const std::vector<Identifier>& strip_ids = prd->rdoList();
2149 unsigned int nstrip = strip_ids.size();
2151 const MuonGM::MuonDetectorManager* MuonDetMgr{*DetectorManagerHandle};
2152 if (MuonDetMgr == nullptr) {
2153 ATH_MSG_ERROR("Null pointer to the read MuonDetectorManager conditions object");
2154 return 0.;
2155 }
2156 const CscReadoutElement* pro = MuonDetMgr->getCscReadoutElement(id);
2157 double pitch = pro->cathodeReadoutPitch(0, measphi);
2158 // Assign position error.
2159 double wmeas = pitch * nstrip;
2160 double weff = wmeas - 20;
2161 double weffmin = 0.5 * wmeas;
2162 if (weff < weffmin) weff = weffmin;
2163 double err = weff / std::sqrt(12.0);
2164 return err;
2165}
2166
2167// Likelihood calculation for xy matching.
2169 // Loop over eta and phi segments.
2171 for (unsigned int irot = 0; irot < rsg.numberOfContainedROTs(); irot++) etarios.push_back(rsg.rioOnTrack(irot));
2173 for (unsigned int irot = 0; irot < psg.numberOfContainedROTs(); irot++) phirios.push_back(psg.rioOnTrack(irot)); // CHECK THIS
2174 int maxeta = etarios.size();
2175 int maxphi = phirios.size();
2176
2177 double prob_real = 1, prob_ghost = 1;
2178 bool match = false;
2179 for (int ieta = 0; ieta < maxeta; ieta++) {
2180 for (int iphi = 0; iphi < maxphi; iphi++) {
2181 const Trk::RIO_OnTrack* etapold = etarios[ieta];
2182 const Trk::RIO_OnTrack* phipold = phirios[iphi];
2183 double qratio;
2184
2185 const Muon::CscClusterOnTrack* eta_clu = dynamic_cast<const Muon::CscClusterOnTrack*>(etapold);
2186 if (!eta_clu) {
2187 ATH_MSG_DEBUG(" continuing because not a CSC eta cluster");
2188 continue;
2189 }
2190
2191 const Muon::CscClusterOnTrack* phi_clu = dynamic_cast<const Muon::CscClusterOnTrack*>(phipold);
2192 if (!phi_clu) {
2193 ATH_MSG_DEBUG(" continuing because not a CSC phi cluster");
2194 continue;
2195 }
2196
2197 // Get prep raw data
2198 const Muon::CscPrepData* eta_prd = eta_clu->prepRawData();
2199 const Muon::CscPrepData* phi_prd = phi_clu->prepRawData();
2200
2201 // Figure out the layer for each view
2202 Identifier eta_sid = eta_prd->identify();
2203 Identifier phi_sid = phi_prd->identify();
2204 int eta_wlay = m_idHelperSvc->cscIdHelper().wireLayer(eta_sid);
2205 int phi_wlay = m_idHelperSvc->cscIdHelper().wireLayer(phi_sid);
2206
2207 // Calculate the charge ratio for same eta & phi layers
2208 if (eta_wlay == phi_wlay) {
2209 // Get charge.
2210 double eta_chg = eta_prd->charge();
2211 double phi_chg = phi_prd->charge();
2212
2213 if (eta_chg > 0 && phi_chg > 0) {
2214 qratio = eta_chg / phi_chg;
2215 prob_real *= pdf_sig(qratio);
2216 prob_ghost *= pdf_bkg(qratio);
2217 match = true;
2218 }
2219 } // if (eta_wlay)
2220 } // Loop over phi hits
2221 } // Loop over eta hits
2222
2223 // Determine likelihood
2224 double like = qratio_like(prob_real, prob_ghost);
2225 if (m_allEtaPhiMatches) {
2226 if (match) ATH_MSG_VERBOSE(" MATCH allEtaPhiMatches " << like);
2227 if (!match) ATH_MSG_VERBOSE(" NO MATCH allEtaPhiMatches " << like);
2228 if (match) return 0.5;
2229 if (!match) return 0.;
2230 }
2231 return like;
2232}
2233
2234// Function to return pdf value for signal distribution in xy matching.
2235double CscSegmentUtilTool::pdf_sig(const double x) {
2236 double f1, f2;
2237 double par[6] = {1.25049, 1.02934, 0.0517436, 0.0229711, 0.900799, 0.374422};
2238
2239 // Overflow bin.
2240 if (x > 10) return 0.015619;
2241
2242 // Landau
2243 f1 = par[0] * TMath::Landau(x, par[1], par[2]);
2244
2245 // gaussian
2246 f2 = par[3] * TMath::Gaus(x, par[4], par[5]);
2247
2248 // function is the sum of a landau plus gaussian distribution.
2249 return f1 + f2;
2250}
2251
2252// function to return pdf value for background distribution.
2253double CscSegmentUtilTool::pdf_bkg(const double x) {
2254 double e1, e2;
2255 double par[8] = {0.0394188, 0.0486057, 0.0869231, 1.16153, -0.109998, 0.009729, 0.36183, 0.228344};
2256
2257 // Overflow bin
2258 if (x > 10) return 0.0895146;
2259
2260 // Treat values below 0.2 as flat bins.
2261 if (x < 0.1)
2262 e1 = par[0];
2263 else if (x < 0.2)
2264 e1 = par[1];
2265 else
2266 e1 = par[2] * exp(-1 * par[3] * (x - par[4]));
2267
2268 // 2nd exponential
2269 e2 = par[5] * exp(-1 * par[6] * (x - par[7]));
2270
2271 // value is the sum of two functions.
2272 return e1 + e2;
2273}
2274
2275// likelihood function for charge ratio
2276double CscSegmentUtilTool::qratio_like(const double pdf_sig, const double pdf_bkg) {
2277 double like = 0;
2278
2279 // return zero if both probability distribution functions are zero.
2280 if (pdf_sig != 0 && pdf_bkg != 0) like = pdf_sig / (pdf_sig + pdf_bkg);
2281
2282 return like;
2283}
2284
2285bool CscSegmentUtilTool::isGood(const uint32_t stripHashId, const EventContext& ctx) const {
2286 unsigned int status = stripStatusBit(stripHashId, ctx);
2287 bool is_good = !((status & 0x1) || ((status >> 1) & 0x1)); // test for hot/dead channel
2288 return is_good;
2289}
2290
2291int CscSegmentUtilTool::stripStatusBit(const uint32_t stripHashId, const EventContext& ctx) const {
2293 const CscCondDbData* readCdo{*readHandle};
2294
2295 int status = 0;
2296 if (!readCdo->readChannelStatus(stripHashId, status).isSuccess())
2297 ATH_MSG_WARNING(" failed to access CSC conditions database - status - "
2298 << "strip hash id = " << stripHashId);
2299 return status;
2300}
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
bool IsUnspoiled(Muon::CscClusterStatus status)
MuonSegment_v1 MuonSegment
Reference the current persistent version:
std::pair< std::vector< unsigned int >, bool > res
static Double_t rs
static Double_t s0
#define y
#define x
static const Attributes_t empty
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
bool msgLvl(const MSG::Level lvl) const
StatusCode readChannelStatus(IdentifierHash, int &) const
static double pdf_bkg(const double x)
void fit_segment(const ICscSegmentFinder::TrkClusters &clus, const Amg::Vector3D &lpos000, double &s0, double &s1, double &d0, double &d1, double &d01, double &chsq, double &time, double &dtime, double &zshift, const EventContext &ctx, int outlierLayer=-1) const
virtual StatusCode initialize()
bool unique_hits(ICscSegmentFinder::TrkClusters &fitclus, ICscSegmentFinder::Segments &segs) const
Method for checking whether three hit segments are already part of 4 hit segments.
Gaudi::Property< double > m_max_slope_r
Gaudi::Property< bool > m_IPconstraint
void add_2dseg2hits(ICscSegmentFinder::Segments &segs, ICscSegmentFinder::Segments &segs2, int layStat) const
void fit_detailCalcPart2(double q0, double q1, double q2, double q01, double q11, double q02, double &s0, double &s1, double &d0, double &d1, double &d01, double &chsq) const
static double qratio_like(const double pdf_sig, const double pdf_bkg)
SG::ReadCondHandleKey< CscCondDbData > m_readKey
SG::ReadHandleKey< xAOD::EventInfo > m_eventInfo
Gaudi::Property< double > m_max_slope_phi
Gaudi::Property< double > m_max_chisquare
std::unique_ptr< std::vector< std::unique_ptr< Muon::MuonSegment > > > getMuonSegments(Identifier eta_id, Identifier phi_id, ICscSegmentFinder::ChamberTrkClusters &eta_clus, ICscSegmentFinder::ChamberTrkClusters &phi_clus, const Amg::Vector3D &lpos000, const EventContext &ctx) const
double getDefaultError(Identifier id, bool measphi, const Muon::CscPrepData *prd, const EventContext &ctx) const
Gaudi::Property< double > m_max_chisquare_tight
Gaudi::Property< int > m_nunspoil
void fit_residual(const ICscSegmentFinder::TrkClusters &clus, const Amg::Vector3D &lpos000, unsigned int irclu, double &res, double &dres, const EventContext &ctx) const
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
Gaudi::Property< bool > m_remove3Overlap
Muon::MuonSegment * build_segment(const ICscSegmentFinder::Segment &seg, bool measphi, Identifier chid, bool use2Lay, const EventContext &ctx) const
double matchLikelihood(const Muon::MuonSegment &rsg, const Muon::MuonSegment &psg) const
void find_2dseg3hit(bool measphi, int station, int eta, int phi, const ICscSegmentFinder::ChamberTrkClusters &clus, const Amg::Vector3D &lpos000, ICscSegmentFinder::Segments &segs, ICscSegmentFinder::Segments &segs4hit, double localPos, double localSlope, const EventContext &ctx) const
void find_2dsegments(bool measphi, int station, int eta, int phi, const ICscSegmentFinder::ChamberTrkClusters &clus, const Amg::Vector3D &lpos000, ICscSegmentFinder::Segments &segs, double localPos, double localSlope, const EventContext &ctx) const
void get2dSegments(Identifier eta_id, Identifier phi_id, ICscSegmentFinder::ChamberTrkClusters &eta_clus, ICscSegmentFinder::ChamberTrkClusters &phi_clus, ICscSegmentFinder::Segments &etasegs, ICscSegmentFinder::Segments &phisegs, const Amg::Vector3D &lpos000, const EventContext &ctx, int etaStat=0, int phiStat=0) const
void fit_rio_residual(const Trk::PlaneSurface &ssrf, bool dump, const ICscSegmentFinder::RioList &clus, unsigned int irclu, double &res, double &dres, double &rs, double &drs) const
Gaudi::Property< bool > m_remove4Overlap
void fit_rio_segment(const Trk::PlaneSurface &ssrf, bool dump, const ICscSegmentFinder::RioList &clus, double &s0, double &s1, double &d0, double &d1, double &d01, double &chsq, double &zshift) const
Gaudi::Property< double > m_IPerror
int stripStatusBit(const uint32_t stripHashId, const EventContext &ctx) const
void spoiled_count(const ICscSegmentFinder::RioList &rios, double threshold, int &nspoil, int &nunspoil)
ToolHandle< Muon::ICscClusterOnTrackCreator > m_rotCreator
void getRios(const ICscSegmentFinder::Segment &seg, ICscSegmentFinder::MbaseList *prios, bool measphi, const EventContext &ctx) const
bool isGood(const uint32_t stripHashId, const EventContext &ctx) const
Gaudi::Property< bool > m_x5data
Gaudi::Property< double > m_fitsegment_tantheta_tolerance
Muon::MuonSegmentCombination * get4dMuonSegmentCombination(Identifier eta_id, Identifier phi_id, ICscSegmentFinder::ChamberTrkClusters &eta_clus, ICscSegmentFinder::ChamberTrkClusters &phi_clus, const Amg::Vector3D &lpos000, const EventContext &ctx) const
Gaudi::Property< bool > m_allEtaPhiMatches
Gaudi::Property< double > m_min_xylike
Gaudi::Property< double > m_max_chisquare_loose
static double pdf_sig(const double x)
void add_2dsegments(ICscSegmentFinder::Segments &segs4, ICscSegmentFinder::Segments &segs3) const
Adds 3-hit segments to 4-hit segments.
Gaudi::Property< bool > m_zshift
Gaudi::Property< bool > m_TightenChi2
Gaudi::Property< unsigned int > m_max_seg_per_chamber
Gaudi::Property< float > m_cluster_error_scaler
void find_2dseg2hit(bool measphi, int station, int eta, int phi, int layStat, const ICscSegmentFinder::ChamberTrkClusters &clus, const Amg::Vector3D &lpos000, ICscSegmentFinder::Segments &segs, double localPos, double localSlope, const EventContext &ctx) const
Muon::MuonSegment * make_4dMuonSegment(const Muon::MuonSegment &rsg, const Muon::MuonSegment &psg, bool use2LaySegsEta, bool use2LaySegsPhi) const
CscSegmentUtilTool(const std::string &type, const std::string &name, const IInterface *parent)
Muon::MuonSegmentCombination * get2dMuonSegmentCombination(Identifier eta_id, Identifier phi_id, ICscSegmentFinder::ChamberTrkClusters &eta_clus, ICscSegmentFinder::ChamberTrkClusters &phi_clus, const Amg::Vector3D &lpos000, const EventContext &ctx, int etaStat=0, int phiStat=0) const
SG::ReadCondHandleKey< MuonGM::MuonDetectorManager > m_DetectorManagerKey
void fit_detailCalcPart1(const ICscSegmentFinder::TrkClusters &clus, const Amg::Vector3D &lpos000, double &s0, double &s1, double &d0, double &d1, double &d01, double &chsq, bool &measphi, double &time, double &dtime, double &zshift, bool IsSlopeGive, int outlierHitLayer, const EventContext &ctx) const
Gaudi::Property< int > m_max_3hitseg_sharehit
int find_outlier_cluster(const ICscSegmentFinder::TrkClusters &clus, const Amg::Vector3D &lpos000, double &returned_chsq, const EventContext &ctx) const
value_type push_back(value_type pElem)
Add an element to the end of the collection.
ICscStripFitter::Result StripFit
Muon::MuonSegmentCombination::SegmentVec SegmentVec
DataVector< const Trk::MeasurementBase > MbaseList
std::vector< Cluster > ChamberTrkClusters[4]
std::vector< Segment > Segments
std::vector< const Trk::RIO_OnTrack * > RioList
std::vector< Cluster > TrkClusters
bool is_valid() const
Check if id is in a valid state.
double cathodeReadoutPitch(int chLayer, int measuresPhi) const
virtual const Trk::SurfaceBounds & bounds() const override
Return the boundaries of the element.
virtual const Amg::Transform3D & transform() const override
Return local to global transform.
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
const CscReadoutElement * getCscReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
std::vector< std::unique_ptr< MuonSegment > > SegmentVec
Class to represent the calibrated clusters created from CSC strips.
virtual CscClusterOnTrack * clone() const override final
Clone this ROT.
float time() const
Return the time(ns)
virtual const CscPrepData * prepRawData() const override final
Returns the CscPrepData - is a CscPrepData in this scope.
Class representing clusters from the CSC.
Definition CscPrepData.h:39
CscTimeStatus timeStatus() const
Returns the Csc time status flag.
double time() const
Returns the time.
int charge() const
Returns the charge.
CscClusterStatus status() const
Returns the Csc status (position measurement) flag.
virtual const Amg::Vector3D & globalPosition() const override
Returns global position.
Class to hold a set of MuonSegments belonging together.
SegmentVec * stationSegments(unsigned int index) const
Access to segments in a given station.
bool use2LayerSegments(int isEta) const
void setNGoodCscLayers(int nEta, int nPhi)
bool addSegments(std::unique_ptr< SegmentVec >)
Add a set of Segments for a give station.
bool useStripsInSegment(int isEta) const
This is the common class for 3D segments used in the muon spectrometer.
const Trk::RIO_OnTrack * rioOnTrack(unsigned int) const
returns the RIO_OnTrack (also known as ROT) objects depending on the integer
virtual MuonSegment * clone() const override final
needed to avoid excessive RTTI
void setT0Error(float t0, float t0Error)
set the fitted time and error on the time
virtual const Amg::Vector3D & globalPosition() const override final
global position
virtual const Trk::PlaneSurface & associatedSurface() const override final
returns the surface for the local to global transformation
Class to represent and store fit qualities from track reconstruction in terms of and number of degre...
Definition FitQuality.h:97
int numberDoF() const
returns the number of degrees of freedom of the overall track or vertex fit as integer
Definition FitQuality.h:60
double chiSquared() const
returns the of the overall track fit
Definition FitQuality.h:56
represents the three-dimensional global direction with respect to a planar surface frame.
double angleXZ() const
access method for angle of local XZ projection
const LocalParameters & localParameters() const
Interface method to get the LocalParameters.
const Amg::MatrixX & localCovariance() const
Interface method to get the localError.
Class for a planaer rectangular or trapezoidal surface in the ATLAS detector.
virtual PlaneSurface * clone() const override
Virtual constructor.
virtual const SurfaceBounds & bounds() const override final
This method returns the bounds by reference, static NoBounds in case of no boundaries.
const Amg::Vector2D & localPosition() const
return the local position reference
Identifier identify() const
return the identifier
const std::vector< Identifier > & rdoList() const
return the List of rdo identifiers (pointers)
Class to handle RIO On Tracks ROT) for InDet and Muons, it inherits from the common MeasurementBase.
Definition RIO_OnTrack.h:70
virtual RIO_OnTrack * clone() const override=0
Pseudo-constructor, needed to avoid excessive RTTI.
virtual const Surface & associatedSurface() const override=0
returns the surface for the local to global transformation
virtual const Trk::PrepRawData * prepRawData() const =0
returns the PrepRawData (also known as RIO) object to which this RIO_OnTrack is associated.
Identifier identify() const
return the identifier -extends MeasurementBase
virtual const Amg::Vector3D & globalPosition() const override=0
Interface method to get the global Position.
Bounds for a rotated trapezoidal, planar Surface.
const FitQuality * fitQuality() const
return the FitQuality object, returns NULL if no FitQuality is defined
float errorTime() const
access to the error on the measured time
float time() const
access to the measured time
Abstract base class for surface bounds to be specified.
virtual SurfaceBounds * clone() const =0
clone() method to make deep copy in Surface copy constructor and for assigment operator of the Surfac...
Abstract Base Class for tracking surfaces.
virtual bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const =0
Specified by each surface type: GlobalToLocal method without dynamic memory allocation - boolean chec...
virtual bool insideBounds(const Amg::Vector2D &locpos, double tol1=0., double tol2=0.) const =0
virtual methods to be overwritten by the inherited surfaces
virtual const Amg::Vector3D & normal() const
Returns the normal vector of the Surface (i.e.
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
const Amg::Vector3D & center() const
Returns the center position of the Surface.
virtual void localToGlobal(const Amg::Vector2D &locp, const Amg::Vector3D &mom, Amg::Vector3D &glob) const =0
Specified by each surface type: LocalToGlobal method without dynamic memory allocation.
Bounds for a trapezoidal, planar Surface.
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition hcg.cxx:357
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
double error(const Amg::MatrixX &mat, int index)
return diagonal error of the matrix caller should ensure the matrix is symmetric and the index is in ...
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
CscClusterStatus
Enum to represent the cluster status - see the specific enum values for more details.
@ CscStatusUnspoiled
Clean cluster with precision fit.
@ CscStatusSplitUnspoiled
Clean cluster with precision fit after split cluster.
@ CscTimeSuccess
Time measurement is successful to use.
@ CscTimeEarly
Not successful time measurement but samples indicates early time below -50ns in RAW time.
@ CscTimeLate
Not successful time measurement but samples indicates late time above 200ns in RAW time.
ParamDefs
This file defines the parameter enums in the Trk namespace.
Definition ParamDefs.h:32
@ locY
local cartesian
Definition ParamDefs.h:38
@ locX
Definition ParamDefs.h:37
@ theta
Definition ParamDefs.h:66
@ loc2
generic first and second local coordinate
Definition ParamDefs.h:35
@ phi
Definition ParamDefs.h:75
@ loc1
Definition ParamDefs.h:34
std::pair< double, ParamDefs > DefinedParameter
Typedef to of a std::pair<double, ParamDefs> to identify a passed-through double as a specific type o...
str station_name
Simple script to generate a BIS78 cabling map as used for the Monte Carlo processing.
-event-from-file
status
Definition merge.py:16
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.