EmTrackClusterId2out_module.cc
Go to the documentation of this file.
1 /////////////////////////////////////////////////////////////////////////////////
2 // Class: EmTrackClusterId2out
3 // Module Type: producer
4 // File: EmTrackClusterId2out_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 2-output CNN models, see EmTrackClusterId and
12 // EmTrackMichelClusterId for usage of 3 and 4-output models.
13 //
14 /////////////////////////////////////////////////////////////////////////////////
15 
23 #include "fhiclcpp/types/Atom.h"
25 #include "fhiclcpp/types/Table.h"
27 
33 
36 
37 #include <memory>
38 
39 namespace nnet {
40 
42 public:
43 
44  // these types to be replaced with use of feature proposed in redmine #12602
45  typedef std::unordered_map< unsigned int, std::vector< size_t > > view_keymap;
46  typedef std::unordered_map< unsigned int, view_keymap > tpc_view_keymap;
47  typedef std::unordered_map< unsigned int, tpc_view_keymap > cryo_tpc_view_keymap;
48 
49  struct Config {
50  using Name = fhicl::Name;
52 
54  Name("PointIdAlg")
55  };
57  Name("BatchSize"),
58  Comment("number of samples processed in one batch")
59  };
60 
62  Name("WireLabel"),
63  Comment("tag of deconvoluted ADC on wires (recob::Wire)")
64  };
65 
67  Name("HitModuleLabel"),
68  Comment("tag of hits to be EM/track tagged")
69  };
70 
72  Name("ClusterModuleLabel"),
73  Comment("tag of clusters to be used as a source of EM/track 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 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 EmTrackClusterId2out(Parameters const & p);
88 
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<2> fMVAWriter; // <-------------- using 2-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(), "emtrack"),
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("EmTrackClusterId2out") << "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("EmTrackClusterId") << "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("EmTrackClusterId2out") << "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  mf::LogVerbatim("EmTrackClusterId2out") << "cluster in tpc:" << tpc << " view:" << view
281  << " size:" << v.size() << " p:" << vout[0];
282 
283  clusters->emplace_back(
284  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,
285  v.size(), 0.0F, 0.0F, cidx, (geo::View_t)view, v.front()->WireID().planeID()));
286  util::CreateAssn(*this, evt, *clusters, v, *clu2hit);
287  cidx++;
288 
289  fMVAWriter.addOutput(cluID, vout); // add copy of the input cluster
290  }
291 
292  // (2b) make single-hit clusters --------------------------------------------
293  for (size_t h : hitMap[cryo][tpc][view]) // h is the Ptr< recob::Hit >::key()
294  {
295  if (hitUsed[h]) continue;
296 
297  auto vout = fMVAWriter.getOutput<recob::Hit>(h);
298 
299  mf::LogVerbatim("EmTrackClusterId2out") << "single hit in tpc:" << tpc << " view:" << view
300  << " wire:" << hitPtrList[h]->WireID().Wire << " drift:" << hitPtrList[h]->PeakTime() << " p:" << vout[0];
301 
302  art::PtrVector< recob::Hit > cluster_hits;
303  cluster_hits.push_back(hitPtrList[h]);
304  clusters->emplace_back(
305  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,
306  1, 0.0F, 0.0F, cidx, (geo::View_t)view, hitPtrList[h]->WireID().planeID()));
307  util::CreateAssn(*this, evt, *clusters, cluster_hits, *clu2hit);
308  cidx++;
309 
310  fMVAWriter.addOutput(cluID, vout); // add single-hit cluster tagging unclutered hit
311  }
312  mf::LogVerbatim("EmTrackClusterId2out") << "...produced " << cidx - pview.second.size() << " single-hit clusters.";
313  }
314  }
315  }
316 
317  evt.put(std::move(clusters));
318  evt.put(std::move(clu2hit));
319  } // all clusters done ----------------------------------------------------------------------
320 
321  // (3) do tracks when all hits in all cryo/tpc/plane are done -------------------------------
322  if (fDoTracks)
323  {
324  auto trkListHandle = evt.getValidHandle< std::vector<recob::Track> >(fTrackModuleLabel);
325  art::FindManyP< recob::Hit > hitsFromTracks(trkListHandle, evt, fTrackModuleLabel);
326  std::vector< std::vector< art::Ptr<recob::Hit> > > trkHitPtrList(trkListHandle->size());
327  for (size_t t = 0; t < trkListHandle->size(); ++t)
328  {
329  auto v = hitsFromTracks.at(t);
330  size_t nh[3] = { 0, 0, 0 };
331  for (auto const & hptr : v) { ++nh[hptr->View()]; }
332  size_t best_view = 2; // collection
333  if ((nh[0] >= nh[1]) && (nh[0] > 2 * nh[2])) best_view = 0; // ind1
334  if ((nh[1] >= nh[0]) && (nh[1] > 2 * nh[2])) best_view = 1; // ind2
335 
336  size_t k = 0;
337  while (!isViewSelected(best_view))
338  {
339  best_view = (best_view + 1) % 3;
340  if (++k > 3) { throw cet::exception("EmTrackClusterId2out") << "No views selected at all?" << std::endl; }
341  }
342 
343  for (auto const & hptr : v)
344  {
345  if (hptr->View() == best_view) trkHitPtrList[t].emplace_back(hptr);
346  }
347  }
348 
349  auto trkID = fMVAWriter.initOutputs<recob::Track>(fTrackModuleLabel, trkHitPtrList.size(), fPointIdAlg.outputLabels());
350  for (size_t t = 0; t < trkHitPtrList.size(); ++t) // t is the Ptr< recob::Track >::key()
351  {
352  auto vout = fMVAWriter.getOutput<recob::Hit>(trkHitPtrList[t],
353  [&](art::Ptr<recob::Hit> const & ptr) { return (float)hitInFA[ptr.key()]; });
354  fMVAWriter.setOutput(trkID, t, vout);
355  }
356  }
357  // tracks done ------------------------------------------------------------------------------
358 
359  fMVAWriter.saveOutputs(evt);
360 }
361 // ------------------------------------------------------
362 
364 {
365  if (fViews.empty()) return true;
366  else
367  {
368  for (auto k : fViews) if (k == view) { return true; }
369  return false;
370  }
371 }
372 // ------------------------------------------------------
373 
375 
376 }
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
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:576
void produce(art::Event &e) override
bool setWireDriftData(const std::vector< recob::Wire > &wires, unsigned int plane, unsigned int tpc, unsigned int cryo)
std::unordered_map< unsigned int, view_keymap > tpc_view_keymap
std::string const & label() const noexcept
Definition: InputTag.cc:76
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
EmTrackClusterId2out & operator=(EmTrackClusterId2out const &)=delete
#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
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.
fhicl::Atom< art::InputTag > ClusterModuleLabel
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
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
AdcCodeMitigator::Name Name
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
std::unordered_map< unsigned int, std::vector< size_t > > view_keymap
fhicl::Atom< art::InputTag > TrackModuleLabel
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
std::unordered_map< unsigned int, tpc_view_keymap > cryo_tpc_view_keymap
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