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