ATLAS Offline Software
Loading...
Searching...
No Matches
ParabolaCscClusterFitter.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <iomanip>
8#include <sstream>
9
18
23
26using Results = std::vector<Result>;
27
28namespace {
29 std::string splane(CscPlane plane) {
30 switch (plane) {
31 case CSS_ETA: return "CSS eta";
32 case CSL_ETA: return "CSL eta";
33 case CSS_PHI: return "CSS phi";
34 case CSL_PHI: return "CSL phi";
35 case UNKNOWN_PLANE: return "no such plane";
36 }
37 return "no such plane";
38 }
39
40 CscPlane findPlane(int station, bool measphi) {
41 if (station == 1) {
42 if (measphi)
43 return CSS_PHI;
44 else
45 return CSS_ETA;
46 } else if (station == 2) {
47 if (measphi)
48 return CSL_PHI;
49 else
50 return CSL_ETA;
51 }
52 return UNKNOWN_PLANE;
53 }
54} // namespace
55
66 double a, b, c; // correction values
67 switch (plane) {
68 case CSS_ETA: { // small Chamber, X strips
69 a = 2.97043e-01; // from segment186049.root
70 b = 8.73895e+00;
71 c = 2.08465e-01;
72 break;
73 }
74 case CSS_PHI: { // small chamber, Y strips
75 a = 0.2662; // 2rt test with small chambers, longy.root
76 b = 62.19;
77 c = 0.2191;
78 break;
79 }
80 case CSL_ETA: { // large chamber, X strips
81 a = 2.99744e-01; // from segment186049.root
82 b = 8.30484e+00;
83 c = 2.07538e-01;
84 break;
85 }
86 case CSL_PHI: { // large chamber, Y strips
87 a = 0.2766; // Run 1782 in bat 184
88 b = 50.08;
89 c = 0.0301;
90 break;
91 }
92 default: { // invalid plane, should not happen, check beforehand.
93 return -1.0;
94 }
95 } // end switch
96
97 return a * std::atan(b * raw) + c * raw;
98}
99
100//*************************************************************************
101
102ParabolaCscClusterFitter::ParabolaCscClusterFitter(const std::string& type, const std::string& aname, const IInterface* parent) :
103 AthAlgTool(type, aname, parent) {
104 declareInterface<ICscClusterFitter>(this);
105 m_max_width.push_back(5); // CSS eta
106 m_max_width.push_back(5); // CSL eta
107 m_max_width.push_back(3); // CSS phi
108 m_max_width.push_back(3); // CSL phi
109 declareProperty("max_width", m_max_width); // Maximum width (strips) for unspoiled clusters
110 declareProperty("error_tantheta", m_error_tantheta = 0.57); // in mm
111 declareProperty("xtan_css_eta_offset", m_xtan_css_eta_offset = 0.0015); // in mm
112 declareProperty("xtan_css_eta_slope", m_xtan_css_eta_slope = 0.000137); // in mm
113 declareProperty("xtan_csl_eta_offset", m_xtan_csl_eta_offset = -.0045); // in mm
114 declareProperty("xtan_csl_eta_slope", m_xtan_csl_eta_slope = 0.000131); // in mm
115 declareProperty("multi", m_multi = 3.1); // threshold multiplier for cluster peak finding
116}
117
118//**********************************************************************
120 ATH_MSG_VERBOSE("Initalizing " << name());
121
122 ATH_CHECK(m_idHelperSvc.retrieve());
123
124 ATH_MSG_DEBUG("Properties for " << name() << ":");
125 ATH_MSG_DEBUG(" tan(theta) error coeff: " << m_error_tantheta);
126 ATH_MSG_DEBUG(" CSS eta pos-slope offset: " << m_xtan_css_eta_offset);
127 ATH_MSG_DEBUG(" CSS eta pos-slope slope: " << m_xtan_css_eta_slope);
128 ATH_MSG_DEBUG(" CSL eta pos-slope offset: " << m_xtan_csl_eta_offset);
129 ATH_MSG_DEBUG(" CSL eta pos-slope slope: " << m_xtan_csl_eta_slope);
130 // retrieve MuonDetectorManager from the conditions store
131 ATH_CHECK(m_DetectorManagerKey.initialize());
132
133 return StatusCode::SUCCESS;
134}
135
138 static const DataNames dnames ={"qA","qB","qC"};
139 return dnames;
140}
141
155Results ParabolaCscClusterFitter::fit(const StripFitList& sfits, double tantheta) const {
156 ATH_MSG_VERBOSE("Parabola fit with tool " << name());
157
158 Results results; // Vector of fit results
159
160 // Check that the input has at least three strips.
161 unsigned int nstrip = sfits.size(); // number of strips in this cluster
162 if (nstrip < 3) {
163 ATH_MSG_VERBOSE(" CscStatusNarrow: Input has fewer than three strips.");
164 results.emplace_back(1, Muon::CscStatusNarrow);
165 return results;
166 }
167
168 // Check the input array for NULL pointers.
169 for (unsigned int istrip = 0; istrip < nstrip; istrip++) {
170 if (sfits[istrip].strip == nullptr) {
171 ATH_MSG_WARNING("Strip pointer is null.");
172 results.emplace_back(2);
173 return results;
174 }
175 }
176
177 // Use the first strip to extract the layer parameters.
178 const CscStripPrepData* pstrip = sfits[0].strip;
179 Identifier idStrip0 = pstrip->identify();
180
181 // retrieve MuonDetectorManager from the conditions store
183 const MuonGM::MuonDetectorManager* MuonDetMgr = DetectorManagerHandle.cptr();
184 if (MuonDetMgr == nullptr) {
185 ATH_MSG_ERROR("Null pointer to the MuonDetectorManager conditions object");
186 return results;
187 }
188 const CscReadoutElement* pro = MuonDetMgr->getCscReadoutElement(idStrip0);
189
190 // const CscReadoutElement* pro = pstrip->detectorElement(); fixed by Woochun
191 bool measphi = m_idHelperSvc->cscIdHelper().CscIdHelper::measuresPhi(idStrip0);
192 double pitch = pro->cathodeReadoutPitch(0, measphi);
193 unsigned int maxstrip = pro->maxNumberOfStrips(measphi);
194 unsigned int strip0 = m_idHelperSvc->cscIdHelper().strip(idStrip0) - 1;
195 int station = m_idHelperSvc->cscIdHelper().stationName(idStrip0) - 49; // 1=CSS, 2=CSL
196 CscPlane plane = findPlane(station, measphi);
197 if (plane == UNKNOWN_PLANE) {
198 ATH_MSG_WARNING("Invalid CSC plane: station=" << station << "; measphi=" << measphi);
199 results.emplace_back(3);
200 return results;
201 }
202
203 // Count strips above threshold:
204 ATH_MSG_VERBOSE("Parabola fitter input has " << nstrip << " strips:");
205 //unsigned int nstrip_threshold = 0;
206 for (unsigned int istrip = 0; istrip < nstrip; ++istrip) {
207 Identifier id = sfits[istrip].strip->identify();
208 //if (sfits[istrip].charge >= 20000) ++nstrip_threshold;
209 ATH_MSG_VERBOSE(" index: " << istrip << " chn:" << m_idHelperSvc->cscIdHelper().strip(id)
210 << " amp:" << (int)(sfits[istrip].charge / 1000) << " ke.");
211 }
212
213 // Find the highest peak and count all peaks above threshold.
214 // Peaks have to be above threshold to avoid counting noise fluctuations
215 unsigned int istrip_peak = 0;
216 int numPeaks = 0; // count peaks above threshold
217 float qpeak = -1; // charge of the peak strip
218 // Loop over strips excluding the first and last strip
219 double charge_clu = sfits[0].charge + sfits[nstrip - 1].charge; // cluster sum
220 for (unsigned int istrip = 1; istrip < nstrip - 1; ++istrip) {
221 float qthis = sfits[istrip].charge;
222 float qlast = sfits[istrip - 1].charge;
223 float qnext = sfits[istrip + 1].charge;
224 double thr = m_multi * sfits[istrip].dcharge / 10; // correct noise*10
225 Identifier id = sfits[istrip].strip->identify();
226 ATH_MSG_VERBOSE(" index: " << istrip << " chn:" << m_idHelperSvc->cscIdHelper().strip(id)
227 << " amp:" << (int)(sfits[istrip].charge / 1000) << " ke, thr: " << (int)(thr / 1000) << " ke "
228 << ((qthis > thr) ? "signal" : "noise") << sfits[istrip].dcharge / 1000);
229 charge_clu += qthis;
230
231 // Peak if the adjacent strips have less charge.
232 if ((qthis >= qlast) && (qthis >= qnext)) { // There is a peak.
233 if (qthis > qpeak) { // larger peak then before
234 istrip_peak = istrip; // record new peak location
235 qpeak = qthis;
236 }
237 if (qthis > thr) numPeaks++; // Only count peaks above a threshold
238 }
239 } // next istrip
240
241 ATH_MSG_VERBOSE(" Peak is at index " << istrip_peak << " amp = " << qpeak / 1000);
242 if (numPeaks > 1) { // Error if more than one peak above threshold was found.
243 results.emplace_back(6, Muon::CscStatusMultiPeak);
244 ATH_MSG_VERBOSE(" CscStatusMultiPeak: multiple peaks are found: " << numPeaks);
245 return results;
246 }
247
248 if (istrip_peak == 0) { // no peak (even below threshold) was found.
249 results.emplace_back(11);
250 ATH_MSG_VERBOSE(" No peak was found.");
251 return results;
252 }
253
254 // Check that the peak is not on the chamber edge.
255 // This cannot happen due to the prev. loop
257 if (strip0 + istrip_peak <= 0 || strip0 + istrip_peak >= maxstrip - 1) {
258 results.emplace_back(4, Muon::CscStatusEdge);
259 ATH_MSG_VERBOSE(" CscStatusEdge: strip0+istrip_peak = " << strip0 + istrip_peak);
260 return results;
261 }
262
263 // Cluster width cut, should not be done...
264 /*****************************************************
265 if ( nstrip_threshold > m_max_width[plane] ) {
266 results.push_back(Result(5, Muon::CscStatusWide));
267 ATH_MSG_VERBOSE(" CscStatusWide: nstrip_threshold = "
268 << nstrip_threshold);
269 return results;
270 }
271 ********************************************************/
272
273 // Cluster is spoiled if peak is not at the center.
274 // should not be done
275 /*******************************************************
276 bool is_even = 2*(nstrip/2) == nstrip;
277 bool atcenter = istrip_peak == nstrip/2 ||
278 (is_even && istrip_peak+1 == nstrip/2);
279 if ( ! atcenter ) {
280 results.push_back(Result(7, Muon::CscStatusSkewed));
281 ATH_MSG_VERBOSE(" CscStatusSkewed: peak is not at the center.");
282 return results;
283 }
284 *********************************************************/
285
286 // reconstructed position in strip number units:
287 double savg;
288
289 // Charge amplitude per strip:
290 double qA = sfits[istrip_peak - 1].charge;
291 double qB = sfits[istrip_peak].charge;
292 double qC = sfits[istrip_peak + 1].charge;
293
294 // charge errors
295 double dqA = sfits[istrip_peak - 1].dcharge;
296 double dqB = sfits[istrip_peak].dcharge;
297 double dqC = sfits[istrip_peak + 1].dcharge;
298
299 double raw; // uncorrected parabola peak position
300 double denominator = 2 * qB - qA - qC; // denominator for parabola
301 if (denominator <= 0) { // not a peak, should not happen
302 ATH_MSG_WARNING(" Bad parabola denominator: " << denominator);
303 results.emplace_back(9);
304 return results;
305 } else {
306 raw = 0.5 * (qC - qA) / denominator; // peak of parabola through (qA, qB, qC)
307 }
308
309 double pos = ParabolaCorrection(plane, raw);
311 double cog = 1.2 * (qC - qA) / (qA + qB + qC); // for comparism
312 // pos = cog;
313
314 // error calculation: S/N = charge sum / ave charge error.
315 double dpos = (dqA + dqB + dqC) / 3 / (qA + qB + qC) * pitch * std::sqrt(2.0); // pos error
316 dpos = 0.08; // 80 micron error
317 if (measphi) dpos = 2.5; // worse phi resolution of ~2.5 mm
318 // dpos = 200;//*= 2; /** todo Tune this to correct chi 2 of segments */
325
326 // Calculate strip position.
327 savg = pos + strip0 + istrip_peak; // in strip numbers
328 // savg = 0.1 + strip0 + istrip_peak; // in strip numbers
329 ATH_MSG_VERBOSE(" Parabola correction: plane = '" << splane(plane) << "' qA=" << qA << " qB=" << qB << " qC=" << qC << " raw=" << raw
330 << " pos=" << pos << ", cog=" << cog);
331
332 // Position error contribution from incident angle:
333 double dpostht = m_error_tantheta * std::abs(tantheta);
334
335 DataMap dmap;
336 dmap["qA"] = qA;
337 dmap["qB"] = qB;
338 dmap["qC"] = qC;
339
340 // Set return values.
341 Result res(0, Muon::CscStatusUnspoiled); // status 0???
342 res.position = pitch * (savg + 0.5 - 0.5 * maxstrip);
343 res.dposition = std::sqrt(dpos * dpos + dpostht * dpostht); // pos. error estimate
344 res.strip = istrip_peak; // strip number in this cluster
345 res.fstrip = 0;
346 res.lstrip = nstrip - 1; // cluster width
347 res.charge = charge_clu; // total cluster charge over all strips
348 res.time = sfits[res.strip].time; // peaking time at center strip
349 res.qleft = qA; // left charge
350 res.qpeak = qB; // center charge
351 res.qright = qC; // right charge
352 res.dataMap = dmap;
353
354 ATH_MSG_VERBOSE(" Position: pos=" << res.position << " dpos:dtht=" << dpos << ":" << dpostht << " ==>" << res.dposition
355 << " at tanth = " << tantheta);
356
357 results.push_back(res);
358 return results;
359}
360
368double ParabolaCscClusterFitter::getCorrectedError(const CscPrepData* pclu, double slope) const {
369 // Cluster position.
372 double pos = pclu->localPosition()[icor];
373 double dpos = Amg::error(pclu->localCovariance(), ierr);
374
375 Identifier idStrip0 = pclu->identify();
376 int station = m_idHelperSvc->cscIdHelper().stationName(idStrip0) - 49; // 1=CSS, 2=CSL
377 // Calculate the angle of incidence.
378 double tantht = 0.0;
379 if (station == 1) {
381 } else {
383 }
384 // Correct the error using this angle.
385 double old_dpostht = m_error_tantheta * std::abs(tantht);
386
387 double new_dpostht = m_error_tantheta * std::abs(slope);
388
389 double newError = std::sqrt(dpos * dpos - old_dpostht * old_dpostht + new_dpostht * new_dpostht);
390
391 ATH_MSG_VERBOSE(" Position :: pos=" << pos << " dpos:newdpos=" << dpos << " : " << newError << " " << old_dpostht << " "
392 << new_dpostht);
393
394 return newError;
395}
396
397//**********************************************************************
399 Results results = fit(sfits, 0.0);
400 Results new_results;
401 for (unsigned int iresult = 0; iresult < results.size(); ++iresult) {
402 Result res = results[iresult];
403 if (res.fitStatus) {
404 new_results.push_back(res);
405 continue;
406 }
407 // Fetch the chamber type.
408 const CscStripPrepData* pstrip = sfits[0].strip;
409 Identifier idStrip0 = pstrip->identify();
410 int station = m_idHelperSvc->cscIdHelper().stationName(idStrip0) - 49; // 1=CSS, 2=CSL
411 // Calculate the angle of incidence.
412 double tantht = 0.0;
413 double pos = res.position;
414 if (station == 1) {
416 } else {
418 }
419 // Correct the error using this angle.
420 double dpostht = m_error_tantheta * std::abs(tantht);
421 double dpos = res.dposition;
422 res.dposition = std::sqrt(dpos * dpos + dpostht * dpostht);
423
424 // Return the updated result.
425 new_results.push_back(res);
426 }
427
428 return new_results;
429}
#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)
ICscClusterFitter::DataNames DataNames
std::vector< Result > Results
std::pair< std::vector< unsigned int >, bool > res
static Double_t a
Header file for the Parabola method of positoin reconstruction.
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)
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).
double m_multi
threshold multiplier for cluster peak finding
Results fit(const StripFitList &sfits) const
SG::ReadCondHandleKey< MuonGM::MuonDetectorManager > m_DetectorManagerKey
retrieve MuonDetectorManager from the conditions store
const DataNames & dataNames() const
data names for ntuple output in csc_cluster tree
double getCorrectedError(const Muon::CscPrepData *pclu, double slope) const
Correct the positon error for track angle.
static double ParabolaCorrection(CscPlane &plane, double &raw)
Correction of raw parabola positions.
double m_xtan_css_eta_slope
constant to Calculate the angle of incidence.
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
double m_xtan_csl_eta_offset
constant to Calculate the angle of incidence.
double m_xtan_csl_eta_slope
constant to Calculate the angle of incidence.
std::vector< unsigned int > m_max_width
Max.
double m_error_tantheta
error contribution in mm for the tan(theta) track angle correction
double m_xtan_css_eta_offset
constant to Calculate the angle of incidence.
ParabolaCscClusterFitter(const std::string &type, const std::string &aname, const IInterface *parent)
Constructor.
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 ...
CscClusterStatus
Enum to represent the cluster status - see the specific enum values for more details.
@ CscStatusUnspoiled
Clean cluster with precision fit.
@ CscStatusEdge
Cluster reaches the edge of plane.
@ CscStatusMultiPeak
More than one peak in cluster.
@ CscStatusNarrow
Too narrow.
ParamDefs
This file defines the parameter enums in the Trk namespace.
Definition ParamDefs.h:32
@ loc1
Definition ParamDefs.h:34