TPCHitCluster_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: TPCHitCluster
3 // Plugin Type: producer (art v3_00_00)
4 // File: TPCHitCluster_module.cc
5 //
6 // Takes Hits and clusters them together
7 //
8 // Generated at Fri Feb 22 13:16:03 2019 by Thomas Junk using cetskelgen
9 // from cetlib version v3_04_00.
10 ////////////////////////////////////////////////////////////////////////
11 
20 #include "fhiclcpp/ParameterSet.h"
23 
24 #include <memory>
25 
26 #include "TMath.h"
29 #include "Geometry/GeometryGAr.h"
30 
31 namespace gar {
32 
33  namespace rec {
34 
35  class TPCHitCluster : public art::EDProducer {
36  public:
37  explicit TPCHitCluster(fhicl::ParameterSet const& p);
38  // The compiler-generated destructor is fine for non-base
39  // classes without bare pointers or other resource use.
40 
41  // Plugins should not be copied or assigned.
42  TPCHitCluster(TPCHitCluster const&) = delete;
43  TPCHitCluster(TPCHitCluster&&) = delete;
44  TPCHitCluster& operator=(TPCHitCluster const&) = delete;
46 
47  // Required functions.
48  void produce(art::Event& e) override;
49 
50  private:
51 
52  std::string fHitLabel; ///< label of module to get the hits from
53  int fClusterHits; ///< hit clustering algorithm number
54  float fHitClusterDx; ///< range in cm to look for hits to cluster in x
55  float fHitClusterDyDz; ///< range in cm to look for hits to cluster in y and z
56 
57  float fHitClusterDr_I; ///< range in R to look for hits to cluster for IROC, in cm
58  float fHitClusterDfi_I; ///< range in R*dPhi to look for hits to cluster for IROC, in cm
59  float fHitClusterDrIO; ///< range in R to look for hits to cluster for IOROC, in cm
60  float fHitClusterDfiIO; ///< range in R*dPhi to look for hits to cluster for IROC, in cm
61  float fHitClusterDrOO; ///< range in R to look for hits to cluster for OOROC, in cm
62  float fHitClusterDfiOO; ///< range in R*dPhi to look for hits to cluster for IROC, in cm
63 
64  int fPrintLevel; ///< debug printout: 0: none, 1: selected, 2: all
65 
66  };
67 
68 
69 
70 //==============================================================================
71 //==============================================================================
72 //==============================================================================
74  : EDProducer{p}
75  {
76  fHitLabel = p.get<std::string>("HitLabel","hit");
77  fPrintLevel = p.get<int>("PrintLevel",0);
78  fClusterHits = p.get<int>("ClusterHits",1);
79  fHitClusterDx = p.get<float>("HitClusterDx", 1.00);
80  fHitClusterDyDz = p.get<float>("HitClusterDyDz", 1.20);
81  fHitClusterDr_I = p.get<float>("HitClusterDr_I", 1.50);
82  fHitClusterDfi_I = p.get<float>("HitClusterDfi_I",1.06);
83  fHitClusterDrIO = p.get<float>("HitClusterDrIO", 2.00);
84  fHitClusterDfiIO = p.get<float>("HitClusterDfiIO",1.55);
85  fHitClusterDrOO = p.get<float>("HitClusterDrOO", 3.00);
86  fHitClusterDfiOO = p.get<float>("HitClusterDfiO)",1.73);
87 
88  art::InputTag hitTag(fHitLabel);
89  consumes< std::vector<gar::rec::Hit> >(hitTag);
90  produces< std::vector<gar::rec::TPCCluster> >();
91  produces< art::Assns<gar::rec::Hit, gar::rec::TPCCluster> >();
92  }
93 
94 
95 
96 //==============================================================================
97 //==============================================================================
98 //==============================================================================
100  {
102  float xtpccent = euclid->TPCXCent();
103  float ytpccent = euclid->TPCYCent();
104  float ztpccent = euclid->TPCZCent();
105 
106  // input: hits
107 
108  auto hitHandle = e.getValidHandle< std::vector<gar::rec::Hit> >(fHitLabel);
109  auto const& hits = *hitHandle;
110 
111  // output: TPCCluster and associations with hits
112 
113  std::unique_ptr<std::vector<gar::rec::TPCCluster> > TPCClusterCol (new std::vector<gar::rec::TPCCluster> );
114  std::unique_ptr<art::Assns<gar::rec::Hit,gar::rec::TPCCluster> > hitClusterAssns(new ::art::Assns<gar::rec::Hit,gar::rec::TPCCluster>);
115 
116  auto const TPCClusterPtrMaker = art::PtrMaker<gar::rec::TPCCluster>(e);
117  auto const hitPtrMaker = art::PtrMaker<rec::Hit>(e, hitHandle.id());
118 
119  size_t nhits = hits.size();
120  std::vector<float> hptmp(nhits);
121  std::vector<int> hsi(nhits);
122  std::vector<int> used(nhits,0);
123 
124  // sort hits by position in x
125 
126  for (size_t ihit=0;ihit<nhits;++ihit)
127  {
128  hptmp[ihit] = hits.at(ihit).Position()[0];
129  }
130  TMath::Sort( (int) nhits, hptmp.data(), hsi.data() );
131 
132  // loop through hits in x, clustering as we go, marking hits as used.
133 
134  for (size_t ihitx=0; ihitx< nhits; ++ihitx)
135  {
136  size_t ihit = hsi[ihitx]; // unwound index to hit array
137  if (used[ihit]) continue;
138 
139  const float *xyz_fromhit = hits.at(ihit).Position();
140  float xyz[3] = {xyz_fromhit[0] -xtpccent, xyz_fromhit[1] -ytpccent, xyz_fromhit[2] -ztpccent};
141 
142  // start a cluster with just this hit
143  std::vector<size_t> hitsinclus; // keep track of hit indices in this cluster so we can make associations
144  hitsinclus.push_back(ihit);
145  used[ihit] = 1;
146 
147  int side=0; // detector side of the seed hit.
148  auto hitchan = hits.at(ihit).Channel();
149  float chanpos[3] = {0,0,0};
150  euclid->ChannelToPosition(hitchan, chanpos);
151  if (chanpos[0] > xtpccent)
152  {
153  side = 1;
154  }
155  else
156  {
157  side = -1;
158  }
159 
160  // Clusters can be displaced in time. We may want to save which end of the
161  // chamber the data came from however and not cluster together charge
162  // that comes from different sides.
163 
164  if (fPrintLevel > 1)
165  {
166  std::cout << "Started a new TPC cluster. Pos= " << xyz[0] << " " << xyz[1] << " " << xyz[2] << std::endl;
167  std::cout << "Side: " << side << std::endl;
168  }
169 
170  // Determine cluster position in endcap for cuts to accumulate more hits
171  float rHit = std::hypot(xyz[1],xyz[2]);
172  bool In_CROC = rHit < euclid->GetIROCInnerRadius();
173  bool In_IROC = euclid->GetIROCInnerRadius() < rHit && rHit < euclid->GetIROCOuterRadius();
174  bool InIOROC = euclid->GetOROCInnerRadius() < rHit && rHit < euclid->GetOROCPadHeightChangeRadius();
175  bool InOOROC = euclid->GetOROCPadHeightChangeRadius() < rHit && rHit < euclid->GetOROCOuterRadius();
176 
177  for (size_t ix = ihitx+1; ix<nhits; ++ix) // look for candidate hits to cluster in with this one
178  {
179  size_t ihc = hsi[ix]; // candidate hit to add to the cluster if it's in range
180  if (used[ihc]) continue;
181 
182  int sidetest = 0;
183  auto hitchantest = hits.at(ihc).Channel();
184  float chanpostest[3] = {0,0,0};
185  euclid->ChannelToPosition(hitchantest, chanpostest);
186  if (chanpostest[0] > xtpccent)
187  {
188  sidetest = 1;
189  }
190  else
191  {
192  sidetest = -1;
193  }
194  if (sidetest != side) continue; // don't cluster hits that were detected on opposite TPC endplates.
195 
196  const float *xyz2_fromhit = hits.at(ihc).Position();
197  float xyz2[3] = {xyz2_fromhit[0] -xtpccent, xyz2_fromhit[1] -ytpccent, xyz2_fromhit[2] -ztpccent};
198 
199  if (fPrintLevel > 1)
200  {
201  std::cout << " Testing a hit: " << xyz2[0] << " " << xyz2[1] << " " << xyz2[2] << " " << sidetest << " "
202  << used[ihc] << " " << ihc << " " << ix << std::endl;
203  }
204 
205  // Check if hit ix is close to ihit, first in drift direction, then
206  // in transverse plane depending on which ROC has ihit
207  if ( fabs(xyz2[0] -xyz[0]) > fHitClusterDx ) break;
208 
209  if (In_CROC) {
210  if ( fabs(xyz2[1] -xyz[1]) > fHitClusterDyDz ) continue;
211  if ( fabs(xyz2[2] -xyz[2]) > fHitClusterDyDz ) continue;
212  }
213  // Project out the radial and rotational components of xyz2 -xyz.
214  float RhatY = xyz[1]/std::hypot(xyz[1],xyz[2]);
215  float RhatZ = xyz[2]/std::hypot(xyz[1],xyz[2]);
216  float clustDist = std::hypot(xyz2[1] -xyz[1],xyz2[2] -xyz[2]);
217  float dR = TMath::Abs((xyz2[1] -xyz[1])*RhatY +(xyz2[2] -xyz[2])*RhatZ);
218  float Rdfi = sqrt(clustDist*clustDist -dR*dR);
219  if (In_IROC) {
220  if (dR > fHitClusterDr_I) continue;
221  if (Rdfi > fHitClusterDfi_I) continue;
222  }
223  if (InIOROC) {
224  if (dR > fHitClusterDrIO) continue;
225  if (Rdfi > fHitClusterDfiIO) continue;
226  }
227  if (InOOROC) {
228  if (dR > fHitClusterDrOO) continue;
229  if (Rdfi > fHitClusterDfiOO) continue;
230  }
231 
232  // add hit to cluster
233  hitsinclus.push_back(ihc);
234  used[ihc] = 1;
235  if (fPrintLevel > 1)
236  {
237  std::cout << "Added hit with pos: " << xyz2[0] << " " << xyz2[1] << " " << xyz2[2] << std::endl;
238  }
239 
240  }
241 
242  // calculate cluster charge, centroid, min and max times, and covariance
243 
244  double cpos[3] = {0,0,0}; // charge-weighted cluster position
245  double csig = 0; // cluster signal total
246  double cstime = 0; // cluster start time
247  double cetime = 0; // cluster end time
248  double crms = 0; // cluster RMS in X
249  double ctime = 0; // cluster time centroid
250  double cov[3][3] = { {0,0,0}, {0,0,0}, {0,0,0} };
251 
252  for (size_t ix = 0; ix < hitsinclus.size(); ++ix)
253  {
254  size_t ihx = hitsinclus.at(ix);
255  double hsig = hits.at(ihx).Signal();
256  csig += hsig;
257  for (size_t idim=0; idim<3; ++idim)
258  {
259  cpos[idim] += hsig * hits.at(ihx).Position()[idim];
260  }
261  ctime += hsig * hits.at(ihx).Time();
262  if (ix == 0)
263  {
264  cstime = hits.at(ihx).StartTime();
265  cetime = hits.at(ihx).EndTime();
266  }
267  else
268  {
269  cstime = TMath::Min(cstime, (double) hits.at(ihx).StartTime());
270  cetime = TMath::Max(cetime, (double) hits.at(ihx).EndTime());
271  }
272  }
273  if (csig != 0)
274  {
275  ctime /= csig;
276  for (size_t idim=0; idim<3; ++idim)
277  {
278  cpos[idim] /= csig;
279  }
280 
281  // calculate covariance. Do a numerical sum over hit widths assuming Gaussians.
282 
283  for (size_t ix = 0; ix < hitsinclus.size(); ++ix)
284  {
285  size_t ihx = hitsinclus.at(ix);
286  double cfrac = hits.at(ihx).Signal()/csig;
287  const float *hpos = hits.at(ihx).Position();
288  for (size_t idim=0; idim<3; ++idim)
289  {
290  for (size_t jdim=0; jdim<3; ++jdim)
291  {
292  cov[idim][jdim] += cfrac*(hpos[idim]-cpos[idim])*(hpos[jdim]-cpos[jdim]);
293  }
294  }
295  cov[0][0] += cfrac*TMath::Sq(hits.at(ihx).RMS());
296  }
297  }
298  crms = TMath::Sqrt(cov[0][0]); // to mean what it meant before -- RMS along the drift direction
299 
300  float fcpos[3] = {0,0,0};
301  for (int i=0;i<3;++i)
302  {
303  fcpos[i] = cpos[i];
304  }
305  float fccov[6] = {(float) cov[0][0], (float) cov[1][0], (float) cov[2][0],
306  (float) cov[1][1], (float) cov[1][2], (float) cov[2][2]};
307 
308  TPCClusterCol->emplace_back(csig,
309  fcpos,
310  cstime,
311  cetime,
312  ctime,
313  crms,
314  fccov);
315 
316  if (fPrintLevel > 0)
317  {
318  std::cout << "Made a TPC Cluster pos: " << fcpos[0] << " " << fcpos[1] << " " << fcpos[2] <<
319  " signal: " << csig << " nHits: " << hitsinclus.size() << std::endl;
320  }
321  auto const TPCClusterPointer = TPCClusterPtrMaker(TPCClusterCol->size()-1);
322  for (size_t i=0; i<hitsinclus.size(); ++i)
323  {
324  auto const HitPointer = hitPtrMaker(hitsinclus.at(i));
325  hitClusterAssns->addSingle(HitPointer,TPCClusterPointer);
326  }
327 
328  }
329 
330  e.put(std::move(TPCClusterCol));
331  e.put(std::move(hitClusterAssns));
332 
333  }
334 
336 
337  } // namespace rec
338 } // namespace gar
float fHitClusterDyDz
range in cm to look for hits to cluster in y and z
float fHitClusterDr_I
range in R to look for hits to cluster for IROC, in cm
rec
Definition: tracks.py:88
std::string string
Definition: nybbler.cc:12
std::string fHitLabel
label of module to get the hits from
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.h:20
float fHitClusterDrOO
range in R to look for hits to cluster for OOROC, in cm
float fHitClusterDfi_I
range in R*dPhi to look for hits to cluster for IROC, in cm
std::enable_if_t< std::is_arithmetic_v< T >, T > hypot(T x, T y)
Definition: hypot.h:60
const double e
float fHitClusterDx
range in cm to look for hits to cluster in x
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
float fHitClusterDfiIO
range in R*dPhi to look for hits to cluster for IROC, in cm
float fHitClusterDrIO
range in R to look for hits to cluster for IOROC, in cm
def move(depos, offset)
Definition: depos.py:107
float fHitClusterDfiOO
range in R*dPhi to look for hits to cluster for IROC, in cm
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Definition: DataViewImpl.h:441
p
Definition: test.py:223
TPCHitCluster & operator=(TPCHitCluster const &)=delete
int fClusterHits
hit clustering algorithm number
General GArSoft Utilities.
TPCHitCluster(fhicl::ParameterSet const &p)
int fPrintLevel
debug printout: 0: none, 1: selected, 2: all
art framework interface to geometry description
QTextStream & endl(QTextStream &s)
void produce(art::Event &e) override