LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
EmTrackMichelId_module.cc
Go to the documentation of this file.
1 // Class: EmTrackMichelId
3 // Module Type: producer
4 // File: EmTrackMichelId_module.cc
5 // Authors: D.Stefan (dorota.stefan@cern.ch), from DUNE, CERN/NCBJ
6 // P.Plonski (pplonski86@gmail.com), from DUNE, WUT
7 // R.Sulej (robert.sulej@cern.ch), from DUNE, FNAL/NCBJ
8 //
9 // Module applies CNN to 2D image made of deconvoluted wire waveforms in order
10 // to distinguish EM-like activity from track-like objects. In addition the activity
11 // of Michel electrons is recognized. New clusters of hits are produced to include
12 // also unclustered hits and tag all the activity as EM/track in the same way.
13 // Note: Michel electrons are best tagged on the level of single hits, since
14 // clustering may have introduced mistakes (hits of muon and electron clustered
15 // together).
16 //
18 
29 
41 #include "cetlib_except/exception.h"
42 #include "fhiclcpp/ParameterSet.h"
43 #include "fhiclcpp/types/Atom.h"
44 #include "fhiclcpp/types/Comment.h"
45 #include "fhiclcpp/types/Name.h"
47 #include "fhiclcpp/types/Table.h"
49 
50 #include <iostream>
51 #include <memory>
52 #include <string>
53 #include <unordered_map>
54 #include <utility>
55 #include <vector>
56 
57 namespace nnet {
58 
60  public:
61  // these types to be replaced with use of feature proposed in redmine #12602
62  typedef std::unordered_map<unsigned int, std::vector<size_t>> view_keymap;
63  typedef std::unordered_map<unsigned int, view_keymap> tpc_view_keymap;
64  typedef std::unordered_map<unsigned int, tpc_view_keymap> cryo_tpc_view_keymap;
65 
66  struct Config {
67  using Name = fhicl::Name;
69 
72  Comment("number of samples processed in one batch")};
73 
75  Name("WireLabel"),
76  Comment("tag of deconvoluted ADC on wires (recob::Wire)")};
77 
79  Name("HitModuleLabel"),
80  Comment("tag of hits to be EM/track / Michel tagged")};
81 
83  Name("ClusterModuleLabel"),
84  Comment("tag of clusters to be used as a source of EM/track / Michel tagged new clusters "
85  "(incl. single-hit clusters ) using accumulated results from hits")};
86 
88  Name("TrackModuleLabel"),
89  Comment("tag of 3D tracks to be EM/track / Michel tagged using accumulated results from "
90  "hits in the best 2D projection")};
91 
93  Name("Views"),
94  Comment("tag clusters in selected views only, or in all views if empty list")};
95  };
97  explicit EmTrackMichelId(Parameters const& p);
98 
99  EmTrackMichelId(EmTrackMichelId const&) = delete;
100  EmTrackMichelId(EmTrackMichelId&&) = delete;
101  EmTrackMichelId& operator=(EmTrackMichelId const&) = delete;
103 
104  private:
105  void produce(art::Event& e) override;
106 
107  bool isViewSelected(int view) const;
108 
109  size_t fBatchSize;
111  anab::MVAWriter<4> fMVAWriter; // <-------------- using 4-output CNN model
112 
118 
119  std::vector<int> fViews;
120 
121  art::InputTag fNewClustersTag; // input tag for the clusters produced by this module
122  };
123  // ------------------------------------------------------
124 
126  : EDProducer{config}
127  , fBatchSize(config().BatchSize())
128  , fPointIdAlg(config().PointIdAlg())
129  , fMVAWriter(producesCollector(), "emtrkmichel")
130  , fWireProducerLabel(config().WireLabel())
131  , fHitModuleLabel(config().HitModuleLabel())
132  , fClusterModuleLabel(config().ClusterModuleLabel())
133  , fTrackModuleLabel(config().TrackModuleLabel())
134  , fViews(config().Views())
135  ,
136 
137  fNewClustersTag(config.get_PSet().get<std::string>("module_label"),
138  "",
140  {
142 
143  if (!fClusterModuleLabel.label().empty()) {
144  produces<std::vector<recob::Cluster>>();
145  produces<art::Assns<recob::Cluster, recob::Hit>>();
146 
148  fDoClusters = true;
149  }
150  else {
151  fDoClusters = false;
152  }
153 
154  if (!fTrackModuleLabel.label().empty()) {
156  fDoTracks = true;
157  }
158  else {
159  fDoTracks = false;
160  }
161  }
162  // ------------------------------------------------------
163 
165  {
166  mf::LogVerbatim("EmTrackMichelId") << "next event: " << evt.run() << " / " << evt.id().event();
167 
168  auto wireHandle = evt.getValidHandle<std::vector<recob::Wire>>(fWireProducerLabel);
169 
170  unsigned int cryo, tpc, view;
171 
172  // ******************* get and sort hits ********************
173  auto hitListHandle = evt.getValidHandle<std::vector<recob::Hit>>(fHitModuleLabel);
174  std::vector<art::Ptr<recob::Hit>> hitPtrList;
175  art::fill_ptr_vector(hitPtrList, hitListHandle);
176 
178  for (auto const& h : hitPtrList) {
179  view = h->WireID().Plane;
180  if (!isViewSelected(view)) continue;
181 
182  cryo = h->WireID().Cryostat;
183  tpc = h->WireID().TPC;
184 
185  hitMap[cryo][tpc][view].push_back(h.key());
186  }
187 
188  // ********************* classify hits **********************
189  auto hitID = fMVAWriter.initOutputs<recob::Hit>(
190  fHitModuleLabel, hitPtrList.size(), fPointIdAlg.outputLabels());
191 
192  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
193  auto const detProp =
195 
196  std::vector<char> hitInFA(
197  hitPtrList.size(),
198  0); // tag hits in fid. area as 1, use 0 for hits close to the projectrion edges
199  for (auto const& pcryo : hitMap) {
200  cryo = pcryo.first;
201  for (auto const& ptpc : pcryo.second) {
202  tpc = ptpc.first;
203  for (auto const& pview : ptpc.second) {
204  view = pview.first;
205  if (!isViewSelected(view)) continue; // should not happen, hits were selected
206 
207  fPointIdAlg.setWireDriftData(clockData, detProp, *wireHandle, view, tpc, cryo);
208 
209  // (1) do all hits in this plane ------------------------------------------------
210  for (size_t idx = 0; idx < pview.second.size(); idx += fBatchSize) {
211  std::vector<std::pair<unsigned int, float>> points;
212  std::vector<size_t> keys;
213  for (size_t k = 0; k < fBatchSize; ++k) {
214  if (idx + k >= pview.second.size()) { break; } // careful about the tail
215 
216  size_t h = pview.second[idx + k]; // h is the Ptr< recob::Hit >::key()
217  const recob::Hit& hit = *(hitPtrList[h]);
218  points.emplace_back(hit.WireID().Wire, hit.PeakTime());
219  keys.push_back(h);
220  }
221 
222  auto batch_out = fPointIdAlg.predictIdVectors(points);
223  if (points.size() != batch_out.size()) {
224  throw cet::exception("EmTrackMichelId") << "hits processing failed" << std::endl;
225  }
226 
227  for (size_t k = 0; k < points.size(); ++k) {
228  size_t h = keys[k];
229  fMVAWriter.setOutput(hitID, h, batch_out[k]);
230  if (fPointIdAlg.isInsideFiducialRegion(points[k].first, points[k].second)) {
231  hitInFA[h] = 1;
232  }
233  }
234  } // hits done ------------------------------------------------------------------
235  }
236  }
237  }
238 
239  // (2) do clusters when hits are ready in all planes ----------------------------------------
240  if (fDoClusters) {
241  // **************** prepare for new clusters ****************
242  auto clusters = std::make_unique<std::vector<recob::Cluster>>();
243  auto clu2hit = std::make_unique<art::Assns<recob::Cluster, recob::Hit>>();
244 
245  // ************** get and sort input clusters ***************
246  auto cluListHandle = evt.getValidHandle<std::vector<recob::Cluster>>(fClusterModuleLabel);
247  std::vector<art::Ptr<recob::Cluster>> cluPtrList;
248  art::fill_ptr_vector(cluPtrList, cluListHandle);
249 
251  for (auto const& c : cluPtrList) {
252  view = c->Plane().Plane;
253  if (!isViewSelected(view)) continue;
254 
255  cryo = c->Plane().Cryostat;
256  tpc = c->Plane().TPC;
257 
258  cluMap[cryo][tpc][view].push_back(c.key());
259  }
260 
261  auto cluID =
263 
264  unsigned int cidx = 0; // new clusters index
265  art::FindManyP<recob::Hit> hitsFromClusters(cluListHandle, evt, fClusterModuleLabel);
266  std::vector<bool> hitUsed(hitPtrList.size(), false); // tag hits used in clusters
267  for (auto const& pcryo : cluMap) {
268  cryo = pcryo.first;
269  for (auto const& ptpc : pcryo.second) {
270  tpc = ptpc.first;
271  for (auto const& pview : ptpc.second) {
272  view = pview.first;
273  if (!isViewSelected(view)) continue; // should not happen, clusters were pre-selected
274 
275  for (size_t c : pview.second) // c is the Ptr< recob::Cluster >::key()
276  {
277  auto v = hitsFromClusters.at(c);
278  if (v.empty()) continue;
279 
280  for (auto const& hit : v) {
281  if (hitUsed[hit.key()]) {
282  mf::LogWarning("EmTrackMichelId") << "hit already used in another cluster";
283  }
284  hitUsed[hit.key()] = true;
285  }
286 
287  auto vout = fMVAWriter.getOutput<recob::Hit>(
288  v, [&](art::Ptr<recob::Hit> const& ptr) { return (float)hitInFA[ptr.key()]; });
289 
290  float pvalue = vout[0] / (vout[0] + vout[1]);
291  mf::LogVerbatim("EmTrackMichelId") << "cluster in tpc:" << tpc << " view:" << view
292  << " size:" << v.size() << " p:" << pvalue;
293 
294  clusters->emplace_back(recob::Cluster(0.0F,
295  0.0F,
296  0.0F,
297  0.0F,
298  0.0F,
299  0.0F,
300  0.0F,
301  0.0F,
302  0.0F,
303  0.0F,
304  0.0F,
305  0.0F,
306  0.0F,
307  0.0F,
308  0.0F,
309  0.0F,
310  0.0F,
311  0.0F,
312  v.size(),
313  0.0F,
314  0.0F,
315  cidx,
316  (geo::View_t)view,
317  v.front()->WireID().planeID()));
318  util::CreateAssn(evt, *clusters, v, *clu2hit);
319  cidx++;
320 
321  fMVAWriter.addOutput(cluID, vout); // add copy of the input cluster
322  }
323 
324  // (2b) make single-hit clusters --------------------------------------------
325  for (size_t h : hitMap[cryo][tpc][view]) // h is the Ptr< recob::Hit >::key()
326  {
327  if (hitUsed[h]) continue;
328 
329  auto vout = fMVAWriter.getOutput<recob::Hit>(h);
330  float pvalue = vout[0] / (vout[0] + vout[1]);
331 
332  mf::LogVerbatim("EmTrackMichelId")
333  << "single hit in tpc:" << tpc << " view:" << view
334  << " wire:" << hitPtrList[h]->WireID().Wire
335  << " drift:" << hitPtrList[h]->PeakTime() << " p:" << pvalue;
336 
337  art::PtrVector<recob::Hit> cluster_hits;
338  cluster_hits.push_back(hitPtrList[h]);
339  clusters->emplace_back(recob::Cluster(0.0F,
340  0.0F,
341  0.0F,
342  0.0F,
343  0.0F,
344  0.0F,
345  0.0F,
346  0.0F,
347  0.0F,
348  0.0F,
349  0.0F,
350  0.0F,
351  0.0F,
352  0.0F,
353  0.0F,
354  0.0F,
355  0.0F,
356  0.0F,
357  1,
358  0.0F,
359  0.0F,
360  cidx,
361  (geo::View_t)view,
362  hitPtrList[h]->WireID().planeID()));
363  util::CreateAssn(evt, *clusters, cluster_hits, *clu2hit);
364  cidx++;
365 
366  fMVAWriter.addOutput(cluID, vout); // add single-hit cluster tagging unclutered hit
367  }
368  mf::LogVerbatim("EmTrackMichelId")
369  << "...produced " << cidx - pview.second.size() << " single-hit clusters.";
370  }
371  }
372  }
373 
374  evt.put(std::move(clusters));
375  evt.put(std::move(clu2hit));
376  } // all clusters done ----------------------------------------------------------------------
377 
378  // (3) do tracks when all hits in all cryo/tpc/plane are done -------------------------------
379  if (fDoTracks) {
380  auto trkListHandle = evt.getValidHandle<std::vector<recob::Track>>(fTrackModuleLabel);
381  art::FindManyP<recob::Hit> hitsFromTracks(trkListHandle, evt, fTrackModuleLabel);
382  std::vector<std::vector<art::Ptr<recob::Hit>>> trkHitPtrList(trkListHandle->size());
383  for (size_t t = 0; t < trkListHandle->size(); ++t) {
384  auto v = hitsFromTracks.at(t);
385  size_t nh[3] = {0, 0, 0};
386  for (auto const& hptr : v) {
387  ++nh[hptr->View()];
388  }
389  size_t best_view = 2; // collection
390  if ((nh[0] >= nh[1]) && (nh[0] > 2 * nh[2])) best_view = 0; // ind1
391  if ((nh[1] >= nh[0]) && (nh[1] > 2 * nh[2])) best_view = 1; // ind2
392 
393  size_t k = 0;
394  while (!isViewSelected(best_view)) {
395  best_view = (best_view + 1) % 3;
396  if (++k > 3) {
397  throw cet::exception("EmTrackMichelId") << "No views selected at all?" << std::endl;
398  }
399  }
400 
401  for (auto const& hptr : v) {
402  if (hptr->View() == best_view) trkHitPtrList[t].emplace_back(hptr);
403  }
404  }
405 
406  auto trkID = fMVAWriter.initOutputs<recob::Track>(
407  fTrackModuleLabel, trkHitPtrList.size(), fPointIdAlg.outputLabels());
408  for (size_t t = 0; t < trkHitPtrList.size(); ++t) // t is the Ptr< recob::Track >::key()
409  {
410  auto vout =
411  fMVAWriter.getOutput<recob::Hit>(trkHitPtrList[t], [&](art::Ptr<recob::Hit> const& ptr) {
412  return (float)hitInFA[ptr.key()];
413  });
414  fMVAWriter.setOutput(trkID, t, vout);
415  }
416  }
417  // tracks done ------------------------------------------------------------------------------
418 
419  fMVAWriter.saveOutputs(evt);
420  }
421  // ------------------------------------------------------
422 
423  bool EmTrackMichelId::isViewSelected(int view) const
424  {
425  if (fViews.empty())
426  return true;
427  else {
428  bool selected = false;
429  for (auto k : fViews)
430  if (k == view) {
431  selected = true;
432  break;
433  }
434  return selected;
435  }
436  }
437  // ------------------------------------------------------
438 
440 
441 }
bool isInsideFiducialRegion(unsigned int wire, float drift) const
Definition: PointIdAlg.cxx:330
fhicl::Atom< art::InputTag > TrackModuleLabel
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::unordered_map< unsigned int, std::vector< size_t > > view_keymap
fhicl::Atom< art::InputTag > WireLabel
std::vector< std::string > const & outputLabels() const
network output labels
Definition: PointIdAlg.h:121
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
void setOutput(FVector_ID id, size_t key, std::array< float, N > const &values)
Definition: MVAWriter.h:214
Declaration of signal hit object.
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.cc:6
EmTrackMichelId(Parameters const &p)
Set of hits with a 2D structure.
Definition: Cluster.h:69
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:563
geo::WireID const & WireID() const
Initial tdc tick for hit.
Definition: Hit.h:280
EmTrackMichelId & operator=(EmTrackMichelId const &)=delete
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: Event.h:77
std::string const & label() const noexcept
Definition: InputTag.cc:79
bool isViewSelected(int view) const
FVector_ID initOutputs(std::string const &dataTag, size_t dataSize, std::vector< std::string > const &names=std::vector< std::string >(N,""))
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:65
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
void push_back(Ptr< U > const &p)
Definition: PtrVector.h:435
std::array< float, N > getOutput(std::vector< art::Ptr< T >> const &items) const
Definition: MVAWriter.h:251
fhicl::Atom< art::InputTag > HitModuleLabel
Definition: EmTrack.h:40
Provides recob::Track data product.
void produce(art::Event &e) override
Declaration of cluster object.
Definition of data types for geometry description.
void saveOutputs(art::Event &evt)
Check consistency and save all the results in the event.
Definition: MVAWriter.h:404
Detector simulation of raw signals on wires.
ProducesCollector & producesCollector() noexcept
void addOutput(FVector_ID id, std::array< float, N > const &values)
Definition: MVAWriter.h:231
bool CreateAssn(art::Event &evt, std::vector< T > const &a, art::Ptr< U > const &b, art::Assns< U, T > &assn, std::string a_instance, size_t index=UINT_MAX)
Creates a single one-to-one association.
anab::MVAWriter< 4 > fMVAWriter
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:220
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
bool setWireDriftData(const detinfo::DetectorClocksData &clock_data, const detinfo::DetectorPropertiesData &det_prop, const std::vector< recob::Wire > &wires, unsigned int plane, unsigned int tpc, unsigned int cryo)
Utility object to perform functions of association.
std::unordered_map< unsigned int, tpc_view_keymap > cryo_tpc_view_keymap
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
EventNumber_t event() const
Definition: EventID.h:116
Declaration of basic channel signal object.
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:46
constexpr PlaneID const & planeID() const
Definition: geo_types.h:620
TCEvent evt
Definition: DataStructs.cxx:8
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:306
Float_t e
Definition: plot.C:35
RunNumber_t run() const
Definition: Event.cc:29
std::unordered_map< unsigned int, view_keymap > tpc_view_keymap
fhicl::Atom< art::InputTag > ClusterModuleLabel
std::vector< std::vector< float > > predictIdVectors(std::vector< std::pair< unsigned int, float >> points) const
Definition: PointIdAlg.cxx:257
EventID id() const
Definition: Event.cc:23
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a "fitted" track:
Definition: Track.h:49
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33