All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PCAnglePlaneMaker_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: PCAnglePlaneMakerFinder
3 // Plugin Type: producer (art v3_02_06)
4 // File: PCAnglePlaneMaker_module.cc
5 //
6 // Generated at Wed Feb 19 17:38:21 2020 by Gray Putnam using cetskelgen
7 // from cetlib version v3_07_02.
8 ////////////////////////////////////////////////////////////////////////
9 
10 #include "art/Framework/Core/EDProducer.h"
11 #include "art/Framework/Core/ModuleMacros.h"
12 #include "art/Framework/Principal/Event.h"
13 #include "art/Framework/Principal/Handle.h"
14 #include "art/Framework/Principal/Run.h"
15 #include "art/Framework/Principal/SubRun.h"
16 #include "canvas/Utilities/InputTag.h"
17 #include "fhiclcpp/ParameterSet.h"
18 #include "messagefacility/MessageLogger/MessageLogger.h"
20 
22 
23 #include <memory>
24 
34 
35 #include "sbnobj/Common/Reco/PCAnglePlane.h"
36 #include "PCA.h"
37 
38 namespace sbn {
39  class PCAnglePlaneMaker;
40 
41  // struct for organizing each angle info
42  struct PCAngleInfo {
43  sbn::PCAngle angle;
44  unsigned generation;
45  unsigned branch;
46  unsigned hit_ind;
47  };
48 }
49 
50 
51 class sbn::PCAnglePlaneMaker : public art::EDProducer {
52 public:
53  explicit PCAnglePlaneMaker(fhicl::ParameterSet const& p);
54  // The compiler-generated destructor is fine for non-base
55  // classes without bare pointers or other resource use.
56 
57  // Plugins should not be copied or assigned.
58  PCAnglePlaneMaker(PCAnglePlaneMaker const&) = delete;
62 
63  // Required functions.
64  void produce(art::Event& e) override;
65 
66 
67 private:
68  // private data
69  art::InputTag fPFParticleLabel;
73 
74 };
75 
76 
77 // static helper functions
78 void SaveHits(std::map<unsigned, std::array<std::vector<unsigned>, 3>> &pfpToHits, const std::vector<art::Ptr<recob::Hit>> &hits, unsigned plane, const art::Ptr<recob::PFParticle> &pfp) {
79  for (const art::Ptr<recob::Hit> &h: hits) {
80  pfpToHits[pfp.key()][plane].push_back(h.key());
81  }
82 }
83 
84 std::array<std::vector<art::Ptr<recob::Hit>>, 3> SortHits(const std::array<std::vector<art::Ptr<recob::Hit>>, 3> &hits,
85  const recob::Vertex &start,
86  const geo::GeometryCore *geo,
87  const detinfo::DetectorPropertiesData &dprop) {
88  // convert data to linked-list
89  std::array<std::list<art::Ptr<recob::Hit>>, 3> planar {};
90  for (unsigned i_plane = 0; i_plane < 3; i_plane++) {
91  planar[i_plane].insert(planar[i_plane].begin(), hits[i_plane].begin(), hits[i_plane].end());
92  }
93 
94  // start from the zeroth hit and grow from the nearest hit
95  std::array<std::vector<art::Ptr<recob::Hit>>, 3> ret {};
96  for (unsigned i = 0; i < 3; i++) {
97  if (planar[i].size()) {
98 
99  // find the zeroth hit
100  std::list<art::Ptr<recob::Hit>>::iterator firstHit = std::min_element(planar[i].begin(), planar[i].end(),
101  [start, geo, dprop](auto const &lhs, auto const &rhs) {
102  return sbnpca::Vert2HitDistance(*lhs, start, geo, dprop) < sbnpca::Vert2HitDistance(*rhs, start, geo, dprop);
103  });
104  ret[i].push_back(*firstHit);
105  planar[i].erase(firstHit);
106 
107  while (planar[i].size()) {
108  const recob::Hit &lastHit = *ret[i].back();
109  std::list<art::Ptr<recob::Hit>>::iterator closest = std::min_element(planar[i].begin(), planar[i].end(),
110  [lastHit, geo, dprop](auto const &lhs, auto const &rhs) {
111  return sbnpca::HitDistance(*lhs, lastHit, geo, dprop) < sbnpca::HitDistance(*rhs, lastHit, geo, dprop);
112  });
113 
114  ret[i].push_back(*closest);
115  planar[i].erase(closest);
116  }
117  }
118  }
119 
120  return ret;
121 
122 }
123 
124 // TODO: implement
125 //
126 // For now, always returning 'true' is ok -- it just means we do more work than necessary
127 bool DoBranch(art::Ptr<recob::PFParticle> particle, const std::map<unsigned, art::Ptr<recob::PFParticle>> &pfpMap) {
128  (void) particle;
129  (void) pfpMap;
130 
131  return true;
132 }
133 
134 // remove duplicates induced by degenerate-branching and organize by branch ID
135 std::map<unsigned, std::vector<sbn::PCAngleInfo>> RemoveDupes(std::vector<sbn::PCAngleInfo> &angles) {
136  // We will eliminate duplicates by converting to a set and then back to a vector
137  //
138  // Define a struct to implement the comparator
139  struct angle_compare {
140  bool operator() (const sbn::PCAngleInfo &lhs, const sbn::PCAngleInfo &rhs) const {
141  // unique ID is hitID, hitIDLo, hitIDHi
142  if (lhs.angle.hitID != rhs.angle.hitID) return lhs.angle.hitID < rhs.angle.hitID;
143  if (lhs.angle.hitIDLo != rhs.angle.hitIDLo) return lhs.angle.hitIDLo < rhs.angle.hitIDLo;
144  if (lhs.angle.hitIDHi != rhs.angle.hitIDHi) return lhs.angle.hitIDHi < rhs.angle.hitIDHi;
145  // equal
146  return false;
147  }
148  };
149 
150  // Given the choice, we want to keep angles with a smaller generation.
151  //
152  // So first sort the input by generation (lo -> hi). So smaller generations
153  // get inserted into the set first
154  std::sort(angles.begin(), angles.end(),
155  [](auto const &lhs, auto const &rhs) {return lhs.generation < rhs.generation;});
156 
157  // make the set to unique-ify the input
158  std::set<sbn::PCAngleInfo, angle_compare> unique(angles.begin(), angles.end());
159 
160  // organize into output
161  std::map<unsigned, std::vector<sbn::PCAngleInfo>> ret;
162  for (const sbn::PCAngleInfo &angle: unique) {
163  ret[angle.branch].push_back(angle);
164  }
165 
166  // sort each ret by the hit order
167  for (auto &pair: ret) {
168  std::sort(pair.second.begin(), pair.second.end(),
169  [](auto const &lhs, auto const &rhs) {
170  return lhs.hit_ind < rhs.hit_ind;
171  });
172  }
173 
174  return ret;
175 }
176 
177 sbn::PCAnglePlaneMaker::PCAnglePlaneMaker(fhicl::ParameterSet const& p)
178  : EDProducer{p},
179  fPFParticleLabel(p.get<std::string>("PFParticleLabel", "pandora")),
180  fFollowDaughters(p.get<bool>("FollowDaughters", true)),
181  fHitGroupDistance(p.get<float>("HitGroupDistance")),
182  fOnlyPrimary(p.get<bool>("OnlyPrimary", true))
183 {
184  produces<std::vector<sbn::PCAnglePlane>>();
185  produces<art::Assns<recob::PFParticle, sbn::PCAnglePlane>>();
186 }
187 
189 {
190  // output stuff
191  std::unique_ptr<std::vector<sbn::PCAnglePlane>> outAngles(new std::vector<sbn::PCAnglePlane>);
192  std::unique_ptr<art::Assns<recob::PFParticle, sbn::PCAnglePlane>> assn(new art::Assns<recob::PFParticle, sbn::PCAnglePlane>);
193 
194  art::PtrMaker<sbn::PCAnglePlane> anglePtrMaker {evt};
195 
196  // collect services
197  const geo::GeometryCore *geo = lar::providerFrom<geo::Geometry>();
198  auto const clock_data = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
199  auto const dprop =
200  art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(evt, clock_data);
201 
202 
203  // get the PFParticle's and the associated data
204  art::Handle<std::vector<recob::PFParticle>> pfparticle_handle;
205  evt.getByLabel(fPFParticleLabel, pfparticle_handle);
206 
207  std::vector<art::Ptr<recob::PFParticle>> pfparticles;
208  art::fill_ptr_vector(pfparticles, pfparticle_handle);
209 
210  // organize the PFPlist into a map
211  std::map<unsigned, art::Ptr<recob::PFParticle>> id_to_pfp;
212  for (unsigned i = 0; i < pfparticles.size(); i++) {
213  id_to_pfp[pfparticles[i]->Self()] = pfparticles[i];
214  }
215 
216  art::FindManyP<recob::Cluster> pfparticleClusters(pfparticles, evt, fPFParticleLabel);
217  art::FindManyP<recob::Vertex> pfparticleVertices(pfparticles, evt, fPFParticleLabel);
218 
219  // iterate over each particle
220  for (unsigned i_part = 0; i_part < pfparticles.size(); i_part++) {
221  std::cout << "New particle! " << i_part << std::endl;
222  art::Ptr<recob::PFParticle> thisPFP = pfparticles[i_part];
223 
224  std::cout << "Child of: " << thisPFP->Parent() << std::endl;
225 
226  // ignore non-primary or child of primary
227  if (fOnlyPrimary &&
228  thisPFP->Parent() != recob::PFParticle::kPFParticlePrimary &&
229  id_to_pfp.at(thisPFP->Parent())->Parent() != recob::PFParticle::kPFParticlePrimary) {
230  continue;
231  }
232 
233  // keep track of the map between this PFParticle and all the hits
234  std::map<unsigned, std::array<std::vector<unsigned>, 3>> pfpToHits;
235  std::map<unsigned, std::array<std::vector<art::Ptr<recob::Hit>>,3>> allHits;
236 
237  const std::vector<art::Ptr<recob::Cluster>> &thisCluster = pfparticleClusters.at(i_part);
238  art::FindManyP<recob::Hit> clusterHits(thisCluster, evt, fPFParticleLabel);
239 
240  // ignore PFP's w/out hits
241  if (!thisCluster.size()) {
242  std::cout << "No clusters :/\n";
243  continue;
244  }
245 
246  const std::vector<art::Ptr<recob::Vertex>> &pfpVerts = pfparticleVertices.at(i_part);
247 
248  // ignore PFP's w/out vertex
249  if (!pfpVerts.size()) {
250  std::cout << "No vertex :/\n";
251  continue;
252  }
253 
254  // grab the vertex
255  const recob::Vertex &pfpVert = *pfpVerts.at(0);
256 
257  std::cout << "Valid!\n";
258 
259  for (unsigned i_clus = 0; i_clus < thisCluster.size(); i_clus++) {
260  allHits[thisPFP->Self()][thisCluster[i_clus]->Plane().Plane].insert(allHits[thisPFP->Self()][thisCluster[i_clus]->Plane().Plane].begin(),
261  clusterHits.at(i_clus).begin(), clusterHits.at(i_clus).end());
262  SaveHits(pfpToHits, clusterHits.at(i_clus), thisCluster[i_clus]->Plane().Plane, thisPFP);
263  }
264 
265  // also get the hits from each daughter PFP (and so on) if configured
266  if (fFollowDaughters) {
267  // define the data we keep in the stack
268  struct daughter_stack_info {
269  unsigned daughter_id;
270  long unsigned hit_key;
271  };
272 
273  std::stack<daughter_stack_info> d_pfps;
274  for (unsigned d: thisPFP->Daughters()) {
275  daughter_stack_info dsi {d, thisPFP->Self()};
276  d_pfps.push(dsi);
277  }
278 
279  // DFS
280  while (!d_pfps.empty()) {
281  daughter_stack_info daughter_info = d_pfps.top();
282  unsigned daughter = daughter_info.daughter_id;
283  unsigned hit_key = daughter_info.hit_key;
284  d_pfps.pop();
285 
286  // get the PFP
287  const art::Ptr<recob::PFParticle> &d_pfp = id_to_pfp.at(daughter);
288 
289  // determine whether to branch
290  if (DoBranch(d_pfp, id_to_pfp)) {
291  // branching -- make a new entry in the allHits-map with this particle
292  //
293  // First clone the hits we already have
294  allHits[d_pfp->Self()][0] = allHits[hit_key][0];
295  allHits[d_pfp->Self()][1] = allHits[hit_key][1];
296  allHits[d_pfp->Self()][2] = allHits[hit_key][2];
297 
298  // and re-direct this hits to the new location
299  hit_key = d_pfp->Self();
300  }
301 
302  // add the daughter-daughters
303  for (unsigned d: d_pfp->Daughters()) {
304  daughter_stack_info dsi {d, hit_key};
305  d_pfps.push(dsi);
306  }
307 
308  // add the hits
309  const std::vector<art::Ptr<recob::Cluster>> &d_cluster = pfparticleClusters.at(d_pfp.key());
310 
311  // ignore PFP's w/out hits
312  if (!d_cluster.size()) continue;
313 
314  art::FindManyP<recob::Hit> d_cluster_hits(d_cluster, evt, fPFParticleLabel);
315  for (unsigned i_clus = 0; i_clus < d_cluster.size(); i_clus++) {
316  allHits[hit_key][d_cluster[i_clus]->Plane().Plane].insert(allHits[hit_key][d_cluster[i_clus]->Plane().Plane].begin(),
317  d_cluster_hits.at(i_clus).begin(), d_cluster_hits.at(i_clus).end());
318  SaveHits(pfpToHits, d_cluster_hits.at(i_clus), d_cluster[i_clus]->Plane().Plane, d_pfp);
319  }
320  }
321  }
322 
323 
324  std::array<std::vector<sbn::PCAngleInfo>, 3> planeAngles;
325  // Now we have all the hits we need!
326  //
327  // iterate through each branch
328  for (auto const &pair: allHits) {
329  unsigned branch_id = pair.first;
330  const std::array<std::vector<art::Ptr<recob::Hit>>, 3> &branchHits = pair.second;
331 
332  // Now, for each hit, we'll consider the PCA angle and the vec angle
333  //
334  // First, order this hits
335  std::array<std::vector<art::Ptr<recob::Hit>>, 3> sortedHits = SortHits(branchHits, pfpVert, geo, dprop);
336 
337  // iterate through all the Hits
338  for (unsigned i_plane = 0; i_plane < 3; i_plane++) {
339  for (unsigned i_hit = 0; i_hit < sortedHits[i_plane].size(); i_hit++) {
340  // get nearby hits
341  auto [hitslo, hitshi, complete] = sbnpca::GetNearestHits(sortedHits[i_plane], i_hit, fHitGroupDistance, geo, dprop);
342 
343  //std::cout << "Plane: " << i_plane << " Branch: " << branch_id << " hit: " << i_hit << " " << sortedHits[i_plane][i_hit].key();
344  //if (hitslo.size()) std::cout << " lo: " << hitslo.back().key();
345  //else std::cout << " lo: none";
346  //if (hitshi.size()) std::cout << " hi: " << hitshi.back().key();
347  //else std::cout << " hi: none";
348  //std::cout << std::endl;
349 
350  // invalid -- continue
351  // if (hithi.size() < 2 || hitslo.size() < 2) continue;
352 
353  // Get the PCA dirs
354  std::array<float, 2> pca_vec_lo = sbnpca::HitPCAVec(hitslo, *sortedHits[i_plane][i_hit], geo, dprop);
355  std::array<float, 2> pca_vec_hi = sbnpca::HitPCAVec(hitshi, *sortedHits[i_plane][i_hit], geo, dprop);
356  float angle = -100.;
357  // check if valid vecs
358  if (pca_vec_lo[0] > -99. && pca_vec_lo[1] > -99. && pca_vec_hi[0] > -99. && pca_vec_hi[1] > -99.) {
359  // get angle between the two vecs and flip
360  angle = M_PI - sbnpca::VecAngle(pca_vec_lo, pca_vec_hi);
361  }
362 
363  std::array<float, 2> hv = sbnpca::HitVector(*sortedHits[i_plane][i_hit], geo, dprop);
364 
365  // and save
366  sbn::PCAngleInfo thisAngle;
367  thisAngle.angle.wire = sortedHits[i_plane][i_hit]->WireID();
368  thisAngle.angle.angle = angle;
369  thisAngle.angle.lo_vector = pca_vec_lo;
370  thisAngle.angle.hi_vector = pca_vec_hi;
371  thisAngle.angle.hit_wire_cm = hv[0];
372  thisAngle.angle.hit_time_cm = hv[1];
373  thisAngle.angle.complete = complete;
374  thisAngle.angle.hitID = sortedHits[i_plane][i_hit].key();
375 
376  if (hitshi.size()) thisAngle.angle.dist_to_hi = sbnpca::HitDistance(*hitshi.back(), *sortedHits[i_plane][i_hit], geo, dprop);
377  else thisAngle.angle.dist_to_hi = -100.;
378  if (hitslo.size()) thisAngle.angle.dist_to_lo = sbnpca::HitDistance(*hitslo.back(), *sortedHits[i_plane][i_hit], geo, dprop);
379  else thisAngle.angle.dist_to_lo = -100.;
380 
381  if (hitshi.size()) thisAngle.angle.hitIDHi = hitshi.back().key();
382  else thisAngle.angle.hitIDHi = -1;
383  if (hitslo.size()) thisAngle.angle.hitIDLo = hitslo.back().key();
384  else thisAngle.angle.hitIDLo = -1;
385 
386  thisAngle.branch = branch_id;
387  thisAngle.hit_ind = i_hit;
388 
389  // get the generation
390  thisAngle.generation = 0;
391  art::Ptr<recob::PFParticle> check = id_to_pfp.at(branch_id);
392  while (check->Self() != thisPFP->Self()) {
393  thisAngle.generation ++;
394  check = id_to_pfp.at(check->Parent());
395  }
396 
397  planeAngles[i_plane].push_back(thisAngle);
398  }
399  }
400  }
401 
402  // Save the angles on each plane
403  for (unsigned i_plane = 0; i_plane < 3; i_plane++) {
404  std::map<unsigned, std::vector<sbn::PCAngleInfo>> selected = RemoveDupes(planeAngles[i_plane]);
405 
406  sbn::PCAnglePlane thisPlane;
407  geo::PlaneID planeID(0, 0, i_plane); // TPC and cryo are arbitrary
408  thisPlane.plane = planeID;
409  for (auto const &pair: selected) {
410  thisPlane.branchIDs.push_back(pair.first);
411 
412  // look up the hierarchy
413  thisPlane.branchHierarchy.emplace_back();
414  art::Ptr<recob::PFParticle> check = id_to_pfp.at(pair.first);
415  thisPlane.branchHierarchy.back().push_back(check->Self());
416  while (check->Self() != thisPFP->Self()) {
417  check = id_to_pfp.at(check->Parent());
418  thisPlane.branchHierarchy.back().push_back(check->Self());
419  }
420 
421  if (pair.second.size()) thisPlane.generations.push_back(pair.second.front().generation);
422  else thisPlane.generations.push_back(-1);
423 
424  if (pair.second.size()) thisPlane.plane = pair.second.front().angle.wire;
425 
426  thisPlane.angles.emplace_back();
427  for (const sbn::PCAngleInfo &a: pair.second) thisPlane.angles.back().push_back(a.angle);
428  }
429  thisPlane.nBranches = thisPlane.angles.size();
430  outAngles->push_back(thisPlane);
431  art::Ptr<sbn::PCAnglePlane> thisAnglePtr = anglePtrMaker(outAngles->size()-1);
432  assn->addSingle(thisPFP, thisAnglePtr);
433  }
434 
435  }
436 
437  evt.put(std::move(outAngles));
438  evt.put(std::move(assn));
439 
440 }
441 
442 DEFINE_ART_MODULE(sbn::PCAnglePlaneMaker)
void produce(art::Event &e) override
void SaveHits(std::map< unsigned, std::array< std::vector< unsigned >, 3 >> &pfpToHits, const std::vector< art::Ptr< recob::Hit >> &hits, unsigned plane, const art::Ptr< recob::PFParticle > &pfp)
BEGIN_PROLOG true icarus_rawdigitfilter FilterTools FilterPlane1 Plane
float Vert2HitDistance(const recob::Hit &hit, const recob::Vertex &vert, const geo::GeometryCore *geo, const detinfo::DetectorPropertiesData &dprop)
Definition: PCA.cc:174
std::array< float, 2 > HitPCAVec(const std::vector< art::Ptr< recob::Hit >> &hits, const recob::Hit &center, const geo::GeometryCore *geo, const detinfo::DetectorPropertiesData &dprop)
Definition: PCA.cc:69
PCAnglePlaneMaker & operator=(PCAnglePlaneMaker const &)=delete
static constexpr size_t kPFParticlePrimary
Define index to signify primary particle.
Definition: PFParticle.h:61
PCAnglePlaneMaker(fhicl::ParameterSet const &p)
std::map< unsigned, std::vector< sbn::PCAngleInfo > > RemoveDupes(std::vector< sbn::PCAngleInfo > &angles)
Declaration of signal hit object.
pdgs p
Definition: selectors.fcl:22
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
std::size_t size(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:561
Definition of vertex object for LArSoft.
Definition: Vertex.h:35
process_name gaushit a
while getopts h
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
Access the description of detector geometry.
then echo ***************************************echo array
Definition: find_fhicl.sh:28
std::tuple< std::vector< art::Ptr< recob::Hit > >, std::vector< art::Ptr< recob::Hit > >, bool > GetNearestHits(const std::vector< art::Ptr< recob::Hit >> &hits, int ihit, float distance, const geo::GeometryCore *geo, const detinfo::DetectorPropertiesData &dprop)
Definition: PCA.cc:39
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
process_name tightIsolTest check
std::array< std::vector< art::Ptr< recob::Hit > >, 3 > SortHits(const std::array< std::vector< art::Ptr< recob::Hit >>, 3 > &hits, const recob::Vertex &start, const geo::GeometryCore *geo, const detinfo::DetectorPropertiesData &dprop)
float VecAngle(std::array< float, 2 > A, std::array< float, 2 > B)
Definition: PCA.cc:5
float HitDistance(const recob::Hit &A, const recob::Hit &B, const geo::GeometryCore *geo, const detinfo::DetectorPropertiesData &dprop)
Definition: PCA.cc:34
j template void())
Definition: json.hpp:3108
Description of geometry of one entire detector.
Declaration of cluster object.
auto begin(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:573
do i e
Declaration of basic channel signal object.
finds tracks best matching by angle
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:48
TCEvent evt
Definition: DataStructs.cxx:8
bool DoBranch(art::Ptr< recob::PFParticle > particle, const std::map< unsigned, art::Ptr< recob::PFParticle >> &pfpMap)
art framework interface to geometry description
BEGIN_PROLOG could also be cout
std::array< float, 2 > HitVector(const recob::Hit &A, const geo::GeometryCore *geo, const detinfo::DetectorPropertiesData &dprop)
Definition: PCA.cc:12