138 Name(
"PFModuleLabel"),
139 Comment(
"label of producer of the recob::PFParticle to be dumped")};
142 Name(
"OutputCategory"),
143 Comment(
"message facility category used for output (for filtering)"),
147 Comment(
"print all the floating point numbers in base 16"),
152 Comment(
"at most this number of particle generations will be printed")};
155 Name(
"MakeParticleGraphs"),
156 Comment(
"creates a DOT file with particle information for each event"),
217 template <
typename T>
219 using map_type = std::vector<T>;
222 using this_type = int_map<T>;
225 using typename map_type::const_reference;
227 using typename map_type::reference;
228 using typename map_type::value_type;
230 using typename map_type::size_type;
236 int_map(value_type invalid_value) : invalid(invalid_value) {}
239 void resize(
size_t new_size) { get_map().resize(new_size, invalid_value()); }
242 reference operator[](
size_t pos)
244 if (pos >=
size()) resize(pos + 1);
245 return get_map()[pos];
249 const_reference operator[](
size_t pos)
const 251 return (pos >=
size()) ? invalid : get_map()[pos];
260 using map_type::crbegin;
261 using map_type::crend;
263 using map_type::rbegin;
264 using map_type::rend;
267 void swap(this_type& data)
269 swap(data.get_map());
270 std::swap(data.invalid, invalid);
274 void swap(std::vector<T>& data) { map_type::swap(data); }
278 size_type n_invalid()
const {
return std::count(
begin(),
end(), invalid); }
281 size_type n_valid()
const {
return size() - n_invalid(); }
286 return (pos <
size()) ? is_valid_value(get_map()[pos]) : false;
290 bool is_valid_value(value_type
const& v)
const {
return v != invalid; }
293 value_type
const& invalid_value()
const {
return invalid; }
296 value_type
const invalid;
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); }
304 int_map<size_t> CreateMap(std::vector<recob::PFParticle>
const& particles)
307 int_map<size_t> pmap(std::numeric_limits<size_t>::max());
308 pmap.resize(particles.size());
310 size_t const nParticles = particles.size();
311 for (
size_t iPart = 0; iPart < nParticles; ++iPart)
312 pmap[particles[iPart].Self()] = iPart;
320 auto const& daughters = particle.
Daughters();
321 return daughters.end() != std::find(daughters.begin(), daughters.end(), partID);
325 class ParticleDumper {
328 struct PrintOptions_t {
329 bool hexFloats =
false;
330 unsigned int maxDepth = std::numeric_limits<unsigned int>::max();
333 std::string streamName;
337 ParticleDumper(std::vector<recob::PFParticle>
const& particle_list)
338 : ParticleDumper(particle_list, {})
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))
365 spacepoints = sp_query;
373 template <
typename Stream>
374 void DumpParticle(Stream&& out,
376 std::string indentstr =
"",
377 unsigned int gen = 0)
const;
381 template <
typename Stream>
382 void DumpParticleWithID(Stream&& out,
384 std::string indentstr =
"",
385 unsigned int gen = 0)
const;
388 void DumpAllPrimaries(std::string indentstr =
"")
const;
391 void DumpAllParticles(std::string indentstr =
"")
const;
393 template <
typename Stream>
394 static void DumpPDGID(Stream&& out,
int ID);
397 std::vector<recob::PFParticle>
const& particles;
399 PrintOptions_t options;
420 mutable std::vector<unsigned int> visited;
422 int_map<size_t>
const particle_map;
424 template <
typename Stream>
425 void DumpPFParticleInfo(Stream&& out,
428 std::string indentstr)
const;
430 template <
typename Stream>
431 void DumpVertex(Stream&& out,
432 cet::maybe_ref<recob::Vertex const> VertexRef,
433 std::string indentstr)
const;
435 template <
typename Stream>
436 void DumpPCAxisDirection(Stream&& out,
recob::PCAxis const& axis)
const;
438 template <
typename Stream>
440 std::vector<recob::PCAxis const*>
const& myAxes,
441 std::string indentstr)
const;
443 template <
typename Stream>
446 template <
typename Stream>
448 std::vector<recob::Track const*>
const& myTracks,
449 std::string indentstr)
const;
451 template <
typename Stream>
452 void DumpSeed(Stream&& out,
recob::Seed const&
seed, std::string indentstr)
const;
454 template <
typename Stream>
456 std::vector<recob::Seed const*>
const& mySeeds,
457 std::string indentstr)
const;
459 template <
typename Stream>
462 template <
typename Stream>
464 std::vector<recob::SpacePoint const*>
const& mySpacePoints,
465 std::string indentstr)
const;
467 template <
typename Stream>
470 template <
typename Stream>
472 std::vector<recob::Cluster const*>
const& myClusters,
473 std::string indentstr)
const;
478 class PFParticleGraphMaker {
480 PFParticleGraphMaker() =
default;
482 template <
typename Stream>
483 void MakeGraph(Stream&& out, std::vector<recob::PFParticle>
const& particles)
const;
485 template <
typename Stream>
486 void WriteGraphHeader(Stream&& out)
const;
488 template <
typename Stream>
489 void WriteParticleRelations(Stream&& out,
490 std::vector<recob::PFParticle>
const& particles)
const;
492 template <
typename Stream>
493 void WriteParticleNodes(Stream&& out, std::vector<recob::PFParticle>
const& particles)
const;
495 template <
typename Stream>
496 void WriteParticleEdges(Stream&& out, std::vector<recob::PFParticle>
const& particles)
const;
498 template <
typename Stream>
499 void WriteGraphFooter(Stream&& out)
const;
506 template <
typename Stream>
507 void ParticleDumper::DumpParticle(Stream&& out,
509 std::string indentstr ,
518 if (visited[iPart] > 1) {
519 out << indentstr <<
"particle " << part.
Self() <<
" already printed!!!";
526 DumpPFParticleInfo(std::forward<Stream>(out), part, iPart, indentstr);
531 if (vertices) DumpVertex(std::forward<Stream>(out), vertices->at(iPart), indentstr);
537 out <<
" with no daughter";
542 if (pcaxes)
DumpPCAxes(std::forward<Stream>(out), pcaxes->at(iPart), indentstr);
547 if (tracks)
DumpTracks(std::forward<Stream>(out), tracks->at(iPart), indentstr);
558 DumpSpacePoints(std::forward<Stream>(out), spacepoints->at(iPart), indentstr);
564 if (clusters) {
DumpClusters(std::forward<Stream>(out), clusters->at(iPart), indentstr); }
569 auto const PartID = part.
Self();
571 std::vector<size_t>
const& daughters = part.
Daughters();
572 out <<
"\n" << indentstr <<
" " << part.
NumDaughters() <<
" particle daughters";
575 for (
size_t DaughterID : daughters) {
576 if (DaughterID == PartID) {
577 out <<
"\n" << indentstr <<
" oh, just great: this particle is its own daughter!";
581 DumpParticleWithID(out, DaughterID, indentstr +
" ", gen - 1);
586 out <<
" (further descend suppressed)";
593 if (visited[iPart] == 2) {
595 << indentstr <<
" WARNING: particle ID=" << PartID <<
" connected more than once!";
605 template <
typename Stream>
606 void ParticleDumper::DumpParticleWithID(Stream&& out,
608 std::string indentstr ,
612 size_t const pos = particle_map[pID];
613 if (particle_map.is_valid_value(pos)) { DumpParticle(out, pos, indentstr, gen); }
615 out << indentstr <<
"<ID=" << pID <<
" not found>";
620 void ParticleDumper::DumpAllPrimaries(std::string indentstr )
const 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);
629 if (nPrimaries == 0) {
630 mf::LogVerbatim(options.streamName) << indentstr <<
"No primary particle found";
635 void ParticleDumper::DumpAllParticles(std::string indentstr )
const 638 DumpAllPrimaries(indentstr);
640 unsigned int const nDisconnected = std::count(visited.begin(), visited.end(), 0U);
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;
648 mf::LogVerbatim(options.streamName), iPart, indentstr +
" ", options.maxDepth);
651 << indentstr <<
"(end of " << nDisconnected <<
" particles not from primaries)";
658 template <
typename Stream>
659 void ParticleDumper::DumpPDGID(Stream&& out,
int 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;
671 template <
typename Stream>
672 void ParticleDumper::DumpPFParticleInfo(Stream&& out,
675 std::string indentstr)
const 677 auto const PartID = part.
Self();
678 out << indentstr <<
"ID=" << PartID;
679 if (iPart != PartID) out <<
" [#" << iPart <<
"]";
681 DumpPDGID(out, part.
PdgCode());
686 out <<
" from ID=" << part.
Parent();
690 template <
typename Stream>
691 void ParticleDumper::DumpVertex(Stream&& out,
692 cet::maybe_ref<recob::Vertex const> VertexRef,
693 std::string indentstr)
const 695 if (!VertexRef.isValid()) {
696 out <<
" [no vertex found!]";
700 std::array<double, 3> vtx_pos;
701 vertex.
XYZ(vtx_pos.data());
703 out <<
" [decay at (" << hexfloat(vtx_pos[0]) <<
"," << hexfloat(vtx_pos[1]) <<
"," 704 << hexfloat(vtx_pos[2]) <<
"), ID=" << vertex.
ID() <<
"]";
709 template <
typename Stream>
710 void ParticleDumper::DumpPCAxisDirection(Stream&& out,
recob::PCAxis const& axis)
const 713 out <<
"axis is invalid";
722 template <
typename Stream>
723 void ParticleDumper::DumpPCAxes(Stream&& out,
724 std::vector<recob::PCAxis const*>
const& myAxes,
725 std::string indentstr)
const 727 out <<
"\n" << indentstr;
728 if (myAxes.empty()) {
729 out <<
" [no axis found!]";
732 if (myAxes.size() == 1) { DumpPCAxisDirection(std::forward<Stream>(out), *(myAxes.front())); }
734 out <<
" " << myAxes.size() <<
" axes present:";
736 out <<
"\n" << indentstr <<
" ";
737 DumpPCAxisDirection(std::forward<Stream>(out), *axis);
743 template <
typename Stream>
744 void ParticleDumper::DumpSeed(Stream&& out,
recob::Seed const&
seed, std::string indentstr)
const 750 std::array<double, 3> start,
dir;
752 seed.
GetPoint(start.data(),
nullptr);
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";
760 template <
typename Stream>
761 void ParticleDumper::DumpSeeds(Stream&& out,
762 std::vector<recob::Seed const*>
const& mySeeds,
763 std::string indentstr)
const 765 if (mySeeds.empty())
return;
766 out <<
"\n" << indentstr <<
" " << mySeeds.size() <<
" seeds:";
768 DumpSeed(std::forward<Stream>(out), *seed, indentstr);
772 template <
typename Stream>
775 const double* pos = sp.
XYZ();
777 out <<
" ID=" << sp.
ID() <<
" at (" << hexfloat(pos[0]) <<
"," << hexfloat(pos[1]) <<
"," 778 << hexfloat(pos[2]) <<
") cm";
781 template <
typename Stream>
782 void ParticleDumper::DumpSpacePoints(Stream&& out,
783 std::vector<recob::SpacePoint const*>
const& mySpacePoints,
784 std::string indentstr)
const 786 out <<
"\n" << indentstr <<
" ";
787 if (mySpacePoints.empty()) {
788 out <<
"no space points";
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 <<
" ";
801 template <
typename Stream>
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() <<
")";
811 template <
typename Stream>
812 void ParticleDumper::DumpTracks(Stream&& out,
813 std::vector<recob::Track const*>
const& myTracks,
814 std::string indentstr)
const 816 if (myTracks.empty())
return;
817 out <<
"\n" << indentstr <<
" " << myTracks.size() <<
" tracks:";
819 if (myTracks.size() > 1) out <<
"\n" << indentstr <<
" ";
820 DumpTrack(std::forward<Stream>(out), *track);
825 template <
typename Stream>
828 out <<
" " << cluster.
NHits() <<
" hits on " << cluster.
Plane() <<
" (ID=" << cluster.
ID()
832 template <
typename Stream>
833 void ParticleDumper::DumpClusters(Stream&& out,
834 std::vector<recob::Cluster const*>
const& myClusters,
835 std::string indentstr)
const 837 if (myClusters.empty())
return;
838 out <<
"\n" << indentstr <<
" " << myClusters.size() <<
" clusters:";
840 if (myClusters.size() > 1) out <<
"\n" << indentstr <<
" ";
841 DumpClusterSummary(std::forward<Stream>(out), *cluster);
848 template <
typename Stream>
849 void PFParticleGraphMaker::MakeGraph(Stream&& out,
850 std::vector<recob::PFParticle>
const& particles)
const 853 WriteGraphHeader(std::forward<Stream>(out));
854 WriteParticleRelations(std::forward<Stream>(out), particles);
855 WriteGraphFooter(std::forward<Stream>(out));
860 template <
typename Stream>
861 void PFParticleGraphMaker::WriteGraphHeader(Stream&& out)
const 867 template <
typename Stream>
868 void PFParticleGraphMaker::WriteParticleNodes(
870 std::vector<recob::PFParticle>
const& particles)
const 873 for (
auto const& particle : particles) {
875 std::ostringstream label;
876 label <<
"#" << particle.
Self();
879 ParticleDumper::DumpPDGID(label, particle.
PdgCode());
882 out <<
"\n P" << particle.
Self() <<
" [" 883 <<
" label = \"" << label.str() <<
"\"";
884 if (particle.
IsPrimary()) out <<
", style = bold";
890 template <
typename Stream>
891 void PFParticleGraphMaker::WriteParticleEdges(
893 std::vector<recob::PFParticle>
const& particles)
const 895 auto particle_map = CreateMap(particles);
900 <<
"\n // the arrow is close to the information provider,;" 901 <<
"\n // and it points from parent to daughter" 906 for (
auto const& particle : particles) {
907 auto const partID = particle.
Self();
911 auto const parentID = particle.
Parent();
912 size_t const iParent = particle_map[parentID];
913 if (!particle_map.is_valid_value(iParent)) {
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 ]";
925 if (hasDaughter(parent, partID)) {
926 out <<
"\nP" << parentID <<
" -> P" << partID <<
" [ dir = both, arrowtail = inv ]";
929 out <<
"\nP" << parentID <<
" -> P" << partID <<
" [ dir = forward, color = red ]" 930 <<
" // claimed parent";
937 for (
auto daughterID : particle.
Daughters()) {
938 size_t const iDaughter = particle_map[daughterID];
939 if (!particle_map.is_valid_value(iDaughter)) {
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 ]";
951 if (daughter.
Parent() != partID) {
952 out <<
"\nP" << partID <<
" -> P" << daughterID
953 <<
" [ dir = both, arrowhead = none, arrowtail = inv, color = orange ]" 954 <<
" // claimed daughter";
965 template <
typename Stream>
966 void PFParticleGraphMaker::WriteParticleRelations(
968 std::vector<recob::PFParticle>
const& particles)
const 970 out <<
"\n // " << particles.size() <<
" particles (nodes)";
971 WriteParticleNodes(std::forward<Stream>(out), particles);
974 <<
"\n // parent/children relations";
975 WriteParticleEdges(std::forward<Stream>(out), particles);
979 template <
typename Stream>
980 void PFParticleGraphMaker::WriteGraphFooter(Stream&& out)
const 983 <<
"\n} // digraph" << std::endl;
1003 if (!config().MaxDepth(
fMaxDepth))
fMaxDepth = std::numeric_limits<unsigned int>::max();
1022 std::string fileName =
DotFileName(eventID, *(handle.provenance()));
1023 std::ofstream outFile(fileName);
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;
1031 PFParticleGraphMaker graphMaker;
1032 graphMaker.MakeGraph(outFile, *handle);
1056 size_t const nParticles = PFParticles->size();
1061 ParticleDumper::PrintOptions_t options;
1065 ParticleDumper dumper(*PFParticles, options);
1066 if (ParticleVertices.isValid())
1067 dumper.SetVertices(&ParticleVertices);
1069 mf::LogPrint(
"DumpPFParticles") <<
"WARNING: vertex information not available";
1070 if (ParticleTracks.isValid())
1071 dumper.SetTracks(&ParticleTracks);
1073 mf::LogPrint(
"DumpPFParticles") <<
"WARNING: track information not available";
1074 if (ParticleClusters.isValid())
1075 dumper.SetClusters(&ParticleClusters);
1077 mf::LogPrint(
"DumpPFParticles") <<
"WARNING: cluster information not available";
1078 if (ParticleSeeds.isValid())
1079 dumper.SetSeeds(&ParticleSeeds);
1081 mf::LogPrint(
"DumpPFParticles") <<
"WARNING: seed information not avaialble";
1082 if (ParticleSpacePoints.isValid())
1083 dumper.SetSpacePoints(&ParticleSpacePoints);
1085 mf::LogPrint(
"DumpPFParticles") <<
"WARNING: space point information not available";
1087 if (ParticlePCAxes.isValid())
1088 dumper.SetPCAxes(&ParticlePCAxes);
1090 mf::LogPrint(
"DumpPFParticles") <<
"WARNING: principal component axis not available";
1092 dumper.DumpAllParticles(
" ");
void XYZ(double *xyz) const
Legacy method to access vertex position, preserved to avoid breaking code. Please try to use Vertex::...
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.
const EigenVectors & getEigenVectors() const
fhicl::Atom< bool > PrintHexFloats
int NumDaughters() const
Returns the number of daughter particles flowing from this one.
decltype(auto) constexpr cend(T &&obj)
ADL-aware version of std::cend.
Reconstruction base classes.
size_t Self() const
Returns the index of this particle.
std::string const & productInstanceName() const noexcept
void GetPoint(double *Pt, double *Err) const
Prints the content of all the space points on screen.
Prints the content of all the clusters on screen.
fhicl::Atom< bool > MakeParticleGraphs
int PdgCode() const
Return the type of particle as a PDG ID.
Set of hits with a 2D structure.
geo::PlaneID Plane() const
Returns the plane ID this cluster lies on.
Cluster finding and building.
Prints the content of all the seeds on screen.
EDAnalyzer(fhicl::ParameterSet const &pset)
fhicl::OptionalAtom< unsigned int > MaxDepth
Definition of vertex object for LArSoft.
std::string const & moduleLabel() const noexcept
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
double Length(size_t p=0) const
Access to various track properties.
std::string fOutputCategory
category for LogInfo output
constexpr bool is_valid(IDNumber_t< L > const id) noexcept
#define DEFINE_ART_MODULE(klass)
unsigned int fMaxDepth
maximum generation to print (0: only primaries)
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
Point_t const & Vertex() const
Access to track position at different points.
Provides recob::Track data product.
bool IsPrimary() const
Returns whether the particle is the root of the flow.
const Double32_t * XYZ() const
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
Declaration of cluster object.
Helper for formatting floats in base 16.
std::vector< TrajPoint > seeds
Prints the content of all the tracks on screen.
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Hierarchical representation of particle flow.
Helper to support output of real numbers in base 16.
ID_t ID() const
Identifier of this cluster.
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.
fhicl::Atom< std::string > OutputCategory
decltype(auto) constexpr cbegin(T &&obj)
ADL-aware version of std::cbegin.
static std::string DotFileName(art::EventID const &evtID, art::Provenance const &prodInfo)
EventNumber_t event() const
Point_t const & End() const
Access to track position at different points.
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.
unsigned int NHits() const
Number of hits in the cluster.
fhicl::Atom< art::InputTag > PFModuleLabel
void GetDirection(double *Dir, double *Err) const
bool fPrintHexFloats
whether to print floats in base 16
SubRunNumber_t subRun() const
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a "fitted" track:
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.
MaybeLogger_< ELseverityLevel::ELsev_warning, true > LogPrint
Event finding and building.