LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
PointIdAlg.cxx
Go to the documentation of this file.
1 // Class: PointIdAlg
3 // Authors: D.Stefan (Dorota.Stefan@ncbj.gov.pl), from DUNE, CERN/NCBJ, since May 2016
4 // R.Sulej (Robert.Sulej@cern.ch), from DUNE, FNAL/NCBJ, since May 2016
5 // P.Plonski, from DUNE, WUT, since May 2016
6 // D.Smith, from LArIAT, BU, 2017: real data dump
8 
10 #include "tensorflow/core/public/session.h"
11 
15 
16 #include "larcorealg/Geometry/ChannelMapAlg.h" // geo::InvalidWireIDError
17 #include "larcore/CoreUtils/ServiceUtil.h" // lar::providerFrom<>()
18 
21 
22 #include "larevt/CalibrationDBI/Interface/ChannelStatusService.h"
23 #include "larevt/CalibrationDBI/Interface/ChannelStatusProvider.h"
24 
26 
27 #include "CLHEP/Random/RandGauss.h"
28 
29 #include <sys/stat.h>
30 
31 // ------------------------------------------------------
32 // -------------------ModelInterface---------------------
33 // ------------------------------------------------------
34 
35 std::vector< std::vector<float> > nnet::ModelInterface::Run(std::vector< std::vector< std::vector<float> > > const & inps, int samples)
36 {
37  if ((samples == 0) || inps.empty() || inps.front().empty() || inps.front().front().empty())
38  return std::vector< std::vector<float> >();
39 
40  if ((samples == -1) || (samples > (int)inps.size())) { samples = inps.size(); }
41 
42  std::vector< std::vector<float> > results;
43  for (int i = 0; i < samples; ++i)
44  {
45  results.push_back(Run(inps[i]));
46  }
47  return results;
48 }
49 
50 
51 std::string nnet::ModelInterface::findFile(const char* fileName) const
52 {
53  std::string fname_out;
54  cet::search_path sp("FW_SEARCH_PATH");
55  if (!sp.find_file(fileName, fname_out))
56  {
57  struct stat buffer;
58  if (stat(fileName, &buffer) == 0) { fname_out = fileName; }
59  else
60  {
62  << "Could not find the model file " << fileName;
63  }
64  }
65  return fname_out;
66 }
67 
68 
69 // ------------------------------------------------------
70 // ----------------KerasModelInterface-------------------
71 // ------------------------------------------------------
72 
74  m(nnet::ModelInterface::findFile(modelFileName).c_str())
75 {
76  mf::LogInfo("KerasModelInterface") << "Keras model loaded.";
77 }
78 // ------------------------------------------------------
79 
80 std::vector<float> nnet::KerasModelInterface::Run(std::vector< std::vector<float> > const & inp2d)
81 {
82  std::vector< std::vector< std::vector<float> > > inp3d;
83  inp3d.push_back(inp2d); // lots of copy, should add 2D to keras...
84 
85  keras::DataChunk *sample = new keras::DataChunk2D();
86  sample->set_data(inp3d); // and more copy...
87  std::vector<float> out = m.compute_output(sample);
88  delete sample;
89  return out;
90 }
91 
92 
93 // ------------------------------------------------------
94 // -----------------TfModelInterface---------------------
95 // ------------------------------------------------------
96 
97 nnet::TfModelInterface::TfModelInterface(const char* modelFileName)
98 {
99  g = tf::Graph::create(nnet::ModelInterface::findFile(modelFileName).c_str(), {"cnn_output", "_netout"});
100  if (!g) { throw art::Exception(art::errors::Unknown) << "TF model failed."; }
101 
102  mf::LogInfo("TfModelInterface") << "TF model loaded.";
103 }
104 // ------------------------------------------------------
105 
106 std::vector< std::vector<float> > nnet::TfModelInterface::Run(std::vector< std::vector< std::vector<float> > > const & inps, int samples)
107 {
108  if ((samples == 0) || inps.empty() || inps.front().empty() || inps.front().front().empty())
109  return std::vector< std::vector<float> >();
110 
111  if ((samples == -1) || (samples > (long long int)inps.size())) { samples = inps.size(); }
112 
113  long long int rows = inps.front().size(), cols = inps.front().front().size();
114 
115  tensorflow::Tensor _x(tensorflow::DT_FLOAT, tensorflow::TensorShape({ samples, rows, cols, 1 }));
116  auto input_map = _x.tensor<float, 4>();
117  for (long long int s = 0; s < samples; ++s) {
118  const auto & sample = inps[s];
119  for (long long int r = 0; r < rows; ++r) {
120  const auto & row = sample[r];
121  for (long long int c = 0; c < cols; ++c) {
122  input_map(s, r, c, 0) = row[c];
123  }
124  }
125  }
126 
127  return g->run(_x);
128 }
129 // ------------------------------------------------------
130 
131 std::vector<float> nnet::TfModelInterface::Run(std::vector< std::vector<float> > const & inp2d)
132 {
133  long long int rows = inp2d.size(), cols = inp2d.front().size();
134 
135  tensorflow::Tensor _x(tensorflow::DT_FLOAT, tensorflow::TensorShape({ 1, rows, cols, 1 }));
136  auto input_map = _x.tensor<float, 4>();
137  for (long long int r = 0; r < rows; ++r) {
138  const auto & row = inp2d[r];
139  for (long long int c = 0; c < cols; ++c) {
140  input_map(0, r, c, 0) = row[c];
141  }
142  }
143 
144  auto out = g->run(_x);
145  if (!out.empty()) return out.front();
146  else return std::vector<float>();
147 }
148 
149 
150 // ------------------------------------------------------
151 // --------------------PointIdAlg------------------------
152 // ------------------------------------------------------
153 
154 nnet::PointIdAlg::PointIdAlg(const Config& config) : img::DataProviderAlg(config),
155  fNNet(0),
156  fPatchSizeW(config.PatchSizeW()), fPatchSizeD(config.PatchSizeD()),
157  fCurrentWireIdx(99999), fCurrentScaledDrift(99999)
158 {
160  fNNetOutputs = config.NNetOutputs();
161 
162  deleteNNet();
163 
164  if ((fNNetModelFilePath.length() > 5) &&
165  (fNNetModelFilePath.compare(fNNetModelFilePath.length() - 5, 5, ".nnet") == 0))
166  {
168  }
169  else if ((fNNetModelFilePath.length() > 3) &&
170  (fNNetModelFilePath.compare(fNNetModelFilePath.length() - 3, 3, ".pb") == 0))
171  {
173  }
174  else
175  {
176  mf::LogError("PointIdAlg") << "File name extension not supported.";
177  }
178 
179  if (!fNNet) { throw cet::exception("nnet::PointIdAlg") << "Loading model from file failed."; }
180 
181  resizePatch();
182 }
183 // ------------------------------------------------------
184 
186 {
187  deleteNNet();
188 }
189 // ------------------------------------------------------
190 
192 {
194  for (auto & r : fWireDriftPatch) r.resize(fPatchSizeD);
195 }
196 // ------------------------------------------------------
197 
198 float nnet::PointIdAlg::predictIdValue(unsigned int wire, float drift, size_t outIdx) const
199 {
200  float result = 0.;
201 
202  if (!bufferPatch(wire, drift))
203  {
204  mf::LogError("PointIdAlg") << "Patch buffering failed.";
205  return result;
206  }
207 
208  if (fNNet)
209  {
210  auto out = fNNet->Run(fWireDriftPatch);
211  if (!out.empty()) { result = out[outIdx]; }
212  else
213  {
214  mf::LogError("PointIdAlg") << "Problem with applying model to input.";
215  }
216  }
217 
218  return result;
219 }
220 // ------------------------------------------------------
221 
222 std::vector<float> nnet::PointIdAlg::predictIdVector(unsigned int wire, float drift) const
223 {
224  std::vector<float> result;
225 
226  if (!bufferPatch(wire, drift))
227  {
228  mf::LogError("PointIdAlg") << "Patch buffering failed.";
229  return result;
230  }
231 
232  if (fNNet)
233  {
234  result = fNNet->Run(fWireDriftPatch);
235  if (result.empty())
236  {
237  mf::LogError("PointIdAlg") << "Problem with applying model to input.";
238  }
239  }
240 
241  return result;
242 }
243 // ------------------------------------------------------
244 
245 std::vector< std::vector<float> > nnet::PointIdAlg::predictIdVectors(std::vector< std::pair<unsigned int, float> > points) const
246 {
247  if (points.empty() || !fNNet) { return std::vector< std::vector<float> >(); }
248 
249  std::vector< std::vector< std::vector<float> > > inps(
250  points.size(), std::vector< std::vector<float> >(
251  fPatchSizeW, std::vector<float>(fPatchSizeD)));
252  for (size_t i = 0; i < points.size(); ++i)
253  {
254  unsigned int wire = points[i].first;
255  float drift = points[i].second;
256  if (!bufferPatch(wire, drift, inps[i]))
257  {
258  throw cet::exception("PointIdAlg") << "Patch buffering failed" << std::endl;
259  }
260 
261  }
262 
263  return fNNet->Run(inps);
264 }
265 // ------------------------------------------------------
266 
267 bool nnet::PointIdAlg::isSamePatch(unsigned int wire1, float drift1, unsigned int wire2, float drift2) const
268 {
269  if (fDownscaleFullView)
270  {
271  size_t sd1 = (size_t)(drift1 / fDriftWindow);
272  size_t sd2 = (size_t)(drift2 / fDriftWindow);
273  if ((wire1 == wire2) && (sd1 == sd2))
274  return true; // the same position
275  }
276  else
277  {
278  if ((wire1 == wire2) && ((size_t)drift1 == (size_t)drift2))
279  return true; // the same position
280  }
281 
282  return false; // not the same position
283 }
284 
285 bool nnet::PointIdAlg::isCurrentPatch(unsigned int wire, float drift) const
286 {
287  if (fDownscaleFullView)
288  {
289  size_t sd = (size_t)(drift / fDriftWindow);
290  if ((fCurrentWireIdx == wire) && (fCurrentScaledDrift == sd))
291  return true; // still within the current position
292  }
293  else
294  {
295  if ((fCurrentWireIdx == wire) && (fCurrentScaledDrift == drift))
296  return true; // still within the current position
297  }
298 
299  return false; // not a current position
300 }
301 // ------------------------------------------------------
302 
303 std::vector<float> nnet::PointIdAlg::flattenData2D(std::vector< std::vector<float> > const & patch)
304 {
305  std::vector<float> flat;
306  if (patch.empty() || patch.front().empty())
307  {
308  mf::LogError("DataProviderAlg") << "Patch is empty.";
309  return flat;
310  }
311 
312  flat.resize(patch.size() * patch.front().size());
313 
314  for (size_t w = 0, i = 0; w < patch.size(); ++w)
315  {
316  auto const & wire = patch[w];
317  for (size_t d = 0; d < wire.size(); ++d, ++i)
318  {
319  flat[i] = wire[d];
320  }
321  }
322 
323  return flat;
324 }
325 // ------------------------------------------------------
326 
327 bool nnet::PointIdAlg::isInsideFiducialRegion(unsigned int wire, float drift) const
328 {
329  size_t marginW = fPatchSizeW / 8; // fPatchSizeX/2 will make patch always completely filled
330  size_t marginD = fPatchSizeD / 8;
331 
332  size_t scaledDrift = (size_t)(drift / fDriftWindow);
333  if ((wire >= marginW) && (wire < fNWires - marginW) &&
334  (scaledDrift >= marginD) && (scaledDrift < fNScaledDrifts - marginD)) return true;
335  else return false;
336 }
337 // ------------------------------------------------------
338 
339 // ------------------------------------------------------
340 // ------------------TrainingDataAlg---------------------
341 // ------------------------------------------------------
342 
344  fEdepTot(0),
345  fWireProducerLabel(config.WireLabel()),
346  fHitProducerLabel(config.HitLabel()),
347  fTrackModuleLabel(config.TrackLabel()),
348  fSimulationProducerLabel(config.SimulationLabel()),
349  fSaveVtxFlags(config.SaveVtxFlags()),
350  fAdcDelay(config.AdcDelayTicks()),
351  fEventsPerBin(100, 0)
352 {
354 }
355 // ------------------------------------------------------
356 
358 {
359 }
360 // ------------------------------------------------------
361 
362 void nnet::TrainingDataAlg::resizeView(size_t wires, size_t drifts)
363 {
364  img::DataProviderAlg::resizeView(wires, drifts);
365 
366  fWireDriftEdep.resize(wires);
367  for (auto & w : fWireDriftEdep)
368  {
369  w.resize(fNCachedDrifts);
370  std::fill(w.begin(), w.end(), 0.0F);
371  }
372 
373  fWireDriftPdg.resize(wires);
374  for (auto & w : fWireDriftPdg)
375  {
376  w.resize(fNCachedDrifts);
377  std::fill(w.begin(), w.end(), 0);
378  }
379 }
380 // ------------------------------------------------------
381 
383  std::vector<float> const & edeps, std::vector<int> const & pdgs, size_t wireIdx)
384 {
385  if ((wireIdx >= fWireDriftEdep.size()) || (edeps.size() != pdgs.size())) { return false; }
386 
387  size_t dstep = 1;
388  if (fDownscaleFullView) { dstep = fDriftWindow; }
389 
390  if (edeps.size() / dstep > fNCachedDrifts) { return false; }
391 
392  auto & wEdep = fWireDriftEdep[wireIdx];
393  auto & wPdg = fWireDriftPdg[wireIdx];
394 
395  for (size_t i = 0; i < fNCachedDrifts; ++i)
396  {
397  size_t i0 = i * dstep;
398  size_t i1 = (i + 1) * dstep;
399 
400  int best_pdg = pdgs[i0] & nnet::TrainingDataAlg::kPdgMask;
401  int vtx_flags = pdgs[i0] & nnet::TrainingDataAlg::kVtxMask;
402  int type_flags = pdgs[i0] & nnet::TrainingDataAlg::kTypeMask;
403  float max_edep = edeps[i0];
404  for (size_t k = i0 + 1; k < i1; ++k)
405  {
406  float ek = edeps[k];
407  if (ek > max_edep)
408  {
409  max_edep = ek;
410  best_pdg = pdgs[k] & nnet::TrainingDataAlg::kPdgMask; // remember best matching pdg
411  }
412  type_flags |= pdgs[k] & nnet::TrainingDataAlg::kTypeMask; // accumulate track type flags
413  vtx_flags |= pdgs[k] & nnet::TrainingDataAlg::kVtxMask; // accumulate all vtx flags
414  }
415 
416  wEdep[i] = max_edep;
417 
418  best_pdg |= type_flags;
419  if (fSaveVtxFlags) best_pdg |= vtx_flags;
420  wPdg[i] = best_pdg;
421  }
422 
423  return true;
424 }
425 // ------------------------------------------------------
426 
427 nnet::TrainingDataAlg::WireDrift nnet::TrainingDataAlg::getProjection(const TLorentzVector& tvec, unsigned int plane) const
428 {
429  auto const* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
431  wd.Wire = 0; wd.Drift = 0; wd.TPC = -1; wd.Cryo = -1;
432 
433  try
434  {
435  double vtx[3] = {tvec.X(), tvec.Y(), tvec.Z()};
437  {
438  geo::TPCID tpcid = fGeometry->FindTPCAtPosition(vtx);
439  unsigned int tpc = tpcid.TPC, cryo = tpcid.Cryostat;
440 
441  // correct for the time offset
442  float dx = tvec.T() * 1.e-3 * detprop->DriftVelocity();
443  int driftDir = fGeometry->TPC(tpcid).DetectDriftDirection();
444  if (driftDir == 1) { dx *= -1; }
445  else if (driftDir != -1)
446  {
447  throw cet::exception("nnet::TrainingDataAlg") << "drift direction is not X." << std::endl;
448  }
449  vtx[0] = tvec.X() + dx;
450 
451  wd.Wire = fGeometry->NearestWire(vtx, plane, tpc, cryo);
452  wd.Drift = fDetProp->ConvertXToTicks(vtx[0], plane, tpc, cryo);
453  wd.TPC = tpc; wd.Cryo = cryo;
454  }
455  }
456  catch (const geo::InvalidWireIDError & e)
457  {
458  mf::LogWarning("TrainingDataAlg") << "Vertex projection out of wire planes, just skipping this vertex.";
459  }
460  catch (...)
461  {
462  mf::LogWarning("TrainingDataAlg") << "Vertex projection out of wire planes, skip MC vertex.";
463  }
464  return wd;
465 }
466 // ------------------------------------------------------
467 
469  const std::unordered_map< int, const simb::MCParticle* > & particleMap) const
470 {
471  const float minElectronLength2 = 2.5*2.5;
472  const float maxDeltaLength2 = 0.15*0.15;
473 
474  int pdg = abs(particle.PdgCode());
475  if (pdg != 11) return false; // should be applied only to electrons
476 
477  size_t nSec = particle.NumberDaughters();
478  for (size_t d = 0; d < nSec; ++d)
479  {
480  auto d_search = particleMap.find(particle.Daughter(d));
481  if (d_search != particleMap.end())
482  {
483  auto const & daughter = *((*d_search).second);
484  int d_pdg = abs(daughter.PdgCode());
485  if (d_pdg != 22) { return false; } // not the end of the shower
486  }
487  }
488 
489  float trkLength2 = 0;
490  auto const * p = &particle;
491  bool branching = false;
492  while (!branching)
493  {
494  trkLength2 += particleRange2(*p);
495  auto m_search = particleMap.find(p->Mother());
496  if (m_search != particleMap.end())
497  {
498  p = (*m_search).second;
499  int m_pdg = abs(p->PdgCode());
500  if (m_pdg == 11)
501  {
502  nSec = p->NumberDaughters();
503  size_t ne = 0;
504  for (size_t d = 0; d < nSec; ++d)
505  {
506  auto d_search = particleMap.find(p->Daughter(d));
507  if (d_search != particleMap.end())
508  {
509  auto const & daughter = *((*d_search).second);
510  int d_pdg = abs(daughter.PdgCode());
511  if (d_pdg == 11)
512  {
513  if (particleRange2(daughter) > maxDeltaLength2) { ne++; }
514  }
515  }
516  }
517  if (ne > 1) { branching = true; }
518  }
519  else break;
520  }
521  else break;
522  }
523 
524  return (trkLength2 > minElectronLength2);
525 }
526 
528  const std::unordered_map< int, const simb::MCParticle* > & particleMap) const
529 {
530  bool hasElectron = false, hasNuMu = false, hasNuE = false;
531 
532  int pdg = abs(particle.PdgCode());
533  if ((pdg == 13) && (particle.EndProcess() == "FastScintillation")) // potential muon decay at rest
534  {
535  unsigned int nSec = particle.NumberDaughters();
536  for (size_t d = 0; d < nSec; ++d)
537  {
538  auto d_search = particleMap.find(particle.Daughter(d));
539  if (d_search != particleMap.end())
540  {
541  auto const & daughter = *((*d_search).second);
542  int d_pdg = abs(daughter.PdgCode());
543  if (d_pdg == 11) hasElectron = true;
544  else if (d_pdg == 14) hasNuMu = true;
545  else if (d_pdg == 12) hasNuE = true;
546  }
547  }
548  }
549 
550  return (hasElectron && hasNuMu && hasNuE);
551 }
552 
554  std::unordered_map< size_t, std::unordered_map< int, int > > & wireToDriftToVtxFlags,
555  const std::unordered_map< int, const simb::MCParticle* > & particleMap,
556  unsigned int plane) const
557 {
558  for (auto const & p : particleMap)
559  {
560  auto const & particle = *p.second;
561 
562  double ekStart = 1000. * (particle.E() - particle.Mass());
563  double ekEnd = 1000. * (particle.EndE() - particle.Mass());
564 
565  int pdg = abs(particle.PdgCode());
566  int flagsStart = nnet::TrainingDataAlg::kNone;
567  int flagsEnd = nnet::TrainingDataAlg::kNone;
568 
569  switch (pdg)
570  {
571  case 22: // gamma
572  if ((particle.EndProcess() == "conv") &&
573  (ekStart > 40.0)) // conversion, gamma > 40MeV
574  {
575  //std::cout << "---> gamma conversion at " << ekStart << std::endl;
576  flagsEnd = nnet::TrainingDataAlg::kConv;
577  }
578  break;
579 
580  case 11: // e+/-
581  if (isElectronEnd(particle, particleMap))
582  {
584  }
585  break;
586 
587 
588  case 13: // mu+/-
589  if (isMuonDecaying(particle, particleMap))
590  {
591  //std::cout << "---> mu decay to electron" << std::endl;
593  }
594  break;
595 
596  case 111: // pi0
597  //std::cout << "---> pi0" << std::endl;
598  flagsStart = nnet::TrainingDataAlg::kPi0;
599  break;
600 
601  case 321: // K+/-
602  case 211: // pi+/-
603  case 2212: // proton
604  if (ekStart > 50.0)
605  {
606  if (particle.Mother() != 0)
607  {
608  auto search = particleMap.find(particle.Mother());
609  if (search != particleMap.end())
610  {
611  auto const & mother = *((*search).second);
612  int m_pdg = abs(mother.PdgCode());
613  unsigned int nSec = mother.NumberDaughters();
614  unsigned int nVisible = 0;
615  if (nSec > 1)
616  {
617  for (size_t d = 0; d < nSec; ++d)
618  {
619  auto d_search = particleMap.find(mother.Daughter(d));
620  if (d_search != particleMap.end())
621  {
622  auto const & daughter = *((*d_search).second);
623  int d_pdg = abs(daughter.PdgCode());
624  if (((d_pdg == 2212) || (d_pdg == 211) || (d_pdg == 321)) &&
625  (1000. * (daughter.E() - daughter.Mass()) > 50.0))
626  {
627  ++nVisible;
628  }
629  }
630  }
631  }
632  // hadron with Ek > 50MeV (so well visible) and
633  // produced by another hadron (but not neutron, so not single track from nothing) or
634  // at least secondary hadrons with Ek > 50MeV (so this is a good kink or V-like)
635  if (((m_pdg != pdg) && (m_pdg != 2112)) || ((m_pdg != 2112) && (nVisible > 0)) || ((m_pdg == 2112) && (nVisible > 1)))
636  {
637  // std::cout << "---> hadron at " << ekStart
638  // << ", pdg: " << pdg << ", mother pdg: " << m_pdg
639  // << ", vis.daughters: " << nVisible << std::endl;
640  flagsStart = nnet::TrainingDataAlg::kHadr;
641  }
642  }
643  // else std::cout << "---> mother not found for tid: " << particle.Mother() << std::endl;
644  }
645 
646  if (particle.EndProcess() == "FastScintillation") // potential decay at rest
647  {
648  unsigned int nSec = particle.NumberDaughters();
649  for (size_t d = 0; d < nSec; ++d)
650  {
651  auto d_search = particleMap.find(particle.Daughter(d));
652  if (d_search != particleMap.end())
653  {
654  auto const & daughter = *((*d_search).second);
655  int d_pdg = abs(daughter.PdgCode());
656  if ((pdg == 321) && (d_pdg == 13))
657  {
658  //std::cout << "---> K decay to mu" << std::endl;
660  break;
661  }
662  if ((pdg == 211) && (d_pdg == 13))
663  {
664  //std::cout << "---> pi decay to mu" << std::endl;
666  break;
667  }
668  }
669  }
670  }
671 
672  if ((particle.EndProcess() == "Decay") && (ekEnd > 200.0)) // decay in flight
673  {
674  unsigned int nSec = particle.NumberDaughters();
675  for (size_t d = 0; d < nSec; ++d)
676  {
677  auto d_search = particleMap.find(particle.Daughter(d));
678  if (d_search != particleMap.end())
679  {
680  auto const & daughter = *((*d_search).second);
681  int d_pdg = abs(daughter.PdgCode());
682  if ((pdg == 321) && (d_pdg == 13))
683  {
684  //std::cout << "---> in-flight K decay to mu" << std::endl;
685  flagsEnd = nnet::TrainingDataAlg::kHadr;
686  break;
687  }
688  if ((pdg == 211) && (d_pdg == 13))
689  {
690  //std::cout << "---> in-flight pi decay to mu" << std::endl;
691  flagsEnd = nnet::TrainingDataAlg::kHadr;
692  break;
693  }
694  }
695  }
696  }
697  }
698  break;
699 
700  default: continue;
701  }
702 
703  if (particle.Process() == "primary")
704  {
705  flagsStart |= nnet::TrainingDataAlg::kNuPri;
706  }
707 
708 
709  if (flagsStart != nnet::TrainingDataAlg::kNone)
710  {
711  auto wd = getProjection(particle.Position(), plane);
712 
713  if ((wd.TPC == (int)fTPC) && (wd.Cryo == (int)fCryo))
714  {
715  wireToDriftToVtxFlags[wd.Wire][wd.Drift] |= flagsStart;
716  // std::cout << "---> flagsStart:" << flagsStart << " plane:" << plane << " wire:" << wd.Wire << " drift:" << wd.Drift << std::endl;
717  }
718  // else std::cout << "---> not in current TPC" << std::endl;
719  }
720  if (flagsEnd != nnet::TrainingDataAlg::kNone)
721  {
722  auto wd = getProjection(particle.EndPosition(), plane);
723  if ((wd.TPC == (int)fTPC) && (wd.Cryo == (int)fCryo))
724  {
725  //if (flagsEnd == nnet::TrainingDataAlg::kElectronEnd) { std::cout << "---> clear electron endpoint" << std::endl; }
726  wireToDriftToVtxFlags[wd.Wire][wd.Drift] |= flagsEnd;
727  //if (flagsEnd == nnet::TrainingDataAlg::kElectronEnd)
728  // std::cout << "---> flagsEnd:" << flagsEnd << " plane:" << plane << " wire:" << wd.Wire << " drift:" << wd.Drift << std::endl;
729  }
730  // else std::cout << "---> not in current TPC" << std::endl;
731  }
732 
733  //if (ekStart > 30.0)
734  //{
735  // std::cout << particle.PdgCode() << ", " << ekStart << ": "
736  // << particle.Process() << " --> " << particle.EndProcess()
737  // << " " << ekEnd << std::endl;
738  //}
739  }
740 }
741 // ------------------------------------------------------
742 
744  unsigned int plane, unsigned int tpc, unsigned int cryo)
745 {
746 
748  std::vector< art::Ptr<recob::Wire> > Wirelist;
749 
750  if(event.getByLabel(fWireProducerLabel, wireHandle))
751  art::fill_ptr_vector(Wirelist, wireHandle);
752 
753  if(!setWireDriftData(*wireHandle, plane, tpc, cryo)) {
754  mf::LogError("TrainingDataAlg") << "Wire data not set.";
755  return false;
756  }
757 
758  // Hit info
760  std::vector< art::Ptr<recob::Hit> > Hitlist;
761 
762  if(event.getByLabel(fHitProducerLabel, HitHandle))
763  art::fill_ptr_vector(Hitlist, HitHandle);
764 
765  // Track info
767  std::vector< art::Ptr<recob::Track> > Tracklist;
768 
769  if(event.getByLabel(fTrackModuleLabel, TrackHandle))
770  art::fill_ptr_vector(Tracklist, TrackHandle);
771 
772  art::FindManyP<recob::Track> ass_trk_hits(HitHandle, event, fTrackModuleLabel);
773 
774  // Loop over wires (sorry about hard coded value) to fill in 1) pdg and 2) charge depo
775  for (size_t widx = 0; widx < 240; ++widx) {
776 
777  std::vector< float > labels_deposit(fNDrifts, 0); // full-drift-length buffers
778  std::vector< int > labels_pdg(fNDrifts, 0);
779 
780  // First, the charge depo
781  for(size_t subwidx = 0; subwidx < Wirelist.size(); ++subwidx) {
782  if(widx+240 == Wirelist[subwidx]->Channel()) {
783  labels_deposit = Wirelist[subwidx]->Signal();
784  break;
785  }
786  }
787 
788  // Second, the pdg code
789  // This code finds the angle of the track and records
790  // events based on its angle to try to get an isometric sample
791  // instead of just a bunch of straight tracks
792 
793  // Meta code:
794  // For each hit:
795  // find farthest hit from point
796  // then find farthest hit from THAT one
797  // should be start and end of track, then just use trig
798 
799  for(size_t iHit = 0; iHit < Hitlist.size(); ++iHit) {
800 
801  if(Hitlist[iHit]->Channel() != widx+240) { continue; }
802  if(Hitlist[iHit]->View() != 1) { continue; }
803 
804  // Make sure there is a track association
805  if(ass_trk_hits.at(iHit).size() == 0) { continue; }
806 
807  // Not sure about this
808  // Cutting on length to not just get a bunch of shower stubs
809  // Might add a lot of bias though
810  if(ass_trk_hits.at(iHit)[0]->Length() < 5) { continue; }
811 
812  // Search for farest hit from this one
813  int far_index = 0;
814  double far_dist = 0;
815 
816  for(size_t jHit = 0; jHit < Hitlist.size(); ++jHit) {
817  if(jHit == iHit) { continue; }
818  if(Hitlist[jHit]->View() != 1) { continue; }
819 
820  if(ass_trk_hits.at(jHit).size() == 0) { continue; }
821  if(ass_trk_hits.at(jHit)[0]->ID() !=
822  ass_trk_hits.at(iHit)[0]->ID()) { continue; }
823 
824  double dist = sqrt((Hitlist[iHit]->Channel()-Hitlist[jHit]->Channel()) *
825  (Hitlist[iHit]->Channel()-Hitlist[jHit]->Channel()) +
826  (Hitlist[iHit]->PeakTime()-Hitlist[jHit]->PeakTime()) *
827  (Hitlist[iHit]->PeakTime()-Hitlist[jHit]->PeakTime()));
828 
829  if(far_dist < dist){
830  far_dist = dist;
831  far_index = jHit;
832  }
833  }
834 
835  // Search for the other end of the track
836  int other_end = 0;
837  int other_dist = 0;
838 
839  for(size_t jHit = 0; jHit < Hitlist.size(); ++jHit) {
840  if(jHit == iHit or int(jHit) == far_index) { continue; }
841  if(Hitlist[jHit]->View() != 1) { continue; }
842 
843  if(ass_trk_hits.at(jHit).size() == 0) { continue; }
844  if(ass_trk_hits.at(jHit)[0]->ID() !=
845  ass_trk_hits.at(iHit)[0]->ID()) { continue; }
846 
847  double dist = sqrt((Hitlist[far_index]->Channel()-Hitlist[jHit]->Channel()) *
848  (Hitlist[far_index]->Channel()-Hitlist[jHit]->Channel()) +
849  (Hitlist[far_index]->PeakTime()-Hitlist[jHit]->PeakTime()) *
850  (Hitlist[far_index]->PeakTime()-Hitlist[jHit]->PeakTime()));
851 
852  if(other_dist < dist){
853  other_dist = dist;
854  other_end = jHit;
855  }
856  }
857 
858  // We have the end points now
859  double del_wire = double(Hitlist[other_end]->Channel() - Hitlist[far_index]->Channel());
860  double del_time = double(Hitlist[other_end]->PeakTime() - Hitlist[far_index]->PeakTime());
861  double hypo = sqrt(del_wire * del_wire + del_time * del_time);
862 
863  if(hypo == 0) { continue; } // Should never happen, but doing it anyway
864 
865  double cosser = TMath::Abs(del_wire / hypo);
866  double norm_ang = TMath::ACos(cosser) * 2 / TMath::Pi();
867 
868  // Using fEventsPerBin to keep track of number of hits per angle (normalized to 0 to 1)
869 
870  int binner = int(norm_ang * fEventsPerBin.size());
871  if(binner >= (int)fEventsPerBin.size()) { binner = fEventsPerBin.size() - 1; } // Dealing with rounding errors
872 
873  // So we should get a total of 5000 * 100 = 50,000 if we use the whole set
874  if(fEventsPerBin[binner] > 5000) { continue; }
875  fEventsPerBin[binner]++;
876 
877  // If survives everything, saves the pdg
878  labels_pdg[Hitlist[iHit]->PeakTime()] = 211; // Same as pion for now
879 
880  }
881 
882  setWireEdepsAndLabels(labels_deposit, labels_pdg, widx);
883 
884  } // for each Wire
885 
886  /*
887  for(size_t i = 0; i < fEventsPerBin.size(); i ++) {
888  std::cout << i << ") " << fEventsPerBin[i] << " - ";
889  }
890  */
891 
892  return true;
893 
894 }
895 
897  unsigned int plane, unsigned int tpc, unsigned int cryo)
898 {
900  = event.getValidHandle< std::vector<recob::Wire> >(fWireProducerLabel);
901 
902  if (!setWireDriftData(*wireHandle, plane, tpc, cryo))
903  {
904  mf::LogError("TrainingDataAlg") << "Wire data not set.";
905  return false;
906  }
907 
908  if (!fSaveSimInfo || event.isRealData())
909  {
910  mf::LogInfo("TrainingDataAlg") << "Skip MC simulation info.";
911  return true;
912  }
913 
915  double electronsToGeV = 1. / larParameters->GeVToElectrons();
916 
917  auto particleHandle = event.getValidHandle< std::vector<simb::MCParticle> >(fSimulationProducerLabel);
918 
919  auto simChannelHandle = event.getValidHandle< std::vector<sim::SimChannel> >(fSimulationProducerLabel);
920 
921  std::unordered_map< int, const simb::MCParticle* > particleMap;
922  for (auto const & particle : *particleHandle)
923  {
924  particleMap[particle.TrackId()] = &particle;
925  }
926 
927  std::unordered_map< size_t, std::unordered_map< int, int > > wireToDriftToVtxFlags;
928  if (fSaveVtxFlags) collectVtxFlags(wireToDriftToVtxFlags, particleMap, plane);
929 
930  fEdepTot = 0;
931 
932  std::map< int, int > trackToPDG;
933  for (size_t widx = 0; widx < fNWires; ++widx)
934  {
935  auto wireChannelNumber = fWireChannels[widx];
936  if (wireChannelNumber == raw::InvalidChannelID) continue;
937 
938  std::vector< float > labels_deposit(fNDrifts, 0); // full-drift-length buffers,
939  std::vector< int > labels_pdg(labels_deposit.size(), 0); // both of the same size,
940  int labels_size = labels_deposit.size(); // cached as int for comparisons below
941 
942  std::map< int, std::map< int, double > > timeToTrackToCharge;
943  for (auto const & channel : *simChannelHandle)
944  {
945  if (channel.Channel() != wireChannelNumber) continue;
946 
947  auto const & timeSlices = channel.TDCIDEMap();
948  for (auto const & timeSlice : timeSlices)
949  {
950  int time = timeSlice.first;
951 
952  auto const & energyDeposits = timeSlice.second;
953  for (auto const & energyDeposit : energyDeposits)
954  {
955  int pdg = 0;
956  int tid = energyDeposit.trackID;
957  if (tid < 0) // negative tid means it is EM activity, and -tid is the mother
958  {
959  pdg = 11; tid = -tid;
960 
961  auto search = particleMap.find(tid);
962  if (search == particleMap.end())
963  {
964  mf::LogWarning("TrainingDataAlg") << "PARTICLE NOT FOUND";
965  continue;
966  }
967  auto const & mother = *((*search).second); // mother particle of this EM
968  int mPdg = abs(mother.PdgCode());
969  if ((mPdg == 13) || (mPdg == 211) || (mPdg == 2212))
970  {
971  if (energyDeposit.numElectrons > 10) pdg |= nnet::TrainingDataAlg::kDelta; // tag delta ray
972  }
973  }
974  else
975  {
976  auto search = particleMap.find(tid);
977  if (search == particleMap.end())
978  {
979  mf::LogWarning("TrainingDataAlg") << "PARTICLE NOT FOUND";
980  continue;
981  }
982  auto const & particle = *((*search).second);
983  pdg = abs(particle.PdgCode());
984 
985  if (particle.Process() == "primary")
986  {
987  if (pdg == 11)
988  {
989  pdg |= nnet::TrainingDataAlg::kPriEl; // tag primary
990  }
991  else if (pdg == 13)
992  {
993  pdg |= nnet::TrainingDataAlg::kPriMu; // tag primary
994  }
995  }
996 
997  auto msearch = particleMap.find(particle.Mother());
998  if (msearch != particleMap.end())
999  {
1000  auto const & mother = *((*msearch).second);
1001  if (pdg == 11) // electron, check if it is Michel
1002  {
1003  if (nnet::TrainingDataAlg::isMuonDecaying(mother, particleMap))
1004  {
1005  pdg |= nnet::TrainingDataAlg::kMichel; // tag Michel
1006  }
1007  }
1008  }
1009  }
1010 
1011  trackToPDG[energyDeposit.trackID] = pdg;
1012 
1013  double energy = energyDeposit.numElectrons * electronsToGeV;
1014  timeToTrackToCharge[time][energyDeposit.trackID] += energy;
1015  fEdepTot += energy;
1016 
1017  } // loop over energy deposits
1018  } // loop over time slices
1019  } // for each SimChannel
1020 
1022  for (auto const & ttc : timeToTrackToCharge)
1023  {
1024  float max_deposit = 0.0;
1025  int max_pdg = 0;
1026  for (auto const & tc : ttc.second) {
1027 
1028  if( tc.second > max_deposit )
1029  {
1030  max_deposit = tc.second;
1031  max_pdg = trackToPDG[tc.first];
1032  }
1033  }
1034 
1035  if (ttc.first < labels_size)
1036  {
1037  int tick_idx = ttc.first + fAdcDelay;
1038  if (tick_idx < labels_size)
1039  {
1040  labels_deposit[tick_idx] = max_deposit;
1041  labels_pdg[tick_idx] = max_pdg & type_pdg_mask;
1042  }
1043  }
1044  }
1045 
1046  for (auto const & drift_flags : wireToDriftToVtxFlags[widx])
1047  {
1048  int drift = drift_flags.first, flags = drift_flags.second;
1049  if ((drift >= 0) && (drift < labels_size))
1050  {
1051  labels_pdg[drift] |= flags;
1052  }
1053  }
1054 
1055  setWireEdepsAndLabels(labels_deposit, labels_pdg, widx);
1056 
1057  } // for each Wire
1058 
1059  return true;
1060 }
1061 // ------------------------------------------------------
1062 
1063 bool nnet::TrainingDataAlg::findCrop(float max_e_cut, unsigned int & w0, unsigned int & w1, unsigned int & d0, unsigned int & d1) const
1064 {
1065  if (fWireDriftEdep.empty() || fWireDriftEdep.front().empty()) return false;
1066 
1067  float max_cut = 0.25 * max_e_cut;
1068 
1069  w0 = 0;
1070  float cut = 0;
1071  while (w0 < fWireDriftEdep.size())
1072  {
1073  for (auto const d : fWireDriftEdep[w0]) cut += d;
1074  if (cut < max_cut) w0++;
1075  else break;
1076  }
1077  w1 = fWireDriftEdep.size() - 1;
1078  cut = 0;
1079  while (w1 > w0)
1080  {
1081  for (auto const d : fWireDriftEdep[w1]) cut += d;
1082  if (cut < max_cut) w1--;
1083  else break;
1084  }
1085  w1++;
1086 
1087  d0 = 0;
1088  cut = 0;
1089  while (d0 < fWireDriftEdep.front().size())
1090  {
1091  for (size_t i = w0; i < w1; ++i) cut += fWireDriftEdep[i][d0];
1092  if (cut < max_cut) d0++;
1093  else break;
1094  }
1095  d1 = fWireDriftEdep.front().size() - 1;
1096  cut = 0;
1097  while (d1 > d0)
1098  {
1099  for (size_t i = w0; i < w1; ++i) cut += fWireDriftEdep[i][d1];
1100  if (cut < max_cut) d1--;
1101  else break;
1102  }
1103  d1++;
1104 
1105  unsigned int margin = 20;
1106  if ((w1 - w0 > 8) && (d1 - d0 > 8))
1107  {
1108  if (w0 < margin) w0 = 0;
1109  else w0 -= margin;
1110 
1111  if (w1 > fWireDriftEdep.size() - margin) w1 = fWireDriftEdep.size();
1112  else w1 += margin;
1113 
1114  if (d0 < margin) d0 = 0;
1115  else d0 -= margin;
1116 
1117  if (d1 > fWireDriftEdep.front().size() - margin) d1 = fWireDriftEdep.front().size();
1118  else d1 += margin;
1119 
1120  return true;
1121  }
1122  else return false;
1123 }
1124 // ------------------------------------------------------
1125 
bool isInsideFiducialRegion(unsigned int wire, float drift) const
Definition: PointIdAlg.cxx:327
virtual void resizeView(size_t wires, size_t drifts)
Store parameters for running LArG4.
Float_t s
Definition: plot.C:23
geo::GeometryCore const * fGeometry
bool bufferPatch(size_t wire, float drift, std::vector< std::vector< float > > &patch) const
Definition: PointIdAlg.h:156
void collectVtxFlags(std::unordered_map< size_t, std::unordered_map< int, int > > &wireToDriftToVtxFlags, const std::unordered_map< int, const simb::MCParticle * > &particleMap, unsigned int plane) const
Definition: PointIdAlg.cxx:553
void resizePatch(void)
Definition: PointIdAlg.cxx:191
int PdgCode() const
Definition: MCParticle.h:216
bool setWireEdepsAndLabels(std::vector< float > const &edeps, std::vector< int > const &pdgs, size_t wireIdx)
Definition: PointIdAlg.cxx:382
std::vector< raw::ChannelID_t > fWireChannels
Utilities related to art service access.
bool isMuonDecaying(const simb::MCParticle &particle, const std::unordered_map< int, const simb::MCParticle * > &particleMap) const
Definition: PointIdAlg.cxx:527
std::vector< std::vector< float > > Run(std::vector< std::vector< std::vector< float > > > const &inps, int samples=-1) override
Definition: PointIdAlg.cxx:106
std::vector< std::vector< int > > fWireDriftPdg
Definition: PointIdAlg.h:322
unsigned int fAdcDelay
Definition: PointIdAlg.h:331
void deleteNNet(void)
Definition: PointIdAlg.h:181
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
art::InputTag fTrackModuleLabel
Definition: PointIdAlg.h:326
bool isValid
Whether this ID points to a valid element.
Definition: geo_types.h:129
static std::vector< float > flattenData2D(std::vector< std::vector< float > > const &patch)
Definition: PointIdAlg.cxx:303
virtual std::vector< float > Run(std::vector< std::vector< float > > const &inp2d)=0
virtual void set_data(std::vector< std::vector< std::vector< float > > > const &)
Definition: keras_model.h:47
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:130
DataProviderAlg(const fhicl::ParameterSet &pset)
bool setEventData(const art::Event &event, unsigned int plane, unsigned int tpc, unsigned int cryo)
Definition: PointIdAlg.cxx:896
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
bool isRealData() const
Definition: Event.h:83
std::vector< float > compute_output(keras::DataChunk *dc)
Definition: keras_model.cc:403
bool isCurrentPatch(unsigned int wire, float drift) const
Definition: PointIdAlg.cxx:285
int NumberDaughters() const
Definition: MCParticle.h:221
~TrainingDataAlg(void) override
Definition: PointIdAlg.cxx:357
std::vector< std::string > fNNetOutputs
Definition: PointIdAlg.h:149
bool setWireDriftData(const std::vector< recob::Wire > &wires, unsigned int plane, unsigned int tpc, unsigned int cryo)
static std::unique_ptr< Graph > create(const char *graph_file_name, const std::vector< std::string > &outputs={})
Definition: tf_graph.h:29
int Daughter(const int i) const
Definition: MCParticle.cxx:112
virtual double ConvertXToTicks(double X, int p, int t, int c) const =0
art::InputTag fWireProducerLabel
Definition: PointIdAlg.h:324
geo::TPCID FindTPCAtPosition(double const worldLoc[3]) const
Returns the ID of the TPC at specified location.
~PointIdAlg(void) override
Definition: PointIdAlg.cxx:185
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
bool isElectronEnd(const simb::MCParticle &particle, const std::unordered_map< int, const simb::MCParticle * > &particleMap) const
Definition: PointIdAlg.cxx:468
std::vector< float > predictIdVector(unsigned int wire, float drift) const
calculate multi-class probabilities for [wire, drift] point
Definition: PointIdAlg.cxx:222
constexpr ChannelID_t InvalidChannelID
ID of an invalid channel.
Definition: RawTypes.h:31
std::vector< std::vector< float > > fWireDriftPatch
Definition: PointIdAlg.h:152
std::string EndProcess() const
Definition: MCParticle.h:220
detinfo::DetectorProperties const * fDetProp
fhicl::Sequence< std::string > NNetOutputs
Definition: PointIdAlg.h:101
unsigned int fNCachedDrifts
geo::WireID::WireID_t NearestWire(geo::Point_t const &point, geo::PlaneID const &planeid) const
Returns the index of wire closest to position in the specified TPC.
double energy
Definition: plottest35.C:25
std::vector< size_t > fEventsPerBin
Definition: PointIdAlg.h:333
Float_t d
Definition: plot.C:237
KerasModelInterface(const char *modelFileName)
Definition: PointIdAlg.cxx:73
void fill(const art::PtrVector< recob::Hit > &hits, int only_plane)
bool findCrop(float max_e_cut, unsigned int &w0, unsigned int &w1, unsigned int &d0, unsigned int &d1) const
WireDrift getProjection(const TLorentzVector &tvec, unsigned int plane) const
Definition: PointIdAlg.cxx:427
size_t fPatchSizeD
Definition: PointIdAlg.h:153
The data type to uniquely identify a TPC.
Definition: geo_types.h:195
keras::KerasModel m
Definition: PointIdAlg.h:72
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
fhicl::Atom< std::string > NNetModelFile
Definition: PointIdAlg.h:98
TfModelInterface(const char *modelFileName)
Definition: PointIdAlg.cxx:97
std::vector< float > Run(std::vector< std::vector< float > > const &inp2d) override
Definition: PointIdAlg.cxx:80
bool getByLabel(std::string const &label, std::string const &productInstanceName, Handle< PROD > &result) const
Definition: DataViewImpl.h:344
std::string findFile(const char *fileName) const
Definition: PointIdAlg.cxx:51
short int DetectDriftDirection() const
Returns the expected drift direction based on geometry.
Definition: TPCGeo.cxx:181
std::vector< std::vector< float > > predictIdVectors(std::vector< std::pair< unsigned int, float > > points) const
Definition: PointIdAlg.cxx:245
unsigned int fNScaledDrifts
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
static float particleRange2(const simb::MCParticle &particle)
Definition: PointIdAlg.h:305
object containing MC truth information necessary for making RawDigits and doing back tracking ...
size_t fCurrentScaledDrift
Definition: PointIdAlg.h:155
nnet::ModelInterface * fNNet
Definition: PointIdAlg.h:150
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
size_t fPatchSizeW
Definition: PointIdAlg.h:153
Exception thrown on invalid wire number (e.g. NearestWireID())
Definition: Exceptions.h:158
art::InputTag fSimulationProducerLabel
Definition: PointIdAlg.h:327
Interface to algorithm class for a specific detector channel mapping.
std::string fNNetModelFilePath
Definition: PointIdAlg.h:148
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:464
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:203
bool isSamePatch(unsigned int wire1, float drift1, unsigned int wire2, float drift2) const
test if two wire/drift coordinates point to the same patch
Definition: PointIdAlg.cxx:267
bool setDataEventData(const art::Event &event, unsigned int plane, unsigned int tpc, unsigned int cryo)
Definition: PointIdAlg.cxx:743
Float_t e
Definition: plot.C:34
std::vector< std::vector< float > > fWireDriftEdep
Definition: PointIdAlg.h:321
Float_t w
Definition: plot.C:23
void resizeView(size_t wires, size_t drifts) override
Definition: PointIdAlg.cxx:362
std::string const & label() const noexcept
Definition: InputTag.h:55
art::InputTag fHitProducerLabel
Definition: PointIdAlg.h:325
double GeVToElectrons() const
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
Event finding and building.
TrainingDataAlg(const fhicl::ParameterSet &pset)
Definition: PointIdAlg.h:254
size_t fCurrentWireIdx
Definition: PointIdAlg.h:155
float predictIdValue(unsigned int wire, float drift, size_t outIdx=0) const
calculate single-value prediction (2-class probability) for [wire, drift] point
Definition: PointIdAlg.cxx:198
PointIdAlg(const fhicl::ParameterSet &pset)
Definition: PointIdAlg.h:114