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 
35 
37 
38 #include <memory>
39 
40 namespace nnet {
41 
43  public:
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 
55  Comment("number of samples processed in one batch")};
56 
58  Name("WireLabel"),
59  Comment("tag of deconvoluted ADC on wires (recob::Wire)")};
60 
62  Comment("tag of hits to be EM/track tagged")};
63 
65  Name("ClusterModuleLabel"),
66  Comment("tag of clusters to be used as a source of EM/track tagged new clusters (incl. "
67  "single-hit clusters ) using accumulated results from hits")};
68 
70  Name("TrackModuleLabel"),
71  Comment("tag of 3D tracks to be EM/track tagged using accumulated results from hits in the "
72  "best 2D projection")};
73 
75  Name("Views"),
76  Comment("tag clusters in selected views only, or in all views if empty list")};
77  };
79  explicit EmTrackClusterId2out(Parameters const& p);
80 
85 
86  private:
87  void produce(art::Event& e) override;
88 
89  bool isViewSelected(int view) const;
90 
91  size_t fBatchSize;
93  anab::MVAWriter<2> fMVAWriter; // <-------------- using 2-output CNN model
94 
100 
101  std::vector<int> fViews;
102 
103  art::InputTag fNewClustersTag; // input tag for the clusters produced by this module
104  };
105  // ------------------------------------------------------
106 
108  : EDProducer{config}
109  , fBatchSize(config().BatchSize())
111  , fMVAWriter(producesCollector(), "emtrack")
112  , fWireProducerLabel(config().WireLabel())
113  , fHitModuleLabel(config().HitModuleLabel())
114  , fClusterModuleLabel(config().ClusterModuleLabel())
115  , fTrackModuleLabel(config().TrackModuleLabel())
116  , fViews(config().Views())
117  ,
118 
119  fNewClustersTag(config.get_PSet().get<std::string>("module_label"),
120  "",
122  {
124 
125  if (!fClusterModuleLabel.label().empty()) {
126  produces<std::vector<recob::Cluster>>();
127  produces<art::Assns<recob::Cluster, recob::Hit>>();
128 
130  fDoClusters = true;
131  }
132  else {
133  fDoClusters = false;
134  }
135 
136  if (!fTrackModuleLabel.label().empty()) {
138  fDoTracks = true;
139  }
140  else {
141  fDoTracks = false;
142  }
143  }
144  // ------------------------------------------------------
145 
146  void
148  {
149  mf::LogVerbatim("EmTrackClusterId2out")
150  << "next event: " << evt.run() << " / " << evt.id().event();
151 
152  auto wireHandle = evt.getValidHandle<std::vector<recob::Wire>>(fWireProducerLabel);
153 
154  unsigned int cryo, tpc, view;
155 
156  // ******************* get and sort hits ********************
157  auto hitListHandle = evt.getValidHandle<std::vector<recob::Hit>>(fHitModuleLabel);
158  std::vector<art::Ptr<recob::Hit>> hitPtrList;
159  art::fill_ptr_vector(hitPtrList, hitListHandle);
160 
162  for (auto const& h : hitPtrList) {
163  view = h->WireID().Plane;
164  if (!isViewSelected(view)) continue;
165 
166  cryo = h->WireID().Cryostat;
167  tpc = h->WireID().TPC;
168 
169  hitMap[cryo][tpc][view].push_back(h.key());
170  }
171 
172  // ********************* classify hits **********************
173  auto hitID = fMVAWriter.initOutputs<recob::Hit>(
174  fHitModuleLabel, hitPtrList.size(), fPointIdAlg.outputLabels());
175 
176  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
177  auto const detProp =
179 
180  std::vector<char> hitInFA(
181  hitPtrList.size(),
182  0); // tag hits in fid. area as 1, use 0 for hits close to the projectrion edges
183  for (auto const& pcryo : hitMap) {
184  cryo = pcryo.first;
185  for (auto const& ptpc : pcryo.second) {
186  tpc = ptpc.first;
187  for (auto const& pview : ptpc.second) {
188  view = pview.first;
189  if (!isViewSelected(view)) continue; // should not happen, hits were selected
190 
191  fPointIdAlg.setWireDriftData(clockData, detProp, *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  std::vector<std::pair<unsigned int, float>> points;
196  std::vector<size_t> keys;
197  for (size_t k = 0; k < fBatchSize; ++k) {
198  if (idx + k >= pview.second.size()) { break; } // careful about the tail
199 
200  size_t h = pview.second[idx + k]; // h is the Ptr< recob::Hit >::key()
201  const recob::Hit& hit = *(hitPtrList[h]);
202  points.emplace_back(hit.WireID().Wire, hit.PeakTime());
203  keys.push_back(h);
204  }
205 
206  auto batch_out = fPointIdAlg.predictIdVectors(points);
207  if (points.size() != batch_out.size()) {
208  throw cet::exception("EmTrackClusterId") << "hits processing failed" << std::endl;
209  }
210 
211  for (size_t k = 0; k < points.size(); ++k) {
212  size_t h = keys[k];
213  fMVAWriter.setOutput(hitID, h, batch_out[k]);
214  if (fPointIdAlg.isInsideFiducialRegion(points[k].first, points[k].second)) {
215  hitInFA[h] = 1;
216  }
217  }
218  } // hits done ------------------------------------------------------------------
219  }
220  }
221  }
222 
223  // (2) do clusters when hits are ready in all planes ----------------------------------------
224  if (fDoClusters) {
225  // **************** prepare for new clusters ****************
226  auto clusters = std::make_unique<std::vector<recob::Cluster>>();
227  auto clu2hit = std::make_unique<art::Assns<recob::Cluster, recob::Hit>>();
228 
229  // ************** get and sort input clusters ***************
230  auto cluListHandle = evt.getValidHandle<std::vector<recob::Cluster>>(fClusterModuleLabel);
231  std::vector<art::Ptr<recob::Cluster>> cluPtrList;
232  art::fill_ptr_vector(cluPtrList, cluListHandle);
233 
235  for (auto const& c : cluPtrList) {
236  view = c->Plane().Plane;
237  if (!isViewSelected(view)) continue;
238 
239  cryo = c->Plane().Cryostat;
240  tpc = c->Plane().TPC;
241 
242  cluMap[cryo][tpc][view].push_back(c.key());
243  }
244 
245  auto cluID =
247 
248  unsigned int cidx = 0; // new clusters index
249  art::FindManyP<recob::Hit> hitsFromClusters(cluListHandle, evt, fClusterModuleLabel);
250  std::vector<bool> hitUsed(hitPtrList.size(), false); // tag hits used in clusters
251  for (auto const& pcryo : cluMap) {
252  cryo = pcryo.first;
253  for (auto const& ptpc : pcryo.second) {
254  tpc = ptpc.first;
255  for (auto const& pview : ptpc.second) {
256  view = pview.first;
257  if (!isViewSelected(view)) continue; // should not happen, clusters were pre-selected
258 
259  for (size_t c : pview.second) // c is the Ptr< recob::Cluster >::key()
260  {
261  auto v = hitsFromClusters.at(c);
262  if (v.empty()) continue;
263 
264  for (auto const& hit : v) {
265  if (hitUsed[hit.key()]) {
266  mf::LogWarning("EmTrackClusterId2out") << "hit already used in another cluster";
267  }
268  hitUsed[hit.key()] = true;
269  }
270 
271  auto vout = fMVAWriter.getOutput<recob::Hit>(
272  v, [&](art::Ptr<recob::Hit> const& ptr) { return (float)hitInFA[ptr.key()]; });
273 
274  mf::LogVerbatim("EmTrackClusterId2out")
275  << "cluster in tpc:" << tpc << " view:" << view << " size:" << v.size()
276  << " p:" << vout[0];
277 
278  clusters->emplace_back(recob::Cluster(0.0F,
279  0.0F,
280  0.0F,
281  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  v.size(),
297  0.0F,
298  0.0F,
299  cidx,
300  (geo::View_t)view,
301  v.front()->WireID().planeID()));
302  util::CreateAssn(*this, evt, *clusters, v, *clu2hit);
303  cidx++;
304 
305  fMVAWriter.addOutput(cluID, vout); // add copy of the input cluster
306  }
307 
308  // (2b) make single-hit clusters --------------------------------------------
309  for (size_t h : hitMap[cryo][tpc][view]) // h is the Ptr< recob::Hit >::key()
310  {
311  if (hitUsed[h]) continue;
312 
313  auto vout = fMVAWriter.getOutput<recob::Hit>(h);
314 
315  mf::LogVerbatim("EmTrackClusterId2out")
316  << "single hit in tpc:" << tpc << " view:" << view
317  << " wire:" << hitPtrList[h]->WireID().Wire
318  << " drift:" << hitPtrList[h]->PeakTime() << " p:" << vout[0];
319 
320  art::PtrVector<recob::Hit> cluster_hits;
321  cluster_hits.push_back(hitPtrList[h]);
322  clusters->emplace_back(recob::Cluster(0.0F,
323  0.0F,
324  0.0F,
325  0.0F,
326  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  1,
341  0.0F,
342  0.0F,
343  cidx,
344  (geo::View_t)view,
345  hitPtrList[h]->WireID().planeID()));
346  util::CreateAssn(*this, evt, *clusters, cluster_hits, *clu2hit);
347  cidx++;
348 
349  fMVAWriter.addOutput(cluID, vout); // add single-hit cluster tagging unclutered hit
350  }
351  mf::LogVerbatim("EmTrackClusterId2out")
352  << "...produced " << cidx - pview.second.size() << " single-hit clusters.";
353  }
354  }
355  }
356 
357  evt.put(std::move(clusters));
358  evt.put(std::move(clu2hit));
359  } // all clusters done ----------------------------------------------------------------------
360 
361  // (3) do tracks when all hits in all cryo/tpc/plane are done -------------------------------
362  if (fDoTracks) {
363  auto trkListHandle = evt.getValidHandle<std::vector<recob::Track>>(fTrackModuleLabel);
364  art::FindManyP<recob::Hit> hitsFromTracks(trkListHandle, evt, fTrackModuleLabel);
365  std::vector<std::vector<art::Ptr<recob::Hit>>> trkHitPtrList(trkListHandle->size());
366  for (size_t t = 0; t < trkListHandle->size(); ++t) {
367  auto v = hitsFromTracks.at(t);
368  size_t nh[3] = {0, 0, 0};
369  for (auto const& hptr : v) {
370  ++nh[hptr->View()];
371  }
372  size_t best_view = 2; // collection
373  if ((nh[0] >= nh[1]) && (nh[0] > 2 * nh[2])) best_view = 0; // ind1
374  if ((nh[1] >= nh[0]) && (nh[1] > 2 * nh[2])) best_view = 1; // ind2
375 
376  size_t k = 0;
377  while (!isViewSelected(best_view)) {
378  best_view = (best_view + 1) % 3;
379  if (++k > 3) {
380  throw cet::exception("EmTrackClusterId2out")
381  << "No views selected at all?" << std::endl;
382  }
383  }
384 
385  for (auto const& hptr : v) {
386  if (hptr->View() == best_view) trkHitPtrList[t].emplace_back(hptr);
387  }
388  }
389 
390  auto trkID = fMVAWriter.initOutputs<recob::Track>(
391  fTrackModuleLabel, trkHitPtrList.size(), fPointIdAlg.outputLabels());
392  for (size_t t = 0; t < trkHitPtrList.size(); ++t) // t is the Ptr< recob::Track >::key()
393  {
394  auto vout =
395  fMVAWriter.getOutput<recob::Hit>(trkHitPtrList[t], [&](art::Ptr<recob::Hit> const& ptr) {
396  return (float)hitInFA[ptr.key()];
397  });
398  fMVAWriter.setOutput(trkID, t, vout);
399  }
400  }
401  // tracks done ------------------------------------------------------------------------------
402 
403  fMVAWriter.saveOutputs(evt);
404  }
405  // ------------------------------------------------------
406 
407  bool
409  {
410  if (fViews.empty())
411  return true;
412  else {
413  for (auto k : fViews)
414  if (k == view) { return true; }
415  return false;
416  }
417  }
418  // ------------------------------------------------------
419 
421 
422 }
bool isInsideFiducialRegion(unsigned int wire, float drift) const
Definition: PointIdAlg.cxx:316
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
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
fhicl::Atom< art::InputTag > ClusterModuleLabel
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
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
void produce(art::Event &e) override
art framework interface to geometry description
fhicl::Atom< art::InputTag > TrackModuleLabel
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,""))
const double e
EmTrackClusterId2out & operator=(EmTrackClusterId2out const &)=delete
#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
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.
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
std::unordered_map< unsigned int, tpc_view_keymap > cryo_tpc_view_keymap
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, std::vector< size_t > > 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
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)