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 
38 
40 
41 #include <memory>
42 
43 namespace nnet {
44 
46  public:
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 
58  Comment("number of samples processed in one batch")};
59 
61  Name("WireLabel"),
62  Comment("tag of deconvoluted ADC on wires (recob::Wire)")};
63 
65  Name("HitModuleLabel"),
66  Comment("tag of hits to be EM/track / Michel tagged")};
67 
69  Name("ClusterModuleLabel"),
70  Comment("tag of clusters to be used as a source of EM/track / Michel tagged new clusters "
71  "(incl. single-hit clusters ) using accumulated results from hits")};
72 
74  Name("TrackModuleLabel"),
75  Comment("tag of 3D tracks to be EM/track / Michel tagged using accumulated results from "
76  "hits in the best 2D projection")};
77 
79  Name("Views"),
80  Comment("tag clusters in selected views only, or in all views if empty list")};
81  };
83  explicit EmTrackMichelId(Parameters const& p);
84 
85  EmTrackMichelId(EmTrackMichelId const&) = delete;
86  EmTrackMichelId(EmTrackMichelId&&) = delete;
87  EmTrackMichelId& operator=(EmTrackMichelId const&) = delete;
89 
90  private:
91  void produce(art::Event& e) override;
92 
93  bool isViewSelected(int view) const;
94 
95  size_t fBatchSize;
97  anab::MVAWriter<4> fMVAWriter; // <-------------- using 4-output CNN model
98 
104 
105  std::vector<int> fViews;
106 
107  art::InputTag fNewClustersTag; // input tag for the clusters produced by this module
108  };
109  // ------------------------------------------------------
110 
112  : EDProducer{config}
113  , fBatchSize(config().BatchSize())
115  , fMVAWriter(producesCollector(), "emtrkmichel")
116  , fWireProducerLabel(config().WireLabel())
117  , fHitModuleLabel(config().HitModuleLabel())
118  , fClusterModuleLabel(config().ClusterModuleLabel())
119  , fTrackModuleLabel(config().TrackModuleLabel())
120  , fViews(config().Views())
121  ,
122 
123  fNewClustersTag(config.get_PSet().get<std::string>("module_label"),
124  "",
126  {
128 
129  if (!fClusterModuleLabel.label().empty()) {
130  produces<std::vector<recob::Cluster>>();
131  produces<art::Assns<recob::Cluster, recob::Hit>>();
132 
134  fDoClusters = true;
135  }
136  else {
137  fDoClusters = false;
138  }
139 
140  if (!fTrackModuleLabel.label().empty()) {
142  fDoTracks = true;
143  }
144  else {
145  fDoTracks = false;
146  }
147  }
148  // ------------------------------------------------------
149 
150  void
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  view = h->WireID().Plane;
167  if (!isViewSelected(view)) continue;
168 
169  cryo = h->WireID().Cryostat;
170  tpc = h->WireID().TPC;
171 
172  hitMap[cryo][tpc][view].push_back(h.key());
173  }
174 
175  // ********************* classify hits **********************
176  auto hitID = fMVAWriter.initOutputs<recob::Hit>(
177  fHitModuleLabel, hitPtrList.size(), fPointIdAlg.outputLabels());
178 
179  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
180  auto const detProp =
182 
183  std::vector<char> hitInFA(
184  hitPtrList.size(),
185  0); // tag hits in fid. area as 1, use 0 for hits close to the projectrion edges
186  for (auto const& pcryo : hitMap) {
187  cryo = pcryo.first;
188  for (auto const& ptpc : pcryo.second) {
189  tpc = ptpc.first;
190  for (auto const& pview : ptpc.second) {
191  view = pview.first;
192  if (!isViewSelected(view)) continue; // should not happen, hits were selected
193 
194  fPointIdAlg.setWireDriftData(clockData, detProp, *wireHandle, view, tpc, cryo);
195 
196  // (1) do all hits in this plane ------------------------------------------------
197  for (size_t idx = 0; idx < pview.second.size(); idx += fBatchSize) {
198  std::vector<std::pair<unsigned int, float>> points;
199  std::vector<size_t> keys;
200  for (size_t k = 0; k < fBatchSize; ++k) {
201  if (idx + k >= pview.second.size()) { break; } // careful about the tail
202 
203  size_t h = pview.second[idx + k]; // h is the Ptr< recob::Hit >::key()
204  const recob::Hit& hit = *(hitPtrList[h]);
205  points.emplace_back(hit.WireID().Wire, hit.PeakTime());
206  keys.push_back(h);
207  }
208 
209  auto batch_out = fPointIdAlg.predictIdVectors(points);
210  if (points.size() != batch_out.size()) {
211  throw cet::exception("EmTrackMichelId") << "hits processing failed" << std::endl;
212  }
213 
214  for (size_t k = 0; k < points.size(); ++k) {
215  size_t h = keys[k];
216  fMVAWriter.setOutput(hitID, h, batch_out[k]);
217  if (fPointIdAlg.isInsideFiducialRegion(points[k].first, points[k].second)) {
218  hitInFA[h] = 1;
219  }
220  }
221  } // hits done ------------------------------------------------------------------
222  }
223  }
224  }
225 
226  // (2) do clusters when hits are ready in all planes ----------------------------------------
227  if (fDoClusters) {
228  // **************** prepare for new clusters ****************
229  auto clusters = std::make_unique<std::vector<recob::Cluster>>();
230  auto clu2hit = std::make_unique<art::Assns<recob::Cluster, recob::Hit>>();
231 
232  // ************** get and sort input clusters ***************
233  auto cluListHandle = evt.getValidHandle<std::vector<recob::Cluster>>(fClusterModuleLabel);
234  std::vector<art::Ptr<recob::Cluster>> cluPtrList;
235  art::fill_ptr_vector(cluPtrList, cluListHandle);
236 
238  for (auto const& c : cluPtrList) {
239  view = c->Plane().Plane;
240  if (!isViewSelected(view)) continue;
241 
242  cryo = c->Plane().Cryostat;
243  tpc = c->Plane().TPC;
244 
245  cluMap[cryo][tpc][view].push_back(c.key());
246  }
247 
248  auto cluID =
250 
251  unsigned int cidx = 0; // new clusters index
252  art::FindManyP<recob::Hit> hitsFromClusters(cluListHandle, evt, fClusterModuleLabel);
253  std::vector<bool> hitUsed(hitPtrList.size(), false); // tag hits used in clusters
254  for (auto const& pcryo : cluMap) {
255  cryo = pcryo.first;
256  for (auto const& ptpc : pcryo.second) {
257  tpc = ptpc.first;
258  for (auto const& pview : ptpc.second) {
259  view = pview.first;
260  if (!isViewSelected(view)) continue; // should not happen, clusters were pre-selected
261 
262  for (size_t c : pview.second) // c is the Ptr< recob::Cluster >::key()
263  {
264  auto v = hitsFromClusters.at(c);
265  if (v.empty()) continue;
266 
267  for (auto const& hit : v) {
268  if (hitUsed[hit.key()]) {
269  mf::LogWarning("EmTrackMichelId") << "hit already used in another cluster";
270  }
271  hitUsed[hit.key()] = true;
272  }
273 
274  auto vout = fMVAWriter.getOutput<recob::Hit>(
275  v, [&](art::Ptr<recob::Hit> const& ptr) { return (float)hitInFA[ptr.key()]; });
276 
277  float pvalue = vout[0] / (vout[0] + vout[1]);
278  mf::LogVerbatim("EmTrackMichelId") << "cluster in tpc:" << tpc << " view:" << view
279  << " size:" << v.size() << " p:" << pvalue;
280 
281  clusters->emplace_back(recob::Cluster(0.0F,
282  0.0F,
283  0.0F,
284  0.0F,
285  0.0F,
286  0.0F,
287  0.0F,
288  0.0F,
289  0.0F,
290  0.0F,
291  0.0F,
292  0.0F,
293  0.0F,
294  0.0F,
295  0.0F,
296  0.0F,
297  0.0F,
298  0.0F,
299  v.size(),
300  0.0F,
301  0.0F,
302  cidx,
303  (geo::View_t)view,
304  v.front()->WireID().planeID()));
305  util::CreateAssn(*this, evt, *clusters, v, *clu2hit);
306  cidx++;
307 
308  fMVAWriter.addOutput(cluID, vout); // add copy of the input cluster
309  }
310 
311  // (2b) make single-hit clusters --------------------------------------------
312  for (size_t h : hitMap[cryo][tpc][view]) // h is the Ptr< recob::Hit >::key()
313  {
314  if (hitUsed[h]) continue;
315 
316  auto vout = fMVAWriter.getOutput<recob::Hit>(h);
317  float pvalue = vout[0] / (vout[0] + vout[1]);
318 
319  mf::LogVerbatim("EmTrackMichelId")
320  << "single hit in tpc:" << tpc << " view:" << view
321  << " wire:" << hitPtrList[h]->WireID().Wire
322  << " drift:" << hitPtrList[h]->PeakTime() << " p:" << pvalue;
323 
324  art::PtrVector<recob::Hit> cluster_hits;
325  cluster_hits.push_back(hitPtrList[h]);
326  clusters->emplace_back(recob::Cluster(0.0F,
327  0.0F,
328  0.0F,
329  0.0F,
330  0.0F,
331  0.0F,
332  0.0F,
333  0.0F,
334  0.0F,
335  0.0F,
336  0.0F,
337  0.0F,
338  0.0F,
339  0.0F,
340  0.0F,
341  0.0F,
342  0.0F,
343  0.0F,
344  1,
345  0.0F,
346  0.0F,
347  cidx,
348  (geo::View_t)view,
349  hitPtrList[h]->WireID().planeID()));
350  util::CreateAssn(*this, evt, *clusters, cluster_hits, *clu2hit);
351  cidx++;
352 
353  fMVAWriter.addOutput(cluID, vout); // add single-hit cluster tagging unclutered hit
354  }
355  mf::LogVerbatim("EmTrackMichelId")
356  << "...produced " << cidx - pview.second.size() << " single-hit clusters.";
357  }
358  }
359  }
360 
361  evt.put(std::move(clusters));
362  evt.put(std::move(clu2hit));
363  } // all clusters done ----------------------------------------------------------------------
364 
365  // (3) do tracks when all hits in all cryo/tpc/plane are done -------------------------------
366  if (fDoTracks) {
367  auto trkListHandle = evt.getValidHandle<std::vector<recob::Track>>(fTrackModuleLabel);
368  art::FindManyP<recob::Hit> hitsFromTracks(trkListHandle, evt, fTrackModuleLabel);
369  std::vector<std::vector<art::Ptr<recob::Hit>>> trkHitPtrList(trkListHandle->size());
370  for (size_t t = 0; t < trkListHandle->size(); ++t) {
371  auto v = hitsFromTracks.at(t);
372  size_t nh[3] = {0, 0, 0};
373  for (auto const& hptr : v) {
374  ++nh[hptr->View()];
375  }
376  size_t best_view = 2; // collection
377  if ((nh[0] >= nh[1]) && (nh[0] > 2 * nh[2])) best_view = 0; // ind1
378  if ((nh[1] >= nh[0]) && (nh[1] > 2 * nh[2])) best_view = 1; // ind2
379 
380  size_t k = 0;
381  while (!isViewSelected(best_view)) {
382  best_view = (best_view + 1) % 3;
383  if (++k > 3) {
384  throw cet::exception("EmTrackMichelId") << "No views selected at all?" << std::endl;
385  }
386  }
387 
388  for (auto const& hptr : v) {
389  if (hptr->View() == best_view) trkHitPtrList[t].emplace_back(hptr);
390  }
391  }
392 
393  auto trkID = fMVAWriter.initOutputs<recob::Track>(
394  fTrackModuleLabel, trkHitPtrList.size(), fPointIdAlg.outputLabels());
395  for (size_t t = 0; t < trkHitPtrList.size(); ++t) // t is the Ptr< recob::Track >::key()
396  {
397  auto vout =
398  fMVAWriter.getOutput<recob::Hit>(trkHitPtrList[t], [&](art::Ptr<recob::Hit> const& ptr) {
399  return (float)hitInFA[ptr.key()];
400  });
401  fMVAWriter.setOutput(trkID, t, vout);
402  }
403  }
404  // tracks done ------------------------------------------------------------------------------
405 
406  fMVAWriter.saveOutputs(evt);
407  }
408  // ------------------------------------------------------
409 
410  bool
412  {
413  if (fViews.empty())
414  return true;
415  else {
416  bool selected = false;
417  for (auto k : fViews)
418  if (k == view) {
419  selected = true;
420  break;
421  }
422  return selected;
423  }
424  }
425  // ------------------------------------------------------
426 
428 
429 }
bool isInsideFiducialRegion(unsigned int wire, float drift) const
Definition: PointIdAlg.cxx:316
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:112
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
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.h:20
ChannelGroupService::Name Name
EmTrackMichelId(Parameters const &p)
Set of hits with a 2D structure.
Definition: Cluster.h:71
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:580
EmTrackMichelId & operator=(EmTrackMichelId const &)=delete
art framework interface to geometry description
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,""))
const double e
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
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
fhicl::Atom< art::InputTag > HitModuleLabel
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Definition: DataViewImpl.h:441
p
Definition: test.py:223
ProductID put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: DataViewImpl.h:686
bool CreateAssn(PRODUCER const &prod, art::Event &evt, std::vector< T > const &a, art::Ptr< U > const &b, art::Assns< U, T > &assn, std::string a_instance, size_t indx=UINT_MAX)
Creates a single one-to-one association.
void produce(art::Event &e) override
RunNumber_t run() const
Definition: DataViewImpl.cc:71
std::array< float, N > getOutput(std::vector< art::Ptr< T > > const &items) const
Definition: MVAWriter.h:189
void saveOutputs(art::Event &evt)
Check consistency and save all the results in the event.
Definition: MVAWriter.h:325
Detector simulation of raw signals on wires.
ProducesCollector & producesCollector() noexcept
void addOutput(FVector_ID id, std::array< float, N > const &values)
Definition: MVAWriter.h:180
anab::MVAWriter< 4 > fMVAWriter
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:218
Declaration of signal hit object.
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)
#define Comment
std::unordered_map< unsigned int, tpc_view_keymap > cryo_tpc_view_keymap
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
Provides recob::Track data product.
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:638
TCEvent evt
Definition: DataStructs.cxx:7
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:297
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:240
EventID id() const
Definition: Event.cc:34
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)