All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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
11 #include "art/Utilities/ToolMacros.h"
12 
13 //LArSoft Includes
21 
22 namespace ShowerRecoTools {
23 
25  public:
26  Shower2DLinearRegressionTrackHitFinder(const fhicl::ParameterSet& pset);
27 
28  //Calculate the 2D initial track hits
29  int CalculateElement(const art::Ptr<recob::PFParticle>& pfparticle,
30  art::Event& Event,
31  reco::shower::ShowerElementHolder& ShowerEleHolder) override;
32 
33  private:
34  //Function to find the
35  std::vector<art::Ptr<recob::Hit>> FindInitialTrackHits(
37  std::vector<art::Ptr<recob::Hit>>& hits);
38 
39  //Function to perform a weighted regression fit.
40  Int_t WeightedFit(const Int_t n,
41  const Double_t* x,
42  const Double_t* y,
43  const Double_t* w,
44  Double_t* parm);
45 
46  //fcl parameters
47  unsigned int fNfitpass; //Number of time to fit the straight
48  //line the hits.
49  std::vector<unsigned int> fNfithits; //Max number of hits to fit to.
50  std::vector<double> fToler; //Tolerance or each interaction.
51  //Defined as the perpendicualar
52  //distance from the best fit line.
53  bool fApplyChargeWeight; //Apply charge weighting to the fit.
54  art::InputTag fPFParticleLabel;
55  int fVerbose;
56  art::InputTag fHitLabel;
61  };
62 
64  const fhicl::ParameterSet& pset)
65  : IShowerTool(pset.get<fhicl::ParameterSet>("BaseTools"))
66  , fNfitpass(pset.get<unsigned int>("Nfitpass"))
67  , fNfithits(pset.get<std::vector<unsigned int>>("Nfithits"))
68  , fToler(pset.get<std::vector<double>>("Toler"))
69  , fApplyChargeWeight(pset.get<bool>("ApplyChargeWeight"))
70  , fPFParticleLabel(pset.get<art::InputTag>("PFParticleLabel"))
71  , fVerbose(pset.get<int>("Verbose"))
72  , fHitLabel(pset.get<art::InputTag>("HitsModuleLabel"))
73  , fShowerStartPositionInputLabel(pset.get<std::string>("ShowerStartPositionInputLabel"))
74  , fShowerDirectionInputLabel(pset.get<std::string>("ShowerDirectionInputLabel"))
75  , fInitialTrackHitsOutputLabel(pset.get<std::string>("InitialTrackHitsOutputLabel"))
76  , fInitialTrackSpacePointsOutputLabel(
77  pset.get<std::string>("InitialTrackSpacePointsOutputLabel"))
78  {
79  if (fNfitpass != fNfithits.size() || fNfitpass != fToler.size()) {
80  throw art::Exception(art::errors::Configuration)
81  << "Shower2DLinearRegressionTrackHitFinderEMShower: fNfithits and fToler need to have size "
82  "fNfitpass";
83  }
84  }
85 
86  int
88  const art::Ptr<recob::PFParticle>& pfparticle,
89  art::Event& Event,
90  reco::shower::ShowerElementHolder& ShowerEleHolder)
91  {
92 
93  //This is all based on the shower vertex being known. If it is not lets not do the track
94  if (!ShowerEleHolder.CheckElement(fShowerStartPositionInputLabel)) {
95  if (fVerbose)
96  mf::LogError("Shower2DLinearRegressionTrackHitFinder")
97  << "Start position not set, returning " << std::endl;
98  return 1;
99  }
100  if (!ShowerEleHolder.CheckElement(fShowerDirectionInputLabel)) {
101  if (fVerbose)
102  mf::LogError("Shower2DLinearRegressionTrackHitFinder")
103  << "Direction not set, returning " << std::endl;
104  return 1;
105  }
106 
107  TVector3 ShowerStartPosition = {-999, -999, -999};
108  ShowerEleHolder.GetElement(fShowerStartPositionInputLabel, ShowerStartPosition);
109 
110  TVector3 ShowerDirection = {-999, -999, -999};
111  ShowerEleHolder.GetElement(fShowerDirectionInputLabel, ShowerDirection);
112 
113  // Get the assocated pfParicle vertex PFParticles
114  auto const pfpHandle = Event.getValidHandle<std::vector<recob::PFParticle>>(fPFParticleLabel);
115 
116  //Get the clusters
117  auto const clusHandle = Event.getValidHandle<std::vector<recob::Cluster>>(fPFParticleLabel);
118 
119  const art::FindManyP<recob::Cluster>& fmc =
120  ShowerEleHolder.GetFindManyP<recob::Cluster>(pfpHandle, Event, fPFParticleLabel);
121  std::vector<art::Ptr<recob::Cluster>> clusters = fmc.at(pfparticle.key());
122 
123  if (clusters.size() < 2) {
124  if (fVerbose)
125  mf::LogError("Shower2DLinearRegressionTrackHitFinder")
126  << "Not enough clusters: " << clusters.size() << std::endl;
127  return 1;
128  }
129 
130  //Get the hit association
131  const art::FindManyP<recob::Hit>& fmhc =
132  ShowerEleHolder.GetFindManyP<recob::Hit>(clusHandle, Event, fPFParticleLabel);
133  std::map<geo::PlaneID, std::vector<art::Ptr<recob::Hit>>> plane_clusters;
134  //Loop over the clusters in the plane and get the hits
135  for (auto const& cluster : clusters) {
136 
137  //Get the hits
138  std::vector<art::Ptr<recob::Hit>> hits = fmhc.at(cluster.key());
139 
140  for (auto hit : hits) {
141  geo::WireID wire = hit->WireID();
142  geo::PlaneID plane = wire.asPlaneID();
143  plane_clusters[plane].push_back(hit);
144  }
145 
146  // Was having issues with clusters having hits in multiple planes breaking PMA
147  // So switched to the method above. May want to switch back when using PandoraTrack
148  //plane_clusters[plane].insert(plane_clusters[plane].end(),hits.begin(),hits.end());
149  }
150 
151  auto const clockData =
152  art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(Event);
153  auto const detProp =
154  art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(Event, clockData);
155 
156  std::vector<art::Ptr<recob::Hit>> InitialTrackHits;
157  //Loop over the clusters and order the hits and get the initial track hits in that plane
158  for (auto const& cluster : plane_clusters) {
159 
160  //Get the hits
161  std::vector<art::Ptr<recob::Hit>> hits = cluster.second;
162 
163  //Order the hits
165  detProp, hits, ShowerStartPosition, ShowerDirection);
166 
167  //Find the initial track hits
168  std::vector<art::Ptr<recob::Hit>> trackhits = FindInitialTrackHits(detProp, hits);
169 
170  InitialTrackHits.insert(InitialTrackHits.end(), trackhits.begin(), trackhits.end());
171  }
172 
173  //Holders for the initial track values.
174  ShowerEleHolder.SetElement(InitialTrackHits, fInitialTrackHitsOutputLabel);
175 
176  //Get the associated spacepoints
177  //Get the hits
178  auto const hitHandle = Event.getValidHandle<std::vector<recob::Hit>>(fHitLabel);
179 
180  //get the sp<->hit association
181  const art::FindManyP<recob::SpacePoint>& fmsp =
182  ShowerEleHolder.GetFindManyP<recob::SpacePoint>(hitHandle, Event, fPFParticleLabel);
183 
184  //Get the spacepoints associated to the track hit
185  std::vector<art::Ptr<recob::SpacePoint>> intitaltrack_sp;
186  for (auto const& hit : InitialTrackHits) {
187  std::vector<art::Ptr<recob::SpacePoint>> sps = fmsp.at(hit.key());
188  for (auto const sp : sps) {
189  intitaltrack_sp.push_back(sp);
190  }
191  }
192  ShowerEleHolder.SetElement(intitaltrack_sp, fInitialTrackSpacePointsOutputLabel);
193  return 0;
194  }
195 
196  //Function to calculate the what are the initial tracks hits. Adapted from EMShower FindInitialTrackHits
197  std::vector<art::Ptr<recob::Hit>>
200  std::vector<art::Ptr<recob::Hit>>& hits)
201  {
202 
203  std::vector<art::Ptr<recob::Hit>> trackHits;
204 
205  double parm[2];
206  int fitok = 0;
207  std::vector<double> wfit;
208  std::vector<double> tfit;
209  std::vector<double> cfit;
210 
211  for (size_t i = 0; i < fNfitpass; ++i) {
212 
213  // Fit a straight line through hits
214  unsigned int nhits = 0;
215  for (auto& hit : hits) {
216 
217  //Not sure I am a fan of doing things in wire tick space. What if id doesn't not iterate properly or the
218  //two planes in each TPC are not symmetric.
220 
221  if (i == 0 ||
222  (std::abs((coord.Y() - (parm[0] + coord.X() * parm[1])) *
223  std::cos(std::atan(parm[1]))) < fToler[i - 1]) ||
224  fitok == 1) {
225  ++nhits;
226  if (nhits == fNfithits[i] + 1) break;
227  wfit.push_back(coord.X());
228  tfit.push_back(coord.Y());
229 
230  if (fApplyChargeWeight) { cfit.push_back(hit->Integral()); }
231  else {
232  cfit.push_back(1.);
233  };
234  if (i == fNfitpass - 1) { trackHits.push_back(hit); }
235  }
236  }
237 
238  if (i < fNfitpass - 1 && wfit.size()) {
239  fitok = WeightedFit(wfit.size(), &wfit[0], &tfit[0], &cfit[0], &parm[0]);
240  }
241 
242  wfit.clear();
243  tfit.clear();
244  cfit.clear();
245  }
246  return trackHits;
247  }
248 
249  //Stolen from EMShowerAlg, a linear regression fitting function
250  Int_t
252  const Double_t* x,
253  const Double_t* y,
254  const Double_t* w,
255  Double_t* parm)
256  {
257 
258  Double_t sumx = 0.;
259  Double_t sumx2 = 0.;
260  Double_t sumy = 0.;
261  Double_t sumy2 = 0.;
262  Double_t sumxy = 0.;
263  Double_t sumw = 0.;
264  Double_t eparm[2];
265 
266  parm[0] = 0.;
267  parm[1] = 0.;
268  eparm[0] = 0.;
269  eparm[1] = 0.;
270 
271  for (Int_t i = 0; i < n; i++) {
272  sumx += x[i] * w[i];
273  sumx2 += x[i] * x[i] * w[i];
274  sumy += y[i] * w[i];
275  sumy2 += y[i] * y[i] * w[i];
276  sumxy += x[i] * y[i] * w[i];
277  sumw += w[i];
278  }
279 
280  if (sumx2 * sumw - sumx * sumx == 0.) return 1;
281  if (sumx2 - sumx * sumx / sumw == 0.) return 1;
282 
283  parm[0] = (sumy * sumx2 - sumx * sumxy) / (sumx2 * sumw - sumx * sumx);
284  parm[1] = (sumxy - sumx * sumy / sumw) / (sumx2 - sumx * sumx / sumw);
285 
286  eparm[0] = sumx2 * (sumx2 * sumw - sumx * sumx);
287  eparm[1] = (sumx2 - sumx * sumx / sumw);
288 
289  if (eparm[0] < 0. || eparm[1] < 0.) return 1;
290 
291  eparm[0] = sqrt(eparm[0]) / (sumx2 * sumw - sumx * sumx);
292  eparm[1] = sqrt(eparm[1]) / (sumx2 - sumx * sumx / sumw);
293 
294  return 0;
295  }
296 }
297 
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
process_name opflash particleana ie x
process_name cluster
Definition: cheaterreco.fcl:51
auto coord(Vector &v, unsigned int n) noexcept
Returns an object to manage the coordinate n of a vector.
Declaration of signal hit object.
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
void SetElement(T &dataproduct, const std::string &Name, bool checktag=false)
static constexpr bool
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)
process_name hit
Definition: cheaterreco.fcl:51
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
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)
process_name opflash particleana ie ie y
int CalculateElement(const art::Ptr< recob::PFParticle > &pfparticle, art::Event &Event, reco::shower::ShowerElementHolder &ShowerEleHolder) override
std::vector< art::Ptr< recob::Hit > > FindInitialTrackHits(const detinfo::DetectorPropertiesData &detProp, std::vector< art::Ptr< recob::Hit >> &hits)
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
Declaration of cluster object.
const shower::LArPandoraShowerAlg & GetLArPandoraShowerAlg() const
Definition: IShowerTool.h:88
TVector2 HitCoordinates(detinfo::DetectorPropertiesData const &detProp, art::Ptr< recob::Hit > const &hit) const
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:48
auto const detProp
void OrderShowerHits(detinfo::DetectorPropertiesData const &detProp, std::vector< art::Ptr< recob::Hit >> &hits, TVector3 const &ShowerDirection, TVector3 const &ShowerPosition) const