All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MergedTrackIdentifier_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: MergedTrackIdentifier
3 // Plugin Type: producer (art v3_02_06)
4 // File: MergedTrackIdentifier_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"
23 
39 
40 #include <memory>
41 
43 
44 namespace sbn {
45  class MergedTrackIdentifier;
46 }
47 
48 
49 class sbn::MergedTrackIdentifier : public art::EDProducer {
50 public:
51  explicit MergedTrackIdentifier(fhicl::ParameterSet const& p);
52  // The compiler-generated destructor is fine for non-base
53  // classes without bare pointers or other resource use.
54 
55  // Plugins should not be copied or assigned.
60 
61  // Required functions.
62  void produce(art::Event& e) override;
63 
64 private:
65 
66  art::InputTag fPFPLabel;
67  art::InputTag fTrackLabel;
68 
69  // helper functions
71  const geo::GeometryCore *geo, const recob::Vertex &vtx,
72  const recob::PFParticle &A, const recob::Track &Atrk,
73  const recob::PFParticle &B, const recob::Track &Btrk, bool assume_a_is_trunk=false);
74 
75 };
76 
78  : EDProducer{p},
79  fPFPLabel(p.get<art::InputTag>("PFPLabel", "pandora")),
80  fTrackLabel(p.get<art::InputTag>("TrackLabel", "pandoraTrack"))
81 {
82  produces<std::vector<sbn::MergedTrackInfo>>();
83  produces<art::Assns<sbn::MergedTrackInfo, recob::PFParticle>>();
84 }
85 
86 
87 // static helper
88 TVector3 MeanDirection(const recob::Vertex &vtx, const recob::Track &trk) {
89  TVector3 start(vtx.position().x(), vtx.position().y(), vtx.position().z());
90 
91  TVector3 avg_dir(0., 0., 0.);
92 
93  for (unsigned i_tp = trk.FirstValidPoint(); i_tp < trk.NumberTrajectoryPoints(); i_tp = trk.NextValidPoint(i_tp+1)) {
94  TVector3 p = trk.LocationAtPoint<TVector3>(i_tp);
95  avg_dir += (p - start).Unit();
96  }
97 
98  return avg_dir.Unit();
99 
100 }
101 
103  const geo::GeometryCore *geo, const recob::Vertex &vtx,
104  const recob::PFParticle &A, const recob::Track &Atrk,
105  const recob::PFParticle &B, const recob::Track &Btrk, bool assume_a_is_trunk) {
106 
108 
109  ret.vertex = TVector3(vtx.position().x(), vtx.position().y(), vtx.position().z());
110 
111  ret.direction = (MeanDirection(vtx, Atrk) + MeanDirection(vtx, Btrk)).Unit();
112 
113  bool a_is_trunk = assume_a_is_trunk || ret.direction.Dot(Atrk.Start<TVector3>() - ret.vertex) < ret.direction.Dot(Btrk.Start<TVector3>() - ret.vertex);
114 
115  const recob::PFParticle &trunk = (a_is_trunk) ? A : B;
116  const recob::PFParticle &branch = (a_is_trunk) ? B : A;
117 
118  const recob::Track &trunk_trk = (a_is_trunk) ? Atrk : Btrk;
119  const recob::Track &branch_trk = (a_is_trunk) ? Btrk : Atrk;
120 
121  ret.trunk = trunk.Self();
122  ret.branch = branch.Self();
123 
124  ret.branch_start = ret.direction.Dot(branch_trk.Start<TVector3>() - ret.vertex);
125  ret.trunk_start = ret.direction.Dot(trunk_trk.Start<TVector3>() - ret.vertex);
126 
127  // TVector3 branch_start = branch_trk.LocationAtPoint<TVector3>(branch_trk.FirstValidPoint());
128  // for (unsigned i = 0; i < 3; i++) {
129  // ret.branch_wire_start[i] = geo->WireCoordinate(branch_start.Y(), branch_start.Z(), i, 0, 0);
130 
131  // TVector3 trunk_start = trunk_trk.LocationAtPoint<TVector3>(trunk_trk.FirstValidPoint());
132  // TVector3 trunk_start_p1 = trunk_trk.LocationAtPoint<TVector3>(trunk_trk.NextValidPoint(trunk_trk.FirstValidPoint()+1));
133 
134  // check if the tracks are ascending or descending
135  // ret.trunk_wire_direction_is_ascending[i] =
136  // geo->WireCoordinate(trunk_start.Y(), trunk_start.Z(), i, 0, 0) <
137  // geo->WireCoordinate(trunk_start_p1.Y(), trunk_start_p1.Z(), i, 0, 0);
138  // }
139 
140  bool set = false;
141  float trunk_min = -1;
142  float trunk_max = -1;
143 
144  for (unsigned i = trunk_trk.FirstValidPoint(); i < trunk_trk.NumberTrajectoryPoints(); i = trunk_trk.NextValidPoint(i+1)) {
145  float proj = ret.direction.Dot(trunk_trk.DirectionAtPoint<TVector3>(i) - ret.vertex);
146  if (!set || proj < trunk_min) trunk_min = proj;
147  if (!set || proj > trunk_max) trunk_max = proj;
148  set = true;
149  }
150 
151  unsigned n_point = 0;
152  unsigned n_overlap_point = 0;
153  for (unsigned i = branch_trk.FirstValidPoint(); i < branch_trk.NumberTrajectoryPoints(); i = branch_trk.NextValidPoint(i+1)) {
154  float proj = ret.direction.Dot(branch_trk.DirectionAtPoint<TVector3>(i) - ret.vertex);
155  if (proj > trunk_min && proj < trunk_max) {
156  n_overlap_point ++;
157  }
158  n_point ++;
159  }
160 
161  ret.branch_overlap = ((float)n_overlap_point) / n_point;
162 
163 
164  return ret;
165 }
166 
168 {
169  // output data products
170  std::unique_ptr<std::vector<sbn::MergedTrackInfo>> infos(new std::vector<sbn::MergedTrackInfo>);
171  std::unique_ptr<art::Assns<sbn::MergedTrackInfo, recob::PFParticle>> assn(new art::Assns<sbn::MergedTrackInfo, recob::PFParticle>);
172 
173  art::PtrMaker<sbn::MergedTrackInfo> infoPtrMaker {e};
174 
175  // input data
176  art::Handle<std::vector<recob::Slice>> slice_handle;
177  e.getByLabel(fPFPLabel, slice_handle);
178 
179  std::vector<art::Ptr<recob::Slice>> slices;
180  art::fill_ptr_vector(slices, slice_handle);
181 
182  art::FindManyP<recob::PFParticle> slicePFPs(slices, e, fPFPLabel);
183 
184  // services
185  const geo::GeometryCore *geo = lar::providerFrom<geo::Geometry>();
186 
187  for (unsigned i_slc = 0; i_slc < slices.size(); i_slc++) {
188  // collect the PFPs
189  const std::vector<art::Ptr<recob::PFParticle>> &this_slice_pfps = slicePFPs.at(i_slc);
190 
191  art::FindManyP<recob::Vertex> slicePFPVtxs(this_slice_pfps, e, fPFPLabel);
192 
193  art::Ptr<recob::Vertex> vtx;
194  art::Ptr<recob::PFParticle> primary;
195  // get the primary particle in each Slice
196  for (unsigned i_pfp = 0; i_pfp < this_slice_pfps.size(); i_pfp++) {
197  if (this_slice_pfps[i_pfp]->IsPrimary() && slicePFPVtxs.at(i_pfp).size()) {
198  primary = this_slice_pfps[i_pfp];
199  vtx = slicePFPVtxs.at(i_pfp).at(0);
200  break;
201  }
202  }
203 
204  // no primary PFParticle -- ignore
205  if (!primary) continue;
206 
207  std::vector<art::Ptr<recob::PFParticle>> topTracks;
208 
209  // primary is a Neutrino -- will have a number of daughters -- which we call primary
211  for (unsigned d: primary->Daughters()) {
212  for (unsigned i_pfp = 0; i_pfp < this_slice_pfps.size(); i_pfp++) {
213  if (this_slice_pfps[i_pfp]->Self() == d) {
214  if (lar_pandora::LArPandoraHelper::IsTrack(this_slice_pfps[i_pfp])) topTracks.push_back(this_slice_pfps[i_pfp]);
215  break;
216  }
217  }
218  }
219  }
220  // primary is a track -- this is the only top-level-track
221  else if (lar_pandora::LArPandoraHelper::IsTrack(primary)) {
222  topTracks.push_back(primary);
223  }
224 
225  art::FindManyP<recob::Track> topTrackTracks(topTracks, e, fTrackLabel);
226 
227  std::map<art::Ptr<recob::PFParticle>, std::vector<std::pair<art::Ptr<recob::PFParticle>, sbn::MergedTrackInfo>>> possible_merge_parents;
228  std::map<art::Ptr<recob::PFParticle>, std::vector<std::pair<art::Ptr<recob::PFParticle>, sbn::MergedTrackInfo>>> possible_merge_children;
229 
230  // First iterate over all pairs of top-level tracks
231  for (unsigned i = 0; i < topTracks.size(); i++) {
232  for (unsigned j = i+1; j < topTracks.size(); j++) {
233  if (!topTrackTracks.at(i).size() || !topTrackTracks.at(j).size()) continue;
234 
235  sbn::MergedTrackInfo info = BuildTrackInfo(geo, *vtx, *topTracks[i], *topTrackTracks.at(i).at(0), *topTracks[j], *topTrackTracks.at(j).at(0));
236 
237  // std::cout << "CONSIDERING MATCH: " << topTracks[i]->Self() << " paired " << topTracks[j]->Self() << " overlap: " << info.branch_overlap << " trunk: " << info.trunk << std::endl;
238 
239  // only take cases with 50% overlap
240  if (info.branch_overlap < 0.5) continue;
241 
242  // std::cout << "Overlaps!\n";
243 
244  if ((unsigned)info.trunk == topTracks[i]->Self()) {
245  possible_merge_parents[topTracks[i]].push_back({topTracks[j], info});
246  possible_merge_children[topTracks[j]].push_back({topTracks[i], info});
247 
248  }
249  else {
250  possible_merge_parents[topTracks[j]].push_back({topTracks[i], info});
251  possible_merge_children[topTracks[i]].push_back({topTracks[j], info});
252  }
253 
254  }
255  }
256 
257  // also get cases with a top-track w/ a daughter track
258  for (unsigned i = 0; i < topTracks.size(); i++) {
259  std::vector<art::Ptr<recob::PFParticle>> daughters;
260  for (unsigned d: topTracks[i]->Daughters()) {
261  for (unsigned i_pfp = 0; i_pfp < this_slice_pfps.size(); i_pfp++) {
262  if (this_slice_pfps[i_pfp]->Self() == d) {
263  if (lar_pandora::LArPandoraHelper::IsTrack(this_slice_pfps[i_pfp])) daughters.push_back(this_slice_pfps[i_pfp]);
264  break;
265  }
266  }
267  }
268 
269  art::FindManyP<recob::Track> daughterTracks(daughters, e, fTrackLabel);
270  for (unsigned j = 0; j < daughters.size(); j++) {
271  if (!topTrackTracks.at(i).size() || !daughterTracks.at(j).size()) continue;
272 
273  sbn::MergedTrackInfo info = BuildTrackInfo(geo, *vtx, *topTracks[i], *topTrackTracks.at(i).at(0), *daughters[j], *daughterTracks.at(j).at(0), true);
274 
275  // std::cout << "CONSIDERING MATCH: " << topTracks[i]->Self() << " daughter " << daughters[j]->Self() << " overlap: " << info.branch_overlap << " trunk: " << info.trunk << std::endl;
276 
277  if (info.branch_overlap < 0.5) continue;
278 
279  possible_merge_parents[topTracks[i]].push_back({daughters[j], info});
280  possible_merge_children[daughters[j]].push_back({topTracks[j], info});
281  }
282  }
283 
284  // Evaluate all the possible merges
285  // Each track should only have one other possible merge
286  for (auto const &pair: possible_merge_parents) {
287  // std::cout << "Possible Merged: " << pair.first->Self() << " N parents: " << possible_merge_children[pair.first].size() << std::endl;
288  // for (auto const &pair_v: pair.second) {
289  // std::cout << "Child: " << pair_v.first->Self() << " with N parents: " << possible_merge_children[pair_v.first].size() << std::endl;
290  // std::cout << "Info: trunk: " << pair_v.second.trunk << " overlap: " << pair_v.second.branch_overlap << std::endl;
291  // }
292 
293  if (pair.second.size() == 1 && possible_merge_children[pair.first].size() == 0) {
294  art::Ptr<recob::PFParticle> branch = pair.second[0].first;
295  if (possible_merge_parents[branch].size() == 0 && possible_merge_children[branch].size() == 1) {
296  infos->push_back(pair.second[0].second);
297  art::Ptr<sbn::MergedTrackInfo> infoPtr = infoPtrMaker(infos->size()-1);
298  assn->addSingle(infoPtr, pair.first);
299  assn->addSingle(infoPtr, branch);
300  }
301  }
302  }
303  } // end iterate over slices
304 
305  e.put(std::move(infos));
306  e.put(std::move(assn));
307 
308 }
309 
310 DEFINE_ART_MODULE(sbn::MergedTrackIdentifier)
sbn::MergedTrackInfo BuildTrackInfo(const geo::GeometryCore *geo, const recob::Vertex &vtx, const recob::PFParticle &A, const recob::Track &Atrk, const recob::PFParticle &B, const recob::Track &Btrk, bool assume_a_is_trunk=false)
Data product for reconstructed trajectory in space.
Utilities related to art service access.
size_t Self() const
Returns the index of this particle.
Definition: PFParticle.h:92
static bool IsNeutrino(const art::Ptr< recob::PFParticle > particle)
Determine whether a particle has been reconstructed as a neutrino.
Declaration of signal hit object.
Point_t const & LocationAtPoint(size_t i) const
pdgs p
Definition: selectors.fcl:22
size_t NumberTrajectoryPoints() const
Various functions related to the presence and the number of (valid) points.
Class to keep data related to recob::Hit associated with recob::Track.
std::size_t size(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:561
MergedTrackIdentifier(fhicl::ParameterSet const &p)
bool IsPrimary(const caf::SRTrueParticleProxy &p)
Whether this is a primary particle or generated by a secondary interaction.
Definition of vertex object for LArSoft.
Definition: Vertex.h:35
Access the description of detector geometry.
Collection of exceptions for Geometry system.
Point_t const & Start() const
Access to track position at different points.
Data product for reconstructed trajectory in space.
Description of geometry of one entire detector.
Provides recob::Track data product.
std::vector< TCSlice > slices
Definition: DataStructs.cxx:13
size_t FirstValidPoint() const
Hierarchical representation of particle flow.
Definition: PFParticle.h:44
size_t NextValidPoint(size_t index) const
static bool IsTrack(const art::Ptr< recob::PFParticle > particle)
Determine whether a particle has been reconstructed as track-like.
do i e
MergedTrackIdentifier & operator=(MergedTrackIdentifier const &)=delete
Declaration of basic channel signal object.
Vector_t DirectionAtPoint(size_t i) const
TVector3 MeanDirection(const recob::Vertex &vtx, const recob::Track &trk)
Class defining a sparse vector (holes are zeroes)
float A
Definition: dedx.py:137
helper function for LArPandoraInterface producer module
const Point_t & position() const
Return vertex 3D position.
Definition: Vertex.h:60
art framework interface to geometry description
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a &quot;fitted&quot; track:
void produce(art::Event &e) override