ATLAS Offline Software
STgcClusterBuilderCommon.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
8 #include "GaudiKernel/SystemOfUnits.h"
9 
11  : AthMessaging("STgcClusterBuilderCommon"),
12  m_stgcIdHelper(idHelper),
13  m_errorCalibData{errorCalibData}
14 {
15 }
16 
17 
18 //=============================================================================
19 std::array<std::vector<Muon::sTgcPrepData>, 8>
20 Muon::STgcClusterBuilderCommon::sortSTGCPrdPerLayer(std::vector<Muon::sTgcPrepData>&& stripPrds) const {
21 
22 
23  std::array<std::vector<Muon::sTgcPrepData>, 8> stgcPrdsPerLayer;
24  for (Muon::sTgcPrepData& prd : stripPrds) {
25  const Identifier id = prd.identify();
26  int layer = 4 * (m_stgcIdHelper.multilayer(id) - 1) + (m_stgcIdHelper.gasGap(id) - 1);
27  ATH_MSG_DEBUG("Sorting PRD into layer, layer: " << layer << " gas_gap: " << m_stgcIdHelper.gasGap(id)
28  << "multilayer: " << m_stgcIdHelper.multilayer(id));
29  stgcPrdsPerLayer.at(layer).push_back(std::move(prd));
30  }
31 
32  // sort prds by channel
33  for (unsigned int i_layer = 0; i_layer < stgcPrdsPerLayer.size(); i_layer++) {
34  std::sort(stgcPrdsPerLayer.at(i_layer).begin(), stgcPrdsPerLayer.at(i_layer).end(),
35  [this](const sTgcPrepData& a, const sTgcPrepData& b) {
36  return m_stgcIdHelper.channel(a.identify()) < m_stgcIdHelper.channel(b.identify());
37  });
38  }
39  return stgcPrdsPerLayer;
40 }
41 
42 
43 //=============================================================================
44 std::vector<std::vector<Muon::sTgcPrepData>> Muon::STgcClusterBuilderCommon::findStripCluster(std::vector<Muon::sTgcPrepData>&& strips,
45  const int maxMissingStrip) const {
46  std::vector<std::vector<Muon::sTgcPrepData>> clusters;
47 
48  if (strips.empty()) return clusters;
49 
50  // Get the Id of the first strip to verify all the strips are from the same layer
51  const Identifier& firstStripId = strips.front().identify();
52 
53  for (Muon::sTgcPrepData& prd : strips) {
54  // If no element has been added to the vector of clusters yet
55  if (clusters.empty()) {
56  clusters.emplace_back();
57  clusters.back().push_back(std::move(prd));
58  continue;
59  }
60 
61  const Identifier prd_id = prd.identify();
62  if (m_stgcIdHelper.multilayerID(firstStripId) != m_stgcIdHelper.multilayerID(prd_id) ||
63  m_stgcIdHelper.gasGap(firstStripId) != m_stgcIdHelper.gasGap(prd_id) ||
64  m_stgcIdHelper.channelType(firstStripId) != m_stgcIdHelper.channelType(prd_id)) {
65  ATH_MSG_WARNING("Strips must be separated by layer before attempting to build clusters,"
66  << " but found strips from different chambers");
67  continue;
68  }
69 
70  // Add another strip to a vector of clusters
71  if (std::abs(m_stgcIdHelper.channel(prd.identify()) -
72  m_stgcIdHelper.channel(clusters.back().back().identify())) > maxMissingStrip + 1) {
73  clusters.emplace_back();
74  }
75  clusters.back().push_back(std::move(prd));
76  }
77 
78  return clusters;
79 }
80 
81 
82 //=============================================================================
83 std::optional<Muon::STgcClusterPosition> Muon::STgcClusterBuilderCommon::weightedAverage(
84  const std::vector<Muon::sTgcPrepData>& cluster,
85  const double resolution,
86  bool isStrip) const
87 {
88 
89  if (cluster.empty()) {
90  ATH_MSG_VERBOSE("Skipping empty cluster");
91  return std::nullopt;
92  }
93 
94  double weightedPosX{0.0}, maxCharge{-1.0}, sumWeight{0.0}, sigmaSq{0.0};
95  Identifier clusterId;
97 
98  ATH_MSG_DEBUG("Running weighted average method on a cluster with " << cluster.size() << " strips");
99  for (const Muon::sTgcPrepData& prd : cluster) {
100  // Skip channel if its charge is negative
101  if (prd.charge() < 0) continue;
102 
103  double weight = isStrip ? prd.charge() : 1.0;
104  ATH_MSG_DEBUG("isStrip: " << isStrip << " weight: " << weight);
105 
106  weightedPosX += prd.localPosition().x()*weight;
107  sumWeight += weight;
108  sigmaSq += weight*weight*resolution*resolution;
109  clusDir += weight * NswClustering::toLocal(prd);
110  ATH_MSG_DEBUG("Channel local position and charge: " << prd.localPosition().x() << " " << prd.charge() );
111 
112  // Set the cluster identifier to the max charge strip
113  if (!isStrip) {
114  clusterId = prd.identify();
115  } else if (prd.charge() > maxCharge) {
116  maxCharge = prd.charge();
117  clusterId = prd.identify();
118  }
119  }
120 
121  // Charge in PRD is an integer, so the sum of weights should be greater than 1 unless the data is corrupted.
122  // Skip corrupted cluster
123  if (sumWeight < 1) {
124  ATH_MSG_VERBOSE("Got unexpected sum of weights: " << sumWeight);
125  return std::nullopt;
126  }
127 
128  // Mean position of the cluster
129  double reconstructedPosX = weightedPosX / sumWeight;
130  sigmaSq /= sumWeight;
131 
132  NswErrorCalibData::Input errorCalibIn{};
133  errorCalibIn.stripId = clusterId;
134  errorCalibIn.clusterAuthor = static_cast<unsigned>(sTgcPrepData::Author::SimpleClusterBuilder);
135  errorCalibIn.locPhi = clusDir.phi();
136  errorCalibIn.locTheta = clusDir.theta();
137  errorCalibIn.localPos = Amg::Vector2D{reconstructedPosX, 0};
138  errorCalibIn.clusterSize = cluster.size();
139 
140  const double localUncertainty = m_errorCalibData.clusterUncertainty(errorCalibIn);
141 
142  ATH_MSG_VERBOSE("Reconstructed a cluster using the weighted average,"
143  << " cluster Id: " << m_stgcIdHelper.print_to_string(clusterId)
144  <<", direction: "<<Amg::toString(clusDir.unit())
145  <<", theta: "<<clusDir.theta() / Gaudi::Units::deg
146  << ", mean position = " << reconstructedPosX
147  << ", uncertainty = " << localUncertainty
148  <<", sigmaSQ: "<<sigmaSq);
149 
150  return std::make_optional<Muon::STgcClusterPosition>(clusterId, reconstructedPosX, localUncertainty*localUncertainty);
151 }
152 
153 
154 //=============================================================================
155 std::optional<Muon::STgcClusterPosition> Muon::STgcClusterBuilderCommon::caruanaGaussianFitting(
156  const std::vector<sTgcPrepData>& cluster,
157  const double positionResolution,
158  const double angularResolution,
159  const MuonGM::MuonDetectorManager* detManager) const
160 {
161 
162  // Verify that there are 3 or more strips with non-zero charge, and the shape is not similar to a staircase
163  std::vector<int> charges;
164  charges.reserve(cluster.size());
165  std::vector<double> stripPositions;
166  stripPositions.reserve(cluster.size());
167  bool isStairUp{true}, isStairDown{true};
168  int multiplicity = 0;
169  for (unsigned int j = 0; j < cluster.size(); ++j){
170  int stripCharge = cluster.at(j).charge();
171  if (stripCharge > 0) {
172  multiplicity += 1;
173  charges.push_back(stripCharge);
174  stripPositions.push_back(cluster.at(j).localPosition().x());
175 
176  if (j > 0) {
177  int prevStripCharge = cluster.at(j-1).charge();
178  if (isStairUp && (stripCharge - prevStripCharge < 0))
179  isStairUp = false;
180  if (isStairDown && (prevStripCharge > 0) && (stripCharge - prevStripCharge > 0))
181  isStairDown = false;
182  }
183  }
184  }
185 
186  // Caruana fitting method doesn't support clusters having least than 3 strips or staircase-like clusters
187  if (multiplicity < 3 || isStairUp || isStairDown) {
188  if (msgLvl(MSG::VERBOSE)) {
189  std::stringstream sstr{};
190  for (const Muon::sTgcPrepData& prd : cluster) {
191  sstr << m_stgcIdHelper.print_to_string(prd.identify())
192  << ", local pos: ("<< prd.localPosition().x() << "," << prd.localPosition().y()
193  << "), charge: " << prd.charge() << ", time: " << static_cast<int>(prd.time())
194  << std::endl;
195  }
196  ATH_MSG_VERBOSE("Reject cluster incompatible with the Caruana method..." << std::endl << sstr.str());
197  }
198  return std::nullopt;
199  }
200 
201  // Here we implement the Caruana method to reconstruct the position of the cluster
202  AmgSymMatrix(3) elementPosMatrix;
203  for (int i=0; i<3; i++) {
204  for (int j=0; j<=i; j++) elementPosMatrix.fillSymmetric(i, j, 0);
205  }
206  Amg::Vector3D chargeVector(0., 0., 0.);
207 
208  // The reconstruction method becomes much simpiler when the strip positions are shifted such that
209  // the center of the cluster is at zero.
210  float clusterCenter = 0;
211  for (size_t i_strip = 0; i_strip < stripPositions.size(); i_strip++) {
212  clusterCenter += stripPositions.at(i_strip);
213  }
214  clusterCenter = clusterCenter / stripPositions.size();
215 
216  std::vector<double> stripPositions_shifted = {};
217  for (size_t i_strip = 0; i_strip < stripPositions.size(); i_strip++) {
218  stripPositions_shifted.push_back(stripPositions.at(i_strip)-clusterCenter);
219  }
220 
221  // Now build the matrix equation
222  for (size_t i_element = 0; i_element < stripPositions_shifted.size(); i_element++) {
223  elementPosMatrix.fillSymmetric(0, 0, elementPosMatrix(0,0) + 1);
224  elementPosMatrix.fillSymmetric(0, 1, elementPosMatrix(0,1) + stripPositions_shifted.at(i_element));
225  elementPosMatrix.fillSymmetric(0, 2, elementPosMatrix(0,2) + std::pow(stripPositions_shifted.at(i_element), 2));
226  elementPosMatrix.fillSymmetric(1, 2, elementPosMatrix(1,2) + std::pow(stripPositions_shifted.at(i_element), 3));
227  elementPosMatrix.fillSymmetric(2, 2, elementPosMatrix(2,2) + std::pow(stripPositions_shifted.at(i_element), 4));
228  const double log_charge = std::log(charges.at(i_element));
229  chargeVector(0) += log_charge;
230  chargeVector(1) += stripPositions_shifted.at(i_element) * log_charge;
231  chargeVector(2) += std::pow(stripPositions_shifted.at(i_element), 2) * log_charge;
232  }
233  elementPosMatrix(1,1) = elementPosMatrix(0,2);
234 
235  // If the matrix is singular then the reconstruction method will fail
236  if (elementPosMatrix.determinant() == 0) {
237  if (msgLvl(MSG::VERBOSE)) {
238  std::stringstream sstr{};
239  for (const Muon::sTgcPrepData& prd : cluster) {
240  sstr << m_stgcIdHelper.print_to_string(prd.identify())
241  << ", local pos: ("<< prd.localPosition().x() << "," << prd.localPosition().y()
242  << "), charge: " << prd.charge() << ", time: " << static_cast<int>(prd.time())
243  << std::endl;
244  }
245  ATH_MSG_VERBOSE("Failed to compute the position of the cluster..." << std::endl << sstr.str());
246  }
247  return std::nullopt;
248  }
249 
250  // Solve the matrix equation to find the Caruana parameters
251  Amg::Vector3D caruanaPars = (elementPosMatrix.inverse()) * chargeVector;
252 
253  // The 3rd parameter is related to the standard deviation: sigma = sqrt(-1 / (2 * caruanaPars(2))).
254  // Hence use the Caruana method if the std dev is small i.e. < 3*strip_pitch or caruanaPars(2) > -0.005,
255  // or if std dev is not physical i.e. caruanaPars(2) >= 0
256  double reconstructedPosX{0.};
257  if (caruanaPars(2) < -0.005) {
258  reconstructedPosX = clusterCenter - caruanaPars(1) / (2*caruanaPars(2));
259  } else {
260  if (msgLvl(MSG::VERBOSE)) {
261  std::stringstream sstr{};
262  for (const Muon::sTgcPrepData& prd : cluster) {
263  sstr << m_stgcIdHelper.print_to_string(prd.identify())
264  << ", local pos: ("<< prd.localPosition().x() << "," << prd.localPosition().y()
265  << "), charge: " << prd.charge() << ", time: " << static_cast<int>(prd.time())
266  << std::endl;
267  }
268  ATH_MSG_VERBOSE("Reject cluster with large standard deviation..." << std::endl << sstr.str());
269  }
270  return std::nullopt;
271  }
272 
273  // Find the channel that the cluster position reconstructs on top of and set the cluster id to its id
274  double minCenterDistance = 9999.99;
275  int channelIndex = 0;
276  for (size_t i_elem = 0; i_elem < cluster.size(); i_elem++) {
277  double strip_localPos = cluster.at(i_elem).localPosition().x();
278  if (minCenterDistance > abs(strip_localPos - reconstructedPosX)) {
279  minCenterDistance = abs(strip_localPos - reconstructedPosX);
280  channelIndex = i_elem;
281  }
282  }
283  const Identifier clusterId = cluster.at(channelIndex).identify();
284 
285  // Get the sTGC readoutElement and the strip pitch
286  const MuonGM::sTgcReadoutElement* detEl = detManager->getsTgcReadoutElement(clusterId);
287  const double stripPitch = detEl->channelPitch(clusterId);
288 
289  // If the reconstructed cluster position is far, such as one strip pitch, from any strip position in the cluster,
290  // then the Caruana reconstruction method isn't a good method to use.
291  if (minCenterDistance > stripPitch) {
292  if (msgLvl(MSG::VERBOSE)) {
293  std::stringstream sstr{};
294  for (const Muon::sTgcPrepData& prd : cluster) {
295  sstr << m_stgcIdHelper.print_to_string(prd.identify())
296  << ", local pos: ("<< prd.localPosition().x() << "," << prd.localPosition().y()
297  << "), charge: " << prd.charge() << ", time: " << static_cast<int>(prd.time())
298  << std::endl;
299  }
300  ATH_MSG_VERBOSE("Reject cluster since its position is more than " << stripPitch << " mm too far from the nearest strip..."
301  << std::endl << sstr.str());
302  }
303  return std::nullopt;
304  }
305 
306  // We denote caruanaPars = (a, b, c) and find the error on the b and c components
307  double gamma0 = 0;
308  double gamma2 = 0;
309  double gamma4 = 0;
310  for (size_t i_strip = 0; i_strip < stripPositions_shifted.size(); i_strip++) {
311  gamma0 += 1;
312  gamma2 += std::pow(stripPositions_shifted.at(i_strip), 2);
313  gamma4 += std::pow(stripPositions_shifted.at(i_strip), 4);
314  }
315 
316  // We also need the tan(theta) of the cluster
317  Amg::Vector3D globPos(0., 0., 0.);
318  detEl->stripGlobalPosition(clusterId, globPos);
319  double tan_theta = std::hypot(globPos.x(), globPos.y()) / globPos.z();
320  double spreadFactor = std::hypot(positionResolution, angularResolution * tan_theta);
321 
322  double sigma_b = spreadFactor / std::sqrt(gamma2);
323  double sigma_c = spreadFactor * std::sqrt(gamma0 / (gamma0 * gamma4 - gamma2 * gamma2));
324 
325  // Now propagate the Uncertainty to find the uncertainty on the mean
326  double sigmaSq = std::pow((1 / (2 * caruanaPars(2))) * sigma_b, 2) +
327  std::pow((caruanaPars(1) / (2 * caruanaPars(2) * caruanaPars(2))) * sigma_c, 2);
328 
329  // Caruana method fails, if the uncertainty on the mean position is too large such as greater than 2mm
330  if (sigmaSq > 4) {
331  if (msgLvl(MSG::VERBOSE)) {
332  std::stringstream sstr{};
333  for (const Muon::sTgcPrepData& prd : cluster) {
334  sstr << m_stgcIdHelper.print_to_string(prd.identify())
335  << ", local pos: ("<< prd.localPosition().x() << "," << prd.localPosition().y()
336  << "), charge: " << prd.charge() << ", time: " << static_cast<int>(prd.time())
337  << std::endl;
338  }
339  ATH_MSG_VERBOSE("Reject cluster with large error on the mean position..." << std::endl << sstr.str());
340  }
341  return std::nullopt;
342  }
343 
344 
345  Amg::Vector3D globalClusterPos {detEl->surface(clusterId).transform()*Amg::Vector3D{reconstructedPosX, 0,0}};
346  Amg::Vector3D clusDir{ NswClustering::toLocal(detEl->surface(clusterId), globalClusterPos) };
347 
348  NswErrorCalibData::Input errorCalibIn{};
349  errorCalibIn.stripId = clusterId;
350  errorCalibIn.clusterAuthor = static_cast<unsigned>(sTgcPrepData::Author::Caruana);
351  errorCalibIn.clusterError = std::sqrt(sigmaSq);
352  errorCalibIn.locPhi = clusDir.phi();
353  errorCalibIn.locTheta = clusDir.theta();
354  errorCalibIn.localPos = Amg::Vector2D{reconstructedPosX, 0};
355  errorCalibIn.clusterSize = cluster.size();
356 
357  const double localUncertainty = m_errorCalibData.clusterUncertainty(errorCalibIn);
358 
359  ATH_MSG_DEBUG("Reconstructed a cluster using the Caruana method,"
360  << " cluster Id: " << m_stgcIdHelper.print_to_string(clusterId)
361  << ", mean position = " << reconstructedPosX
362  << ", uncertainty = " << std::sqrt(sigmaSq));
363 
364  return std::make_optional<Muon::STgcClusterPosition>(clusterId, reconstructedPosX, localUncertainty*localUncertainty);
365 }
NswErrorCalibData
Definition: NswErrorCalibData.h:19
Muon::STgcClusterBuilderCommon::sortSTGCPrdPerLayer
std::array< std::vector< sTgcPrepData >, 8 > sortSTGCPrdPerLayer(std::vector< sTgcPrepData > &&stripPrds) const
Separate the sTGC PRDs by layer, from 0 to 7, and sort the PRDs per layer in ascending order of strip...
Definition: STgcClusterBuilderCommon.cxx:20
Amg::Vector2D
Eigen::Matrix< double, 2, 1 > Vector2D
Definition: GeoPrimitives.h:48
conifer::pow
constexpr int pow(int x)
Definition: conifer.h:20
Muon::sTgcPrepData::Author::Caruana
@ Caruana
deg
#define deg
Definition: SbPolyhedron.cxx:17
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
Dedxcorrection::resolution
double resolution[nGasTypes][nParametersResolution]
Definition: TRT_ToT_Corrections.h:46
MuonGM::MuonClusterReadoutElement::surface
virtual const Trk::PlaneSurface & surface() const override
access to chamber surface (phi orientation), uses the first gas gap
Definition: MuonClusterReadoutElement.h:123
AmgSymMatrix
#define AmgSymMatrix(dim)
Definition: EventPrimitives.h:50
dqt_zlumi_pandas.weight
int weight
Definition: dqt_zlumi_pandas.py:189
sTgcPrepData.h
Amg::toString
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Definition: GeoPrimitivesToStringConverter.h:40
lumiFormat.i
int i
Definition: lumiFormat.py:85
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
TRT::Hit::layer
@ layer
Definition: HitInfo.h:79
MuonGM::sTgcReadoutElement
An sTgcReadoutElement corresponds to a single STGC module; therefore typicaly a barrel muon station c...
Definition: MuonDetDescr/MuonReadoutGeometry/MuonReadoutGeometry/sTgcReadoutElement.h:30
AthMessaging
Class to provide easy MsgStream access and capabilities.
Definition: AthMessaging.h:55
Muon::STgcClusterBuilderCommon::weightedAverage
std::optional< STgcClusterPosition > weightedAverage(const std::vector< sTgcPrepData > &cluster, const double resolution, bool isStrip) const
Compute the cluster position using the weighted average method.
Definition: STgcClusterBuilderCommon.cxx:83
MuonGM::sTgcReadoutElement::channelPitch
double channelPitch(const Identifier &id) const
Channel pitch.
Definition: MuonDetDescr/MuonReadoutGeometry/src/sTgcReadoutElement.cxx:578
NswErrorCalibData::Input::stripId
Identifier stripId
Identifier of the strip.
Definition: NswErrorCalibData.h:27
dumpTgcDigiThreshold.isStrip
list isStrip
Definition: dumpTgcDigiThreshold.py:33
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
MuonGM::sTgcReadoutElement::stripGlobalPosition
bool stripGlobalPosition(const Identifier &id, Amg::Vector3D &gpos) const
Definition: MuonDetDescr/MuonReadoutGeometry/MuonReadoutGeometry/sTgcReadoutElement.h:332
sTgcIdHelper
Definition: sTgcIdHelper.h:55
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
MuonDetectorManager.h
Muon::sTgcPrepData::Author::SimpleClusterBuilder
@ SimpleClusterBuilder
STgcClusterBuilderCommon.h
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:50
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
python.CaloCondTools.log
log
Definition: CaloCondTools.py:20
RunTileMonitoring.clusters
clusters
Definition: RunTileMonitoring.py:133
Muon::NswClustering::toLocal
Amg::Vector3D toLocal(const Trk::Surface &surf, const Amg::Vector3D &dir)
Rotates a direction vector into a local frame: x-axis : Parallell to the radial direction of the dete...
Definition: NswClusteringUtils.h:21
Muon::STgcClusterBuilderCommon::findStripCluster
std::vector< std::vector< sTgcPrepData > > findStripCluster(std::vector< sTgcPrepData > &&strips, const int maxMissingStrip) const
Find strip clusters, assuming the input vector of PRDs are sorted in ascending order of strip number.
Definition: STgcClusterBuilderCommon.cxx:44
NswErrorCalibData::Input
Helper struct to be parsed to the object to derive the specific error of the cluster.
Definition: NswErrorCalibData.h:25
python.Constants.VERBOSE
int VERBOSE
Definition: Control/AthenaCommon/python/Constants.py:14
MuonGM::MuonDetectorManager::getsTgcReadoutElement
const sTgcReadoutElement * getsTgcReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
Definition: MuonDetDescr/MuonReadoutGeometry/src/MuonDetectorManager.cxx:259
Muon::STgcClusterBuilderCommon::caruanaGaussianFitting
std::optional< STgcClusterPosition > caruanaGaussianFitting(const std::vector< sTgcPrepData > &cluster, const double positionResolution, const double angularResolution, const MuonGM::MuonDetectorManager *detManager) const
Method to fit analytically a cluster to a Gaussian function to obtain the position of the cluster The...
Definition: STgcClusterBuilderCommon.cxx:155
Muon::STgcClusterBuilderCommon::STgcClusterBuilderCommon
STgcClusterBuilderCommon(const sTgcIdHelper &idHelper, const NswErrorCalibData &errorCalibData)
Constructor.
Definition: STgcClusterBuilderCommon.cxx:10
Muon::sTgcPrepData
Class to represent sTgc measurements.
Definition: sTgcPrepData.h:20
Trk::Surface::transform
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
generate::Zero
void Zero(TH1D *hin)
Definition: generate.cxx:32
Identifier
Definition: IdentifierFieldParser.cxx:14