LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
EmTrackClusterId3out_module.cc
Go to the documentation of this file.
1 // Class: EmTrackClusterId
3 // Module Type: producer
4 // File: EmTrackClusterId_module.cc
5 // Authors: dorota.stefan@cern.ch pplonski86@gmail.com robert.sulej@cern.ch
6 //
7 // Module applies CNN to 2D image made of deconvoluted wire waveforms in order
8 // to distinguish EM-like activity from track-like objects. New clusters of
9 // hits are produced to include also unclustered hits and tag everything in
10 // a common way.
11 // NOTE: This module uses 3-output CNN models, see EmTrackMichelClusterId for
12 // usage of 4-output models and EmTrackClusterId2out_module.cc for 2-output
13 // models.
14 //
16 
27 
39 #include "cetlib_except/exception.h"
40 #include "fhiclcpp/ParameterSet.h"
41 #include "fhiclcpp/types/Atom.h"
42 #include "fhiclcpp/types/Comment.h"
43 #include "fhiclcpp/types/Name.h"
45 #include "fhiclcpp/types/Table.h"
47 
48 #include <iostream>
49 #include <memory>
50 #include <string>
51 #include <unordered_map>
52 #include <utility>
53 #include <vector>
54 
55 namespace nnet {
56 
58  public:
59  // these types to be replaced with use of feature proposed in redmine #12602
60  typedef std::unordered_map<unsigned int, std::vector<size_t>> view_keymap;
61  typedef std::unordered_map<unsigned int, view_keymap> tpc_view_keymap;
62  typedef std::unordered_map<unsigned int, tpc_view_keymap> cryo_tpc_view_keymap;
63 
64  struct Config {
65  using Name = fhicl::Name;
67 
70  Comment("number of samples processed in one batch")};
71 
73  Name("WireLabel"),
74  Comment("tag of deconvoluted ADC on wires (recob::Wire)")};
75 
77  Comment("tag of hits to be EM/track tagged")};
78 
80  Name("ClusterModuleLabel"),
81  Comment("tag of clusters to be used as a source of EM/track tagged new clusters (incl. "
82  "single-hit clusters ) using accumulated results from hits")};
83 
85  Name("TrackModuleLabel"),
86  Comment("tag of 3D tracks to be EM/track tagged using accumulated results from hits in the "
87  "best 2D projection")};
88 
90  Name("Views"),
91  Comment("tag clusters in selected views only, or in all views if empty list")};
92  };
94  explicit EmTrackClusterId(Parameters const& p);
95 
96  EmTrackClusterId(EmTrackClusterId const&) = delete;
100 
101  private:
102  void produce(art::Event& e) override;
103 
104  bool isViewSelected(int view) const;
105 
106  size_t fBatchSize;
108  anab::MVAWriter<3> fMVAWriter; // <-------------- using 3-output CNN model
109 
115 
116  std::vector<int> fViews;
117 
118  art::InputTag fNewClustersTag; // input tag for the clusters produced by this module
119  };
120  // ------------------------------------------------------
121 
123  : EDProducer{config}
124  , fBatchSize(config().BatchSize())
125  , fPointIdAlg(config().PointIdAlg())
126  , fMVAWriter(producesCollector(), "emtrack")
127  , fWireProducerLabel(config().WireLabel())
128  , fHitModuleLabel(config().HitModuleLabel())
129  , fClusterModuleLabel(config().ClusterModuleLabel())
130  , fTrackModuleLabel(config().TrackModuleLabel())
131  , fViews(config().Views())
132  ,
133 
134  fNewClustersTag(config.get_PSet().get<std::string>("module_label"),
135  "",
137  {
139 
140  if (!fClusterModuleLabel.label().empty()) {
141  produces<std::vector<recob::Cluster>>();
142  produces<art::Assns<recob::Cluster, recob::Hit>>();
143 
145  fDoClusters = true;
146  }
147  else {
148  fDoClusters = false;
149  }
150 
151  if (!fTrackModuleLabel.label().empty()) {
153  fDoTracks = true;
154  }
155  else {
156  fDoTracks = false;
157  }
158  }
159  // ------------------------------------------------------
160 
162  {
163  mf::LogVerbatim("EmTrackClusterId") << "next event: " << evt.run() << " / " << evt.id().event();
164 
165  auto wireHandle = evt.getValidHandle<std::vector<recob::Wire>>(fWireProducerLabel);
166 
167  unsigned int cryo, tpc, view;
168 
169  // ******************* get and sort hits ********************
170  auto hitListHandle = evt.getValidHandle<std::vector<recob::Hit>>(fHitModuleLabel);
171  std::vector<art::Ptr<recob::Hit>> hitPtrList;
172  art::fill_ptr_vector(hitPtrList, hitListHandle);
173 
175  for (auto const& h : hitPtrList) {
176  view = h->WireID().Plane;
177  if (!isViewSelected(view)) continue;
178 
179  cryo = h->WireID().Cryostat;
180  tpc = h->WireID().TPC;
181 
182  hitMap[cryo][tpc][view].push_back(h.key());
183  }
184 
185  // ********************* classify hits **********************
186  auto hitID = fMVAWriter.initOutputs<recob::Hit>(
187  fHitModuleLabel, hitPtrList.size(), fPointIdAlg.outputLabels());
188 
189  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
190  auto const detProp =
192 
193  std::vector<char> hitInFA(
194  hitPtrList.size(),
195  0); // tag hits in fid. area as 1, use 0 for hits close to the projectrion edges
196  for (auto const& [cryo, tpcs] : hitMap) {
197  for (auto const& [tpc, views] : tpcs) {
198  for (auto const& pview : views) {
199  view = pview.first;
200  if (!isViewSelected(view)) continue; // should not happen, hits were selected
201 
202  fPointIdAlg.setWireDriftData(clockData, detProp, *wireHandle, view, tpc, cryo);
203 
204  // (1) do all hits in this plane ------------------------------------------------
205  for (size_t idx = 0; idx < pview.second.size(); idx += fBatchSize) {
206  std::vector<std::pair<unsigned int, float>> points;
207  std::vector<size_t> keys;
208  for (size_t k = 0; k < fBatchSize; ++k) {
209  if (idx + k >= pview.second.size()) { break; } // careful about the tail
210 
211  size_t h = pview.second[idx + k]; // h is the Ptr< recob::Hit >::key()
212  const recob::Hit& hit = *(hitPtrList[h]);
213  points.emplace_back(hit.WireID().Wire, hit.PeakTime());
214  keys.push_back(h);
215  }
216 
217  auto batch_out = fPointIdAlg.predictIdVectors(points);
218  if (points.size() != batch_out.size()) {
219  throw cet::exception("EmTrackClusterId") << "hits processing failed" << std::endl;
220  }
221 
222  for (size_t k = 0; k < points.size(); ++k) {
223  size_t h = keys[k];
224  fMVAWriter.setOutput(hitID, h, batch_out[k]);
225  if (fPointIdAlg.isInsideFiducialRegion(points[k].first, points[k].second)) {
226  hitInFA[h] = 1;
227  }
228  }
229  } // hits done ------------------------------------------------------------------
230  }
231  }
232  }
233 
234  // (2) do clusters when hits are ready in all planes ----------------------------------------
235  if (fDoClusters) {
236  // **************** prepare for new clusters ****************
237  auto clusters = std::make_unique<std::vector<recob::Cluster>>();
238  auto clu2hit = std::make_unique<art::Assns<recob::Cluster, recob::Hit>>();
239 
240  // ************** get and sort input clusters ***************
241  auto cluListHandle = evt.getValidHandle<std::vector<recob::Cluster>>(fClusterModuleLabel);
242  std::vector<art::Ptr<recob::Cluster>> cluPtrList;
243  art::fill_ptr_vector(cluPtrList, cluListHandle);
244 
246  for (auto const& c : cluPtrList) {
247  view = c->Plane().Plane;
248  if (!isViewSelected(view)) continue;
249 
250  cryo = c->Plane().Cryostat;
251  tpc = c->Plane().TPC;
252 
253  cluMap[cryo][tpc][view].push_back(c.key());
254  }
255 
256  auto cluID =
258 
259  unsigned int cidx = 0; // new clusters index
260  art::FindManyP<recob::Hit> hitsFromClusters(cluListHandle, evt, fClusterModuleLabel);
261  std::vector<bool> hitUsed(hitPtrList.size(), false); // tag hits used in clusters
262  for (auto const& pcryo : cluMap) {
263  cryo = pcryo.first;
264  for (auto const& ptpc : pcryo.second) {
265  tpc = ptpc.first;
266  for (auto const& pview : ptpc.second) {
267  view = pview.first;
268  if (!isViewSelected(view)) continue; // should not happen, clusters were pre-selected
269 
270  for (size_t c : pview.second) // c is the Ptr< recob::Cluster >::key()
271  {
272  auto v = hitsFromClusters.at(c);
273  if (v.empty()) continue;
274 
275  for (auto const& hit : v) {
276  if (hitUsed[hit.key()]) {
277  mf::LogWarning("EmTrackClusterId") << "hit already used in another cluster";
278  }
279  hitUsed[hit.key()] = true;
280  }
281 
282  auto vout = fMVAWriter.getOutput<recob::Hit>(
283  v, [&](art::Ptr<recob::Hit> const& ptr) { return (float)hitInFA[ptr.key()]; });
284 
285  float pvalue = vout[0] / (vout[0] + vout[1]);
286  mf::LogVerbatim("EmTrackClusterId") << "cluster in tpc:" << tpc << " view:" << view
287  << " size:" << v.size() << " p:" << pvalue;
288 
289  clusters->emplace_back(recob::Cluster(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  0.0F,
300  0.0F,
301  0.0F,
302  0.0F,
303  0.0F,
304  0.0F,
305  0.0F,
306  0.0F,
307  v.size(),
308  0.0F,
309  0.0F,
310  cidx,
311  (geo::View_t)view,
312  v.front()->WireID().planeID()));
313  util::CreateAssn(evt, *clusters, v, *clu2hit);
314  cidx++;
315 
316  fMVAWriter.addOutput(cluID, vout); // add copy of the input cluster
317  }
318 
319  // (2b) make single-hit clusters --------------------------------------------
320  for (size_t h : hitMap[cryo][tpc][view]) // h is the Ptr< recob::Hit >::key()
321  {
322  if (hitUsed[h]) continue;
323 
324  auto vout = fMVAWriter.getOutput<recob::Hit>(h);
325  float pvalue = vout[0] / (vout[0] + vout[1]);
326 
327  mf::LogVerbatim("EmTrackClusterId")
328  << "single hit in tpc:" << tpc << " view:" << view
329  << " wire:" << hitPtrList[h]->WireID().Wire
330  << " drift:" << hitPtrList[h]->PeakTime() << " p:" << pvalue;
331 
332  art::PtrVector<recob::Hit> cluster_hits;
333  cluster_hits.push_back(hitPtrList[h]);
334  clusters->emplace_back(recob::Cluster(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  0.0F,
345  0.0F,
346  0.0F,
347  0.0F,
348  0.0F,
349  0.0F,
350  0.0F,
351  0.0F,
352  1,
353  0.0F,
354  0.0F,
355  cidx,
356  (geo::View_t)view,
357  hitPtrList[h]->WireID().planeID()));
358  util::CreateAssn(evt, *clusters, cluster_hits, *clu2hit);
359  cidx++;
360 
361  fMVAWriter.addOutput(cluID, vout); // add single-hit cluster tagging unclutered hit
362  }
363  mf::LogVerbatim("EmTrackClusterId")
364  << "...produced " << cidx - pview.second.size() << " single-hit clusters.";
365  }
366  }
367  }
368 
369  evt.put(std::move(clusters));
370  evt.put(std::move(clu2hit));
371  } // all clusters done ----------------------------------------------------------------------
372 
373  // (3) do tracks when all hits in all cryo/tpc/plane are done -------------------------------
374  if (fDoTracks) {
375  auto trkListHandle = evt.getValidHandle<std::vector<recob::Track>>(fTrackModuleLabel);
376  art::FindManyP<recob::Hit> hitsFromTracks(trkListHandle, evt, fTrackModuleLabel);
377  std::vector<std::vector<art::Ptr<recob::Hit>>> trkHitPtrList(trkListHandle->size());
378  for (size_t t = 0; t < trkListHandle->size(); ++t) {
379  auto v = hitsFromTracks.at(t);
380  size_t nh[3] = {0, 0, 0};
381  for (auto const& hptr : v) {
382  ++nh[hptr->View()];
383  }
384  size_t best_view = 2; // collection
385  if ((nh[0] >= nh[1]) && (nh[0] > 2 * nh[2])) best_view = 0; // ind1
386  if ((nh[1] >= nh[0]) && (nh[1] > 2 * nh[2])) best_view = 1; // ind2
387 
388  size_t k = 0;
389  while (!isViewSelected(best_view)) {
390  best_view = (best_view + 1) % 3;
391  if (++k > 3) {
392  throw cet::exception("EmTrackClusterId") << "No views selected at all?" << std::endl;
393  }
394  }
395 
396  for (auto const& hptr : v) {
397  if (hptr->View() == best_view) trkHitPtrList[t].emplace_back(hptr);
398  }
399  }
400 
401  auto trkID = fMVAWriter.initOutputs<recob::Track>(
402  fTrackModuleLabel, trkHitPtrList.size(), fPointIdAlg.outputLabels());
403  for (size_t t = 0; t < trkHitPtrList.size(); ++t) // t is the Ptr< recob::Track >::key()
404  {
405  auto vout =
406  fMVAWriter.getOutput<recob::Hit>(trkHitPtrList[t], [&](art::Ptr<recob::Hit> const& ptr) {
407  return (float)hitInFA[ptr.key()];
408  });
409  fMVAWriter.setOutput(trkID, t, vout);
410  }
411  }
412  // tracks done ------------------------------------------------------------------------------
413 
414  fMVAWriter.saveOutputs(evt);
415  }
416  // ------------------------------------------------------
417 
418  bool EmTrackClusterId::isViewSelected(int view) const
419  {
420  if (fViews.empty())
421  return true;
422  else {
423  for (auto k : fViews)
424  if (k == view) { return true; }
425  return false;
426  }
427  }
428  // ------------------------------------------------------
429 
431 
432 }
bool isInsideFiducialRegion(unsigned int wire, float drift) const
Definition: PointIdAlg.cxx:330
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
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
fhicl::Atom< art::InputTag > WireLabel
void produce(art::Event &e) override
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
fhicl::Atom< art::InputTag > TrackModuleLabel
bool isViewSelected(int view) const
std::unordered_map< unsigned int, view_keymap > tpc_view_keymap
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
FVector_ID initOutputs(std::string const &dataTag, size_t dataSize, std::vector< std::string > const &names=std::vector< std::string >(N,""))
fhicl::Atom< art::InputTag > ClusterModuleLabel
#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.
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.
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:220
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
std::unordered_map< unsigned int, std::vector< size_t > > view_keymap
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.
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::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
EmTrackClusterId & operator=(EmTrackClusterId const &)=delete
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
std::unordered_map< unsigned int, tpc_view_keymap > cryo_tpc_view_keymap
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33