ATLAS Offline Software
Loading...
Searching...
No Matches
SimpleCscClusterFitter.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
14
19
21using Results = std::vector<Result>;
22
23namespace {
25enum CscPlane { CSS_R, CSL_R, CSS_PHI, CSL_PHI, UNKNOWN_PLANE };
26}
27
28SimpleCscClusterFitter::SimpleCscClusterFitter(const std::string& type, const std::string& aname, const IInterface* parent) :
29 AthAlgTool(type, aname, parent) {
30 declareInterface<ICscClusterFitter>(this);
31 declareProperty("position_option", m_option = "MEAN", "Cluster fitting option: MEAN, PEAK, CENTROID");
32 declareProperty("intrinsic_cluster_width", m_intrinsic_cluster_width = 20.0, "Intrinsic cluster width (mm)");
33 declareProperty("use_peakthreshold", m_use_peakthreshold = false);
34 declareProperty("defaultErrorScaler_eta", m_defaultErrorScaler_eta = 1.0);
35 declareProperty("defaultErrorScaler_phi", m_defaultErrorScaler_phi = 1.0);
36}
37
38//**********************************************************************
39
41 ATH_MSG_DEBUG(" Position option: " << m_option);
42 ATH_MSG_DEBUG(" Intrinsic width: " << m_intrinsic_cluster_width << " mm");
43
44 ATH_CHECK(m_idHelperSvc.retrieve());
45 ATH_CHECK(m_alignmentTool.retrieve());
46 // retrieve MuonDetectorManager from the conditions store
47 ATH_CHECK(m_DetectorManagerKey.initialize());
48 return StatusCode::SUCCESS;
49}
50
51//**********************************************************************
52
54 Results results;
55 Result res;
56
57 // Check the input lists.
58 unsigned int nstrip = sfits.size();
59 if (nstrip == 0) {
60 ATH_MSG_WARNING("Strip list is empty.");
61 res.fitStatus = 1;
62 results.push_back(res);
63 return results;
64 }
65 if (sfits.size() != nstrip) {
66 ATH_MSG_WARNING("Fit and strip lists have different sizes");
67 res.fitStatus = 2;
68 results.push_back(res);
69 return results;
70 }
71
72 if (sfits.empty() || !sfits[0].strip) {
73 ATH_MSG_WARNING("Strip pointer is null.");
74 res.fitStatus = 4;
75 results.push_back(res);
76 return results;
77 }
78 const CscStripPrepData* pstrip = sfits[0].strip;
79 const Identifier idStrip0 = pstrip->identify();
80
81 // retrieve MuonDetectorManager from the conditions store
83 const MuonGM::MuonDetectorManager* MuonDetMgr = DetectorManagerHandle.cptr();
84 if (!MuonDetMgr) {
85 ATH_MSG_ERROR("Null pointer to the MuonDetectorManager conditions object");
86 return results;
87 }
88 const CscReadoutElement* pro = MuonDetMgr->getCscReadoutElement(idStrip0);
89
90 bool measphi = m_idHelperSvc->cscIdHelper().CscIdHelper::measuresPhi(idStrip0);
91 double pitch = pro->cathodeReadoutPitch(0, measphi);
92 int maxstrip = pro->maxNumberOfStrips(measphi);
93 int strip0 = m_idHelperSvc->cscIdHelper().strip(idStrip0) - 1;
94
95 int zsec = m_idHelperSvc->cscIdHelper().stationEta(idStrip0);
96 int station = m_idHelperSvc->cscIdHelper().stationName(idStrip0) - 49; // 1=CSS, 2=CSL
97 int phisec = m_idHelperSvc->cscIdHelper().stationPhi(idStrip0);
98
99 int sector = zsec * (2 * phisec - station + 1);
100 int wlay = m_idHelperSvc->cscIdHelper().wireLayer(idStrip0);
101
102 // In SimpleCscClusterFitter istrip_peak = strip0;
103 int peak_count = 0; // # peaks in the cluster
104 bool edge = (strip0 == 0); // is cluster on the edge of the chamber?
105 int stripidx = 0; // actual strip position [0-191] or [0-47]
106 int countstrip = 0; // counting strip in for loop
107 double qsum = 0; // charge sum of strips in cluster
108 double xsum = 0; // stripidx sum in cluster
109 double qxsum = 0; // position weighted (stripidx) charge sum
110 double qerravg = 0;
111 // istrip starts from 0.
112 // stripidx is for actual strip position [0-191] or [0-47].
113 // Out of for loop, stripidx will be the last strip of cluster.
114 unsigned int istrip_peak = 0;
115 double lastqpeak = 0;
116 float qlast = 0.;
117 float q_second_last = 0.;
118
119 for (unsigned int istrip = 0; istrip < nstrip; ++istrip) {
120 const StripFit& sfit = sfits[istrip];
121 const float qthis = sfit.charge;
122 const float qnext = (istrip + 1 < nstrip) ? sfits[istrip + 1].charge : 0.;
123 const float q_over_next = (istrip + 2 < nstrip) ? sfits[istrip + 2].charge : 0.;
124 countstrip = istrip + 1;
125
126 stripidx = strip0 + istrip;
127 qsum += qthis;
128 qerravg += qthis;
129 xsum += stripidx;
130 qxsum += qthis * stripidx;
131
132 if (countstrip == 2 && qthis < qlast) ++peak_count;
133 if (countstrip > 2 && qthis < qlast && qlast >= q_second_last) ++peak_count;
134
135 bool ispeak = qthis > qlast && qthis > qnext;
136 // Special case: next strip has the same charge.
137 // Require the previous strip has less charge and the next following
138 // strip be absent or have less charge.
141 if (!ispeak && qthis == qnext) { ispeak = qthis > qlast && q_over_next < qthis; }
142
143 // Special case: first and second strips have the same charge.
144 // Require the third strip has less charge.
145 if (!ispeak && istrip == 1 && qthis == qlast) {
146 ispeak = qthis > qnext; // bug found 10/13/07
147 }
148
149 // Record if peak.
150 if (ispeak && qthis > lastqpeak) {
151 istrip_peak = istrip;
152 lastqpeak = qthis;
153 }
155 q_second_last = qlast;
156 qlast = qthis;
157 }
158 if (stripidx == maxstrip - 1) edge = true;
159 // Update peak count and edge.
160 if (countstrip == 1) ++peak_count;
161 if (countstrip > 1 && sfits[nstrip - 1].charge >= sfits[nstrip - 2].charge) ++peak_count;
162
163 // Fix to avoid division-by-zero (W.L. 29 Jun 2012)
164 if (qsum <= 0) {
165 // ATH_MSG_WARNING("Charge sum is not positive.");
166 // ATH_MSG_WARNING("Charge sum : "<<qsum);
167 res.fitStatus = 0;
168 double savg = strip0 + istrip_peak; // peak position: this strip has Q>0
169 res.position = pitch * (savg + 0.5 - 0.5 * maxstrip);
170 res.strip = istrip_peak; // relative to cluster start
171 double errorScaler = measphi ? m_defaultErrorScaler_phi : m_defaultErrorScaler_eta;
172 res.dposition = errorScaler * pitch / sqrt(12.0);
173 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++added 13/06/2014 to avoid index out of range in
174 // CscThreshholdClusterBuilder.cxx
175 res.fstrip = 0;
176 res.lstrip = nstrip - 1;
177 res.time = sfits[istrip_peak].time;
178 res.timeStatus = sfits[istrip_peak].timeStatus;
179 res.qpeak = sfits[istrip_peak].charge;
180
181 res.charge = res.qpeak;
182 res.charge_beforeBPCorr = sfits[res.strip].charge_beforeBPCorr;
183
184 res.qleft = 0.;
185 res.qright = 0.;
186
187 if (istrip_peak >= 1) {
188 res.qleft = sfits[istrip_peak - 1].charge;
189 res.charge += res.qleft;
190 res.charge_beforeBPCorr += sfits[istrip_peak - 1].charge_beforeBPCorr;
191 }
192 if (istrip_peak + 1 < nstrip) {
193 res.qright = sfits[istrip_peak + 1].charge;
194 res.charge += res.qright;
195 res.charge_beforeBPCorr += sfits[istrip_peak + 1].charge_beforeBPCorr;
196 }
197 res.time_beforeT0Corr = sfits[res.strip].time_beforeT0Corr;
198 res.time_beforeBPCorr = sfits[res.strip].time_beforeBPCorr;
199 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
200 results.emplace_back(res);
201 return results;
202 }
203
204 // Calculate strip averages.
205 double strip_mean = xsum / nstrip; // Avg strip position
206 double strip_qmean = qxsum / qsum; // Avg strip position weighted by charge
207 qerravg = qerravg / nstrip; // for centroid error calculation....
208 // Assign cluster status.
209 // Cluster is spoiled if it is on the edge or has multiple peaks.
210 res.fitStatus = 0;
211 res.clusterStatus = Muon::CscStatusSimple;
212 if (edge)
213 res.clusterStatus = Muon::CscStatusEdge;
214 else if (peak_count > 1)
215 res.clusterStatus = Muon::CscStatusMultiPeak;
216
217 double savg = -99.;
218 if (m_option == "MEAN") {
219 savg = strip_mean;
220 } else if (m_option == "PEAK") {
221 savg = strip0 + istrip_peak;
222 } else if (m_option == "CENTROID") {
223 savg = strip_qmean;
224 } else {
225 ATH_MSG_WARNING("Invalid position option: " << m_option);
226 res.clusterStatus = Muon::CscStatusUndefined;
227 }
228
229 // WP treats.... special centroid method....
230 if (m_use_peakthreshold && nstrip > 2 && peak_count == 1) savg = strip_qmean;
231
232 if (measphi) savg = strip_mean;
233
234 // Assign cluster identifier and time using the center of the cluster.
235 // res.strip = (sfits.size()-1)/2;
236 // Assign cluster identifier and time using peak strip 2/24/2009
237 res.strip = istrip_peak;
238
239 // Assign position.
240 res.position = pitch * (savg + 0.5 - 0.5 * maxstrip);
241
242 // internal alignment ...
243 Identifier id = sfits[res.strip].strip->identify();
244 double offset = m_alignmentTool->getAlignmentOffset(id);
245 res.position -= offset;
246
247 // Assign position error.
248 double wmeas = pitch * nstrip;
249 double weff = wmeas - m_intrinsic_cluster_width;
250 double weffmin = 0.5 * wmeas;
251 if (weff < weffmin) weff = weffmin;
252 double errorScaler = measphi ? m_defaultErrorScaler_phi : m_defaultErrorScaler_eta;
253 res.dposition = errorScaler * weff / sqrt(12.0); // CENTROID doesn't make any effect on the case nstrip=1
254 /*
255 if (nstrip>1) {
256 if ( m_option == "CENTROID" || ( m_use_peakthreshold && nstrip>2 && peak_count==1) ) {
257 double scale_centroid = qerravg/qsum;
258 double xxsum =0;
259 for ( unsigned int istrip =0; istrip<nstrip; ++istrip ) {
260 StripFit sfit = sfits[istrip];
261 stripidx = strip0+istrip;
262 xxsum += (stripidx-strip_qmean)*(stripidx-strip_qmean);
263 }
264
265 res.dposition = pitch*scale_centroid*sqrt(xxsum);
266 ATH_MSG_VERBOSE ("qerravg:qsum:scale_centroid:xxsum:res.dposition= "
267 << qerravg << ":" << qsum << ":" << scale_centroid << ":"<< xxsum << ":"<< res.dposition);
268 }
269 }
270 */
271 ATH_MSG_VERBOSE(" Simple Fit Result "
272 << " nstr=" << nstrip << "[sector:wlay:measphi]= " << sector << ":" << wlay << ":" << measphi << " strip0=" << strip0
273 << " istrip_peak=" << istrip_peak << " peaktime=" << sfits[istrip_peak].time
274 << " peakstatus=" << sfits[istrip_peak].status << " peaktimeStatus=" << sfits[istrip_peak].timeStatus
275 << " pos=" << res.position << " dpos=" << res.dposition << " chg=" << qsum);
276
277 // cluster charge should be qsum over three strip... 3/21/2011
278 res.fstrip = 0;
279 res.lstrip = nstrip - 1;
280 res.time = sfits[istrip_peak].time;
281 res.timeStatus = sfits[istrip_peak].timeStatus;
282 res.qpeak = sfits[istrip_peak].charge;
283
284 res.charge = res.qpeak;
285 res.charge_beforeBPCorr = sfits[res.strip].charge_beforeBPCorr;
286
287 res.qleft = 0.;
288 res.qright = 0.;
289
290 if (istrip_peak >= 1) {
291 res.qleft = sfits[istrip_peak - 1].charge;
292 res.charge += res.qleft;
293 res.charge_beforeBPCorr += sfits[istrip_peak - 1].charge_beforeBPCorr;
294 }
295 if (istrip_peak + 1 < nstrip) {
296 res.qright = sfits[istrip_peak + 1].charge;
297 res.charge += res.qright;
298 res.charge_beforeBPCorr += sfits[istrip_peak + 1].charge_beforeBPCorr;
299 }
300 res.time_beforeT0Corr = sfits[res.strip].time_beforeT0Corr;
301 res.time_beforeBPCorr = sfits[res.strip].time_beforeBPCorr;
302
303 // res.charge = qsum;
304
305 results.emplace_back(res);
306 return results;
307}
308
309//**********************************************************************
310
311Results SimpleCscClusterFitter::fit(const StripFitList& sfits, double) const { return fit(sfits); }
312
313//**********************************************************************
314double SimpleCscClusterFitter::getCorrectedError(const CscPrepData* /*pclu*/, double /*slope*/) const { return 0; }
#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
std::vector< Result > Results
std::pair< std::vector< unsigned int >, bool > res
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< Result > Results
std::vector< StripFit > StripFitList
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).
const_pointer_type cptr()
Results fit(const StripFitList &sfits) const
ToolHandle< ICscAlignmentTool > m_alignmentTool
SimpleCscClusterFitter(const std::string &, const std::string &, const IInterface *)
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
double getCorrectedError(const Muon::CscPrepData *pclu, double slope) const
SG::ReadCondHandleKey< MuonGM::MuonDetectorManager > m_DetectorManagerKey
retrieve MuonDetectorManager from the conditions store
Identifier identify() const
return the identifier
CscClusterStatus
Enum to represent the cluster status - see the specific enum values for more details.
@ CscStatusSimple
Cluster with non-precision fit.
@ CscStatusUndefined
Undefined, should not happen, most likely indicates a problem.
@ CscStatusEdge
Cluster reaches the edge of plane.
@ CscStatusMultiPeak
More than one peak in cluster.