EmTrackMichelId_module.cc
Go to the documentation of this file.
1 /////////////////////////////////////////////////////////////////////////////////////
2 // 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 //
17 /////////////////////////////////////////////////////////////////////////////////////
18 
26 #include "fhiclcpp/types/Atom.h"
28 #include "fhiclcpp/types/Table.h"
30 
36 
39 
40 #include <memory>
41 
42 namespace nnet {
43 
45 public:
46 
47  // these types to be replaced with use of feature proposed in redmine #12602
48  typedef std::unordered_map< unsigned int, std::vector< size_t > > view_keymap;
49  typedef std::unordered_map< unsigned int, view_keymap > tpc_view_keymap;
50  typedef std::unordered_map< unsigned int, tpc_view_keymap > cryo_tpc_view_keymap;
51 
52  struct Config {
53  using Name = fhicl::Name;
55 
57  Name("PointIdAlg")
58  };
60  Name("BatchSize"), Comment("number of samples processed in one batch")
61  };
62 
64  Name("WireLabel"), Comment("tag of deconvoluted ADC on wires (recob::Wire)")
65  };
66 
68  Name("HitModuleLabel"), Comment("tag of hits to be EM/track / Michel tagged")
69  };
70 
72  Name("ClusterModuleLabel"),
73  Comment("tag of clusters to be used as a source of EM/track / Michel tagged new clusters (incl. single-hit clusters ) using accumulated results from hits")
74  };
75 
77  Name("TrackModuleLabel"),
78  Comment("tag of 3D tracks to be EM/track / Michel tagged using accumulated results from hits in the best 2D projection")
79  };
80 
82  Name("Views"),
83  Comment("tag clusters in selected views only, or in all views if empty list")
84  };
85  };
87  explicit EmTrackMichelId(Parameters const & p);
88 
89  EmTrackMichelId(EmTrackMichelId const &) = delete;
90  EmTrackMichelId(EmTrackMichelId &&) = delete;
91  EmTrackMichelId & operator = (EmTrackMichelId const &) = delete;
93 
94 private:
95  void produce(art::Event & e) override;
96 
97  bool isViewSelected(int view) const;
98 
99  size_t fBatchSize;
101  anab::MVAWriter<4> fMVAWriter; // <-------------- using 4-output CNN model
102 
108 
109  std::vector< int > fViews;
110 
111  art::InputTag fNewClustersTag; // input tag for the clusters produced by this module
112 };
113 // ------------------------------------------------------
114 
116  EDProducer{config},
117  fBatchSize(config().BatchSize()),
119  fMVAWriter(producesCollector(), "emtrkmichel"),
120  fWireProducerLabel(config().WireLabel()),
121  fHitModuleLabel(config().HitModuleLabel()),
122  fClusterModuleLabel(config().ClusterModuleLabel()),
123  fTrackModuleLabel(config().TrackModuleLabel()),
124  fViews(config().Views()),
125 
127  config.get_PSet().get<std::string>("module_label"), "",
129 {
131 
132  if (!fClusterModuleLabel.label().empty())
133  {
134  produces< std::vector<recob::Cluster> >();
135  produces< art::Assns<recob::Cluster, recob::Hit> >();
136 
138  fDoClusters = true;
139  }
140  else { fDoClusters = false; }
141 
142  if (!fTrackModuleLabel.label().empty())
143  {
145  fDoTracks = true;
146  }
147  else { fDoTracks = false; }
148 }
149 // ------------------------------------------------------
150 
152 {
153  mf::LogVerbatim("EmTrackMichelId") << "next event: " << evt.run() << " / " << evt.id().event();
154 
155  auto wireHandle = evt.getValidHandle< std::vector<recob::Wire> >(fWireProducerLabel);
156 
157  unsigned int cryo, tpc, view;
158 
159  // ******************* get and sort hits ********************
160  auto hitListHandle = evt.getValidHandle< std::vector<recob::Hit> >(fHitModuleLabel);
161  std::vector< art::Ptr<recob::Hit> > hitPtrList;
162  art::fill_ptr_vector(hitPtrList, hitListHandle);
163 
165  for (auto const& h : hitPtrList)
166  {
167  view = h->WireID().Plane;
168  if (!isViewSelected(view)) continue;
169 
170  cryo = h->WireID().Cryostat;
171  tpc = h->WireID().TPC;
172 
173  hitMap[cryo][tpc][view].push_back(h.key());
174  }
175 
176  // ********************* classify hits **********************
177  auto hitID = fMVAWriter.initOutputs<recob::Hit>(fHitModuleLabel, hitPtrList.size(), fPointIdAlg.outputLabels());
178 
179  std::vector< char > hitInFA(hitPtrList.size(), 0); // tag hits in fid. area as 1, use 0 for hits close to the projectrion edges
180  for (auto const & pcryo : hitMap)
181  {
182  cryo = pcryo.first;
183  for (auto const & ptpc : pcryo.second)
184  {
185  tpc = ptpc.first;
186  for (auto const & pview : ptpc.second)
187  {
188  view = pview.first;
189  if (!isViewSelected(view)) continue; // should not happen, hits were selected
190 
191  fPointIdAlg.setWireDriftData(*wireHandle, view, tpc, cryo);
192 
193  // (1) do all hits in this plane ------------------------------------------------
194  for (size_t idx = 0; idx < pview.second.size(); idx += fBatchSize)
195  {
196  std::vector< std::pair<unsigned int, float> > points;
197  std::vector< size_t > keys;
198  for (size_t k = 0; k < fBatchSize; ++k)
199  {
200  if (idx + k >= pview.second.size()) { break; } // careful about the tail
201 
202  size_t h = pview.second[idx+k]; // h is the Ptr< recob::Hit >::key()
203  const recob::Hit & hit = *(hitPtrList[h]);
204  points.emplace_back(hit.WireID().Wire, hit.PeakTime());
205  keys.push_back(h);
206  }
207 
208  auto batch_out = fPointIdAlg.predictIdVectors(points);
209  if (points.size() != batch_out.size())
210  {
211  throw cet::exception("EmTrackMichelId") << "hits processing failed" << std::endl;
212  }
213 
214  for (size_t k = 0; k < points.size(); ++k)
215  {
216  size_t h = keys[k];
217  fMVAWriter.setOutput(hitID, h, batch_out[k]);
218  if (fPointIdAlg.isInsideFiducialRegion(points[k].first, points[k].second))
219  { hitInFA[h] = 1; }
220  }
221  } // hits done ------------------------------------------------------------------
222  }
223  }
224  }
225 
226  // (2) do clusters when hits are ready in all planes ----------------------------------------
227  if (fDoClusters)
228  {
229  // **************** prepare for new clusters ****************
230  auto clusters = std::make_unique< std::vector< recob::Cluster > >();
231  auto clu2hit = std::make_unique< art::Assns< recob::Cluster, recob::Hit > >();
232 
233  // ************** get and sort input clusters ***************
234  auto cluListHandle = evt.getValidHandle< std::vector<recob::Cluster> >(fClusterModuleLabel);
235  std::vector< art::Ptr<recob::Cluster> > cluPtrList;
236  art::fill_ptr_vector(cluPtrList, cluListHandle);
237 
239  for (auto const& c : cluPtrList)
240  {
241  view = c->Plane().Plane;
242  if (!isViewSelected(view)) continue;
243 
244  cryo = c->Plane().Cryostat;
245  tpc = c->Plane().TPC;
246 
247  cluMap[cryo][tpc][view].push_back(c.key());
248  }
249 
251 
252  unsigned int cidx = 0; // new clusters index
253  art::FindManyP< recob::Hit > hitsFromClusters(cluListHandle, evt, fClusterModuleLabel);
254  std::vector< bool > hitUsed(hitPtrList.size(), false); // tag hits used in clusters
255  for (auto const & pcryo : cluMap)
256  {
257  cryo = pcryo.first;
258  for (auto const & ptpc : pcryo.second)
259  {
260  tpc = ptpc.first;
261  for (auto const & pview : ptpc.second)
262  {
263  view = pview.first;
264  if (!isViewSelected(view)) continue; // should not happen, clusters were pre-selected
265 
266  for (size_t c : pview.second) // c is the Ptr< recob::Cluster >::key()
267  {
268  auto v = hitsFromClusters.at(c);
269  if (v.empty()) continue;
270 
271  for (auto const & hit : v)
272  {
273  if (hitUsed[hit.key()]) { mf::LogWarning("EmTrackMichelId") << "hit already used in another cluster"; }
274  hitUsed[hit.key()] = true;
275  }
276 
277  auto vout = fMVAWriter.getOutput<recob::Hit>(v,
278  [&](art::Ptr<recob::Hit> const & ptr) { return (float)hitInFA[ptr.key()]; });
279 
280  float pvalue = vout[0] / (vout[0] + vout[1]);
281  mf::LogVerbatim("EmTrackMichelId") << "cluster in tpc:" << tpc << " view:" << view
282  << " size:" << v.size() << " p:" << pvalue;
283 
284  clusters->emplace_back(
285  recob::Cluster(0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F,
286  v.size(), 0.0F, 0.0F, cidx, (geo::View_t)view, v.front()->WireID().planeID()));
287  util::CreateAssn(*this, evt, *clusters, v, *clu2hit);
288  cidx++;
289 
290  fMVAWriter.addOutput(cluID, vout); // add copy of the input cluster
291  }
292 
293  // (2b) make single-hit clusters --------------------------------------------
294  for (size_t h : hitMap[cryo][tpc][view]) // h is the Ptr< recob::Hit >::key()
295  {
296  if (hitUsed[h]) continue;
297 
298  auto vout = fMVAWriter.getOutput<recob::Hit>(h);
299  float pvalue = vout[0] / (vout[0] + vout[1]);
300 
301  mf::LogVerbatim("EmTrackMichelId") << "single hit in tpc:" << tpc << " view:" << view
302  << " wire:" << hitPtrList[h]->WireID().Wire << " drift:" << hitPtrList[h]->PeakTime() << " p:" << pvalue;
303 
304  art::PtrVector< recob::Hit > cluster_hits;
305  cluster_hits.push_back(hitPtrList[h]);
306  clusters->emplace_back(
307  recob::Cluster(0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F,
308  1, 0.0F, 0.0F, cidx, (geo::View_t)view, hitPtrList[h]->WireID().planeID()));
309  util::CreateAssn(*this, evt, *clusters, cluster_hits, *clu2hit);
310  cidx++;
311 
312  fMVAWriter.addOutput(cluID, vout); // add single-hit cluster tagging unclutered hit
313  }
314  mf::LogVerbatim("EmTrackMichelId") << "...produced " << cidx - pview.second.size() << " single-hit clusters.";
315  }
316  }
317  }
318 
319  evt.put(std::move(clusters));
320  evt.put(std::move(clu2hit));
321  } // all clusters done ----------------------------------------------------------------------
322 
323  // (3) do tracks when all hits in all cryo/tpc/plane are done -------------------------------
324  if (fDoTracks)
325  {
326  auto trkListHandle = evt.getValidHandle< std::vector<recob::Track> >(fTrackModuleLabel);
327  art::FindManyP< recob::Hit > hitsFromTracks(trkListHandle, evt, fTrackModuleLabel);
328  std::vector< std::vector< art::Ptr<recob::Hit> > > trkHitPtrList(trkListHandle->size());
329  for (size_t t = 0; t < trkListHandle->size(); ++t)
330  {
331  auto v = hitsFromTracks.at(t);
332  size_t nh[3] = { 0, 0, 0 };
333  for (auto const & hptr : v) { ++nh[hptr->View()]; }
334  size_t best_view = 2; // collection
335  if ((nh[0] >= nh[1]) && (nh[0] > 2 * nh[2])) best_view = 0; // ind1
336  if ((nh[1] >= nh[0]) && (nh[1] > 2 * nh[2])) best_view = 1; // ind2
337 
338  size_t k = 0;
339  while (!isViewSelected(best_view))
340  {
341  best_view = (best_view + 1) % 3;
342  if (++k > 3) { throw cet::exception("EmTrackMichelId") << "No views selected at all?" << std::endl; }
343  }
344 
345  for (auto const & hptr : v)
346  {
347  if (hptr->View() == best_view) trkHitPtrList[t].emplace_back(hptr);
348  }
349  }
350 
351  auto trkID = fMVAWriter.initOutputs<recob::Track>(fTrackModuleLabel, trkHitPtrList.size(), fPointIdAlg.outputLabels());
352  for (size_t t = 0; t < trkHitPtrList.size(); ++t) // t is the Ptr< recob::Track >::key()
353  {
354  auto vout = fMVAWriter.getOutput<recob::Hit>(trkHitPtrList[t],
355  [&](art::Ptr<recob::Hit> const & ptr) { return (float)hitInFA[ptr.key()]; });
356  fMVAWriter.setOutput(trkID, t, vout);
357  }
358  }
359  // tracks done ------------------------------------------------------------------------------
360 
361  fMVAWriter.saveOutputs(evt);
362 }
363 // ------------------------------------------------------
364 
366 {
367  if (fViews.empty()) return true;
368  else
369  {
370  bool selected = false;
371  for (auto k : fViews) if (k == view) { selected = true; break; }
372  return selected;
373  }
374 }
375 // ------------------------------------------------------
376 
378 
379 }
bool isInsideFiducialRegion(unsigned int wire, float drift) const
Definition: PointIdAlg.cxx:328
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
std::string string
Definition: nybbler.cc:12
geo::WireID WireID() const
Definition: Hit.h:233
void setOutput(FVector_ID id, size_t key, std::array< float, N > const &values)
Definition: MVAWriter.h:175
Declaration of signal hit object.
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.h:20
fhicl::Atom< art::InputTag > WireLabel
EmTrackMichelId(Parameters const &p)
Set of hits with a 2D structure.
Definition: Cluster.h:71
std::unordered_map< unsigned int, std::vector< size_t > > view_keymap
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:576
fhicl::Atom< art::InputTag > TrackModuleLabel
fhicl::Atom< art::InputTag > HitModuleLabel
EmTrackMichelId & operator=(EmTrackMichelId const &)=delete
bool setWireDriftData(const std::vector< recob::Wire > &wires, unsigned int plane, unsigned int tpc, unsigned int cryo)
std::string const & label() const noexcept
Definition: InputTag.cc:76
anab::MVAWriter< 4 > fMVAWriter
bool isViewSelected(int view) const
std::vector< std::string > const & outputLabels(void) const
network output labels
Definition: PointIdAlg.h:122
FVector_ID initOutputs(std::string const &dataTag, size_t dataSize, std::vector< std::string > const &names=std::vector< std::string >(N,""))
const double e
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:69
void push_back(Ptr< U > const &p)
Definition: PtrVector.h:435
static Config * config
Definition: config.cpp:1054
def move(depos, offset)
Definition: depos.py:107
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Definition: DataViewImpl.h:491
void produce(art::Event &e) override
RunNumber_t run() const
Definition: DataViewImpl.cc:82
std::array< float, N > getOutput(std::vector< art::Ptr< T > > const &items) const
Definition: MVAWriter.h:189
Declaration of cluster object.
void saveOutputs(art::Event &evt)
Check consistency and save all the results in the event.
Definition: MVAWriter.h:325
Provides recob::Track data product.
Detector simulation of raw signals on wires.
ProducesCollector & producesCollector() noexcept
std::unordered_map< unsigned int, tpc_view_keymap > cryo_tpc_view_keymap
void addOutput(FVector_ID id, std::array< float, N > const &values)
Definition: MVAWriter.h:180
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.
p
Definition: test.py:223
fhicl::Atom< art::InputTag > ClusterModuleLabel
AdcCodeMitigator::Name Name
std::unordered_map< unsigned int, view_keymap > tpc_view_keymap
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:218
#define Comment
Utility object to perform functions of association.
std::vector< std::vector< float > > predictIdVectors(std::vector< std::pair< unsigned int, float > > points) const
Definition: PointIdAlg.cxx:246
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
EventNumber_t event() const
Definition: EventID.h:116
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:48
constexpr PlaneID const & planeID() const
Definition: geo_types.h:634
TCEvent evt
Definition: DataStructs.cxx:7
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:291
ProductID put(std::unique_ptr< PROD > &&edp, FullSemantic< Level::Run > const semantic)
Definition: DataViewImpl.h:730
EventID id() const
Definition: Event.cc:37
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
QTextStream & endl(QTextStream &s)
h
training ###############################
Definition: train_cnn.py:186