LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
DumpPFParticles_module.cc
Go to the documentation of this file.
1 
8 // LArSoft includes
11 
12 // art libraries
18 
19 // support libraries
20 #include "fhiclcpp/types/Atom.h"
22 
23 // C//C++ standard libraries
24 #include <string>
25 
26 // ... and more in the implementation part
27 
28 namespace recob {
29 
132  public:
133  struct Config {
134  using Name = fhicl::Name;
136 
138  Name("PFModuleLabel"),
139  Comment("label of producer of the recob::PFParticle to be dumped")};
140 
142  Name("OutputCategory"),
143  Comment("message facility category used for output (for filtering)"),
144  "DumpPFParticles"};
145 
147  Comment("print all the floating point numbers in base 16"),
148  false};
149 
151  Name("MaxDepth"),
152  Comment("at most this number of particle generations will be printed")};
153 
155  Name("MakeParticleGraphs"),
156  Comment("creates a DOT file with particle information for each event"),
157  false};
158 
159  }; // struct Config
160 
162 
164  explicit DumpPFParticles(Parameters const& config);
165 
167  virtual void analyze(const art::Event& evt) override;
168 
169  private:
171  std::string fOutputCategory;
173  unsigned int fMaxDepth;
175 
176  static std::string DotFileName(art::EventID const& evtID, art::Provenance const& prodInfo);
177 
179  art::ValidHandle<std::vector<recob::PFParticle>> const& handle) const;
180 
181  }; // class DumpPFParticles
182 
183 } // namespace recob
184 
185 //==============================================================================
186 //=== Implementation section
187 //==============================================================================
188 // LArSoft includes
196 
197 // art libraries
202 
203 // support libraries
205 
206 // C//C++ standard libraries
207 #include <algorithm> // std::count(), std::find()
208 #include <fstream>
209 #include <limits> // std::numeric_limits<>
210 #include <utility> // std::swap()
211 
212 namespace {
217  template <typename T>
218  class int_map : private std::vector<T> {
219  using map_type = std::vector<T>;
220 
221  public:
222  using this_type = int_map<T>;
223 
224  using typename map_type::const_iterator;
225  using typename map_type::const_reference;
226  using typename map_type::iterator;
227  using typename map_type::reference;
228  using typename map_type::value_type;
229 
230  using typename map_type::size_type;
231 
233  int_map() = default;
234 
236  int_map(value_type invalid_value) : invalid(invalid_value) {}
237 
239  void resize(size_t new_size) { get_map().resize(new_size, invalid_value()); }
240 
242  reference operator[](size_t pos)
243  {
244  if (pos >= size()) resize(pos + 1);
245  return get_map()[pos];
246  }
247 
249  const_reference operator[](size_t pos) const
250  {
251  return (pos >= size()) ? invalid : get_map()[pos];
252  }
253 
254  using map_type::empty;
255  using map_type::size;
256 
257  using map_type::begin;
258  using map_type::cbegin;
259  using map_type::cend;
260  using map_type::crbegin;
261  using map_type::crend;
262  using map_type::end;
263  using map_type::rbegin;
264  using map_type::rend;
265 
267  void swap(this_type& data)
268  {
269  swap(data.get_map());
270  std::swap(data.invalid, invalid);
271  }
272 
274  void swap(std::vector<T>& data) { map_type::swap(data); }
275 
276  // non-standard calls follow
278  size_type n_invalid() const { return std::count(begin(), end(), invalid); }
279 
281  size_type n_valid() const { return size() - n_invalid(); }
282 
284  bool is_valid(size_type pos) const
285  {
286  return (pos < size()) ? is_valid_value(get_map()[pos]) : false;
287  }
288 
290  bool is_valid_value(value_type const& v) const { return v != invalid; }
291 
293  value_type const& invalid_value() const { return invalid; }
294 
295  private:
296  value_type const invalid;
297 
298  map_type& get_map() { return static_cast<map_type&>(*this); }
299  map_type const& get_map() const { return static_cast<map_type const&>(*this); }
300 
301  }; // int_map<>
302 
303  //----------------------------------------------------------------------------
304  int_map<size_t> CreateMap(std::vector<recob::PFParticle> const& particles)
305  {
306 
307  int_map<size_t> pmap(std::numeric_limits<size_t>::max());
308  pmap.resize(particles.size());
309 
310  size_t const nParticles = particles.size();
311  for (size_t iPart = 0; iPart < nParticles; ++iPart)
312  pmap[particles[iPart].Self()] = iPart;
313 
314  return pmap;
315  } // CreateMap()
316 
317  //----------------------------------------------------------------------------
318  bool hasDaughter(recob::PFParticle const& particle, size_t partID)
319  {
320  auto const& daughters = particle.Daughters();
321  return daughters.end() != std::find(daughters.begin(), daughters.end(), partID);
322  } // hasDaughter()
323 
324  //----------------------------------------------------------------------------
325  class ParticleDumper {
326  public:
328  struct PrintOptions_t {
329  bool hexFloats = false;
330  unsigned int maxDepth = std::numeric_limits<unsigned int>::max();
333  std::string streamName;
334  }; // PrintOptions_t
335 
337  ParticleDumper(std::vector<recob::PFParticle> const& particle_list)
338  : ParticleDumper(particle_list, {})
339  {}
340 
342  ParticleDumper(std::vector<recob::PFParticle> const& particle_list,
343  PrintOptions_t print_options)
344  : particles(particle_list)
345  , options(print_options)
346  , visited(particles.size(), 0U)
347  , particle_map(CreateMap(particles))
348  {}
349 
351  void SetVertices(art::FindOne<recob::Vertex> const* vtx_query) { vertices = vtx_query; }
352 
354  void SetTracks(art::FindMany<recob::Track> const* trk_query) { tracks = trk_query; }
355 
357  void SetClusters(art::FindMany<recob::Cluster> const* cls_query) { clusters = cls_query; }
358 
360  void SetSeeds(art::FindMany<recob::Seed> const* seed_query) { seeds = seed_query; }
361 
363  void SetSpacePoints(art::FindMany<recob::SpacePoint> const* sp_query)
364  {
365  spacepoints = sp_query;
366  }
367 
369  void SetPCAxes(art::FindMany<recob::PCAxis> const* pca_query) { pcaxes = pca_query; }
370 
373  template <typename Stream>
374  void DumpParticle(Stream&& out,
375  size_t iPart,
376  std::string indentstr = "",
377  unsigned int gen = 0) const;
378 
381  template <typename Stream>
382  void DumpParticleWithID(Stream&& out,
383  size_t pID,
384  std::string indentstr = "",
385  unsigned int gen = 0) const;
386 
388  void DumpAllPrimaries(std::string indentstr = "") const;
389 
391  void DumpAllParticles(std::string indentstr = "") const;
392 
393  template <typename Stream>
394  static void DumpPDGID(Stream&& out, int ID);
395 
396  protected:
397  std::vector<recob::PFParticle> const& particles;
398 
399  PrintOptions_t options;
400 
402  art::FindOne<recob::Vertex> const* vertices = nullptr;
403 
405  art::FindMany<recob::Track> const* tracks = nullptr;
406 
408  art::FindMany<recob::Cluster> const* clusters = nullptr;
409 
411  art::FindMany<recob::Seed> const* seeds = nullptr;
412 
414  art::FindMany<recob::SpacePoint> const* spacepoints = nullptr;
415 
417  art::FindMany<recob::PCAxis> const* pcaxes = nullptr;
418 
420  mutable std::vector<unsigned int> visited;
421 
422  int_map<size_t> const particle_map;
423 
424  template <typename Stream>
425  void DumpPFParticleInfo(Stream&& out,
426  recob::PFParticle const& part,
427  unsigned int iPart,
428  std::string indentstr) const;
429 
430  template <typename Stream>
431  void DumpVertex(Stream&& out,
432  cet::maybe_ref<recob::Vertex const> VertexRef,
433  std::string indentstr) const;
434 
435  template <typename Stream>
436  void DumpPCAxisDirection(Stream&& out, recob::PCAxis const& axis) const;
437 
438  template <typename Stream>
439  void DumpPCAxes(Stream&& out,
440  std::vector<recob::PCAxis const*> const& myAxes,
441  std::string indentstr) const;
442 
443  template <typename Stream>
444  void DumpTrack(Stream&& out, recob::Track const& track) const;
445 
446  template <typename Stream>
447  void DumpTracks(Stream&& out,
448  std::vector<recob::Track const*> const& myTracks,
449  std::string indentstr) const;
450 
451  template <typename Stream>
452  void DumpSeed(Stream&& out, recob::Seed const& seed, std::string indentstr) const;
453 
454  template <typename Stream>
455  void DumpSeeds(Stream&& out,
456  std::vector<recob::Seed const*> const& mySeeds,
457  std::string indentstr) const;
458 
459  template <typename Stream>
460  void DumpSpacePoint(Stream&& out, recob::SpacePoint const& sp) const;
461 
462  template <typename Stream>
463  void DumpSpacePoints(Stream&& out,
464  std::vector<recob::SpacePoint const*> const& mySpacePoints,
465  std::string indentstr) const;
466 
467  template <typename Stream>
468  void DumpClusterSummary(Stream&& out, recob::Cluster const& track) const;
469 
470  template <typename Stream>
471  void DumpClusters(Stream&& out,
472  std::vector<recob::Cluster const*> const& myClusters,
473  std::string indentstr) const;
474 
475  }; // class ParticleDumper
476 
477  //----------------------------------------------------------------------------
478  class PFParticleGraphMaker {
479  public:
480  PFParticleGraphMaker() = default;
481 
482  template <typename Stream>
483  void MakeGraph(Stream&& out, std::vector<recob::PFParticle> const& particles) const;
484 
485  template <typename Stream>
486  void WriteGraphHeader(Stream&& out) const;
487 
488  template <typename Stream>
489  void WriteParticleRelations(Stream&& out,
490  std::vector<recob::PFParticle> const& particles) const;
491 
492  template <typename Stream>
493  void WriteParticleNodes(Stream&& out, std::vector<recob::PFParticle> const& particles) const;
494 
495  template <typename Stream>
496  void WriteParticleEdges(Stream&& out, std::vector<recob::PFParticle> const& particles) const;
497 
498  template <typename Stream>
499  void WriteGraphFooter(Stream&& out) const;
500 
501  }; // class PFParticleGraphMaker
502 
503  //----------------------------------------------------------------------------
504  //--- ParticleDumper implementation
505  //---
506  template <typename Stream>
507  void ParticleDumper::DumpParticle(Stream&& out,
508  size_t iPart,
509  std::string indentstr /* = "" */,
510  unsigned int gen /* = 0 */
511  ) const
512  {
513  lar::OptionalHexFloat hexfloat(options.hexFloats);
514 
515  recob::PFParticle const& part = particles.at(iPart);
516  ++visited[iPart];
517 
518  if (visited[iPart] > 1) {
519  out << indentstr << "particle " << part.Self() << " already printed!!!";
520  return;
521  }
522 
523  //
524  // intro
525  //
526  DumpPFParticleInfo(std::forward<Stream>(out), part, iPart, indentstr);
527 
528  //
529  // vertex information
530  //
531  if (vertices) DumpVertex(std::forward<Stream>(out), vertices->at(iPart), indentstr);
532 
533  // daughters tag
534  if (part.NumDaughters() > 0)
535  out << " with " << part.NumDaughters() << " daughters";
536  else
537  out << " with no daughter";
538 
539  //
540  // axis
541  //
542  if (pcaxes) DumpPCAxes(std::forward<Stream>(out), pcaxes->at(iPart), indentstr);
543 
544  //
545  // tracks
546  //
547  if (tracks) DumpTracks(std::forward<Stream>(out), tracks->at(iPart), indentstr);
548 
549  //
550  // seeds
551  //
552  if (seeds) DumpSeeds(std::forward<Stream>(out), seeds->at(iPart), indentstr);
553 
554  //
555  // space points
556  //
557  if (spacepoints) {
558  DumpSpacePoints(std::forward<Stream>(out), spacepoints->at(iPart), indentstr);
559  }
560 
561  //
562  // clusters
563  //
564  if (clusters) { DumpClusters(std::forward<Stream>(out), clusters->at(iPart), indentstr); }
565 
566  //
567  // daughters
568  //
569  auto const PartID = part.Self();
570  if (part.NumDaughters() > 0) {
571  std::vector<size_t> const& daughters = part.Daughters();
572  out << "\n" << indentstr << " " << part.NumDaughters() << " particle daughters";
573  if (gen > 0) {
574  out << ":";
575  for (size_t DaughterID : daughters) {
576  if (DaughterID == PartID) {
577  out << "\n" << indentstr << " oh, just great: this particle is its own daughter!";
578  }
579  else {
580  out << '\n';
581  DumpParticleWithID(out, DaughterID, indentstr + " ", gen - 1);
582  }
583  }
584  } // if descending
585  else {
586  out << " (further descend suppressed)";
587  }
588  } // if has daughters
589 
590  //
591  // warnings
592  //
593  if (visited[iPart] == 2) {
594  out << "\n"
595  << indentstr << " WARNING: particle ID=" << PartID << " connected more than once!";
596  }
597 
598  //
599  // done
600  //
601 
602  } // ParticleDumper::DumpParticle()
603 
604  //----------------------------------------------------------------------------
605  template <typename Stream>
606  void ParticleDumper::DumpParticleWithID(Stream&& out,
607  size_t pID,
608  std::string indentstr /* = "" */,
609  unsigned int gen /* = 0 */
610  ) const
611  {
612  size_t const pos = particle_map[pID];
613  if (particle_map.is_valid_value(pos)) { DumpParticle(out, pos, indentstr, gen); }
614  else {
615  out /* << "\n" */ << indentstr << "<ID=" << pID << " not found>";
616  }
617  } // ParticleDumper::DumpParticleWithID()
618 
619  //----------------------------------------------------------------------------
620  void ParticleDumper::DumpAllPrimaries(std::string indentstr /* = "" */) const
621  {
622  indentstr += " ";
623  size_t const nParticles = particles.size();
624  unsigned int nPrimaries = 0;
625  for (size_t iPart = 0; iPart < nParticles; ++iPart) {
626  if (!particles[iPart].IsPrimary()) continue;
627  DumpParticle(mf::LogVerbatim(options.streamName), iPart, indentstr, options.maxDepth);
628  } // for
629  if (nPrimaries == 0) {
630  mf::LogVerbatim(options.streamName) << indentstr << "No primary particle found";
631  }
632  } // ParticleDumper::DumpAllPrimaries()
633 
634  //----------------------------------------------------------------------------
635  void ParticleDumper::DumpAllParticles(std::string indentstr /* = "" */) const
636  {
637  // first print all the primary particles
638  DumpAllPrimaries(indentstr);
639  // then find out if there are any that are "disconnected"
640  unsigned int const nDisconnected = std::count(visited.begin(), visited.end(), 0U);
641  if (nDisconnected) {
642  mf::LogVerbatim(options.streamName)
643  << indentstr << nDisconnected << " particles not coming from primary ones:";
644  size_t const nParticles = visited.size();
645  for (size_t iPart = 0; iPart < nParticles; ++iPart) {
646  if (visited[iPart] > 0) continue;
647  DumpParticle(
648  mf::LogVerbatim(options.streamName), iPart, indentstr + " ", options.maxDepth);
649  } // for unvisited particles
650  mf::LogVerbatim(options.streamName)
651  << indentstr << "(end of " << nDisconnected << " particles not from primaries)";
652  } // if there are disconnected particles
653  // TODO finally, note if there are multiply-connected particles
654 
655  } // ParticleDumper::DumpAllParticles()
656 
657  //----------------------------------------------------------------------------
658  template <typename Stream>
659  void ParticleDumper::DumpPDGID(Stream&& out, int ID)
660  {
661  switch (ID) {
662  case -11: out << "e+"; break;
663  case 11: out << "e-"; break;
664  case -13: out << "mu+"; break;
665  case 13: out << "mu-"; break;
666  default: out << "MCID=" << ID; break;
667  } // switch
668  } // DumpPDGID()
669 
670  //----------------------------------------------------------------------------
671  template <typename Stream>
672  void ParticleDumper::DumpPFParticleInfo(Stream&& out,
673  recob::PFParticle const& part,
674  unsigned int iPart,
675  std::string indentstr) const
676  {
677  auto const PartID = part.Self();
678  out << indentstr << "ID=" << PartID;
679  if (iPart != PartID) out << " [#" << iPart << "]";
680  out << " (type: ";
681  DumpPDGID(out, part.PdgCode());
682  out << ")";
683  if (part.IsPrimary())
684  out << " (primary)";
685  else
686  out << " from ID=" << part.Parent();
687  } // ParticleDumper::DumpPFParticleInfo()
688 
689  //----------------------------------------------------------------------------
690  template <typename Stream>
691  void ParticleDumper::DumpVertex(Stream&& out,
692  cet::maybe_ref<recob::Vertex const> VertexRef,
693  std::string indentstr) const
694  {
695  if (!VertexRef.isValid()) {
696  out << " [no vertex found!]";
697  return;
698  }
699  recob::Vertex const& vertex = VertexRef.ref();
700  std::array<double, 3> vtx_pos;
701  vertex.XYZ(vtx_pos.data());
702  lar::OptionalHexFloat hexfloat(options.hexFloats);
703  out << " [decay at (" << hexfloat(vtx_pos[0]) << "," << hexfloat(vtx_pos[1]) << ","
704  << hexfloat(vtx_pos[2]) << "), ID=" << vertex.ID() << "]";
705 
706  } // ParticleDumper::DumpVertex()
707 
708  //----------------------------------------------------------------------------
709  template <typename Stream>
710  void ParticleDumper::DumpPCAxisDirection(Stream&& out, recob::PCAxis const& axis) const
711  {
712  if (!axis.getSvdOK()) {
713  out << "axis is invalid";
714  return;
715  }
716  lar::OptionalHexFloat hexfloat(options.hexFloats);
717  out << "axis ID=" << axis.getID() << ", principal: (" << hexfloat(axis.getEigenVectors()[0][0])
718  << ", " << hexfloat(axis.getEigenVectors()[0][1]) << ", "
719  << hexfloat(axis.getEigenVectors()[0][2]) << ")";
720  } // ParticleDumper::DumpPCAxisDirection()
721 
722  template <typename Stream>
723  void ParticleDumper::DumpPCAxes(Stream&& out,
724  std::vector<recob::PCAxis const*> const& myAxes,
725  std::string indentstr) const
726  {
727  out << "\n" << indentstr;
728  if (myAxes.empty()) {
729  out << " [no axis found!]";
730  return;
731  }
732  if (myAxes.size() == 1) { DumpPCAxisDirection(std::forward<Stream>(out), *(myAxes.front())); }
733  else {
734  out << " " << myAxes.size() << " axes present:";
735  for (recob::PCAxis const* axis : myAxes) {
736  out << "\n" << indentstr << " ";
737  DumpPCAxisDirection(std::forward<Stream>(out), *axis);
738  } // for axes
739  } // else
740  } // ParticleDumper::DumpPCAxes()
741 
742  //----------------------------------------------------------------------------
743  template <typename Stream>
744  void ParticleDumper::DumpSeed(Stream&& out, recob::Seed const& seed, std::string indentstr) const
745  {
746  if (!seed.IsValid()) {
747  out << " <invalid>";
748  return;
749  }
750  std::array<double, 3> start, dir;
751  seed.GetDirection(dir.data(), nullptr);
752  seed.GetPoint(start.data(), nullptr);
753  lar::OptionalHexFloat hexfloat(options.hexFloats);
754  out << "\n"
755  << indentstr << " (" << hexfloat(start[0]) << "," << hexfloat(start[1]) << ","
756  << hexfloat(start[2]) << ")=>(" << hexfloat(dir[0]) << "," << hexfloat(dir[1]) << ","
757  << hexfloat(dir[2]) << "), " << hexfloat(seed.GetLength()) << " cm";
758  } // ParticleDumper::DumpSeed()
759 
760  template <typename Stream>
761  void ParticleDumper::DumpSeeds(Stream&& out,
762  std::vector<recob::Seed const*> const& mySeeds,
763  std::string indentstr) const
764  {
765  if (mySeeds.empty()) return;
766  out << "\n" << indentstr << " " << mySeeds.size() << " seeds:";
767  for (recob::Seed const* seed : mySeeds)
768  DumpSeed(std::forward<Stream>(out), *seed, indentstr);
769  } // ParticleDumper::DumpSeeds()
770 
771  //----------------------------------------------------------------------------
772  template <typename Stream>
773  void ParticleDumper::DumpSpacePoint(Stream&& out, recob::SpacePoint const& sp) const
774  {
775  const double* pos = sp.XYZ();
776  lar::OptionalHexFloat hexfloat(options.hexFloats);
777  out << " ID=" << sp.ID() << " at (" << hexfloat(pos[0]) << "," << hexfloat(pos[1]) << ","
778  << hexfloat(pos[2]) << ") cm";
779  } // ParticleDumper::DumpSpacePoints()
780 
781  template <typename Stream>
782  void ParticleDumper::DumpSpacePoints(Stream&& out,
783  std::vector<recob::SpacePoint const*> const& mySpacePoints,
784  std::string indentstr) const
785  {
786  out << "\n" << indentstr << " ";
787  if (mySpacePoints.empty()) {
788  out << "no space points";
789  return;
790  }
791  constexpr unsigned int PointsPerLine = 2;
792  out << mySpacePoints.size() << " space points:";
793  for (size_t iSP = 0; iSP < mySpacePoints.size(); ++iSP) {
794  if ((iSP % PointsPerLine) == 0) out << "\n" << indentstr << " ";
795 
796  DumpSpacePoint(std::forward<Stream>(out), *(mySpacePoints[iSP]));
797  } // for points
798  } // ParticleDumper::DumpSpacePoints()
799 
800  //----------------------------------------------------------------------------
801  template <typename Stream>
802  void ParticleDumper::DumpTrack(Stream&& out, recob::Track const& track) const
803  {
804  lar::OptionalHexFloat hexfloat(options.hexFloats);
805  out << " length " << hexfloat(track.Length()) << "cm from (" << hexfloat(track.Vertex().X())
806  << ";" << hexfloat(track.Vertex().Y()) << ";" << hexfloat(track.Vertex().Z()) << ") to ("
807  << hexfloat(track.End().X()) << ";" << hexfloat(track.End().Y()) << ";"
808  << hexfloat(track.End().Z()) << ") (ID=" << track.ID() << ")";
809  } // ParticleDumper::DumpTrack()
810 
811  template <typename Stream>
812  void ParticleDumper::DumpTracks(Stream&& out,
813  std::vector<recob::Track const*> const& myTracks,
814  std::string indentstr) const
815  {
816  if (myTracks.empty()) return;
817  out << "\n" << indentstr << " " << myTracks.size() << " tracks:";
818  for (recob::Track const* track : myTracks) {
819  if (myTracks.size() > 1) out << "\n" << indentstr << " ";
820  DumpTrack(std::forward<Stream>(out), *track);
821  } // for tracks
822  } // ParticleDumper::DumpTracks()
823 
824  //----------------------------------------------------------------------------
825  template <typename Stream>
826  void ParticleDumper::DumpClusterSummary(Stream&& out, recob::Cluster const& cluster) const
827  {
828  out << " " << cluster.NHits() << " hits on " << cluster.Plane() << " (ID=" << cluster.ID()
829  << ")";
830  } // ParticleDumper::DumpClusterSummary()
831 
832  template <typename Stream>
833  void ParticleDumper::DumpClusters(Stream&& out,
834  std::vector<recob::Cluster const*> const& myClusters,
835  std::string indentstr) const
836  {
837  if (myClusters.empty()) return;
838  out << "\n" << indentstr << " " << myClusters.size() << " clusters:";
839  for (recob::Cluster const* cluster : myClusters) {
840  if (myClusters.size() > 1) out << "\n" << indentstr << " ";
841  DumpClusterSummary(std::forward<Stream>(out), *cluster);
842  }
843  } // ParticleDumper::DumpClusters()
844 
845  //----------------------------------------------------------------------------
846  //--- PFParticleGraphMaker
847  //---
848  template <typename Stream>
849  void PFParticleGraphMaker::MakeGraph(Stream&& out,
850  std::vector<recob::PFParticle> const& particles) const
851  {
852 
853  WriteGraphHeader(std::forward<Stream>(out));
854  WriteParticleRelations(std::forward<Stream>(out), particles);
855  WriteGraphFooter(std::forward<Stream>(out));
856 
857  } // PFParticleGraphMaker::MakeGraph()
858 
859  //----------------------------------------------------------------------------
860  template <typename Stream>
861  void PFParticleGraphMaker::WriteGraphHeader(Stream&& out) const
862  {
863  out << "\ndigraph {"
864  << "\n";
865  } // PFParticleGraphMaker::WriteGraphHeader()
866 
867  template <typename Stream>
868  void PFParticleGraphMaker::WriteParticleNodes(
869  Stream&& out,
870  std::vector<recob::PFParticle> const& particles) const
871  {
872 
873  for (auto const& particle : particles) {
874 
875  std::ostringstream label;
876  label << "#" << particle.Self();
877  if (particle.PdgCode() != 0) {
878  label << ", ";
879  ParticleDumper::DumpPDGID(label, particle.PdgCode());
880  }
881 
882  out << "\n P" << particle.Self() << " ["
883  << " label = \"" << label.str() << "\"";
884  if (particle.IsPrimary()) out << ", style = bold";
885  out << " ]";
886  } // for
887 
888  } // PFParticleGraphMaker::WriteParticleNodes()
889 
890  template <typename Stream>
891  void PFParticleGraphMaker::WriteParticleEdges(
892  Stream&& out,
893  std::vector<recob::PFParticle> const& particles) const
894  {
895  auto particle_map = CreateMap(particles);
896 
897  out << "\n "
898  << "\n // relations"
899  << "\n // "
900  << "\n // the arrow is close to the information provider,;"
901  << "\n // and it points from parent to daughter"
902  << "\n // "
903  << "\n // "
904  << "\n ";
905 
906  for (auto const& particle : particles) {
907  auto const partID = particle.Self();
908 
909  // draw parent line
910  if (!particle.IsPrimary()) {
911  auto const parentID = particle.Parent();
912  size_t const iParent = particle_map[parentID];
913  if (!particle_map.is_valid_value(iParent)) {
914  // parent is ghost
915  out << "\nP" << parentID << " [ style = dashed, color = red"
916  << ", label = \"(#" << parentID << ")\" ] // ghost particle"
917  << "\nP" << parentID << " -> P" << partID
918  << " [ dir = both, arrowhead = empty, arrowtail = none ]";
919  }
920  else {
921  // parent is a known particle
922  recob::PFParticle const& parent = particles[iParent];
923 
924  // is the relation bidirectional?
925  if (hasDaughter(parent, partID)) {
926  out << "\nP" << parentID << " -> P" << partID << " [ dir = both, arrowtail = inv ]";
927  } // if bidirectional
928  else {
929  out << "\nP" << parentID << " -> P" << partID << " [ dir = forward, color = red ]"
930  << " // claimed parent";
931  } // if parent disowns
932 
933  } // if ghost ... else
934  } // if not primary
935 
936  // print daughter relationship only if daughters do not recognise us
937  for (auto daughterID : particle.Daughters()) {
938  size_t const iDaughter = particle_map[daughterID];
939  if (!particle_map.is_valid_value(iDaughter)) {
940  // daughter is ghost
941  out << "\nP" << daughterID << " [ style = dashed, color = red"
942  << ", label = \"(#" << daughterID << ")\" ] // ghost daughter"
943  << "\nP" << partID << " -> P" << daughterID
944  << " [ dir = both, arrowhead = none, arrowtail = invempty ]";
945  }
946  else {
947  // daughter is a known particle
948  recob::PFParticle const& daughter = particles[iDaughter];
949 
950  // is the relation bidirectional? (if so, the daughter will draw)
951  if (daughter.Parent() != partID) {
952  out << "\nP" << partID << " -> P" << daughterID
953  << " [ dir = both, arrowhead = none, arrowtail = inv, color = orange ]"
954  << " // claimed daughter";
955  } // if parent disowns
956 
957  } // if ghost ... else
958 
959  } // for all daughters
960 
961  } // for all particles
962 
963  } // PFParticleGraphMaker::WriteParticleNodes()
964 
965  template <typename Stream>
966  void PFParticleGraphMaker::WriteParticleRelations(
967  Stream&& out,
968  std::vector<recob::PFParticle> const& particles) const
969  {
970  out << "\n // " << particles.size() << " particles (nodes)";
971  WriteParticleNodes(std::forward<Stream>(out), particles);
972 
973  out << "\n"
974  << "\n // parent/children relations";
975  WriteParticleEdges(std::forward<Stream>(out), particles);
976 
977  } // PFParticleGraphMaker::WriteParticleRelations()
978 
979  template <typename Stream>
980  void PFParticleGraphMaker::WriteGraphFooter(Stream&& out) const
981  {
982  out << "\n"
983  << "\n} // digraph" << std::endl;
984  } // PFParticleGraphMaker::WriteGraphFooter()
985 
986  //----------------------------------------------------------------------------
987 
988 } // local namespace
989 
990 namespace recob {
991 
992  //----------------------------------------------------------------------------
994  : EDAnalyzer(config)
995  , fInputTag(config().PFModuleLabel())
996  , fOutputCategory(config().OutputCategory())
997  , fPrintHexFloats(config().PrintHexFloats())
998  , fMaxDepth(std::numeric_limits<unsigned int>::max())
1000  {
1001  // here we are handling the optional configuration key as it had just a
1002  // default value
1003  if (!config().MaxDepth(fMaxDepth)) fMaxDepth = std::numeric_limits<unsigned int>::max();
1004  }
1005 
1006  //----------------------------------------------------------------------------
1007  std::string DumpPFParticles::DotFileName(art::EventID const& evtID,
1008  art::Provenance const& prodInfo)
1009  {
1010  return prodInfo.processName() + '_' + prodInfo.moduleLabel() + '_' +
1011  prodInfo.productInstanceName() + "_Run" + std::to_string(evtID.run()) + "_Subrun" +
1012  std::to_string(evtID.subRun()) + "_Event" + std::to_string(evtID.event()) +
1013  "_particles.dot";
1014  } // DumpPFParticles::DotFileName()
1015 
1016  //----------------------------------------------------------------------------
1018  art::Event const& event,
1019  art::ValidHandle<std::vector<recob::PFParticle>> const& handle) const
1020  {
1021  art::EventID const eventID = event.id();
1022  std::string fileName = DotFileName(eventID, *(handle.provenance()));
1023  std::ofstream outFile(fileName); // overwrite by default
1024 
1025  outFile << "// " << fileName << "\n// "
1026  << "\n// Created for run " << eventID.run() << " subrun " << eventID.subRun()
1027  << " event " << eventID.event() << "\n// "
1028  << "\n// dump of " << handle->size() << " particles"
1029  << "\n// " << std::endl;
1030 
1031  PFParticleGraphMaker graphMaker;
1032  graphMaker.MakeGraph(outFile, *handle);
1033 
1034  } // DumpPFParticles::MakePFParticleGraph()
1035 
1036  //----------------------------------------------------------------------------
1038  {
1039 
1040  //
1041  // collect all the available information
1042  //
1043  // fetch the data to be dumped on screen
1045  evt.getValidHandle<std::vector<recob::PFParticle>>(fInputTag);
1046 
1047  if (fMakeEventGraphs) MakePFParticleGraph(evt, PFParticles);
1048 
1049  art::FindOne<recob::Vertex> const ParticleVertices(PFParticles, evt, fInputTag);
1050  art::FindMany<recob::Track> const ParticleTracks(PFParticles, evt, fInputTag);
1051  art::FindMany<recob::Cluster> const ParticleClusters(PFParticles, evt, fInputTag);
1052  art::FindMany<recob::Seed> const ParticleSeeds(PFParticles, evt, fInputTag);
1053  art::FindMany<recob::SpacePoint> const ParticleSpacePoints(PFParticles, evt, fInputTag);
1054  art::FindMany<recob::PCAxis> const ParticlePCAxes(PFParticles, evt, fInputTag);
1055 
1056  size_t const nParticles = PFParticles->size();
1057  mf::LogVerbatim(fOutputCategory) << "Event " << evt.id() << " contains " << nParticles
1058  << " particles from '" << fInputTag.encode() << "'";
1059 
1060  // prepare the dumper
1061  ParticleDumper::PrintOptions_t options;
1062  options.hexFloats = fPrintHexFloats;
1063  options.maxDepth = fMaxDepth;
1064  options.streamName = fOutputCategory;
1065  ParticleDumper dumper(*PFParticles, options);
1066  if (ParticleVertices.isValid())
1067  dumper.SetVertices(&ParticleVertices);
1068  else
1069  mf::LogPrint("DumpPFParticles") << "WARNING: vertex information not available";
1070  if (ParticleTracks.isValid())
1071  dumper.SetTracks(&ParticleTracks);
1072  else
1073  mf::LogPrint("DumpPFParticles") << "WARNING: track information not available";
1074  if (ParticleClusters.isValid())
1075  dumper.SetClusters(&ParticleClusters);
1076  else
1077  mf::LogPrint("DumpPFParticles") << "WARNING: cluster information not available";
1078  if (ParticleSeeds.isValid())
1079  dumper.SetSeeds(&ParticleSeeds);
1080  else
1081  mf::LogPrint("DumpPFParticles") << "WARNING: seed information not avaialble";
1082  if (ParticleSpacePoints.isValid())
1083  dumper.SetSpacePoints(&ParticleSpacePoints);
1084  else {
1085  mf::LogPrint("DumpPFParticles") << "WARNING: space point information not available";
1086  }
1087  if (ParticlePCAxes.isValid())
1088  dumper.SetPCAxes(&ParticlePCAxes);
1089  else {
1090  mf::LogPrint("DumpPFParticles") << "WARNING: principal component axis not available";
1091  }
1092  dumper.DumpAllParticles(" ");
1093 
1094  mf::LogVerbatim(fOutputCategory) << "\n"; // two empty lines
1095 
1096  } // DumpPFParticles::analyze()
1097 
1099 
1100 } // namespace recob
void XYZ(double *xyz) const
Legacy method to access vertex position, preserved to avoid breaking code. Please try to use Vertex::...
Definition: Vertex.cxx:34
intermediate_table::iterator iterator
DumpPFParticles(Parameters const &config)
Default constructor.
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
const std::vector< size_t > & Daughters() const
Returns the collection of daughter particles.
Definition: PFParticle.h:110
const EigenVectors & getEigenVectors() const
Definition: PCAxis.h:74
int NumDaughters() const
Returns the number of daughter particles flowing from this one.
Definition: PFParticle.h:85
decltype(auto) constexpr cend(T &&obj)
ADL-aware version of std::cend.
Definition: StdUtils.h:93
Reconstruction base classes.
size_t Self() const
Returns the index of this particle.
Definition: PFParticle.h:88
bool IsValid() const
Definition: Seed.cxx:58
std::string const & productInstanceName() const noexcept
Definition: Provenance.cc:60
void GetPoint(double *Pt, double *Err) const
Definition: Seed.cxx:89
Prints the content of all the space points on screen.
STL namespace.
Prints the content of all the clusters on screen.
int PdgCode() const
Return the type of particle as a PDG ID.
Definition: PFParticle.h:79
Set of hits with a 2D structure.
Definition: Cluster.h:69
intermediate_table::const_iterator const_iterator
geo::PlaneID Plane() const
Returns the plane ID this cluster lies on.
Definition: Cluster.h:717
Cluster finding and building.
Prints the content of all the seeds on screen.
EDAnalyzer(fhicl::ParameterSet const &pset)
Definition: EDAnalyzer.cc:6
fhicl::OptionalAtom< unsigned int > MaxDepth
std::string encode() const
Definition: InputTag.cc:97
Definition of vertex object for LArSoft.
Definition: Vertex.h:35
RunNumber_t run() const
Definition: EventID.h:98
std::string const & moduleLabel() const noexcept
Definition: Provenance.cc:54
size_t getID() const
Definition: PCAxis.h:86
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:101
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:289
TString part[npart]
Definition: Style.C:32
double Length(size_t p=0) const
Access to various track properties.
Definition: Track.h:207
std::string fOutputCategory
category for LogInfo output
constexpr bool is_valid(IDNumber_t< L > const id) noexcept
Definition: IDNumber.h:113
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:65
unsigned int fMaxDepth
maximum generation to print (0: only primaries)
long seed
Definition: chem4.cc:67
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
size_t Parent() const
Definition: PFParticle.h:92
Point_t const & Vertex() const
Access to track position at different points.
Definition: Track.h:158
Provides recob::Track data product.
bool IsPrimary() const
Returns whether the particle is the root of the flow.
Definition: PFParticle.h:82
const Double32_t * XYZ() const
Definition: SpacePoint.h:78
Prints the content of all the PCA axis object on screen.
virtual void analyze(const art::Event &evt) override
Does the printing.
std::string const & processName() const noexcept
Definition: Provenance.cc:66
Declaration of cluster object.
Helper for formatting floats in base 16.
Definition: hexfloat.h:109
std::vector< TrajPoint > seeds
Definition: DataStructs.cxx:14
int ID() const
Definition: Track.h:244
Prints the content of all the tracks on screen.
ID_t ID() const
Definition: SpacePoint.h:74
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Hierarchical representation of particle flow.
Definition: PFParticle.h:44
TDirectory * dir
Definition: macro.C:5
Helper to support output of real numbers in base 16.
ID_t ID() const
Identifier of this cluster.
Definition: Cluster.h:711
bool fMakeEventGraphs
whether to create one DOT file per event
Prints the content of all the ParticleFlow particles on screen.
int ID() const
Return vertex id.
Definition: Vertex.h:101
fhicl::Atom< std::string > OutputCategory
decltype(auto) constexpr cbegin(T &&obj)
ADL-aware version of std::cbegin.
Definition: StdUtils.h:85
static std::string DotFileName(art::EventID const &evtID, art::Provenance const &prodInfo)
EventNumber_t event() const
Definition: EventID.h:116
Point_t const & End() const
Access to track position at different points.
Definition: Track.h:159
void MakePFParticleGraph(art::Event const &event, art::ValidHandle< std::vector< recob::PFParticle >> const &handle) const
art::InputTag fInputTag
input tag of the PFParticle product
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:69
unsigned int NHits() const
Number of hits in the cluster.
Definition: Cluster.h:265
TCEvent evt
Definition: DataStructs.cxx:8
fhicl::Atom< art::InputTag > PFModuleLabel
Float_t track
Definition: plot.C:35
void GetDirection(double *Dir, double *Err) const
Definition: Seed.cxx:80
bool fPrintHexFloats
whether to print floats in base 16
SubRunNumber_t subRun() const
Definition: EventID.h:110
EventID id() const
Definition: Event.cc:23
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
auto DumpSpacePoint(Stream &&out, recob::SpacePoint const &sp, SpacePointPrintOptions_t const &options={}) -> std::enable_if_t< std::is_same< NewLine< std::decay_t< Stream >>, std::decay_t< NewLineRef >>::value >
Dumps the content of the specified space point into a stream.
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:109
MaybeLogger_< ELseverityLevel::ELsev_warning, true > LogPrint
Event finding and building.
double GetLength() const
Definition: Seed.cxx:132
bool getSvdOK() const
Definition: PCAxis.h:62
vertex reconstruction