All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
EMShower_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////
2 // Class: EMShower
3 // Module Type: producer
4 // File: EMShower_module.cc
5 // Author: Mike Wallbank (m.wallbank@sheffield.ac.uk), September 2015
6 //
7 // Module to make EM showers.
8 // Takes the output from cluster finding and track finding and combines
9 // information to make complete 3D shower.
10 //
11 // See DUNE-DocDB 1369 (public) for a detailed description.
12 ////////////////////////////////////////////////////////////////////////////
13 
14 // Framework includes:
15 #include "art/Framework/Core/EDProducer.h"
16 #include "art/Framework/Core/ModuleMacros.h"
17 #include "art/Framework/Principal/Event.h"
18 #include "art/Framework/Principal/Handle.h"
19 #include "art/Framework/Services/Registry/ServiceHandle.h"
20 #include "art/Persistency/Common/PtrMaker.h"
21 #include "canvas/Persistency/Common/FindManyP.h"
22 #include "canvas/Persistency/Common/Ptr.h"
23 #include "canvas/Persistency/Common/PtrVector.h"
24 #include "cetlib/pow.h"
25 #include "fhiclcpp/ParameterSet.h"
26 #include "messagefacility/MessageLogger/MessageLogger.h"
27 
28 // LArSoft includes
42 
43 // ROOT includes
44 #include "RtypesCore.h"
45 #include "TVector3.h"
46 
47 // C++ STL includes
48 #include <algorithm>
49 #include <array>
50 #include <float.h>
51 #include <iostream>
52 #include <map>
53 #include <math.h>
54 #include <memory>
55 #include <stddef.h>
56 #include <string>
57 #include <vector>
58 
59 #include "range/v3/view.hpp"
60 
61 namespace {
62  template <typename T, typename U>
63  struct AddMany {
64  AddMany(art::Ptr<T> const& ptr, art::Assns<T, U>& assns) : ptr_{ptr}, assns_{assns} {}
65 
66  void
67  operator()(art::Ptr<U> const& b) const
68  {
69  assns_.addSingle(ptr_, b);
70  }
71 
72  art::Ptr<T> const ptr_;
73  art::Assns<T, U>& assns_;
74  };
75 }
76 
77 using lar::to_element;
78 
79 namespace shower {
80  class EMShower;
81 }
82 
83 class shower::EMShower : public art::EDProducer {
84 public:
85  EMShower(fhicl::ParameterSet const& pset);
86 
87 private:
88  void produce(art::Event& evt);
89 
90  art::InputTag const fHitsModuleLabel;
91  art::InputTag const fClusterModuleLabel;
92  art::InputTag const fTrackModuleLabel;
93  art::InputTag const fPFParticleModuleLabel;
94  art::InputTag const fVertexModuleLabel;
95  art::InputTag const fCNNEMModuleLabel;
96  int const fShower;
97  int const fPlane;
98  int const fDebug;
101  bool const fFindBadPlanes;
102  bool const fMakeSpacePoints;
103  bool const fUseCNNtoIDEMPFP;
104  bool const fUseCNNtoIDEMHit;
105  double const fMinTrackLikeScore;
106 
107  art::ServiceHandle<geo::Geometry const> fGeom;
108 };
109 
110 shower::EMShower::EMShower(fhicl::ParameterSet const& pset)
111  : EDProducer{pset}
112  , fHitsModuleLabel{pset.get<art::InputTag>("HitsModuleLabel")}
113  , fClusterModuleLabel{pset.get<art::InputTag>("ClusterModuleLabel")}
114  , fTrackModuleLabel{pset.get<art::InputTag>("TrackModuleLabel")}
115  , fPFParticleModuleLabel{pset.get<art::InputTag>("PFParticleModuleLabel", "")}
116  , fVertexModuleLabel{pset.get<art::InputTag>("VertexModuleLabel", "")}
117  , fCNNEMModuleLabel{pset.get<art::InputTag>("CNNEMModuleLabel", "")}
118  , fShower{pset.get<int>("Shower", -1)}
119  , fPlane{pset.get<int>("Plane", -1)}
120  , fDebug{pset.get<int>("Debug", 0)}
121  , fEMShowerAlg{pset.get<fhicl::ParameterSet>("EMShowerAlg"), fDebug}
122  , fSaveNonCompleteShowers{pset.get<bool>("SaveNonCompleteShowers")}
123  , fFindBadPlanes{pset.get<bool>("FindBadPlanes")}
124  , fMakeSpacePoints{pset.get<bool>("MakeSpacePoints")}
125  , fUseCNNtoIDEMPFP{pset.get<bool>("UseCNNtoIDEMPFP")}
126  , fUseCNNtoIDEMHit{pset.get<bool>("UseCNNtoIDEMHit")}
127  , fMinTrackLikeScore{pset.get<double>("MinTrackLikeScore")}
128 {
129  produces<std::vector<recob::Shower>>();
130  produces<std::vector<recob::SpacePoint>>();
131  produces<art::Assns<recob::Shower, recob::Hit>>();
132  produces<art::Assns<recob::Shower, recob::Cluster>>();
133  produces<art::Assns<recob::Shower, recob::Track>>();
134  produces<art::Assns<recob::Shower, recob::SpacePoint>>();
135  produces<art::Assns<recob::SpacePoint, recob::Hit>>();
136 }
137 
138 void
140 {
141  // Output -- showers and associations with hits and clusters
142  auto showers = std::make_unique<std::vector<recob::Shower>>();
143  auto spacePoints = std::make_unique<std::vector<recob::SpacePoint>>();
144  auto clusterAssociations = std::make_unique<art::Assns<recob::Shower, recob::Cluster>>();
145  auto hitShowerAssociations = std::make_unique<art::Assns<recob::Shower, recob::Hit>>();
146  auto trackAssociations = std::make_unique<art::Assns<recob::Shower, recob::Track>>();
147  auto spShowerAssociations = std::make_unique<art::Assns<recob::Shower, recob::SpacePoint>>();
148  auto hitSpAssociations = std::make_unique<art::Assns<recob::SpacePoint, recob::Hit>>();
149 
150  // Event has hits, tracks and clusters found already
151 
152  // Hits
153  art::Handle<std::vector<recob::Hit>> hitHandle;
154  std::vector<art::Ptr<recob::Hit>> hits;
155  if (evt.getByLabel(fHitsModuleLabel, hitHandle)) art::fill_ptr_vector(hits, hitHandle);
156 
157  // Tracks
158  art::Handle<std::vector<recob::Track>> trackHandle;
159  std::vector<art::Ptr<recob::Track>> tracks;
160  if (evt.getByLabel(fTrackModuleLabel, trackHandle)) art::fill_ptr_vector(tracks, trackHandle);
161 
162  // Clusters
163  art::Handle<std::vector<recob::Cluster>> clusterHandle;
164  std::vector<art::Ptr<recob::Cluster>> clusters;
165  if (evt.getByLabel(fClusterModuleLabel, clusterHandle))
166  art::fill_ptr_vector(clusters, clusterHandle);
167 
168  // PFParticles
169  art::Handle<std::vector<recob::PFParticle>> pfpHandle;
170  std::vector<art::Ptr<recob::PFParticle>> pfps;
171  if (evt.getByLabel(fPFParticleModuleLabel, pfpHandle)) art::fill_ptr_vector(pfps, pfpHandle);
172 
173  // PFParticles
174  art::Handle<std::vector<recob::Vertex>> vtxHandle;
175  std::vector<art::Ptr<recob::Vertex>> vertices;
176  if (evt.getByLabel(fVertexModuleLabel, vtxHandle)) art::fill_ptr_vector(vertices, vtxHandle);
177 
178  // Associations
179  art::FindManyP<recob::Hit> fmh(clusterHandle, evt, fClusterModuleLabel);
180  art::FindManyP<recob::Track> fmt(hitHandle, evt, fTrackModuleLabel);
181  art::FindManyP<recob::SpacePoint> fmsp(trackHandle, evt, fTrackModuleLabel);
182  art::FindManyP<recob::Cluster> fmc(hitHandle, evt, fHitsModuleLabel);
183 
184  // Make showers
185  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
186  auto const detProp =
187  art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(evt, clockData);
188  std::vector<std::vector<int>> newShowers;
189  std::vector<unsigned int> pfParticles;
190 
191  std::map<int, std::vector<int>> clusterToTracks;
192  std::map<int, std::vector<int>> trackToClusters;
193 
194  if (!pfpHandle.isValid()) {
195 
196  // Map between tracks and clusters
197  fEMShowerAlg.AssociateClustersAndTracks(clusters, fmh, fmt, clusterToTracks, trackToClusters);
198 
199  // Make initial showers
200  std::vector<std::vector<int>> initialShowers = fEMShowerAlg.FindShowers(trackToClusters);
201 
202  // Deal with views in which 2D reconstruction failed
203  std::vector<int> clustersToIgnore;
204  if (fFindBadPlanes)
205  clustersToIgnore = fEMShowerAlg.CheckShowerPlanes(initialShowers, clusters, fmh);
206 
207  if (clustersToIgnore.size() > 0) {
208  clusterToTracks.clear();
209  trackToClusters.clear();
210  fEMShowerAlg.AssociateClustersAndTracks(
211  clusters, fmh, fmt, clustersToIgnore, clusterToTracks, trackToClusters);
212  newShowers = fEMShowerAlg.FindShowers(trackToClusters);
213  }
214  else
215  newShowers = initialShowers;
216  }
217 
218  else {
219 
220  // Use pfparticle information
221  art::FindManyP<recob::Cluster> fmcp(pfpHandle, evt, fPFParticleModuleLabel);
222  for (size_t ipfp = 0; ipfp < pfps.size(); ++ipfp) {
223  art::Ptr<recob::PFParticle> pfp = pfps[ipfp];
224  if (fCNNEMModuleLabel != "" && fUseCNNtoIDEMPFP) { //use CNN to identify EM pfparticle
225  auto hitResults = anab::MVAReader<recob::Hit, 4>::create(evt, fCNNEMModuleLabel);
226  if (!hitResults) {
227  throw cet::exception("EMShower") << "Cannot get MVA results from " << fCNNEMModuleLabel;
228  }
229  int trkLikeIdx = hitResults->getIndex("track");
230  int emLikeIdx = hitResults->getIndex("em");
231  if ((trkLikeIdx < 0) || (emLikeIdx < 0)) {
232  throw cet::exception("EMShower") << "No em/track labeled columns in MVA data products.";
233  }
234  if (fmcp.isValid()) { //find clusters
235  std::vector<art::Ptr<recob::Hit>> pfphits;
236  std::vector<art::Ptr<recob::Cluster>> clus = fmcp.at(ipfp);
237  for (size_t iclu = 0; iclu < clus.size(); ++iclu) {
238  std::vector<art::Ptr<recob::Hit>> ClusterHits = fmh.at(clus[iclu].key());
239  pfphits.insert(pfphits.end(), ClusterHits.begin(), ClusterHits.end());
240  }
241  if (pfphits.size()) { //find hits
242  auto vout = hitResults->getOutput(pfphits);
243  double trk_like = -1, trk_or_em = vout[trkLikeIdx] + vout[emLikeIdx];
244  if (trk_or_em > 0) {
245  trk_like = vout[trkLikeIdx] / trk_or_em;
246  if (trk_like < fMinTrackLikeScore) { //EM like
247  std::vector<int> clusters;
248  for (size_t iclu = 0; iclu < clus.size(); ++iclu) {
249  clusters.push_back(clus[iclu].key());
250  }
251  if (clusters.size()) {
252  newShowers.push_back(clusters);
253  pfParticles.push_back(ipfp);
254  }
255  }
256  }
257  }
258  }
259  else {
260  throw cet::exception("EMShower") << "Cannot get associated cluster for PFParticle "
261  << fPFParticleModuleLabel.encode() << "[" << ipfp << "]";
262  }
263  }
264  else if (pfp->PdgCode() == 11) { //shower particle
265  if (fmcp.isValid()) {
266  std::vector<int> clusters;
267  std::vector<art::Ptr<recob::Cluster>> clus = fmcp.at(ipfp);
268  for (size_t iclu = 0; iclu < clus.size(); ++iclu) {
269  clusters.push_back(clus[iclu].key());
270  }
271  if (clusters.size()) {
272  newShowers.push_back(clusters);
273  pfParticles.push_back(ipfp);
274  }
275  }
276  }
277  }
278  }
279 
280  // Make output larsoft products
281  int showerNum = 0;
282  for (auto const& newShower : newShowers) {
283 
284  if (showerNum != fShower and fShower != -1) continue;
285 
286  // New shower
287  if (fDebug > 0) std::cout << "\n\nStart shower " << showerNum << '\n';
288 
289  // New associations
290  art::PtrVector<recob::Hit> showerHits;
291  art::PtrVector<recob::Cluster> showerClusters;
292  art::PtrVector<recob::Track> showerTracks;
293  art::PtrVector<recob::SpacePoint> showerSpacePoints_p;
294 
295  std::vector<int> associatedTracks;
296 
297  // Make showers and associations
298  for (int const showerCluster : newShower) {
299 
300  // Clusters
301  art::Ptr<recob::Cluster> const cluster = clusters.at(showerCluster);
302  showerClusters.push_back(cluster);
303 
304  // Hits
305  std::vector<art::Ptr<recob::Hit>> const& showerClusterHits = fmh.at(cluster.key());
306  if (fCNNEMModuleLabel != "" && fUseCNNtoIDEMHit) { // use CNN to identify EM hits
307  auto hitResults = anab::MVAReader<recob::Hit, 4>::create(evt, fCNNEMModuleLabel);
308  if (!hitResults) {
309  throw cet::exception("EMShower")
310  << "Cannot get MVA results from " << fCNNEMModuleLabel.encode();
311  }
312  int trkLikeIdx = hitResults->getIndex("track");
313  int emLikeIdx = hitResults->getIndex("em");
314  if (trkLikeIdx < 0 || emLikeIdx < 0) {
315  throw cet::exception("EMShower") << "No em/track labeled columns in MVA data products.";
316  }
317  for (auto const& showerHit : showerClusterHits) {
318  auto vout = hitResults->getOutput(showerHit);
319  double trk_like = -1, trk_or_em = vout[trkLikeIdx] + vout[emLikeIdx];
320  if (trk_or_em > 0) {
321  trk_like = vout[trkLikeIdx] / trk_or_em;
322  if (trk_like < fMinTrackLikeScore) { // EM like
323  showerHits.push_back(showerHit);
324  }
325  }
326  }
327  }
328  else {
329  for (auto const& showerClusterHit : showerClusterHits)
330  showerHits.push_back(showerClusterHit);
331  }
332  // Tracks
333  if (!pfpHandle.isValid()) { // Only do this for non-pfparticle mode
334  for (int const clusterTrack : clusterToTracks.at(showerCluster))
335  if (not cet::search_all(associatedTracks, clusterTrack))
336  associatedTracks.push_back(clusterTrack);
337  }
338  }
339 
340  if (!pfpHandle.isValid()) { // For non-pfparticles, get space points from tracks
341  // Tracks and space points
342  for (int const trackIndex : associatedTracks) {
343  showerTracks.push_back(tracks.at(trackIndex));
344  }
345  }
346  else { // For pfparticles, get space points from hits
347  art::FindManyP<recob::SpacePoint> fmspp(showerHits, evt, fPFParticleModuleLabel);
348  if (fmspp.isValid()) {
349  for (size_t ihit = 0; ihit < showerHits.size(); ++ihit) {
350  for (auto const& spPtr : fmspp.at(ihit))
351  showerSpacePoints_p.push_back(spPtr);
352  }
353  }
354  }
355 
356  if (!pfpHandle.isValid()) {
357 
358  // First, order the hits into the correct shower order in each plane
359  if (fDebug > 1)
360  std::cout << " ------------------ Ordering shower hits --------------------\n";
361  std::map<int, std::vector<art::Ptr<recob::Hit>>> showerHitsMap =
362  fEMShowerAlg.OrderShowerHits(detProp, showerHits, fPlane);
363  if (fDebug > 1)
364  std::cout << " ------------------ End ordering shower hits "
365  "--------------------\n";
366 
367  // Find the track at the start of the shower
368  std::unique_ptr<recob::Track> initialTrack;
369  std::map<int, std::vector<art::Ptr<recob::Hit>>> initialTrackHits;
370  fEMShowerAlg.FindInitialTrack(detProp, showerHitsMap, initialTrack, initialTrackHits, fPlane);
371 
372  // Make space points
373  std::vector<std::vector<art::Ptr<recob::Hit>>> hitAssns;
374  std::vector<recob::SpacePoint> showerSpacePoints;
375  if (fMakeSpacePoints)
376  showerSpacePoints = fEMShowerAlg.MakeSpacePoints(detProp, showerHitsMap, hitAssns);
377  else {
378  for (auto const& trkPtr : showerTracks) {
379  for (auto const& trackSpacePoint :
380  fmsp.at(trkPtr.key()) | ranges::views::transform(to_element)) {
381  showerSpacePoints.push_back(trackSpacePoint);
382  hitAssns.push_back(std::vector<art::Ptr<recob::Hit>>());
383  }
384  }
385  }
386 
387  // Save space points
388  art::PtrMaker<recob::SpacePoint> const make_space_point_ptr{evt};
389  size_t firstSpacePoint = spacePoints->size(), nSpacePoint = 0;
390  for (auto const& ssp : showerSpacePoints) {
391  spacePoints->emplace_back(ssp.XYZ(), ssp.ErrXYZ(), ssp.Chisq(), spacePoints->size());
392  auto const index = spacePoints->size() - 1;
393  auto const space_point_ptr = make_space_point_ptr(index);
394  cet::for_all(hitAssns.at(nSpacePoint), AddMany{space_point_ptr, *hitSpAssociations});
395  }
396  auto const lastSpacePoint = spacePoints->size();
397 
398  // Make shower object and associations
400  fEMShowerAlg.MakeShower(clockData, detProp, showerHits, initialTrack, initialTrackHits);
401  shower.set_id(showerNum);
402  if (fSaveNonCompleteShowers or
403  (!fSaveNonCompleteShowers and shower.ShowerStart() != TVector3{})) {
404  showers->push_back(shower);
405 
406  auto const shower_ptr = art::PtrMaker<recob::Shower>{evt}(showers->size() - 1);
407  cet::for_all(showerHits, AddMany{shower_ptr, *hitShowerAssociations});
408  cet::for_all(showerClusters, AddMany{shower_ptr, *clusterAssociations});
409  cet::for_all(showerTracks, AddMany{shower_ptr, *trackAssociations});
410  for (size_t i = firstSpacePoint; i < lastSpacePoint; ++i) {
411  spShowerAssociations->addSingle(shower_ptr, make_space_point_ptr(i));
412  }
413  }
414  else
415  mf::LogInfo("EMShower") << "Discarding shower " << showerNum
416  << " due to incompleteness (SaveNonCompleteShowers == false)";
417  }
418 
419  else { // pfParticle
420 
421  if (vertices.size()) {
422  // found the most upstream vertex
424  Point_t nuvtx{0, 0, DBL_MAX};
425  for (auto const& vtx : vertices) {
426  auto const pos = vtx->position();
427  if (pos.Z() < nuvtx.Z()) { nuvtx = pos; }
428  }
429 
430  Point_t shwvtx{0, 0, 0};
431  double mindist2 = DBL_MAX;
432  for (auto const& sp : showerSpacePoints_p | ranges::views::transform(to_element)) {
433  double const dist2 = cet::sum_of_squares(
434  nuvtx.X() - sp.XYZ()[0], nuvtx.Y() - sp.XYZ()[1], nuvtx.Z() - sp.XYZ()[2]);
435  if (dist2 < mindist2) {
436  mindist2 = dist2;
437  shwvtx.SetXYZ(sp.XYZ()[0], sp.XYZ()[1], sp.XYZ()[2]);
438  }
439  }
440 
441  art::Ptr<recob::Vertex> bestvtx;
442  mindist2 = DBL_MAX;
443  for (auto const& vtx : vertices) {
444  auto const pos = vtx->position();
445  double const dist2 =
446  cet::sum_of_squares(pos.X() - shwvtx.X(), pos.Y() - shwvtx.Y(), pos.Z() - shwvtx.Z());
447  if (dist2 < mindist2) {
448  mindist2 = dist2;
449  bestvtx = vtx;
450  }
451  }
452 
453  int iok = 0;
455  fEMShowerAlg.MakeShower(clockData, detProp, showerHits, bestvtx, iok);
456  if (iok == 0) {
457  showers->push_back(shower);
458  auto const index = showers->size() - 1;
459  showers->back().set_id(index);
460 
461  auto const shower_ptr = art::PtrMaker<recob::Shower>{evt}(index);
462  cet::for_all(showerHits, AddMany{shower_ptr, *hitShowerAssociations});
463  cet::for_all(showerClusters, AddMany{shower_ptr, *clusterAssociations});
464  cet::for_all(showerTracks, AddMany{shower_ptr, *trackAssociations});
465  cet::for_all(showerSpacePoints_p, AddMany{shower_ptr, *spShowerAssociations});
466  }
467  }
468  }
469  }
470 
471  // Put in event
472  evt.put(std::move(showers));
473  evt.put(std::move(spacePoints));
474  evt.put(std::move(hitShowerAssociations));
475  evt.put(std::move(clusterAssociations));
476  evt.put(std::move(trackAssociations));
477  evt.put(std::move(spShowerAssociations));
478  evt.put(std::move(hitSpAssociations));
479 }
480 
481 DEFINE_ART_MODULE(shower::EMShower)
bool const fUseCNNtoIDEMPFP
Utilities related to art service access.
constexpr to_element_t to_element
Definition: ToElement.h:24
ClusterModuleLabel join with tracks
static constexpr Sample_t transform(Sample_t sample)
art::InputTag const fVertexModuleLabel
process_name cluster
Definition: cheaterreco.fcl:51
art::InputTag const fClusterModuleLabel
Declaration of signal hit object.
bool const fMakeSpacePoints
EMShower(fhicl::ParameterSet const &pset)
bool const fUseCNNtoIDEMHit
art::InputTag const fTrackModuleLabel
bool const fFindBadPlanes
process_name shower
Definition: cheaterreco.fcl:51
recob::tracking::Point_t Point_t
art::InputTag const fPFParticleModuleLabel
void set_id(const int id)
Definition: Shower.h:128
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
art::InputTag const fHitsModuleLabel
return match has_match and(match.match_pdg==11 or match.match_pdg==-11)
double const fMinTrackLikeScore
Declaration of cluster object.
Provides recob::Track data product.
void produce(art::Event &evt)
EMShowerAlg const fEMShowerAlg
const TVector3 & ShowerStart() const
Definition: Shower.h:192
art::InputTag const fCNNEMModuleLabel
TCEvent evt
Definition: DataStructs.cxx:8
bool const fSaveNonCompleteShowers
art::ServiceHandle< geo::Geometry const > fGeom
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< Coord_t >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space. See recob::tracking::Coord_t for more detai...
Definition: TrackingTypes.h:26
static std::unique_ptr< MVAReader > create(const art::Event &evt, const art::InputTag &tag)
Definition: MVAReader.h:110
art framework interface to geometry description
BEGIN_PROLOG could also be cout
auto const detProp