LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
LineMerger_module.cc
Go to the documentation of this file.
1 //
3 // LineMerger class
4 //
5 // maddalena.antonello@lngs.infn.it
6 // ornella.palamara@lngs.infn.it
7 // biagio.rossi@lhep.unibe.ch
8 // msoderbe@syr.edu
9 // joshua.spitz@yale.edu
10 //
11 // This algorithm is designed to merge 2D lines with similar slope and endpoints
12 //
14 
15 #include <array>
16 #include <cmath> // std::abs(), std::sqrt()
17 #include <iomanip>
18 #include <memory> // std::unique_ptr<>
19 #include <string>
20 #include <utility> // std::move()
21 
22 //Framework includes:
29 #include "fhiclcpp/ParameterSet.h"
31 
32 //LArSoft includes:
44 
45 namespace cluster {
46 
47  class LineMerger : public art::EDProducer {
48  public:
49  explicit LineMerger(fhicl::ParameterSet const& pset);
50 
51  private:
52  void produce(art::Event& evt) override;
53 
54  std::string fClusterModuleLabel;
55  double fSlope; // tolerance for matching angles between two lines (in units of radians)
56  double fEndpointWindow; // tolerance for matching endpoints (in units of time samples)
57 
58  bool SlopeCompatibility(double slope1, double slope2);
59  int EndpointCompatibility(float sclstartwire,
60  float sclstarttime,
61  float sclendwire,
62  float sclendtime,
63  float cl2startwire,
64  float cl2starttime,
65  float cl2endwire,
66  float cl2endtime);
67 
68  }; // class LineMerger
69 
71  class ClusterMerger {
72  public:
73  // NOTE if you feel like copying this class, move it into its own header
74  // instead, and if you need it for a different hit or hit pointer, make it
75  // a template instead
77  using HitVector_t = std::vector<HitPtr_t>;
78 
81 
82  /*
83  typedef enum {
84  clStart, ///< Represents the most likely start of the cluster
85  clEnd, ///< Represents the end, or the alternative start, of the cluster
86  NEnds, ///< End count
87  clFirstEnd = 0 ///< Just an alias for loops
88  } ClusterEnds_t; ///< Used to decide which end to use
89  */
90 
91  ClusterMerger() = default;
92 
93  ClusterMerger(recob::Cluster const& cluster) : ClusterMerger() { Add(cluster); }
94 
110  bool Add(recob::Cluster const& cluster);
111 
114 
116  float StartWire() const { return fEndWires[ClusterEnds_t::clStart]; }
117 
119  float StartTick() const { return fEndTicks[ClusterEnds_t::clStart]; }
120 
122  float SigmaStartWire() const { return fSigmaEndWires[ClusterEnds_t::clStart]; }
123 
124  // Returns the uncertainty on tick coordinate of the start of the cluster
125  float SigmaStartTick() const { return fSigmaEndTicks[ClusterEnds_t::clStart]; }
126 
128  float EndWire() const { return fEndWires[ClusterEnds_t::clEnd]; }
129 
131  float EndTick() const { return fEndTicks[ClusterEnds_t::clEnd]; }
132 
134  float SigmaEndWire() const { return fSigmaEndWires[ClusterEnds_t::clEnd]; }
135 
137  float SigmaEndTick() const { return fSigmaEndTicks[ClusterEnds_t::clEnd]; }
138 
140  float WireCoord(ClusterEnds_t side) const { return fEndWires[side]; }
141  // float WireCoord(unsigned int side) const { return fEndWires[side]; }
142 
144  float TickCoord(ClusterEnds_t side) const { return fEndTicks[side]; }
145  // float TickCoord(unsigned int side) const { return fEndTicks[side]; }
146 
148  float SigmaWireCoord(ClusterEnds_t side) const { return fSigmaEndWires[side]; }
149  // float SigmaWireCoord(unsigned int side) const { return fSigmaEndWires[side]; }
150 
152  float SigmaTickCoord(ClusterEnds_t side) const { return fSigmaEndTicks[side]; }
153  // float SigmaTickCoord(unsigned int side) const { return fSigmaEndTicks[side]; }
154 
156  float StartCharge() const { return fEndCharges[ClusterEnds_t::clStart]; }
157 
159  float StartAngle() const { return fAngles[ClusterEnds_t::clStart]; }
160 
162  float StartOpeningAngle() const { return fOpeningAngles[ClusterEnds_t::clStart]; }
163 
165  float EndCharge() const { return fEndCharges[ClusterEnds_t::clEnd]; }
166 
168  float EndAngle() const { return fAngles[ClusterEnds_t::clEnd]; }
169 
171  float EndOpeningAngle() const { return fOpeningAngles[ClusterEnds_t::clEnd]; }
172 
174  float EdgeCharge(ClusterEnds_t side) const { return fEndCharges[side]; }
175  // float EdgeCharge(unsigned int side) const { return fEndCharges[side]; }
176 
178  float Angle(ClusterEnds_t side) const { return fAngles[side]; }
179  // float Angle(unsigned int side) const { return fAngles[side]; }
180 
182  float OpeningAngle(ClusterEnds_t side) const { return fOpeningAngles[side]; }
183  // float OpeningAngle(unsigned int side) const { return fOpeningAngles[side]; }
184 
186  float Width() const { return fWidth; }
187 
189  geo::View_t View() const { return fView; }
190 
192  geo::PlaneID Plane() const { return fPlaneID; }
193 
195  bool hasPlane() const { return Plane().isValid; }
196 
197  protected:
199  float fEndWires[ClusterEnds_t::NEnds];
200 
202  float fSigmaEndWires[ClusterEnds_t::NEnds];
203 
205  float fEndTicks[ClusterEnds_t::NEnds];
206 
208  float fSigmaEndTicks[ClusterEnds_t::NEnds];
209 
211  float fEndCharges[ClusterEnds_t::NEnds];
212 
214  float fAngles[ClusterEnds_t::NEnds];
215 
217  float fOpeningAngles[ClusterEnds_t::NEnds];
218 
220  float fWidth;
221 
223 
225 
226  unsigned int n_clusters = 0;
227 
229  void AdoptEnd(recob::Cluster const& cluster, ClusterEnds_t iEnd);
230 
231  template <typename T>
232  static void top(T& var, T value)
233  {
234  if (value > var) var = value;
235  }
236  template <typename T>
237  static void bot(T& var, T value)
238  {
239  if (value < var) var = value;
240  }
241  }; // class ClusterMerger
242 
244  {
245  const ClusterEnds_t iDestEnd = iSrcEnd;
246  fEndWires[iDestEnd] = cluster.WireCoord(iSrcEnd);
247  fSigmaEndWires[iDestEnd] = cluster.SigmaWireCoord(iSrcEnd);
248  fEndTicks[iDestEnd] = cluster.TickCoord(iSrcEnd);
249  fSigmaEndTicks[iDestEnd] = cluster.SigmaTickCoord(iSrcEnd);
250  fEndCharges[iDestEnd] = cluster.EdgeCharge(iSrcEnd);
251  fAngles[iDestEnd] = cluster.Angle(iSrcEnd);
252  fOpeningAngles[iDestEnd] = cluster.OpeningAngle(iSrcEnd);
253  } // ClusterMerger::AdoptEnd()
254 
256  {
257  if (!cluster.isValid()) return false;
258 
259  if (n_clusters == 0) { // special case: we are still empty
260  AdoptEnd(cluster, ClusterEnds_t::clStart);
261  AdoptEnd(cluster, ClusterEnds_t::clEnd);
262  fWidth = cluster.Width();
263  fView = cluster.View();
264  fPlaneID = cluster.Plane();
265  ++n_clusters;
266  return true;
267  } // if empty
268 
269  if (cluster.View() != View()) return false;
270 
271  if (cluster.hasPlane() && hasPlane() && (cluster.Plane() != Plane())) return false;
272 
273  // this code has been moved here from the old recon::Cluster::operator+
274  // of recob::Cluster v13.
275  if (cluster.StartWire() < StartWire()) { // adopt the new start
276  AdoptEnd(cluster, ClusterEnds_t::clStart);
277  }
278  if (cluster.EndWire() < EndWire()) { // adopt the new end
279  AdoptEnd(cluster, ClusterEnds_t::clEnd);
280  }
281 
282  top(fWidth, cluster.Width()); // extend width
283 
284  if (!hasPlane()) fPlaneID = cluster.Plane();
285 
286  return true;
287  } // ClusterMerger::Add(Cluster)
288 
291  public:
292  // NOTE if you feel like copying this class, move it into its own header
293  // instead, and if you need it for a different hit or hit pointer, make it
294  // a template instead
296  using HitVector_t = std::vector<HitPtr_t>;
297 
298  ClusterAndHitMerger() = default;
299 
301  {
302  Add(cluster, cluster_hits);
303  }
304 
318  bool Add(recob::Cluster const& cluster, HitVector_t const& cluster_hits, bool prepend = false);
319 
322 
324  HitVector_t const& Hits() const { return hits; }
325 
327  unsigned int NHits() const { return hits.size(); }
328 
330 
331  protected:
333 
334  void AddHits(HitVector_t const& cluster_hits, bool prepend)
335  {
336  hits.insert(prepend ? hits.begin() : hits.end(), cluster_hits.begin(), cluster_hits.end());
337  } // AddHits()
338 
339  }; // class ClusterAndHitMerger
340 
342  HitVector_t const& cluster_hits,
343  bool prepend /* = false */
344  )
345  {
346  if (!ClusterMerger::Add(cluster)) return false;
347 
348  AddHits(cluster_hits, prepend);
349  return true;
350  } // ClusterAndHitMerger::Add()
351 
352  //-------------------------------------------------
354  : EDProducer{pset}
355  , fClusterModuleLabel(pset.get<std::string>("ClusterModuleLabel"))
356  , fSlope(pset.get<double>("Slope"))
357  , fEndpointWindow(pset.get<double>("EndpointWindow"))
358  {
359  produces<std::vector<recob::Cluster>>();
360  produces<art::Assns<recob::Cluster, recob::Hit>>();
361  }
362 
363  //------------------------------------------------------------------------------------//
365  {
366  // Get a Handle for the input Cluster object(s).
367  art::Handle<std::vector<recob::Cluster>> clusterVecHandle;
368  evt.getByLabel(fClusterModuleLabel, clusterVecHandle);
369 
370  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
371  auto const detProp =
373  util::GeometryUtilities const gser{*lar::providerFrom<geo::Geometry>(), clockData, detProp};
374 
375  constexpr size_t nViews = 3; // number of views we map
376 
377  //one vector for each view in the geometry (holds the index of the cluster)
378  std::array<std::vector<size_t>, nViews> ClsIndices;
379 
380  //vector with indicators for whether a cluster has been merged already
381  std::array<std::vector<int>, nViews> Cls_matches;
382 
383  // loop over the input Clusters
384  for (size_t i = 0; i < clusterVecHandle->size(); ++i) {
385 
386  //get a art::Ptr to each Cluster
387  art::Ptr<recob::Cluster> cl(clusterVecHandle, i);
388 
389  size_t view = 0;
390  switch (cl->View()) {
391  case geo::kU: view = 0; break;
392  case geo::kV: view = 1; break;
393  case geo::kZ: view = 2; break;
394  default: continue; // ignore this cluster and process the next one
395  } // end switch on view
396 
397  Cls_matches[view].push_back(0);
398  ClsIndices[view].push_back(i);
399  } // end loop over input clusters
400 
401  auto SuperClusters = std::make_unique<std::vector<recob::Cluster>>();
402  auto assn = std::make_unique<art::Assns<recob::Cluster, recob::Hit>>();
403 
404  // prepare the algorithm to compute the cluster characteristics;
405  // we use the "standard" one here; configuration would happen here,
406  // but we are using the default configuration for that algorithm
408 
409  art::FindManyP<recob::Hit> fmh(clusterVecHandle, evt, fClusterModuleLabel);
410 
411  for (size_t i = 0; i < nViews; ++i) {
412 
413  int clustersfound = 0; // how many merged clusters found in each plane
414  int clsnum1 = 0;
415 
416  for (size_t c = 0; c < ClsIndices[i].size(); ++c) {
417  if (Cls_matches[i][clsnum1] == 1) {
418  ++clsnum1;
419  continue;
420  }
421 
422  // make a new cluster to put into the SuperClusters collection
423  // because we want to be able to adjust it later;
424  // use the hits associated with the current cluster
425  recob::Cluster const& StartingCluster = clusterVecHandle->at(ClsIndices[i][c]);
426  ClusterAndHitMerger cl1(StartingCluster, fmh.at(ClsIndices[i][c]));
427  const recob::Cluster::ID_t clusterID = StartingCluster.ID();
428 
429  Cls_matches[i][clsnum1] = 1;
430  ++clustersfound;
431 
432  int clsnum2 = 0;
433  for (size_t c2 = 0; c2 < ClsIndices[i].size(); ++c2) {
434 
435  if (Cls_matches[i][clsnum2] == 1) {
436  ++clsnum2;
437  continue;
438  }
439 
440  const recob::Cluster& cl2(clusterVecHandle->at(ClsIndices[i][c2]));
441 
442  // check that the slopes are the same
443  // added 13.5 ticks/wirelength in ArgoNeuT.
444  // \todo need to make this detector agnostic
445  // would be nice to have a LArProperties function that returns ticks/wire.
446  bool sameSlope = SlopeCompatibility(cl1.StartAngle(), cl2.EndAngle()) ||
447  SlopeCompatibility(cl1.EndAngle(), cl2.StartAngle());
448 
449  // check that the endpoints fall within a circular window of each other
450  // done in place of intercept matching
451  int sameEndpoint = EndpointCompatibility(cl1.StartWire(),
452  cl1.StartTick(),
453  cl1.EndWire(),
454  cl1.EndTick(),
455  cl2.StartWire(),
456  cl2.StartTick(),
457  cl2.EndWire(),
458  cl2.EndTick());
459 
460  // if the slopes and end points are the same, combine the clusters
461  // note that after 1 combination cl1 is no longer what we started
462  // with
463  if (sameSlope && (sameEndpoint != 0)) {
464  // combine the hit collections too
465  // (find the hits associated with this second cluster);
466  // take into account order when merging hits from two clusters: doc-1776
467  // if sameEndpoint is 1, the new hits come first
468  cl1.Add(cl2, fmh.at(ClsIndices[i][c2]), sameEndpoint == 1);
469  Cls_matches[i][clsnum2] = 1;
470  }
471 
472  ++clsnum2;
473  } // end loop over second cluster iterator
474 
475  // now add the final version of cl1 to the collection of SuperClusters
476  // and create the association between the super cluster and the hits
477  ClusterParamAlgo.ImportHits(gser, cl1.Hits());
478 
479  // create the recob::Cluster directly in the vector
480  SuperClusters->emplace_back(cl1.StartWire(), // start_wire
481  cl1.SigmaStartWire(), // sigma_start_wire
482  cl1.StartTick(), // start_tick
483  cl1.SigmaStartTick(), // sigma_start_tick
484  cl1.StartCharge(), // start_charge
485  cl1.StartAngle(), // start_angle
486  cl1.StartOpeningAngle(), // start_opening
487  cl1.EndWire(), // end_wire
488  cl1.SigmaEndWire(), // sigma_end_wire
489  cl1.EndTick(), // end_time
490  cl1.SigmaEndTick(), // sigma_end_tick
491  cl1.EndCharge(), // end_charge
492  cl1.EndAngle(), // end_angle
493  cl1.EndOpeningAngle(), // end_opening
494  ClusterParamAlgo.Integral().value(), // integral
495  ClusterParamAlgo.IntegralStdDev().value(), // integral_stddev
496  ClusterParamAlgo.SummedADC().value(), // summedADC
497  ClusterParamAlgo.SummedADCStdDev().value(), // summedADC_stddev
498  ClusterParamAlgo.NHits(), // n_hits
499  ClusterParamAlgo.MultipleHitDensity(), // multiple_hit_density
500  cl1.Width(), // width
501  clusterID, // ID
502  cl1.View(), // view
503  cl1.Plane(), // planeID
504  recob::Cluster::Sentry // sentry
505  );
506 
507  util::CreateAssn(evt, *SuperClusters, cl1.Hits(), *assn);
508  ++clsnum1;
509 
510  } // end loop over first cluster iterator
511  } // end loop over planes
512 
513  mf::LogVerbatim("Summary") << std::setfill('-') << std::setw(175) << "-" << std::setfill(' ');
514  mf::LogVerbatim("Summary") << "LineMerger Summary:";
515  for (size_t i = 0; i < SuperClusters->size(); ++i)
516  mf::LogVerbatim("Summary") << SuperClusters->at(i);
517 
518  evt.put(std::move(SuperClusters));
519  evt.put(std::move(assn));
520  }
521 
522  //------------------------------------------------------------------------------------//
523  //checks the difference between angles of the two lines
524  bool LineMerger::SlopeCompatibility(double slope1, double slope2)
525  {
526  double sl1 = atan(slope1);
527  double sl2 = atan(slope2);
528 
529  //the units of fSlope are radians
530  return std::abs(sl1 - sl2) < fSlope;
531  }
532  //------------------------------------------------------------------------------------//
533  int LineMerger::EndpointCompatibility(float sclstartwire,
534  float sclstarttime,
535  float sclendwire,
536  float sclendtime,
537  float cl2startwire,
538  float cl2starttime,
539  float cl2endwire,
540  float cl2endtime)
541  {
542 
544  float distance =
545  std::sqrt((pow(sclendwire - cl2startwire, 2) * 13.5) + pow(sclendtime - cl2starttime, 2));
546 
547  //not sure if this line is necessary--spitz
548  float distance2 =
549  std::sqrt((pow(sclstartwire - cl2endwire, 2) * 13.5) + pow(sclstarttime - cl2endtime, 2));
550 
551  //determine which way the two clusters should be merged. TY
552  int comp = 0;
553  if (distance < fEndpointWindow)
554  comp = 1;
555  else if (distance2 < fEndpointWindow)
556  comp = -1;
557  return comp;
558  }
559 
561 
562 } // end namespace
float EndOpeningAngle() const
Returns the opening angle at the end of the cluster.
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
int EndpointCompatibility(float sclstartwire, float sclstarttime, float sclendwire, float sclendtime, float cl2startwire, float cl2starttime, float cl2endwire, float cl2endtime)
float EndWire() const
Returns the wire coordinate of the end of the cluster.
ClusterAndHitMerger(recob::Cluster const &cluster, HitVector_t const &cluster_hits)
float SigmaStartWire() const
Returns the uncertainty on wire coordinate of the start of the cluster.
Utilities related to art service access.
float StartAngle() const
Returns the starting angle of the cluster.
float SigmaWireCoord(ClusterEnds_t side) const
Returns the uncertainty on wire coordinate of one of the end sides of the cluster.
Definition: Cluster.h:414
float EdgeCharge(ClusterEnds_t side) const
Returns the charge on the first or last wire of the cluster.
float Angle(ClusterEnds_t side) const
Returns the angle at either end of the cluster.
Definition: Cluster.h:553
ClusterMerger(recob::Cluster const &cluster)
float SigmaTickCoord(ClusterEnds_t side) const
Returns the uncertainty on tick coordinate of one of the end sides of the cluster.
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
void AddHits(TCSlice &slc, Trajectory &tj, unsigned short ipt, bool &sigOK)
Definition: StepUtils.cxx:1113
Planes which measure V.
Definition: geo_types.h:136
float TickCoord(ClusterEnds_t side) const
Returns the tick coordinate of one of the end sides of the cluster.
Definition: Cluster.h:401
Declaration of signal hit object.
void produce(art::Event &evt) override
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.cc:6
The data type to uniquely identify a Plane.
Definition: geo_types.h:463
float EdgeCharge(ClusterEnds_t side) const
Returns the charge on the first or last wire of the cluster.
Definition: Cluster.h:528
float SigmaTickCoord(ClusterEnds_t side) const
Returns the uncertainty on tick coordinate of one of the end sides of the cluster.
Definition: Cluster.h:427
constexpr auto abs(T v)
Returns the absolute value of the argument.
float StartWire() const
Returns the wire coordinate of the start of the cluster.
Definition: Cluster.h:276
Planes which measure Z direction.
Definition: geo_types.h:138
Set of hits with a 2D structure.
Definition: Cluster.h:69
geo::PlaneID Plane() const
Returns the plane ID this cluster lies on.
Definition: Cluster.h:717
Cluster finding and building.
static void bot(T &var, T value)
Data referring to start and end of the cluster.
float fWidth
A measure of the cluster width, in homogenized units.
bool isValid() const
Returns if the cluster is valid (that is, if its ID is not invalid)
Definition: Cluster.h:725
float SigmaStartTick() const
Data referring to start and end of the cluster.
float StartWire() const
Returns the wire coordinate of the start of the cluster.
static const SentryArgument_t Sentry
An instance of the sentry object.
Definition: Cluster.h:174
float StartOpeningAngle() const
Returns the opening angle at the start of the cluster.
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: Event.h:77
LineMerger(fhicl::ParameterSet const &pset)
bool Add(recob::Cluster const &cluster, HitVector_t const &cluster_hits, bool prepend=false)
Merges a single cluster into this object.
Planes which measure U.
Definition: geo_types.h:135
float TickCoord(ClusterEnds_t side) const
Returns the tick coordinate of one of the end sides of the cluster.
void hits()
Definition: readHits.C:15
TCanvas * c2
Definition: plot_hist.C:75
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:65
static void top(T &var, T value)
Data referring to start and end of the cluster.
std::string fClusterModuleLabel
Wrapper for ClusterParamsAlgBase objects to accept diverse input.
void AdoptEnd(recob::Cluster const &cluster, ClusterEnds_t iEnd)
Imports all the member of the corresponding end.
float SigmaEndWire() const
Returns the uncertainty on wire coordinate of the end of the cluster.
float Width() const
A measure of the cluster width, in homogenized units.
Definition: Cluster.h:701
float SigmaEndTick() const
Returns the uncertainty on tick coordinate of the end of the cluster.
Wrapper for ClusterParamsAlgBase objects to accept arbitrary input.
float Angle(ClusterEnds_t side) const
Returns the angle at either end of the cluster.
Declaration of cluster object.
float WireCoord(ClusterEnds_t side) const
Returns the wire coordinate of one of the end sides of the cluster.
Definition: Cluster.h:374
Definition of data types for geometry description.
bool hasPlane() const
Returns whether geometry plane is valid.
float SigmaWireCoord(ClusterEnds_t side) const
Returns the uncertainty on wire coordinate of one of the end sides of the cluster.
double value
Definition: spectrum.C:18
float StartTick() const
Returns the tick coordinate of the start of the cluster.
Class merging clusters: recomputes start and end position and hit list.
float Width() const
A measure of the cluster width, in homogenized units.
HitVector_t hits
hits in the cluster
bool CreateAssn(art::Event &evt, std::vector< T > const &a, art::Ptr< U > const &b, art::Assns< U, T > &assn, std::string a_instance, size_t index=UINT_MAX)
Creates a single one-to-one association.
HitVector_t const & Hits() const
Returns a constant reference to the current list of hits.
geo::View_t View() const
Returns the view for this cluster.
Definition: Cluster.h:714
geo::View_t fView
View for this cluster.
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
float StartCharge() const
Returns the charge on the first wire of the cluster.
Utility object to perform functions of association.
float OpeningAngle(ClusterEnds_t side) const
Returns the opening angle at either end of the cluster.
ID_t ID() const
Identifier of this cluster.
Definition: Cluster.h:711
bool SlopeCompatibility(double slope1, double slope2)
unsigned int NHits() const
Number of hits in the cluster.
bool hasPlane() const
Returns whether geometry plane is valid.
Definition: Cluster.h:722
geo::View_t View() const
Returns the view for this cluster.
Interface to class computing cluster parameters.
TCEvent evt
Definition: DataStructs.cxx:8
geo::PlaneID Plane() const
Returns the plane ID this cluster lies on.
std::vector< HitPtr_t > HitVector_t
vector of pointers to hits
recob::tracking::Plane Plane
Definition: TrackState.h:17
Class merging clusters: recomputes start and end position and hit list.
float OpeningAngle(ClusterEnds_t side) const
Returns the opening angle at either end of the cluster.
Definition: Cluster.h:568
float EndAngle() const
Returns the ending angle of the cluster.
recob::Cluster::ID_t ID_t
Type of cluster ID.
float WireCoord(ClusterEnds_t side) const
Returns the wire coordinate of one of the end sides of the cluster.
art framework interface to geometry description
int ID_t
Type of cluster ID.
Definition: Cluster.h:72
void AddHits(HitVector_t const &cluster_hits, bool prepend)
geo::PlaneID fPlaneID
Location of the start of the cluster.
float EndCharge() const
Returns the charge on the last wire of the cluster.
float EndTick() const
Returns the tick coordinate of the end of the cluster.
bool Add(recob::Cluster const &cluster)
Merges a single cluster into this object.
float EndWire() const
Returns the wire coordinate of the end of the cluster.
Definition: Cluster.h:318