ATLAS Offline Software
Loading...
Searching...
No Matches
QratCscClusterFitter.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <iomanip>
8#include <sstream>
9
19
24
27using Results = std::vector<Result>;
28
31
32namespace {
33 std::string splane(CscPlane plane) {
34 switch (plane) {
35 case CSS_ETA: return "CSS eta";
36 case CSL_ETA: return "CSL eta";
37 case CSS_PHI: return "CSS phi";
38 case CSL_PHI: return "CSL phi";
39 case UNKNOWN_PLANE: return "no such plane";
40 }
41 return "no such plane";
42 }
43
44 CscPlane findPlane(int station, bool measphi) {
45 if (station == 1) {
46 if (measphi)
47 return CSS_PHI;
48 else
49 return CSS_ETA;
50 } else if (station == 2) {
51 if (measphi)
52 return CSL_PHI;
53 else
54 return CSL_ETA;
55 }
56 return UNKNOWN_PLANE;
57 }
58} // namespace
59
60//******************************************************************************
61
62int qrat_correction(CscPlane plane, double qrat, double& cor, double& dcordqrat) {
63 std::vector<double> pfac;
64 if (plane == CSS_ETA) {
65 if (qrat < 0.095) return 1;
66 if (qrat > 1.01) return 1;
67 if (qrat < 0.15) {
68 pfac.push_back(-5.483);
69 pfac.push_back(130.6);
70 pfac.push_back(-1296.);
71 pfac.push_back(5994.);
72 pfac.push_back(-10580.);
73 } else if (qrat < 0.30) {
74 pfac.push_back(-0.9225);
75 pfac.push_back(5.569);
76 pfac.push_back(2.908);
77 pfac.push_back(-66.19);
78 pfac.push_back(108.5);
79 } else {
80 pfac.push_back(-0.4246);
81 pfac.push_back(2.619);
82 pfac.push_back(-3.642);
83 pfac.push_back(2.837);
84 pfac.push_back(-0.8916);
85 }
86 } else if (plane == CSL_ETA) {
87 if (qrat < 0.105) return 1;
88 if (qrat > 1.01) return 1;
89 if (qrat < 0.25) {
90 pfac.push_back(-2.823);
91 pfac.push_back(42.71);
92 pfac.push_back(-279.1);
93 pfac.push_back(879.2);
94 pfac.push_back(-1062.);
95 } else {
96 pfac.push_back(-0.5409);
97 pfac.push_back(3.110);
98 pfac.push_back(-4.630);
99 pfac.push_back(3.800);
100 pfac.push_back(-1.241);
101 }
102 } else {
103 return 3;
104 }
105 cor = 0.0;
106 dcordqrat = 0.0;
107 double term = 1.0;
108 for (unsigned int ipow = 0; ipow < pfac.size(); ++ipow) {
109 dcordqrat += ipow * pfac[ipow] * term;
110 if (ipow) term *= qrat;
111 cor += pfac[ipow] * term;
112 }
113 return 0;
114}
115
116//******************************************************************************
117
118// Calculate QRAT correction by interpolation.
119// Input array runs from 0.0 to 1.0.
120// Output is shifted by 0.5.
121// The value in each bin corresponds to upper edge of the bin.
122// qrmin = min value of the qrat distribution
123// corvals = array of corrections
124// qrat = input value of qrat
125// cor = output correction
126// dcordqrat = derivative of cor w.r.t. qrat
127
128int qrat_interpolation(double qrmin, const std::vector<double>& corvals, double qrat, double& cor, double& dcordqrat) {
129 int nbin = corvals.size();
130 if (!nbin) return 1;
131 // Treat any QRAT below the minimum as if it were at the minumum.
132 if (qrat < qrmin) qrat = qrmin;
133 // Find the bin holding dqrat.
134 double dqrat = 1.0 / nbin;
135 int bin = int(qrat / dqrat);
136 // Extract the value for this bin (x1) and the preceding (x0)
137 // and the following (x2).
138 double x1 = corvals[bin];
139 if (x1 == 0.0) return 2;
140 double x0 = bin == 0 ? 0.0 : corvals[bin - 1];
141 double x2 = bin == nbin - 1 ? 1.0 : corvals[bin + 1];
142 // Assign the qrat values for these bins. If this is the first
143 // bin with data, then use the input qrmin.
144 double qrat0 = dqrat * bin;
145 double qrat1 = qrat0 + dqrat;
146
147 if (x0 == 0.0) {
148 if (qrmin > qrat0 && qrmin < qrat1) { qrat0 = qrmin; }
149 }
150 // Calculate correction and derivative.
151 // Use quadratic interpolation with the high edge of this bin,
152 // the preceding and the following. For the last bin, use linear
153 // interpolation.
154 if (bin == nbin - 1) {
155 double a = x0;
156 double b = (x1 - x0) / dqrat;
157 cor = a + b * (qrat - qrat0);
158 dcordqrat = b;
159 } else {
160 double d0 = qrat1 - qrat0;
161 double d = dqrat;
162 double w = 1.0 / (d0 * d * d + d0 * d0 * d);
163 double a = x1;
164 double b = w * d * d * (x1 - x0) + w * d0 * d0 * (x2 - x1);
165 double c = w * d0 * (x2 - x1) - w * d * (x1 - x0);
166 cor = a + b * (qrat - qrat1) + c * (qrat - qrat1) * (qrat - qrat1);
167 dcordqrat = b + 2.0 * c * (qrat - qrat1);
168 }
169 if (cor < 0.0) cor = 0.0;
170 // Shift correction to center of bin.
171 cor -= 0.50;
172 return 0;
173}
174
175//****************************************************************************
176
194int qrat_atanh(const double a, const double b, double c, const double x0, double qrat, double& cor, double& dcordqrat) {
195 if (qrat <= 0) return 1; // avoid trouble in error calculation
196 // minimum qrat value (at pos=-1) or use pos = -0.5?
197 double qrmin = a + b * tanh(c * (-1 - x0));
198
199 // Treat any QRAT below the minimum as if it were at the minumum.
200 if (qrat < qrmin) qrat = qrmin;
201 double z = (qrat - a) / b;
202 cor = atanh(z) / c + x0;
203 dcordqrat = 1.0 / (1.0 - z * z) / b / c;
204
205 return 0;
206}
207
208//****************************************************************************
209
210QratCscClusterFitter::QratCscClusterFitter(const std::string& type, const std::string& aname, const IInterface* parent) :
211 AthAlgTool(type, aname, parent) {
212 declareInterface<ICscClusterFitter>(this);
213 m_max_width.push_back(5); // CSS eta
214 m_max_width.push_back(5); // CSL eta
215 m_max_width.push_back(3); // CSS phi
216 m_max_width.push_back(2); // CSL phi
217 declareProperty("max_width", m_max_width); // Maximum width (strips) for unspoiled clusters
218 declareProperty("position_option_eta", m_posopt_eta = "ATANH");
219 declareProperty("position_option_phi", m_posopt_phi = "NONE");
220 declareProperty("error_option_eta", m_erropt_eta = "CHARGE");
221 declareProperty("error_option_phi", m_erropt_phi = "NONE");
222 declareProperty("error_eta", m_error_eta = 0.050); // in mm this is for fixed error
223 declareProperty("error_phi", m_error_phi = 0.140); // in mm this is for fixed error
224
225 declareProperty("precisionErrorScaler", m_precisionErrorScaler = 1.0); // in mm this is for fixed error
226
227 declareProperty("qrat_maxdiff", m_qrat_maxdiff = 0.15); // in strips
228 declareProperty("qrat_maxsig", m_qrat_maxsig = 6.0); // in strips
229 declareProperty("error_tantheta", m_error_tantheta = 0.57); // in mm
230 declareProperty("xtan_css_eta_offset", m_xtan_css_eta_offset = 0.0015); // in mm
231 declareProperty("xtan_css_eta_slope", m_xtan_css_eta_slope = 0.000137); // in mm
232 declareProperty("xtan_csl_eta_offset", m_xtan_csl_eta_offset = -0.0045); // in mm
233 declareProperty("xtan_csl_eta_slope", m_xtan_csl_eta_slope = 0.000131); // in mm
234 declareProperty("qratmin_css_eta", m_qratmin_css_eta = 0.0940459);
235 declareProperty("qratmin_csl_eta", m_qratmin_csl_eta = 0.108975);
236 declareProperty("qratcor_css_eta", m_qratcor_css_eta); // in strips
237 declareProperty("qratcor_csl_eta", m_qratcor_csl_eta); // in strips
238
239 declareProperty("atanh_a_css_eta", m_atanh_a_css_eta = 1.5);
240 declareProperty("atanh_b_css_eta", m_atanh_b_css_eta = 1.411);
241 declareProperty("atanh_c_css_eta", m_atanh_c_css_eta = 2.329);
242 declareProperty("atanh_x0_css_eta", m_atanh_x0_css_eta = 0.6601);
243 declareProperty("atanh_a_csl_eta", m_atanh_a_csl_eta = 1.516);
244 declareProperty("atanh_b_csl_eta", m_atanh_b_csl_eta = 1.427);
245 declareProperty("atanh_c_csl_eta", m_atanh_c_csl_eta = 2.35);
246 declareProperty("atanh_x0_csl_eta", m_atanh_x0_csl_eta = 0.6615);
247
248 declareProperty("dposmin", m_dposmin = 0.082);
249}
250
251//**********************************************************************
252
254 ATH_MSG_VERBOSE("Initalizing " << name());
255
256 // retrieve MuonDetectorManager from the conditions store
257 ATH_CHECK(m_DetectorManagerKey.initialize());
258
259 ATH_CHECK(m_idHelperSvc.retrieve());
260
261 if (m_alignmentTool.retrieve().isFailure()) {
262 ATH_MSG_WARNING(name() << ": unable to retrieve cluster fitter " << m_alignmentTool);
263 } else {
264 ATH_MSG_DEBUG(name() << ": retrieved " << m_alignmentTool);
265 }
266
267 ATH_MSG_DEBUG("Properties for " << name() << ":");
268 ATH_MSG_DEBUG(" Eta position option: " << m_posopt_eta);
269 ATH_MSG_DEBUG(" Phi position option: " << m_posopt_phi);
270 ATH_MSG_DEBUG(" Eta error option: " << m_erropt_eta);
271 ATH_MSG_DEBUG(" Phi error option: " << m_erropt_phi);
272 ATH_MSG_DEBUG(" Eta assigned error: " << m_error_eta);
273 ATH_MSG_DEBUG(" Phi assigned error: " << m_error_phi);
274 ATH_MSG_DEBUG(" Max strip pos diff: " << m_qrat_maxdiff);
275 ATH_MSG_DEBUG(" Max strip pos sig: " << m_qrat_maxsig);
276 ATH_MSG_DEBUG(" Non-normal error coeff: " << m_error_tantheta);
277 ATH_MSG_DEBUG(" CSS eta pos-slope offset: " << m_xtan_css_eta_offset);
278 ATH_MSG_DEBUG(" CSS eta pos-slope slope: " << m_xtan_css_eta_slope);
279 ATH_MSG_DEBUG(" CSL eta pos-slope offset: " << m_xtan_csl_eta_offset);
280 ATH_MSG_DEBUG(" CSL eta pos-slope slope: " << m_xtan_csl_eta_slope);
281 ATH_MSG_DEBUG(" CSS eta table offset: " << m_qratmin_css_eta);
282 ATH_MSG_DEBUG(" CSL eta table offset: " << m_qratmin_csl_eta);
283 ATH_MSG_DEBUG(" CSS eta table size: " << m_qratcor_css_eta.size());
284 ATH_MSG_DEBUG(" CSL eta table size: " << m_qratcor_csl_eta.size());
285
286 ATH_MSG_DEBUG("atanh_a_css_eta: " << m_atanh_a_css_eta);
287 ATH_MSG_DEBUG("atanh_b_css_eta: " << m_atanh_b_css_eta);
288 ATH_MSG_DEBUG("atanh_c_css_eta: " << m_atanh_c_css_eta);
289 ATH_MSG_DEBUG("atanh_x0_css_eta: " << m_atanh_x0_css_eta);
290 ATH_MSG_DEBUG("atanh_a_csl_eta: " << m_atanh_a_csl_eta);
291 ATH_MSG_DEBUG("atanh_b_csl_eta: " << m_atanh_b_csl_eta);
292 ATH_MSG_DEBUG("atanh_c_csl_eta: " << m_atanh_c_csl_eta);
293 ATH_MSG_DEBUG("atanh_x0_csl_eta: " << m_atanh_x0_csl_eta);
294
295 ATH_MSG_DEBUG("Minimum pos error: " << m_dposmin);
296
297 return StatusCode::SUCCESS;
298}
299
300//**********************************************************************
301
303 auto init = [&]() {
304 DataNames dnames;
305 bool dofixed = false;
306 bool docharge = false;
307 if (m_posopt_phi == "POLYNOMIAL" || m_posopt_phi == "TABLE" || m_posopt_phi == "ATANH") {
308 if (m_erropt_phi == "FIXED") dofixed = true;
309 if (m_erropt_phi == "CHARGE") docharge = true;
310 }
311 if (m_posopt_eta == "POLYNOMIAL" || m_posopt_eta == "TABLE" || m_posopt_eta == "ATANH") {
312 if (m_erropt_eta == "FIXED") dofixed = true;
313 if (m_erropt_eta == "CHARGE") docharge = true;
314 }
315 if (dofixed || docharge) {
316 dnames.emplace_back("scor1");
317 dnames.emplace_back("scor2");
318 dnames.emplace_back("scor");
319 }
320 if (docharge) {
321 dnames.emplace_back("dscor1");
322 dnames.emplace_back("dscor2");
323 dnames.emplace_back("dscor");
324 dnames.emplace_back("scordiff");
325 dnames.emplace_back("dscordiff");
326 }
327 return dnames;
328 };
329 static const DataNames dnames = init();
330 return dnames;
331}
332
333//**********************************************************************
334
335Results QratCscClusterFitter::fit(const StripFitList& sfits, double tantheta) const {
336 ATH_MSG_VERBOSE("QRAT fit with tool " << name());
337
338 Results results;
339
340 // Check input has at least three strips.
341 unsigned int nstrip = sfits.size();
342 if (nstrip < 3) {
343 ATH_MSG_VERBOSE(" Input has fewer than three strips.");
344 if (nstrip == 2) {
345 Muon::CscTimeStatus tstatus = (sfits[0].charge > sfits[1].charge) ? sfits[0].timeStatus : sfits[1].timeStatus;
346 results.emplace_back(1, Muon::CscStatusNarrow, tstatus);
347 } else if (nstrip == 1) {
348 Muon::CscTimeStatus tstatus = sfits[0].timeStatus;
349 results.emplace_back(1, Muon::CscStatusNarrow, tstatus);
350 }
351 return results;
352 }
353
354 // Fetch the number of strips and check the input arrays.
355 for (unsigned int istrip = 0; istrip < nstrip; ++istrip) {
356 if (sfits[istrip].strip == nullptr) {
357 ATH_MSG_WARNING("Strip pointer is null.");
358 results.emplace_back(2);
359 return results;
360 }
361 }
362
363 // Use the first strip to extract the layer parameters.
364 const CscStripPrepData* pstrip = sfits[0].strip;
365 Identifier idStrip0 = pstrip->identify();
366
367 // retrieve MuonDetectorManager from the conditions store
369 const MuonGM::MuonDetectorManager* MuonDetMgr = DetectorManagerHandle.cptr();
370 if (MuonDetMgr == nullptr) {
371 ATH_MSG_ERROR("Null pointer to the MuonDetectorManager conditions object");
372 return results;
373 }
374 const CscReadoutElement* pro = MuonDetMgr->getCscReadoutElement(idStrip0);
375
376 bool measphi = m_idHelperSvc->cscIdHelper().CscIdHelper::measuresPhi(idStrip0);
377 double pitch = pro->cathodeReadoutPitch(0, measphi);
378 unsigned int maxstrip = pro->maxNumberOfStrips(measphi);
379 unsigned int strip0 = m_idHelperSvc->cscIdHelper().strip(idStrip0) - 1;
380 int station = m_idHelperSvc->cscIdHelper().stationName(idStrip0) - 49; // 1=CSS, 2=CSL
381
382 CscPlane plane = findPlane(station, measphi);
383 if (plane == UNKNOWN_PLANE) {
384 ATH_MSG_WARNING("Invalid CSC plane: station=" << station << "; measphi=" << measphi);
385 results.emplace_back(3);
386 return results;
387 }
388
389 // Display input strips.
390 ATH_MSG_VERBOSE("QRAT fittter input has " << nstrip << " strips");
391 for (unsigned int istrip = 0; istrip < nstrip; ++istrip) {
392 Identifier id = sfits[istrip].strip->identify();
393 ATH_MSG_VERBOSE(" " << station << " : " << measphi << " " << m_idHelperSvc->cscIdHelper().wireLayer(id) << " " << istrip << " "
394 << m_idHelperSvc->cscIdHelper().strip(id) << " " << sfits[istrip].charge);
395 }
396
397 // Find the peak strip and check the shape.
398 unsigned int istrip_peak = 0; // strip number within cluster
399 // Loop over strips excluding the edges.
400 for (unsigned int istrip = 1; istrip < nstrip - 1; ++istrip) {
401 // Tell clang to optimize assuming that FP operations may trap.
403 StripFit sfit = sfits[istrip];
404 float qthis = sfit.charge;
405 float qlast = sfits[istrip - 1].charge;
406 float qnext = sfits[istrip + 1].charge;
407 // Peak if the adjacent strips have less charge.
408 bool ispeak = qthis > qlast && qthis > qnext;
409 // Special case: next strip has the same charge.
410 // Require the previous strip has less charge and the next following
411 // strip be absent or have less charge.
412 if (!ispeak) {
413 if (qthis == qnext) { ispeak = (qthis > qlast) && (istrip + 2 == nstrip || sfits[istrip + 2].charge < qthis); }
414 }
415 // Special case: first and second strips have the same charge.
416 // Require the third strip has less charge.
417 if (!ispeak) {
418 if (istrip == 1) {
419 if (qthis == qlast) {
420 ispeak = qthis > qnext; // bug found 10/13/07
421 }
422 }
423 }
424 // Record if peak.
425 if (ispeak) {
426 if (istrip_peak) { // Error if multiple peaks are found.
427 results.emplace_back(6, Muon::CscStatusMultiPeak); // Time status should be defined in SimpleClusterFit...
428 return results;
429 }
430 istrip_peak = istrip;
431 }
432 }
433 ATH_MSG_VERBOSE(" Peak is at " << istrip_peak << "th strip in cluster");
434
435 // Check we are not on the edge.
436 if (strip0 <= 0 || strip0 + nstrip > maxstrip) {
437 results.emplace_back(4, Muon::CscStatusEdge, sfits[istrip_peak].timeStatus);
438 return results;
439 }
440
441 // MS: remove this check since width is amplitude dependent.
442 // use saturation check instead
443 /**************************************
444 if ( nstrip > m_max_width[plane] ) {
445 // if ( nstrip_threshold > m_max_width[plane] ) {
446 results.push_back(Result(5, Muon::CscStatusWide, sfits[istrip_peak].timeStatus));
447 return results;
448 }
449 ***************************************/
450
451 // Cluster is spoiled if peak is not at the center.
452 bool is_even = 2 * (nstrip / 2) == nstrip;
453 bool atcenter = istrip_peak == nstrip / 2 || (is_even && istrip_peak + 1 == nstrip / 2);
454 if (!atcenter) {
455 results.emplace_back(7, Muon::CscStatusSkewed, sfits[istrip_peak].timeStatus);
456 return results;
457 }
458
459 if (sfits[istrip_peak].stripStatus == Muon::CscStrStatSaturated || sfits[istrip_peak - 1].stripStatus == Muon::CscStrStatSaturated ||
460 sfits[istrip_peak + 1].stripStatus == Muon::CscStrStatSaturated) {
461 results.emplace_back(15, Muon::CscStatusSaturated, sfits[istrip_peak].timeStatus);
462 return results;
463 }
464
465 // left/peak/right strip should have good time information....
466 if (sfits[istrip_peak].stripStatus != Muon::CscStrStatSuccess
467 // || sfits[istrip_peak-1].stripStatus != Muon::CscStrStatSuccess
468 // || sfits[istrip_peak+1].stripStatus != Muon::CscStrStatSuccess ) {
469 ) {
470 results.emplace_back(14, Muon::CscStatusStripFitFailed, sfits[istrip_peak].timeStatus);
471 return results;
472 } else if (sfits[istrip_peak - 1].stripStatus == Muon::CscStrStatHot || sfits[istrip_peak - 1].stripStatus == Muon::CscStrStatDead ||
473 sfits[istrip_peak + 1].stripStatus == Muon::CscStrStatHot || sfits[istrip_peak + 1].stripStatus == Muon::CscStrStatDead) {
474 results.emplace_back(14, Muon::CscStatusStripFitFailed, sfits[istrip_peak].timeStatus);
475 return results;
476 }
477
479 // Set initial strip position.
480 double savg = istrip_peak;
481
482 // Calculate QRAT correction to strip position.
483 std::string posopt = m_posopt_eta;
484 std::string erropt = m_erropt_eta;
485 double dpos = 0.0;
486 if (measphi) {
487 posopt = m_posopt_phi;
488 erropt = m_erropt_phi;
489 }
490 double q1 = sfits[istrip_peak - 1].charge;
491 double q0 = sfits[istrip_peak].charge;
492 double q2 = sfits[istrip_peak + 1].charge;
493 double qrat1 = q1 / q0;
494 double qrat2 = q2 / q0;
495 double dq1 = sfits[istrip_peak - 1].dcharge;
496 double dq0 = sfits[istrip_peak].dcharge;
497 double dq2 = sfits[istrip_peak + 1].dcharge;
498
499 ATH_MSG_VERBOSE(" QRAT charge ratios: " << qrat1 << " " << qrat2);
500 double scor1 = 0.; // left side correction.
501 double dscordqrat1 = 0.;
502 double scor2 = 0; // right side correction.
503 double dscordqrat2 = 0.;
504 int stat1 = 0;
505 int stat2 = 0;
506 if (posopt == "POLYNOMIAL") {
507 stat1 = qrat_correction(plane, qrat1, scor1, dscordqrat1);
508 stat2 = qrat_correction(plane, qrat2, scor2, dscordqrat2);
509 } else if (posopt == "TABLE") {
510 double qrmin = 0.0;
511 const std::vector<double>* pcor = nullptr;
512 if (plane == CSS_ETA) {
513 qrmin = m_qratmin_css_eta;
514 pcor = &m_qratcor_css_eta;
515 } else if (plane == CSL_ETA) {
516 qrmin = m_qratmin_csl_eta;
517 pcor = &m_qratcor_csl_eta;
518 } else {
519 ATH_MSG_WARNING(" Invalid QRAT plane: " << splane(plane));
520 results.emplace_back(8);
521 return results;
522 }
523 if (pcor) {
524 stat1 = qrat_interpolation(qrmin, *pcor, qrat1, scor1, dscordqrat1);
525 stat2 = qrat_interpolation(qrmin, *pcor, qrat2, scor2, dscordqrat2);
526 } else {
527 stat1 = 99;
528 }
529 } else if (posopt == "ATANH") { // MS: atanh parametrization
530 double a, b, c, x0; // parameters
531 if (plane == CSS_ETA) {
536 } else if (plane == CSL_ETA) {
541 } else {
542 ATH_MSG_WARNING(" Invalid QRAT plane: " << splane(plane));
543 results.emplace_back(8);
544 return results;
545 }
546 stat1 = qrat_atanh(a, b, c, x0, qrat1, scor1, dscordqrat1);
547 stat2 = qrat_atanh(a, b, c, x0, qrat2, scor2, dscordqrat2);
548
549 } else {
550 ATH_MSG_WARNING(" Invalid position option: " << posopt);
551 results.emplace_back(9);
552 return results;
553 }
554 if (stat1 || stat2) {
555 ATH_MSG_VERBOSE(" QRAT correction failed: SPOILED");
556 results.emplace_back(10);
557 return results;
558 }
559 ATH_MSG_VERBOSE(" QRAT strip corrs: " << scor1 << " " << scor2);
560 ATH_MSG_VERBOSE(" QRAT derivatives: " << dscordqrat1 << " " << dscordqrat2);
561
562 // Compare left and right.
563 // Flip sign of the left side correction.
564 scor1 = -scor1;
565 dscordqrat1 = -dscordqrat1;
566 double scor = 0.0;
567 DataMap dmap;
568 // Calculation weighting corrections by their derivatives, i.e. assuming the
569 // two charge ratios have the same error.
570 if (erropt == "FIXED") {
571 double w1 = 1 / (dscordqrat1 * dscordqrat1);
572 double w2 = 1 / (dscordqrat2 * dscordqrat2);
573 scor = (w1 * scor1 + w2 * scor2) / (w1 + w2);
574 double scor_diff = std::abs(scor2 - scor1);
575 ATH_MSG_VERBOSE(" Combined corr: " << scor);
576 dpos = measphi ? m_error_phi : m_error_eta;
577 // Fill data map.
578 dmap["scor1"] = scor1;
579 dmap["scor2"] = scor2;
580 dmap["scor"] = scor;
581 // Exit if measurements are inconsistent.
582 if (scor_diff > m_qrat_maxdiff) {
583 ATH_MSG_VERBOSE(" SPOILED (scor_diff=" << scor_diff << ")");
584 results.emplace_back(11, Muon::CscStatusQratInconsistent);
585 return results;
586 }
587 // Calculation using the (independent) errors in the three charges.
588 } else if (erropt == "CHARGE") {
589 // Calculate intermediate variables.
590 double x1 = dscordqrat1 * qrat1;
591 double x2 = dscordqrat2 * qrat2;
592 double dqq0 = dq0 / q0;
593 double dqq1 = dq1 / q1;
594 double dqq2 = dq2 / q2;
595 double rnum = (-x1 * x1 * dqq1 * dqq1 + x2 * x2 * dqq2 * dqq2 + (x2 * x2 - x1 * x1) * dqq0 * dqq0);
596 double rden = (x1 * x1 * dqq1 * dqq1 + x2 * x2 * dqq2 * dqq2 + (x2 - x1) * (x2 - x1) * dqq0 * dqq0);
597 double rfac = rnum / rden;
598 // Calculate the significance of the difference between the measurements.
599 double dscor_diff = sqrt(rden);
600 double scor_diff = scor2 - scor1;
601 double scor_sig = std::abs(scor_diff) / dscor_diff;
602 // Calculate the weighted average of the corrections.
603 double w1 = 0.5 * (1.0 + rfac);
604 double w2 = 0.5 * (1.0 - rfac);
605 scor = w1 * scor1 + w2 * scor2;
606 // Calculate the error in this average.
607 double ddscor1 = w1 * x1 * dqq1;
608 double ddscor2 = w2 * x2 * dqq2;
609 double ddscor0 = (w1 * x1 + w2 * x2) * dqq0;
610 double dscor = sqrt(ddscor1 * ddscor1 + ddscor2 * ddscor2 + ddscor0 * ddscor0);
611 dpos = pitch * dscor;
612 // add minimum error (in mm) in quadrature:
613 dpos = sqrt(dpos * dpos + m_dposmin * m_dposmin);
614 // Fill data map.
615 double dscor1 = std::abs(x1) * sqrt(dqq1 * dqq1 + dqq0 * dqq0);
616 double dscor2 = std::abs(x2) * sqrt(dqq2 * dqq2 + dqq0 * dqq0);
617 dmap["scor1"] = scor1;
618 dmap["dscor1"] = dscor1;
619 dmap["scor2"] = scor2;
620 dmap["dscor2"] = dscor2;
621 dmap["scordiff"] = scor_diff;
622 dmap["dscordiff"] = dscor_diff;
623 dmap["scor"] = scor;
624 dmap["dscor"] = dscor;
625 // Debugging.
626 ATH_MSG_VERBOSE("QRAT CHARGE calculation");
627 ATH_MSG_VERBOSE(" q1, q0, q2: " << q1 << " " << q0 << " " << q2);
628 ATH_MSG_VERBOSE(" dq1, dq0, dq2: " << dq1 << " " << dq0 << " " << dq2);
629 ATH_MSG_VERBOSE(" dscordqrat1, x1: " << dscordqrat1 << " " << x1);
630 ATH_MSG_VERBOSE(" dscordqrat2, x2: " << dscordqrat2 << " " << x2);
631 ATH_MSG_VERBOSE(" scor1 = " << scor1 << " +/- " << dscor1);
632 ATH_MSG_VERBOSE(" scor2 = " << scor2 << " +/- " << dscor2);
633 ATH_MSG_VERBOSE(" scor = " << scor << " +/- " << dscor);
634 ATH_MSG_VERBOSE(" scordiff = " << scor_diff << " +/- " << dscor_diff);
635 ATH_MSG_VERBOSE(" scor_sig = " << scor_sig);
636
637 // Exit if measurements are inconsistent.
638 if (scor_sig > m_qrat_maxsig) {
639 ATH_MSG_VERBOSE(" SPOILED (scor_sig=" << scor_sig << ")");
640 results.emplace_back(12, Muon::CscStatusQratInconsistent, sfits[istrip_peak].timeStatus);
641 return results;
642 }
643 } else {
644 ATH_MSG_WARNING(" Invalid error option: " << erropt);
645 results.emplace_back(13, Muon::CscStatusUndefined, sfits[istrip_peak].timeStatus);
646 return results;
647 }
648
649 // Correct strip position.
650 savg += scor + strip0;
651 ATH_MSG_VERBOSE(" QRAT corr " << splane(plane) << " nstrip=" << nstrip << " savg=" << savg << " qrat1=" << qrat1
652 << " qrat2=" << qrat2 << " scor1=" << scor1 << " scor2=" << scor2);
653
654 // Error due to incident angle.
655 double dpostht = m_error_tantheta * std::abs(tantheta);
656
657 // Scale error on dpos
658 dpos = dpos * m_precisionErrorScaler;
659
660 // Set return values.
662 res.strip = istrip_peak;
663 res.position = pitch * (savg + 0.5 - 0.5 * maxstrip);
664
665 // internal alignment ...
666 Identifier id = sfits[res.strip].strip->identify();
667 double offset = m_alignmentTool->getAlignmentOffset(id);
668 res.position -= offset;
669
670 res.dposition = sqrt(dpos * dpos + dpostht * dpostht);
671
672 res.fstrip = 0;
673 res.lstrip = nstrip - 1;
674 res.time = sfits[istrip_peak].time;
675 res.time_beforeT0Corr = sfits[istrip_peak].time_beforeT0Corr;
676 res.time_beforeBPCorr = sfits[istrip_peak].time_beforeBPCorr;
677 res.timeStatus = sfits[istrip_peak].timeStatus;
678
679 res.qleft = q1;
680 res.qpeak = q0;
681 res.qright = q2;
682
683 // res.diff = dmap["scordiff"];
684 // res.sig = dmap["scordiff"]/dmap["dscordiff"];
685
686 // cluster charge should be qsum over three strip... 3/21/2011
687 res.charge = res.qleft + res.qpeak + res.qright;
688 res.charge_beforeBPCorr =
689 sfits[istrip_peak].charge_beforeBPCorr + sfits[istrip_peak - 1].charge_beforeBPCorr + sfits[istrip_peak + 1].charge_beforeBPCorr;
690
691 res.dataMap = dmap;
692
693 ATH_MSG_VERBOSE(" Position :: pos=" << res.position << " dpos:dtht=" << dpos << ":" << dpostht << " ==>" << res.dposition
694 << " at tanth=" << tantheta);
695
696 results.push_back(res);
697 return results;
698}
699// int QratCscClusterFitter::
700// fit(const StripList&, const StripFitList& sfits,
701// double& pos, double& dpos, Muon::CscClusterStatus& clustatus,
702// unsigned int& /*istrip*/, double& /*charge*/, double& /*time*/, DataMap* /*pdmap*/) const { return 0;}
703//**********************************************************************
704
705double QratCscClusterFitter::getCorrectedError(const CscPrepData* pclu, double slope) const {
706 // Cluster position.
709 double pos = pclu->localPosition()[icor];
710 double dpos = Amg::error(pclu->localCovariance(), ierr);
711
712 Identifier idStrip0 = pclu->identify();
713 int station = m_idHelperSvc->cscIdHelper().stationName(idStrip0) - 49; // 1=CSS, 2=CSL
714 // Calculate the angle of incidence.
715 double tantht = 0.0;
716 if (station == 1) {
718 } else {
720 }
721 // Correct the error using this angle.
722 double old_dpostht = m_error_tantheta * std::abs(tantht);
723
724 double new_dpostht = m_error_tantheta * std::abs(slope);
725
726 double newError = sqrt(dpos * dpos - old_dpostht * old_dpostht + new_dpostht * new_dpostht);
727
728 ATH_MSG_VERBOSE(" Position :: pos=" << pos << " dpos:newdpos=" << dpos << " : " << newError << " " << old_dpostht << " "
729 << new_dpostht);
730
731 if (slope < -990) { newError = sqrt(dpos * dpos + old_dpostht * old_dpostht); }
732
733 return newError;
734}
735
736//**********************************************************************
737
739 Results results = fit(sfits, 0.0);
740 Results new_results;
741 for (unsigned int iresult = 0; iresult < results.size(); ++iresult) {
742 Result res = results[iresult];
743 if (res.fitStatus) {
744 new_results.push_back(res);
745 continue;
746 }
747 // Fetch the chamber type.
748 const CscStripPrepData* pstrip = sfits[0].strip;
749 Identifier idStrip0 = pstrip->identify();
750 int station = m_idHelperSvc->cscIdHelper().stationName(idStrip0) - 49; // 1=CSS, 2=CSL
751 // Calculate the angle of incidence.
752 double tantht = 0.0;
753 double pos = res.position;
754 if (station == 1) {
756 } else {
758 }
759 // Correct the error using this angle.
760 double dpostht = m_error_tantheta * std::abs(tantht);
761 double dpos = res.dposition;
762
763 res.dposition = sqrt(dpos * dpos + dpostht * dpostht);
764
765 // Return the updated result.
766 new_results.push_back(res);
767 }
768
769 return new_results;
770}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
double charge(const T &p)
Definition AtlasPID.h:997
ICscClusterFitter::DataNames DataNames
std::vector< Result > Results
std::pair< std::vector< unsigned int >, bool > res
static Double_t a
int qrat_correction(CscPlane plane, double qrat, double &cor, double &dcordqrat)
int qrat_atanh(const double a, const double b, double c, const double x0, double qrat, double &cor, double &dcordqrat)
Calculate QRAT correction from inverse hyperbolic tangent based on a fit to the plot of pos x vs char...
int qrat_interpolation(double qrmin, const std::vector< double > &corvals, double qrat, double &cor, double &dcordqrat)
#define z
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
ICscStripFitter::Result StripFit
std::vector< std::string > DataNames
std::vector< Result > Results
std::vector< StripFit > StripFitList
std::map< std::string, double > DataMap
double cathodeReadoutPitch(int chLayer, int measuresPhi) const
int maxNumberOfStrips(int measuresPhi) const
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)
Class representing clusters from the CSC.
Definition CscPrepData.h:39
Class representing the raw data of one CSC strip (for clusters look at Muon::CscPrepData).
SG::ReadCondHandleKey< MuonGM::MuonDetectorManager > m_DetectorManagerKey
retrieve MuonDetectorManager from the conditions store
std::vector< unsigned int > m_max_width
ToolHandle< ICscAlignmentTool > m_alignmentTool
std::vector< double > m_qratcor_css_eta
QratCscClusterFitter(const std::string &, const std::string &, const IInterface *)
Results fit(const StripFitList &sfits) const
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
double getCorrectedError(const Muon::CscPrepData *pclu, double slope) const
const DataNames & dataNames() const
std::vector< double > m_qratcor_csl_eta
const_pointer_type cptr()
const Amg::Vector2D & localPosition() const
return the local position reference
Identifier identify() const
return the identifier
const Amg::MatrixX & localCovariance() const
return const ref to the error matrix
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 ...
@ CscStrStatDead
@ CscStrStatHot
@ CscStrStatSaturated
@ CscStrStatSuccess
CscClusterStatus
Enum to represent the cluster status - see the specific enum values for more details.
@ CscStatusUnspoiled
Clean cluster with precision fit.
@ CscStatusStripFitFailed
@ CscStatusUndefined
Undefined, should not happen, most likely indicates a problem.
@ CscStatusSkewed
Skewed, e.g.
@ CscStatusEdge
Cluster reaches the edge of plane.
@ CscStatusMultiPeak
More than one peak in cluster.
@ CscStatusSaturated
@ CscStatusQratInconsistent
Positions from Qrat_left and Qrat_right is not consistent.
@ CscStatusNarrow
Too narrow.
CscTimeStatus
Enum to represent the cluster time measurement status - see the specific enum values for more details...
ParamDefs
This file defines the parameter enums in the Trk namespace.
Definition ParamDefs.h:32
@ loc1
Definition ParamDefs.h:34
Tell the compiler to optimize assuming that FP may trap.
#define CXXUTILS_TRAPPING_FP
Definition trapping_fp.h:24