ATLAS Offline Software
Loading...
Searching...
No Matches
CscSplitClusterFitter.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
22using Results = std::vector<Result>;
23
24namespace {
27}
28
29//******************************************************************************
30
31CscSplitClusterFitter::CscSplitClusterFitter(const std::string& type, const std::string& aname, const IInterface* parent) :
32 AthAlgTool(type, aname, parent) {
33 declareInterface<ICscClusterFitter>(this);
34 declareProperty("min_dist", m_min_dist = 2); // Minimum distance between peaks and valley
35 declareProperty("max_qratio", m_max_qratio = 0.15); // Maximum charge ratio between peak strip and valley strip
36}
37
38//**********************************************************************
39
41 ATH_MSG_DEBUG("Initalizing " << name());
42
43 ATH_CHECK(m_idHelperSvc.retrieve());
44
45 // Retrieve the default cluster fitting tool.
47
48 ATH_MSG_DEBUG("CscClusterization " << name() << ": retrieved " << m_pfitter_def);
49
50 // Retrieve the precision cluster fitting tool.
52
53 ATH_MSG_DEBUG("CscClusterization " << name() << ": retrieved " << m_pfitter_prec);
54
55 ATH_MSG_DEBUG("Properties for " << name() << ":");
56 ATH_MSG_DEBUG(" Default cluster fitter is " << m_pfitter_def.typeAndName());
57 ATH_MSG_DEBUG(" Precision cluster fitter is " << m_pfitter_prec.typeAndName());
58 ATH_MSG_DEBUG(" Min dist peak to valley: " << m_min_dist);
59 ATH_MSG_DEBUG(" Max qratio qval / qpeak: " << m_max_qratio);
60
61 return StatusCode::SUCCESS;
62}
63//**********************************************************************
64
66 Results results;
67 // Check input has at least three strips.
68 unsigned int nstrip = sfits.size();
69 // Use the first strip to extract the layer parameters.
70 const CscStripPrepData* pstrip = sfits[0].strip;
71 Identifier idStrip0 = pstrip->identify();
72 bool measphi = m_idHelperSvc->cscIdHelper().CscIdHelper::measuresPhi(idStrip0);
73
74 // Display input strips.
75 ATH_MSG_DEBUG("CscStrip fittter input has " << nstrip << " strips");
76
77 for (unsigned int istrip = 0; istrip < nstrip; ++istrip) {
78 Identifier id = sfits[istrip].strip->identify();
79 ATH_MSG_VERBOSE(" " << istrip << " " << m_idHelperSvc->cscIdHelper().strip(id) << " " << sfits[istrip].charge);
80 }
81 // Find the peak strip and valley strip
82 // Loop over strips
83 std::vector<float> istrip_peaks;
84 std::vector<float> istrip_vals;
85
86 // Start peak all the time...
87 for (unsigned int istrip = 1; istrip < nstrip - 1; ++istrip) {
88 StripFit sfit = sfits[istrip];
89 float qthis = sfit.charge;
90 float qlast = sfits[istrip - 1].charge;
91 float qnext = sfits[istrip + 1].charge;
92 // Peak at first
93 if (istrip == 1 && qlast > qthis) istrip_peaks.push_back(0);
94 // Peak at last
95 if (istrip + 2 == nstrip && qthis < qnext) istrip_peaks.push_back(nstrip - 1);
96 // Peak if the adjacent strips have less charge.
97 bool ispeak = qthis > qlast && qthis > qnext;
98 bool isval = qthis < qlast && qthis < qnext;
99 // Record if peak.
100
101 if (ispeak) istrip_peaks.push_back(istrip);
102 if (isval) istrip_vals.push_back(istrip);
103 if (ispeak || isval) continue;
104
105 // It's only for istrip==1 and 0th and 1st charges are same....
106 if (istrip == 1 && qlast == qthis) {
107 float nstripsameCharge = 2.;
108 unsigned int theStrip = 0;
109 for (unsigned int mstrip = istrip + 1; mstrip < nstrip - 1; ++mstrip) {
110 theStrip = mstrip;
111 if (qthis == sfits[mstrip].charge)
112 nstripsameCharge += 1.;
113 else
114 break;
115 }
116 ispeak = (qthis > sfits[theStrip].charge);
117 isval = (qthis < sfits[theStrip].charge);
118 float offset = 0.5 * (nstripsameCharge - 1);
119 if (ispeak) istrip_peaks.push_back(offset);
120 // We want to start peak all the time...
121 // if ( isval ) istrip_vals.push_back(offset);
122 istrip += int(nstripsameCharge) - 2;
123 continue;
124 }
125
126 // Special case: next strip has the same charge.
127 // Require the previous strip has less charge and the next following
128 // strip be absent or have less charge.
129 if (qthis == qnext) {
130 float nstripsameCharge = 2.;
131 unsigned int theStrip = 0;
132 bool sameCharge = 1;
133 for (unsigned int mstrip = istrip + 2; mstrip < nstrip - 1; ++mstrip) {
134 theStrip = mstrip;
135 if (qthis == sfits[mstrip].charge)
136 nstripsameCharge += 1.;
137 else {
138 sameCharge = 0;
139 break;
140 }
141 }
142 if (sameCharge) {
143 ispeak = (qthis > qlast);
144 isval = (qthis < qlast);
145 } else {
146 ispeak = (qthis > qlast) && (qthis > sfits[theStrip].charge);
147 isval = (qthis < qlast) && (qthis < sfits[theStrip].charge);
148 }
149 float offset = 0.5 * (nstripsameCharge - 1);
150 if (ispeak) istrip_peaks.push_back(istrip + offset);
151 if (isval) istrip_vals.push_back(istrip + offset);
152 istrip += int(nstripsameCharge) - 1;
153 continue;
154 }
155 }
156
157 ATH_MSG_DEBUG(" #Peak is " << istrip_peaks.size());
158
159 // Decide in which valley strip we split cluster
160 // Starting from Peak all the time!!!
161 // Regular case : #peaks - #vals =1
162 // If #peaks == $vals, avoid it at the end of vals..
163
164 std::vector<unsigned int> splitOnValley;
165 for (unsigned int ival = 0; ival < istrip_vals.size() && ival + 1 < istrip_peaks.size(); ++ival) {
166 // Set initial strip position.
167 float istrip_peak0 = istrip_peaks[ival];
168 float istrip_peak1 = istrip_peaks[ival + 1];
169 float istrip_val = istrip_vals[ival];
170
171 float dist_ptov = istrip_val - istrip_peak0;
172 float dist_vtop = istrip_peak1 - istrip_val;
173
174 ATH_MSG_DEBUG(" [ " << istrip_peak0 << ", " << istrip_val << ", " << istrip_peak1 << "] "
175 << "dist p2v:v2p " << dist_ptov << " : " << dist_vtop);
176
177 if (dist_ptov < 0 || dist_vtop < 0) {
178 ATH_MSG_WARNING(" Peak-to-Val dist is " << dist_ptov << " Val-to-Peak dist is " << dist_vtop
179 << " Shouldnot be negative value :" << istrip_peak0 << " " << istrip_val << " "
180 << istrip_peak1);
181 }
182
183 float qlpeak = sfits[int(istrip_peak0)].charge;
184 float qval = sfits[int(istrip_val)].charge;
185 float qrpeak = sfits[int(istrip_peak1)].charge;
186
187 ATH_MSG_DEBUG("qlpk:qval:qrpk " << qlpeak << " " << qval << " " << qrpeak << " " << qval / qlpeak << " " << qval / qrpeak
188 << " " << m_max_qratio);
189
190 if (dist_ptov < m_min_dist || dist_vtop < m_min_dist || qval / qlpeak > m_max_qratio || qval / qrpeak > m_max_qratio)
191 splitOnValley.push_back(0);
192 else
193 splitOnValley.push_back(1);
194 }
195
196 unsigned int cnt = 0;
197 for (unsigned int ii = 0; ii < splitOnValley.size(); ii++)
198 if (splitOnValley[ii] == 1) cnt++;
199
200 if (cnt == 0) {
201 ATH_MSG_DEBUG("No split cluster ");
203 res.fitStatus = 6;
204 res.clusterStatus = Muon::CscStatusWide;
205 results.push_back(res);
206 return results;
207 }
208 ATH_MSG_DEBUG("Cluster is split ");
209
210 // For the last cluster and strip
211 unsigned int nvals = splitOnValley.size();
212 if (istrip_vals[nvals - 1] != nstrip - 1) {
213 istrip_vals.push_back(nstrip - 1);
214 splitOnValley.push_back(1);
215 nvals = splitOnValley.size();
216 }
217
218 // if (splitOnValley.size() != istrip_peaks.size())
219 // ATH_MSG_ERROR << " splitOnValley.size() should be same as istrip_peaks.size()" );
220
221 // Rearrange strips to submit in fitter
222 StripFitList sfits_split;
223 unsigned int firstStripID = 0;
224 unsigned int thisfirstStripID = 0;
225 for (unsigned int isplit = 0; isplit < nvals; ++isplit) {
226 if (splitOnValley[isplit]) {
227 sfits_split.clear();
228
229 for (unsigned int ist = firstStripID; ist <= istrip_vals[isplit]; ++ist) {
230 ATH_MSG_DEBUG(ist << " " << firstStripID << " " << istrip_vals << " lsplit " << splitOnValley);
231
232 sfits_split.push_back(sfits[ist]);
233 }
234 // unsigned int split_nstrip = istrip_vals[isplit]-firstStripID;
235 // bool ledge = (isplit==0 && strip0 <=0) ? 1 : 0;
236 // bool redge = (isplit==nvals-1 && strip0+nstrip>maxstrip) ? 1 : 0;
237
238 thisfirstStripID = firstStripID;
239 firstStripID = int(istrip_vals[isplit]);
240
241 int fitresult = 99;
242 std::vector<ICscClusterFitter::Result> local_results;
244 // Precision fit.
245 if (!measphi && m_pfitter_prec) {
246 ATH_MSG_VERBOSE(" In CscSplit performing precision fit with " << m_pfitter_prec);
247
248 local_results = m_pfitter_prec->fit(sfits_split);
249 res = local_results[0];
250 fitresult = res.fitStatus;
251 if (fitresult) {
252 ATH_MSG_VERBOSE(" Precision fit failed: return=" << fitresult);
253 } else {
254 ATH_MSG_VERBOSE(" Precision fit succeeded");
255 }
256 }
257
258 int prec_fitresult = fitresult;
259 CscClusterStatus oldclustatus = res.clusterStatus;
260 // Default fit.
261 if (fitresult) { // including measphi case
262 ATH_MSG_VERBOSE(" Performing default fit with " << m_pfitter_def);
263 local_results = m_pfitter_def->fit(sfits_split);
264 res = local_results[0];
265 fitresult = res.fitStatus;
266 if (fitresult) {
267 ATH_MSG_VERBOSE(" Default fit failed: return=" << fitresult);
268 } else {
269 ATH_MSG_VERBOSE(" Default fit succeeded");
270 }
271 // Keep the status from the first fit if it is defined.
272 if (oldclustatus != Muon::CscStatusUndefined) res.clusterStatus = oldclustatus;
273 }
274
275 if (prec_fitresult) { // precision fitter is failed...
276 res.fitStatus = 20 + prec_fitresult;
277
278 if (oldclustatus == Muon::CscStatusSimple)
279 res.clusterStatus = Muon::CscStatusSplitSimple;
280 else if (oldclustatus == Muon::CscStatusEdge)
281 res.clusterStatus = Muon::CscStatusSplitEdge;
282 else if (oldclustatus == Muon::CscStatusMultiPeak)
283 res.clusterStatus = Muon::CscStatusSplitMultiPeak;
284 else if (oldclustatus == Muon::CscStatusNarrow)
285 res.clusterStatus = Muon::CscStatusSplitNarrow;
286 else if (oldclustatus == Muon::CscStatusWide)
287 res.clusterStatus = Muon::CscStatusSplitWide;
288 else if (oldclustatus == Muon::CscStatusSkewed)
289 res.clusterStatus = Muon::CscStatusSplitSkewed;
290 else if (oldclustatus == Muon::CscStatusQratInconsistent)
292 else if (oldclustatus == Muon::CscStatusStripFitFailed)
294 else if (oldclustatus == Muon::CscStatusSaturated)
295 res.clusterStatus = Muon::CscStatusSplitSaturated;
296
297 } else { // precision fit is successful
298 res.fitStatus = 20;
299 res.clusterStatus = Muon::CscStatusSplitUnspoiled;
300 }
301 // strip in Result class is filled by Qrat or SimpleClusterFitter which is only relevant to the cluster
302 // passed by CscSplitCluster. This should be corrected here.
303 // fstrip and lstrip should be defined in CscSplitClusterFitter but not for the other fitter.
304 res.strip = res.strip + thisfirstStripID;
305 res.fstrip = res.fstrip + thisfirstStripID;
306 res.lstrip = res.lstrip + thisfirstStripID;
307
308 ATH_MSG_DEBUG(" res.fitStatus " << res.fitStatus << " fitresult " << fitresult);
309
310 results.push_back(res);
311 }
312 } // for
313
314 return results;
315}
316
317//**********************************************************************
318
319Results CscSplitClusterFitter::fit(const StripFitList& sfits, double) const { return fit(sfits); }
320
321//**********************************************************************
322double CscSplitClusterFitter::getCorrectedError(const CscPrepData* /*pclu*/, double /*slope*/) const { return 0; }
#define ATH_CHECK_RECOVERABLE
Evaluate an expression and check for errors.
#define ATH_CHECK
Evaluate an expression and check for errors.
#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
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)
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
ToolHandle< ICscClusterFitter > m_pfitter_prec
Results fit(const StripFitList &sfits) const
double getCorrectedError(const Muon::CscPrepData *pclu, double slope) const
CscSplitClusterFitter(const std::string &, const std::string &, const IInterface *)
ToolHandle< ICscClusterFitter > m_pfitter_def
ICscStripFitter::Result StripFit
std::vector< std::string > DataNames
std::vector< Result > Results
std::vector< StripFit > StripFitList
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).
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.
@ CscStatusStripFitFailed
@ CscStatusSplitQratInconsistent
Positions from Qrat_left and Qrat_right is not consistent after split cluster.
@ CscStatusUndefined
Undefined, should not happen, most likely indicates a problem.
@ CscStatusSplitStripFitFailed
@ CscStatusSkewed
Skewed, e.g.
@ CscStatusSplitUnspoiled
Clean cluster with precision fit after split cluster.
@ CscStatusEdge
Cluster reaches the edge of plane.
@ CscStatusWide
Too wide.
@ CscStatusSplitWide
Too wide.
@ CscStatusSplitEdge
Cluster reaches the edge of plane after split cluster.
@ CscStatusSplitSaturated
@ CscStatusSplitSimple
Cluster with non-precision fit after split cluster.
@ CscStatusMultiPeak
More than one peak in cluster.
@ CscStatusSplitSkewed
Skewed, e.g.
@ CscStatusSaturated
@ CscStatusSplitNarrow
Too narrow after split cluster.
@ CscStatusSplitMultiPeak
More than one peak in cluster after split cluster.
@ CscStatusQratInconsistent
Positions from Qrat_left and Qrat_right is not consistent.
@ CscStatusNarrow
Too narrow.