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:
21 #include "canvas/Persistency/Common/FindManyP.h"
24 #include "cetlib/pow.h"
25 #include "fhiclcpp/ParameterSet.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 
84 public:
85  EMShower(fhicl::ParameterSet const& pset);
86 
87 private:
88  void produce(art::Event& evt);
89 
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 
108 };
109 
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
154  std::vector<art::Ptr<recob::Hit>> hits;
155  if (evt.getByLabel(fHitsModuleLabel, hitHandle)) art::fill_ptr_vector(hits, hitHandle);
156 
157  // Tracks
159  std::vector<art::Ptr<recob::Track>> tracks;
160  if (evt.getByLabel(fTrackModuleLabel, trackHandle)) art::fill_ptr_vector(tracks, trackHandle);
161 
162  // Clusters
164  std::vector<art::Ptr<recob::Cluster>> clusters;
165  if (evt.getByLabel(fClusterModuleLabel, clusterHandle))
166  art::fill_ptr_vector(clusters, clusterHandle);
167 
168  // PFParticles
170  std::vector<art::Ptr<recob::PFParticle>> pfps;
171  if (evt.getByLabel(fPFParticleModuleLabel, pfpHandle)) art::fill_ptr_vector(pfps, pfpHandle);
172 
173  // PFParticles
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 =
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();
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
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
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);
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 
const TVector3 & ShowerStart() const
Definition: Shower.h:192
std::vector< recob::SpacePoint > MakeSpacePoints(detinfo::DetectorPropertiesData const &detProp, std::map< int, std::vector< art::Ptr< recob::Hit >>> const &hits, std::vector< std::vector< art::Ptr< recob::Hit >>> &hitAssns) const
Makes space points from the shower hits in each plane.
bool const fUseCNNtoIDEMPFP
constexpr to_element_t to_element
Definition: ToElement.h:24
art::InputTag const fVertexModuleLabel
art::InputTag const fClusterModuleLabel
recob::Shower MakeShower(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, art::PtrVector< recob::Hit > const &hits, std::unique_ptr< recob::Track > const &initialTrack, std::map< int, std::vector< art::Ptr< recob::Hit >>> const &initialTrackHits) const
Makes a recob::Shower object given the hits in the shower and the initial track-like part...
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
constexpr T sum_of_squares(T x, T y)
Definition: pow.h:139
bool const fMakeSpacePoints
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >> Point_t
struct vector vector
EMShower(fhicl::ParameterSet const &pset)
bool const fUseCNNtoIDEMHit
void AssociateClustersAndTracks(std::vector< art::Ptr< recob::Cluster >> const &clusters, art::FindManyP< recob::Hit > const &fmh, art::FindManyP< recob::Track > const &fmt, std::map< int, std::vector< int >> &clusterToTracks, std::map< int, std::vector< int >> &trackToClusters) const
Map associated tracks and clusters together given their associated hits.
Definition: EMShowerAlg.cxx:60
int PdgCode() const
Return the type of particle as a PDG ID.
Definition: PFParticle.h:83
art::InputTag const fTrackModuleLabel
Cluster finding and building.
bool const fFindBadPlanes
std::string encode() const
Definition: InputTag.cc:97
std::vector< std::vector< int > > FindShowers(std::map< int, std::vector< int >> const &trackToClusters) const
Makes showers given a map between tracks and all clusters associated with them.
art framework interface to geometry description
art::InputTag const fPFParticleModuleLabel
bool isValid() const noexcept
Definition: Handle.h:191
void set_id(const int id)
Definition: Shower.h:128
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
Definition: DataViewImpl.h:633
bool search_all(FwdCont const &, Datum const &)
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
void push_back(Ptr< U > const &p)
Definition: PtrVector.h:435
def key(type, name=None)
Definition: graph.py:13
def move(depos, offset)
Definition: depos.py:107
std::vector< int > CheckShowerPlanes(std::vector< std::vector< int >> const &initialShowers, std::vector< art::Ptr< recob::Cluster >> const &clusters, art::FindManyP< recob::Hit > const &fmh) const
Takes the initial showers found and tries to resolve issues where one bad view ruins the event...
key_type key() const noexcept
Definition: Ptr.h:216
std::map< int, std::vector< art::Ptr< recob::Hit > > > OrderShowerHits(detinfo::DetectorPropertiesData const &detProp, art::PtrVector< recob::Hit > const &shower, int plane) const
Takes the hits associated with a shower and orders them so they follow the direction of the shower...
art::InputTag const fHitsModuleLabel
ProductID put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: DataViewImpl.h:686
double const fMinTrackLikeScore
void produce(art::Event &evt)
size_type size() const
Definition: PtrVector.h:302
void FindInitialTrack(detinfo::DetectorPropertiesData const &detProp, std::map< int, std::vector< art::Ptr< recob::Hit >>> const &hits, std::unique_ptr< recob::Track > &initialTrack, std::map< int, std::vector< art::Ptr< recob::Hit >>> &initialTrackHits, int plane) const
EMShowerAlg const fEMShowerAlg
Declaration of signal hit object.
Provides recob::Track data product.
auto for_all(FwdCont &, Func)
static bool * b
Definition: config.cpp:1043
art::InputTag const fCNNEMModuleLabel
TCEvent evt
Definition: DataStructs.cxx:7
bool const fSaveNonCompleteShowers
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:297
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
Definition: fwd.h:31
static std::unique_ptr< MVAReader > create(const art::Event &evt, const art::InputTag &tag)
Definition: MVAReader.h:110
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33