Shower2DLinearRegressionTrackHitFinder_tool.cc
Go to the documentation of this file.
1 //############################################################################
2 //### Name: Shower2DLinearRegressionTrackHitFinder ###
3 //### Author: Dominic Barker (dominic.barker@sheffield.ac.uk) ###
4 //### Date: 13.05.19 ###
5 //### Description: Tool for finding the initial shower track using a rms ###
6 //### based method to define when the shower starts to ###
7 //### shower. This methd is derived from the EMShower_module ###
8 //############################################################################
9 
10 //Framework Includes
12 
13 //LArSoft Includes
16 
17 namespace ShowerRecoTools {
18 
20  public:
22 
23  //Calculate the 2D initial track hits
24  int CalculateElement(const art::Ptr<recob::PFParticle>& pfparticle,
26  reco::shower::ShowerElementHolder& ShowerEleHolder) override;
27 
28  private:
29  //Function to find the
30  std::vector<art::Ptr<recob::Hit>> FindInitialTrackHits(
31  const detinfo::DetectorPropertiesData& detProp,
33 
34  //Function to perform a weighted regression fit.
35  Int_t WeightedFit(const Int_t n,
36  const Double_t* x,
37  const Double_t* y,
38  const Double_t* w,
39  Double_t* parm);
40 
41  //fcl parameters
42  unsigned int fNfitpass; //Number of time to fit the straight
43  //line the hits.
44  std::vector<unsigned int> fNfithits; //Max number of hits to fit to.
45  std::vector<double> fToler; //Tolerance or each interaction.
46  //Defined as the perpendicualar
47  //distance from the best fit line.
48  bool fApplyChargeWeight; //Apply charge weighting to the fit.
50  int fVerbose;
56  };
57 
59  const fhicl::ParameterSet& pset)
60  : IShowerTool(pset.get<fhicl::ParameterSet>("BaseTools"))
61  , fNfitpass(pset.get<unsigned int>("Nfitpass"))
62  , fNfithits(pset.get<std::vector<unsigned int>>("Nfithits"))
63  , fToler(pset.get<std::vector<double>>("Toler"))
64  , fApplyChargeWeight(pset.get<bool>("ApplyChargeWeight"))
65  , fPFParticleLabel(pset.get<art::InputTag>("PFParticleLabel"))
66  , fVerbose(pset.get<int>("Verbose"))
67  , fHitLabel(pset.get<art::InputTag>("HitsModuleLabel"))
68  , fShowerStartPositionInputLabel(pset.get<std::string>("ShowerStartPositionInputLabel"))
69  , fShowerDirectionInputLabel(pset.get<std::string>("ShowerDirectionInputLabel"))
70  , fInitialTrackHitsOutputLabel(pset.get<std::string>("InitialTrackHitsOutputLabel"))
72  pset.get<std::string>("InitialTrackSpacePointsOutputLabel"))
73  {
74  if (fNfitpass != fNfithits.size() || fNfitpass != fToler.size()) {
76  << "Shower2DLinearRegressionTrackHitFinderEMShower: fNfithits and fToler need to have size "
77  "fNfitpass";
78  }
79  }
80 
81  int
83  const art::Ptr<recob::PFParticle>& pfparticle,
84  art::Event& Event,
85  reco::shower::ShowerElementHolder& ShowerEleHolder)
86  {
87 
88  //This is all based on the shower vertex being known. If it is not lets not do the track
89  if (!ShowerEleHolder.CheckElement(fShowerStartPositionInputLabel)) {
90  if (fVerbose)
91  mf::LogError("Shower2DLinearRegressionTrackHitFinder")
92  << "Start position not set, returning " << std::endl;
93  return 1;
94  }
95  if (!ShowerEleHolder.CheckElement(fShowerDirectionInputLabel)) {
96  if (fVerbose)
97  mf::LogError("Shower2DLinearRegressionTrackHitFinder")
98  << "Direction not set, returning " << std::endl;
99  return 1;
100  }
101 
102  TVector3 ShowerStartPosition = {-999, -999, -999};
103  ShowerEleHolder.GetElement(fShowerStartPositionInputLabel, ShowerStartPosition);
104 
105  TVector3 ShowerDirection = {-999, -999, -999};
106  ShowerEleHolder.GetElement(fShowerDirectionInputLabel, ShowerDirection);
107 
108  // Get the assocated pfParicle vertex PFParticles
109  auto const pfpHandle = Event.getValidHandle<std::vector<recob::PFParticle>>(fPFParticleLabel);
110 
111  //Get the clusters
112  auto const clusHandle = Event.getValidHandle<std::vector<recob::Cluster>>(fPFParticleLabel);
113 
114  const art::FindManyP<recob::Cluster>& fmc =
115  ShowerEleHolder.GetFindManyP<recob::Cluster>(pfpHandle, Event, fPFParticleLabel);
116  std::vector<art::Ptr<recob::Cluster>> clusters = fmc.at(pfparticle.key());
117 
118  if (clusters.size() < 2) {
119  if (fVerbose)
120  mf::LogError("Shower2DLinearRegressionTrackHitFinder")
121  << "Not enough clusters: " << clusters.size() << std::endl;
122  return 1;
123  }
124 
125  //Get the hit association
126  const art::FindManyP<recob::Hit>& fmhc =
127  ShowerEleHolder.GetFindManyP<recob::Hit>(clusHandle, Event, fPFParticleLabel);
128  std::map<geo::PlaneID, std::vector<art::Ptr<recob::Hit>>> plane_clusters;
129  //Loop over the clusters in the plane and get the hits
130  for (auto const& cluster : clusters) {
131 
132  //Get the hits
133  std::vector<art::Ptr<recob::Hit>> hits = fmhc.at(cluster.key());
134 
135  for (auto hit : hits) {
136  geo::WireID wire = hit->WireID();
137  geo::PlaneID plane = wire.asPlaneID();
138  plane_clusters[plane].push_back(hit);
139  }
140 
141  // Was having issues with clusters having hits in multiple planes breaking PMA
142  // So switched to the method above. May want to switch back when using PandoraTrack
143  //plane_clusters[plane].insert(plane_clusters[plane].end(),hits.begin(),hits.end());
144  }
145 
146  auto const clockData =
148  auto const detProp =
150 
151  std::vector<art::Ptr<recob::Hit>> InitialTrackHits;
152  //Loop over the clusters and order the hits and get the initial track hits in that plane
153  for (auto const& cluster : plane_clusters) {
154 
155  //Get the hits
156  std::vector<art::Ptr<recob::Hit>> hits = cluster.second;
157 
158  //Order the hits
160  detProp, hits, ShowerStartPosition, ShowerDirection);
161 
162  //Find the initial track hits
163  std::vector<art::Ptr<recob::Hit>> trackhits = FindInitialTrackHits(detProp, hits);
164 
165  InitialTrackHits.insert(InitialTrackHits.end(), trackhits.begin(), trackhits.end());
166  }
167 
168  //Holders for the initial track values.
169  ShowerEleHolder.SetElement(InitialTrackHits, fInitialTrackHitsOutputLabel);
170 
171  //Get the associated spacepoints
172  //Get the hits
173  auto const hitHandle = Event.getValidHandle<std::vector<recob::Hit>>(fHitLabel);
174 
175  //get the sp<->hit association
176  const art::FindManyP<recob::SpacePoint>& fmsp =
177  ShowerEleHolder.GetFindManyP<recob::SpacePoint>(hitHandle, Event, fPFParticleLabel);
178 
179  //Get the spacepoints associated to the track hit
180  std::vector<art::Ptr<recob::SpacePoint>> intitaltrack_sp;
181  for (auto const& hit : InitialTrackHits) {
182  std::vector<art::Ptr<recob::SpacePoint>> sps = fmsp.at(hit.key());
183  for (auto const sp : sps) {
184  intitaltrack_sp.push_back(sp);
185  }
186  }
187  ShowerEleHolder.SetElement(intitaltrack_sp, fInitialTrackSpacePointsOutputLabel);
188  return 0;
189  }
190 
191  //Function to calculate the what are the initial tracks hits. Adapted from EMShower FindInitialTrackHits
192  std::vector<art::Ptr<recob::Hit>>
194  const detinfo::DetectorPropertiesData& detProp,
196  {
197 
198  std::vector<art::Ptr<recob::Hit>> trackHits;
199 
200  double parm[2];
201  int fitok = 0;
202  std::vector<double> wfit;
203  std::vector<double> tfit;
204  std::vector<double> cfit;
205 
206  for (size_t i = 0; i < fNfitpass; ++i) {
207 
208  // Fit a straight line through hits
209  unsigned int nhits = 0;
210  for (auto& hit : hits) {
211 
212  //Not sure I am a fan of doing things in wire tick space. What if id doesn't not iterate properly or the
213  //two planes in each TPC are not symmetric.
215 
216  if (i == 0 ||
217  (std::abs((coord.Y() - (parm[0] + coord.X() * parm[1])) *
218  std::cos(std::atan(parm[1]))) < fToler[i - 1]) ||
219  fitok == 1) {
220  ++nhits;
221  if (nhits == fNfithits[i] + 1) break;
222  wfit.push_back(coord.X());
223  tfit.push_back(coord.Y());
224 
225  if (fApplyChargeWeight) { cfit.push_back(hit->Integral()); }
226  else {
227  cfit.push_back(1.);
228  };
229  if (i == fNfitpass - 1) { trackHits.push_back(hit); }
230  }
231  }
232 
233  if (i < fNfitpass - 1 && wfit.size()) {
234  fitok = WeightedFit(wfit.size(), &wfit[0], &tfit[0], &cfit[0], &parm[0]);
235  }
236 
237  wfit.clear();
238  tfit.clear();
239  cfit.clear();
240  }
241  return trackHits;
242  }
243 
244  //Stolen from EMShowerAlg, a linear regression fitting function
245  Int_t
247  const Double_t* x,
248  const Double_t* y,
249  const Double_t* w,
250  Double_t* parm)
251  {
252 
253  Double_t sumx = 0.;
254  Double_t sumx2 = 0.;
255  Double_t sumy = 0.;
256  Double_t sumy2 = 0.;
257  Double_t sumxy = 0.;
258  Double_t sumw = 0.;
259  Double_t eparm[2];
260 
261  parm[0] = 0.;
262  parm[1] = 0.;
263  eparm[0] = 0.;
264  eparm[1] = 0.;
265 
266  for (Int_t i = 0; i < n; i++) {
267  sumx += x[i] * w[i];
268  sumx2 += x[i] * x[i] * w[i];
269  sumy += y[i] * w[i];
270  sumy2 += y[i] * y[i] * w[i];
271  sumxy += x[i] * y[i] * w[i];
272  sumw += w[i];
273  }
274 
275  if (sumx2 * sumw - sumx * sumx == 0.) return 1;
276  if (sumx2 - sumx * sumx / sumw == 0.) return 1;
277 
278  parm[0] = (sumy * sumx2 - sumx * sumxy) / (sumx2 * sumw - sumx * sumx);
279  parm[1] = (sumxy - sumx * sumy / sumw) / (sumx2 - sumx * sumx / sumw);
280 
281  eparm[0] = sumx2 * (sumx2 * sumw - sumx * sumx);
282  eparm[1] = (sumx2 - sumx * sumx / sumw);
283 
284  if (eparm[0] < 0. || eparm[1] < 0.) return 1;
285 
286  eparm[0] = sqrt(eparm[0]) / (sumx2 * sumw - sumx * sumx);
287  eparm[1] = sqrt(eparm[1]) / (sumx2 - sumx * sumx / sumw);
288 
289  return 0;
290  }
291 }
292 
#define DEFINE_ART_CLASS_TOOL(tool)
Definition: ToolMacros.h:42
std::string string
Definition: nybbler.cc:12
auto coord(Vector &v, unsigned int n) noexcept
Returns an object to manage the coordinate n of a vector.
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
void SetElement(T &dataproduct, const std::string &Name, bool checktag=false)
struct vector vector
STL namespace.
Set of hits with a 2D structure.
Definition: Cluster.h:71
const art::FindManyP< T1 > & GetFindManyP(const art::ValidHandle< std::vector< T2 > > &handle, const art::Event &evt, const art::InputTag &moduleTag)
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
Cluster finding and building.
Int_t WeightedFit(const Int_t n, const Double_t *x, const Double_t *y, const Double_t *w, Double_t *parm)
T abs(T value)
int CalculateElement(const art::Ptr< recob::PFParticle > &pfparticle, art::Event &Event, reco::shower::ShowerElementHolder &ShowerEleHolder) override
std::void_t< T > n
key_type key() const noexcept
Definition: Ptr.h:216
std::vector< art::Ptr< recob::Hit > > FindInitialTrackHits(const detinfo::DetectorPropertiesData &detProp, std::vector< art::Ptr< recob::Hit >> &hits)
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Definition: DataViewImpl.h:441
bool CheckElement(const std::string &Name) const
constexpr PlaneID const & asPlaneID() const
Conversion to PlaneID (for convenience of notation).
Definition: geo_types.h:534
int GetElement(const std::string &Name, T &Element) const
Detector simulation of raw signals on wires.
const shower::LArPandoraShowerAlg & GetLArPandoraShowerAlg() const
Definition: IShowerTool.h:87
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
TVector2 HitCoordinates(detinfo::DetectorPropertiesData const &detProp, art::Ptr< recob::Hit > const &hit) const
Definition: types.h:32
list x
Definition: train.py:276
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:48
auto const & get(AssnsNode< L, R, D > const &r)
Definition: AssnsNode.h:115
int bool
Definition: qglobal.h:345
QTextStream & endl(QTextStream &s)
void OrderShowerHits(detinfo::DetectorPropertiesData const &detProp, std::vector< art::Ptr< recob::Hit >> &hits, TVector3 const &ShowerDirection, TVector3 const &ShowerPosition) const