LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
EmTrack.h
Go to the documentation of this file.
1 #ifndef EMTRACK_H
2 #define EMTRACK_H
3 
11 #include "larrecodnn/ImagePatternAlgs/ToolInterfaces/IPointIdAlg.h"
12 
23 #include "cetlib/container_algorithms.h"
24 #include "cetlib_except/exception.h"
25 #include "fhiclcpp/types/Atom.h"
26 #include "fhiclcpp/types/Comment.h"
27 #include "fhiclcpp/types/Name.h"
29 #include "fhiclcpp/types/Table.h"
31 
32 #include <map>
33 #include <memory>
34 #include <string>
35 #include <tuple>
36 #include <unordered_map>
37 #include <utility>
38 #include <vector>
39 
40 namespace nnet {
41  template <size_t N>
42  class EmTrack {
43  public:
44  using key = std::tuple<unsigned int, unsigned int, unsigned int>;
45  using cryo_tpc_view_keymap = std::map<key, std::vector<size_t>>;
46 
47  struct Config {
48  using Name = fhicl::Name;
50 
53  Comment("number of samples processed in one batch")};
54 
56  Name("WireLabel"),
57  Comment("tag of deconvoluted ADC on wires (recob::Wire)")};
58 
60  Name("HitModuleLabel"),
61  Comment("tag of hits to be EM/track / Michel tagged")};
62 
64  Name("ClusterModuleLabel"),
65  Comment("tag of clusters to be used as a source of EM/track / Michel "
66  "tagged new clusters (incl. single-hit clusters ) using "
67  "accumulated results from hits")};
68 
70  Name("TrackModuleLabel"),
71  Comment("tag of 3D tracks to be EM/track / Michel tagged using "
72  "accumulated results from hits in the best 2D projection")};
73 
75  Comment("tag clusters in selected views only, "
76  "or in all views if empty list")};
77  };
78  explicit EmTrack(Config const& c, std::string const& s, art::ProducesCollector& pc);
79  void produce(art::Event& e);
80 
81  private:
82  bool isViewSelected(int view) const;
83  const size_t fBatchSize;
84  std::unique_ptr<PointIdAlgTools::IPointIdAlg> fPointIdAlgTool;
91  const bool fDoClusters;
92  const bool fDoTracks;
93  const std::vector<int> fViews;
94  const art::InputTag fNewClustersTag; // input tag for the clusters produced by this module
96  std::vector<art::Ptr<recob::Hit>> const& hitPtrList,
97  std::vector<char> const& hitInFA,
98  EmTrack::cryo_tpc_view_keymap const& hitMap);
99  void make_tracks(art::Event const& evt, std::vector<char> const& hitInFA);
101  std::vector<char> classify_hits(art::Event const& evt,
102  EmTrack::cryo_tpc_view_keymap const& hitMap,
103  std::vector<art::Ptr<recob::Hit>> const& hitPtrList);
104  };
105 
106  template <size_t N>
108  std::vector<art::Ptr<recob::Hit>> const& hitPtrList,
109  std::vector<char> const& hitInFA,
110  EmTrack::cryo_tpc_view_keymap const& hitMap)
111  {
112  // **************** prepare for new clusters ****************
113  auto clusters = std::make_unique<std::vector<recob::Cluster>>();
114  auto clu2hit = std::make_unique<art::Assns<recob::Cluster, recob::Hit>>();
115 
116  // ************** get and sort input clusters ***************
117  auto cluListHandle = evt.getValidHandle<std::vector<recob::Cluster>>(fClusterModuleLabel);
118  std::vector<art::Ptr<recob::Cluster>> cluPtrList;
119  art::fill_ptr_vector(cluPtrList, cluListHandle);
120 
122  for (auto const& c : cluPtrList) {
123  unsigned int view = c->Plane().Plane;
124  if (!isViewSelected(view)) continue;
125 
126  unsigned int cryo = c->Plane().Cryostat;
127  unsigned int tpc = c->Plane().TPC;
128 
129  cluMap[{cryo, tpc, view}].push_back(c.key());
130  }
131 
132  auto cluID = fMVAWriter.template initOutputs<recob::Cluster>(fNewClustersTag,
133  fPointIdAlgTool->outputLabels());
134 
135  unsigned int cidx = 0; // new clusters index
136  art::FindManyP<recob::Hit> hitsFromClusters(cluListHandle, evt, fClusterModuleLabel);
137  std::vector<bool> hitUsed(hitPtrList.size(),
138  false); // tag hits used in clusters
139  // clang-format off
140  for (auto const & [key, clusters_keys] : cluMap)
141  {
142  auto const& [cryo, tpc, view]= key;
143  // clang-format on
144  if (!isViewSelected(view)) continue; // should not happen, clusters were pre-selected
145 
146  for (size_t c : clusters_keys) // c is the Ptr< recob::Cluster >::key()
147  {
148  auto v = hitsFromClusters.at(c);
149  if (v.empty()) continue;
150 
151  for (auto const& hit : v) {
152  if (hitUsed[hit.key()]) {
153  mf::LogWarning("EmTrack") << "hit already used in another cluster";
154  }
155  hitUsed[hit.key()] = true;
156  }
157 
158  auto vout = fMVAWriter.template getOutput<recob::Hit>(
159  v, [&](art::Ptr<recob::Hit> const& ptr) { return (float)hitInFA[ptr.key()]; });
160 
161  float pvalue = vout[0] / (vout[0] + vout[1]);
162  mf::LogVerbatim("EmTrack") << "cluster in tpc:" << tpc << " view:" << view
163  << " size:" << v.size() << " p:" << pvalue;
164 
165  clusters->emplace_back(recob::Cluster(0.0F,
166  0.0F,
167  0.0F,
168  0.0F,
169  0.0F,
170  0.0F,
171  0.0F,
172  0.0F,
173  0.0F,
174  0.0F,
175  0.0F,
176  0.0F,
177  0.0F,
178  0.0F,
179  0.0F,
180  0.0F,
181  0.0F,
182  0.0F,
183  v.size(),
184  0.0F,
185  0.0F,
186  cidx,
187  (geo::View_t)view,
188  v.front()->WireID().planeID()));
189  util::CreateAssn(evt, *clusters, v, *clu2hit);
190  cidx++;
191 
192  fMVAWriter.addOutput(cluID,
193  vout); // add copy of the input cluster
194  }
195 
196  // (2b) make single-hit clusters
197  // --------------------------------------------
198  for (size_t h : hitMap.at({cryo, tpc, view})) // h is the Ptr< recob::Hit >::key()
199  {
200  if (hitUsed[h]) continue;
201 
202  auto vout = fMVAWriter.template getOutput<recob::Hit>(h);
203  float pvalue = vout[0] / (vout[0] + vout[1]);
204 
205  mf::LogVerbatim("EmTrack") << "single hit in tpc:" << tpc << " view:" << view
206  << " wire:" << hitPtrList[h]->WireID().Wire
207  << " drift:" << hitPtrList[h]->PeakTime() << " p:" << pvalue;
208 
209  art::PtrVector<recob::Hit> cluster_hits;
210  cluster_hits.push_back(hitPtrList[h]);
211  clusters->emplace_back(recob::Cluster(0.0F,
212  0.0F,
213  0.0F,
214  0.0F,
215  0.0F,
216  0.0F,
217  0.0F,
218  0.0F,
219  0.0F,
220  0.0F,
221  0.0F,
222  0.0F,
223  0.0F,
224  0.0F,
225  0.0F,
226  0.0F,
227  0.0F,
228  0.0F,
229  1,
230  0.0F,
231  0.0F,
232  cidx,
233  (geo::View_t)view,
234  hitPtrList[h]->WireID().planeID()));
235  util::CreateAssn(evt, *clusters, cluster_hits, *clu2hit);
236  cidx++;
237 
238  fMVAWriter.addOutput(cluID, vout); // add single-hit cluster tagging unclutered hit
239  }
240  mf::LogVerbatim("EmTrack") << "...produced " << cidx - clusters_keys.size()
241  << " single-hit clusters.";
242  }
243 
244  evt.put(std::move(clusters));
245  evt.put(std::move(clu2hit));
246  }
247 
249  template <size_t N>
250  void EmTrack<N>::make_tracks(art::Event const& evt, std::vector<char> const& hitInFA)
251  {
252  auto trkListHandle = evt.getValidHandle<std::vector<recob::Track>>(fTrackModuleLabel);
253  art::FindManyP<recob::Hit> hitsFromTracks(trkListHandle, evt, fTrackModuleLabel);
254  std::vector<std::vector<art::Ptr<recob::Hit>>> trkHitPtrList(trkListHandle->size());
255  for (size_t t = 0; t < trkListHandle->size(); ++t) {
256  auto v = hitsFromTracks.at(t);
257  size_t nh[3] = {0, 0, 0};
258  for (auto const& hptr : v) {
259  ++nh[hptr->View()];
260  }
261  size_t best_view = 2; // collection
262  if ((nh[0] >= nh[1]) && (nh[0] > 2 * nh[2])) best_view = 0; // ind1
263  if ((nh[1] >= nh[0]) && (nh[1] > 2 * nh[2])) best_view = 1; // ind2
264 
265  size_t k = 0;
266  while (!isViewSelected(best_view)) {
267  best_view = (best_view + 1) % 3;
268  if (++k > 3) {
269  throw cet::exception("EmTrack") << "No views selected at all?" << std::endl;
270  }
271  }
272 
273  for (auto const& hptr : v) {
274  if (hptr->View() == best_view) trkHitPtrList[t].emplace_back(hptr);
275  }
276  }
277 
278  auto trkID = fMVAWriter.template initOutputs<recob::Track>(
279  fTrackModuleLabel, trkHitPtrList.size(), fPointIdAlgTool->outputLabels());
280  for (size_t t = 0; t < trkHitPtrList.size(); ++t) // t is the Ptr< recob::Track >::key()
281  {
282  auto vout = fMVAWriter.template getOutput<recob::Hit>(
283  trkHitPtrList[t],
284  [&](art::Ptr<recob::Hit> const& ptr) { return (float)hitInFA[ptr.key()]; });
285  fMVAWriter.setOutput(trkID, t, vout);
286  }
287  }
288  template <size_t N>
290  std::vector<art::Ptr<recob::Hit>> const& hitPtrList) const
291  {
292  cryo_tpc_view_keymap hitMap;
293  for (auto const& hptr : hitPtrList) {
294  auto const& h = *hptr;
295  unsigned int view = h.WireID().Plane;
296  if (!isViewSelected(view)) continue;
297 
298  unsigned int cryo = h.WireID().Cryostat;
299  unsigned int tpc = h.WireID().TPC;
300 
301  hitMap[{cryo, tpc, view}].push_back(hptr.key());
302  }
303  return hitMap;
304  }
305 
306  template <size_t N>
307  std::vector<char> EmTrack<N>::classify_hits(art::Event const& evt,
308  EmTrack::cryo_tpc_view_keymap const& hitMap,
309  std::vector<art::Ptr<recob::Hit>> const& hitPtrList)
310  {
311  auto hitID = fMVAWriter.template initOutputs<recob::Hit>(
312  fHitModuleLabel, hitPtrList.size(), fPointIdAlgTool->outputLabels());
313 
314  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
315  auto const detProp =
317  auto wireHandle = evt.getValidHandle<std::vector<recob::Wire>>(fWireProducerLabel);
318  std::vector<char> hitInFA(hitPtrList.size(),
319  0); // tag hits in fid. area as 1, use 0 for hits
320  // close to the projectrion edges
321  for (auto const& [key, hits] : hitMap) {
322  auto const& [cryo, tpc, view] = key;
323  if (!isViewSelected(view)) continue; // should not happen, hits were selected
324 
325  fPointIdAlgTool->setWireDriftData(clockData, detProp, *wireHandle, view, tpc, cryo);
326 
327  // (1) do all hits in this plane
328  // ------------------------------------------------
329  for (size_t idx = 0; idx < hits.size(); idx += fBatchSize) {
330  std::vector<std::pair<unsigned int, float>> points;
331  std::vector<size_t> keys;
332  for (size_t k = 0; k < fBatchSize; ++k) {
333  if (idx + k >= hits.size()) { break; } // careful about the tail
334 
335  size_t h = hits[idx + k]; // h is the Ptr< recob::Hit >::key()
336  const recob::Hit& hit = *(hitPtrList[h]);
337  points.emplace_back(hit.WireID().Wire, hit.PeakTime());
338  keys.push_back(h);
339  }
340 
341  auto batch_out = fPointIdAlgTool->predictIdVectors(points);
342  if (points.size() != batch_out.size()) {
343  throw cet::exception("EmTrack") << "hits processing failed" << std::endl;
344  }
345 
346  for (size_t k = 0; k < points.size(); ++k) {
347  size_t h = keys[k];
348  fMVAWriter.setOutput(hitID, h, batch_out[k]);
349  if (fPointIdAlgTool->isInsideFiducialRegion(points[k].first, points[k].second)) {
350  hitInFA[h] = 1;
351  }
352  }
353  } // hits done
354  // ------------------------------------------------------------------
355  }
356  return hitInFA;
357  }
358  // make sure fMVAWriter is getting a variable string
359  template <size_t N>
361  std::string const& module_label,
362  art::ProducesCollector& collector)
363  : fBatchSize(config.BatchSize())
364  , fPointIdAlgTool(art::make_tool<PointIdAlgTools::IPointIdAlg>(config.PointIdAlg.get_PSet()))
365  , fMVAWriter(collector, "emtrkmichel")
366  , fWireProducerLabel(config.WireLabel())
367  , fHitModuleLabel(config.HitModuleLabel())
371  , fDoTracks(!fTrackModuleLabel.label().empty())
372  , fViews(config.Views())
373  , fNewClustersTag(module_label,
374  "",
375  art::ServiceHandle<art::TriggerNamesService const>()->getProcessName())
376  {
377  fMVAWriter.template produces_using<recob::Hit>();
378 
379  if (!fClusterModuleLabel.label().empty()) {
380  collector.produces<std::vector<recob::Cluster>>();
382 
383  fMVAWriter.template produces_using<recob::Cluster>();
384  }
385 
386  if (!fTrackModuleLabel.label().empty()) { fMVAWriter.template produces_using<recob::Track>(); }
387  }
388  // ------------------------------------------------------
389 
390  template <size_t N>
392  {
393  mf::LogVerbatim("EmTrack") << "next event: " << evt.run() << " / " << evt.id().event();
394  auto hitListHandle = evt.getValidHandle<std::vector<recob::Hit>>(fHitModuleLabel);
395  std::vector<art::Ptr<recob::Hit>> hitPtrList;
396  art::fill_ptr_vector(hitPtrList, hitListHandle);
397  const EmTrack::cryo_tpc_view_keymap hitMap = create_hitmap(hitPtrList);
398  const std::vector<char> hitInFA = classify_hits(evt, hitMap, hitPtrList);
399 
400  if (fDoClusters) make_clusters(evt, hitPtrList, hitInFA, hitMap);
401 
402  if (fDoTracks) make_tracks(evt, hitInFA);
403  fMVAWriter.saveOutputs(evt);
404  }
405  // ------------------------------------------------------
406 
407  template <size_t N>
408  bool EmTrack<N>::isViewSelected(int view) const
409  {
410  if (fViews.empty()) return true;
411  return cet::search_all(fViews, view);
412  }
413  // ------------------------------------------------------
414 
415 }
416 #endif
const art::InputTag fTrackModuleLabel
Definition: EmTrack.h:90
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
const art::InputTag fWireProducerLabel
Definition: EmTrack.h:87
std::enable_if_t< std::is_class< T >::value, tool_return_type< T > > make_tool(fhicl::ParameterSet const &pset)
Definition: make_tool.h:18
writer fMVAWriter
Definition: EmTrack.h:86
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
fhicl::Comment Comment
Definition: EmTrack.h:49
void make_tracks(art::Event const &evt, std::vector< char > const &hitInFA)
make tracks
Definition: EmTrack.h:250
void setOutput(FVector_ID id, size_t key, std::array< float, N > const &values)
Definition: MVAWriter.h:214
Declaration of signal hit object.
std::unique_ptr< PointIdAlgTools::IPointIdAlg > fPointIdAlgTool
Definition: EmTrack.h:84
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
const std::vector< int > fViews
Definition: EmTrack.h:93
std::vector< char > classify_hits(art::Event const &evt, EmTrack::cryo_tpc_view_keymap const &hitMap, std::vector< art::Ptr< recob::Hit >> const &hitPtrList)
Definition: EmTrack.h:307
fhicl::Atom< art::InputTag > TrackModuleLabel
Definition: EmTrack.h:69
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: Event.h:77
fhicl::Atom< art::InputTag > HitModuleLabel
Definition: EmTrack.h:59
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:289
std::string const & label() const noexcept
Definition: InputTag.cc:79
const bool fDoClusters
Definition: EmTrack.h:91
void hits()
Definition: readHits.C:15
void produces(std::string const &instanceName={}, Persistable const persistable=Persistable::Yes)
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
void push_back(Ptr< U > const &p)
Definition: PtrVector.h:435
void produce(art::Event &e)
Definition: EmTrack.h:391
EmTrack(Config const &c, std::string const &s, art::ProducesCollector &pc)
Definition: EmTrack.h:360
Definition: EmTrack.h:40
std::map< key, std::vector< size_t >> cryo_tpc_view_keymap
Definition: EmTrack.h:45
Provides recob::Track data product.
fhicl::Atom< art::InputTag > ClusterModuleLabel
Definition: EmTrack.h:63
const art::InputTag fHitModuleLabel
Definition: EmTrack.h:88
void make_clusters(art::Event &evt, std::vector< art::Ptr< recob::Hit >> const &hitPtrList, std::vector< char > const &hitInFA, EmTrack::cryo_tpc_view_keymap const &hitMap)
Definition: EmTrack.h:107
Declaration of cluster object.
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.
fhicl::Atom< size_t > BatchSize
Definition: EmTrack.h:52
bool isViewSelected(int view) const
Definition: EmTrack.h:408
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
Utility object to perform functions of association.
fhicl::Sequence< int > Views
Definition: EmTrack.h:74
const art::InputTag fNewClustersTag
Definition: EmTrack.h:94
fhicl::Atom< art::InputTag > WireLabel
Definition: EmTrack.h:55
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
Definition: MVAAlg.h:12
fhicl::Name Name
Definition: EmTrack.h:48
EventNumber_t event() const
Definition: EventID.h:116
cryo_tpc_view_keymap create_hitmap(std::vector< art::Ptr< recob::Hit >> const &hitPtrList) const
Definition: EmTrack.h:289
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:46
const size_t fBatchSize
Definition: EmTrack.h:83
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
const art::InputTag fClusterModuleLabel
Definition: EmTrack.h:89
const bool fDoTracks
Definition: EmTrack.h:92
EventID id() const
Definition: Event.cc:23
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:109
std::tuple< unsigned int, unsigned int, unsigned int > key
Definition: EmTrack.h:44