ATLAS Offline Software
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 
16 using Muon::CscPrepData;
19 
21 using Results = std::vector<Result>;
22 
23 namespace {
25 enum CscPlane { CSS_R, CSL_R, CSS_PHI, CSL_PHI, UNKNOWN_PLANE };
26 }
27 
28 SimpleCscClusterFitter::SimpleCscClusterFitter(const std::string& type, const std::string& aname, const IInterface* 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
48  return StatusCode::SUCCESS;
49 }
50 
51 //**********************************************************************
52 
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 
311 Results SimpleCscClusterFitter::fit(const StripFitList& sfits, double) const { return fit(sfits); }
312 
313 //**********************************************************************
314 double SimpleCscClusterFitter::getCorrectedError(const CscPrepData* /*pclu*/, double /*slope*/) const { return 0; }
SimpleCscClusterFitter::m_option
std::string m_option
Definition: SimpleCscClusterFitter.h:42
CSS
@ CSS
Definition: ParabolaCscClusterFitter.h:25
SG::ReadCondHandle
Definition: ReadCondHandle.h:44
ICscClusterFitter::Results
std::vector< Result > Results
Definition: ICscClusterFitter.h:101
SimpleCscClusterFitter::m_defaultErrorScaler_eta
double m_defaultErrorScaler_eta
Definition: SimpleCscClusterFitter.h:45
AthCommonDataStore< AthCommonMsg< AlgTool > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T > &t)
Definition: AthCommonDataStore.h:145
ICscStripFitter::Result::charge
double charge
Definition: ICscStripFitter.h:31
SimpleCscClusterFitter::getCorrectedError
double getCorrectedError(const Muon::CscPrepData *pclu, double slope) const
Definition: SimpleCscClusterFitter.cxx:314
CscStripPrepData.h
SimpleCscClusterFitter::m_use_peakthreshold
bool m_use_peakthreshold
Definition: SimpleCscClusterFitter.h:44
SimpleCscClusterFitter::fit
Results fit(const StripFitList &sfits) const
Definition: SimpleCscClusterFitter.cxx:53
SimpleCscClusterFitter::initialize
StatusCode initialize()
Definition: SimpleCscClusterFitter.cxx:40
MuonGM::CscReadoutElement
Definition: CscReadoutElement.h:56
CSS_PHI
@ CSS_PHI
Definition: ParabolaCscClusterFitter.h:26
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
SimpleCscClusterFitter::m_alignmentTool
ToolHandle< ICscAlignmentTool > m_alignmentTool
Definition: SimpleCscClusterFitter.h:54
python.Dumpers.aname
string aname
Definition: Dumpers.py:5541
SimpleCscClusterFitter::m_intrinsic_cluster_width
double m_intrinsic_cluster_width
Definition: SimpleCscClusterFitter.h:43
UNKNOWN_STATION
@ UNKNOWN_STATION
Definition: ParabolaCscClusterFitter.h:25
Muon::CscStripPrepData
Class representing the raw data of one CSC strip (for clusters look at Muon::CscPrepData).
Definition: CscStripPrepData.h:40
SimpleCscClusterFitter::m_idHelperSvc
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
Definition: SimpleCscClusterFitter.h:48
MuonGM::CscReadoutElement::maxNumberOfStrips
int maxNumberOfStrips(int measuresPhi) const
Definition: CscReadoutElement.cxx:162
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
ICscClusterFitter::Result
Definition: ICscClusterFitter.h:52
CscPrepData.h
MuonGM::MuonDetectorManager::getCscReadoutElement
const CscReadoutElement * getCscReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
Definition: MuonDetDescr/MuonReadoutGeometry/src/MuonDetectorManager.cxx:225
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::CscStatusSimple
@ CscStatusSimple
Cluster with non-precision fit.
Definition: CscClusterStatus.h:29
res
std::pair< std::vector< unsigned int >, bool > res
Definition: JetGroupProductTest.cxx:14
CscReadoutElement.h
test_pyathena.parent
parent
Definition: test_pyathena.py:15
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
SimpleCscClusterFitter::SimpleCscClusterFitter
SimpleCscClusterFitter(const std::string &, const std::string &, const IInterface *)
Definition: SimpleCscClusterFitter.cxx:28
ICscStripFitter::Result
Definition: ICscStripFitter.h:25
Muon::CscStatusUndefined
@ CscStatusUndefined
Undefined, should not happen, most likely indicates a problem.
Definition: CscClusterStatus.h:94
CscClusterStatus.h
Trk::PrepRawData::identify
Identifier identify() const
return the identifier
Result
Definition: fbtTestBasics.cxx:47
SimpleCscClusterFitter::m_defaultErrorScaler_phi
double m_defaultErrorScaler_phi
Definition: SimpleCscClusterFitter.h:46
charge
double charge(const T &p)
Definition: AtlasPID.h:494
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
Result
ICscClusterFitter::Result Result
Definition: SimpleCscClusterFitter.cxx:20
CaloSwCorrections.time
def time(flags, cells_name, *args, **kw)
Definition: CaloSwCorrections.py:242
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
SimpleCscClusterFitter::m_DetectorManagerKey
SG::ReadCondHandleKey< MuonGM::MuonDetectorManager > m_DetectorManagerKey
retrieve MuonDetectorManager from the conditions store
Definition: SimpleCscClusterFitter.h:51
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
CscStation
CscStation
Definition: ParabolaCscClusterFitter.h:25
convertTimingResiduals.offset
offset
Definition: convertTimingResiduals.py:71
UNKNOWN_PLANE
@ UNKNOWN_PLANE
Definition: ParabolaCscClusterFitter.h:26
merge.status
status
Definition: merge.py:17
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
CSL
@ CSL
Definition: ParabolaCscClusterFitter.h:25
CscPlane
CscPlane
Definition: ParabolaCscClusterFitter.h:26
CSL_PHI
@ CSL_PHI
Definition: ParabolaCscClusterFitter.h:26
Muon::CscStatusEdge
@ CscStatusEdge
Cluster reaches the edge of plane.
Definition: CscClusterStatus.h:34
SimpleCscClusterFitter.h
MuonGM::CscReadoutElement::cathodeReadoutPitch
double cathodeReadoutPitch(int chLayer, int measuresPhi) const
Definition: CscReadoutElement.cxx:147