140 Name(
"PFModuleLabel"),
141 Comment(
"label of producer of the recob::PFParticle to be dumped")
145 Name(
"OutputCategory"),
146 Comment(
"message facility category used for output (for filtering)"),
151 Name(
"PrintHexFloats"),
152 Comment(
"print all the floating point numbers in base 16"),
158 Comment(
"at most this number of particle generations will be printed")
162 Name(
"MakeParticleGraphs"),
163 Comment(
"creates a DOT file with particle information for each event"),
233 template <
typename T>
235 using map_type = std::vector<T>;
237 using this_type = int_map<T>;
239 using typename map_type::value_type;
240 using typename map_type::reference;
241 using typename map_type::const_reference;
245 using typename map_type::size_type;
252 int_map(value_type invalid_value): invalid(invalid_value) {}
256 void resize(
size_t new_size)
257 { get_map().resize(new_size, invalid_value()); }
260 reference operator[] (
size_t pos)
261 {
if (pos >= size()) resize(pos + 1);
return get_map()[pos]; }
264 const_reference operator[] (
size_t pos)
const 265 {
return (pos >= size())? invalid: get_map()[pos]; }
267 using map_type::size;
268 using map_type::empty;
272 using map_type::cbegin;
273 using map_type::cend;
274 using map_type::rbegin;
275 using map_type::rend;
276 using map_type::crbegin;
277 using map_type::crend;
280 void swap(this_type& data)
281 { swap(data.get_map()); std::swap(data.invalid, invalid); }
284 void swap(std::vector<T>& data) { map_type::swap(data); }
288 size_type n_invalid()
const 289 {
return std::count(
begin(),
end(), invalid); }
292 size_type n_valid()
const {
return size() - n_invalid(); }
296 {
return (pos < size())? is_valid_value(get_map()[pos]): false; }
299 bool is_valid_value(value_type
const& v)
const {
return v != invalid; }
302 value_type
const& invalid_value()
const {
return invalid; }
306 value_type
const invalid;
308 map_type& get_map() {
return static_cast<map_type&
>(*this); }
309 map_type
const& get_map()
const 310 {
return static_cast<map_type const&
>(*this); }
316 int_map<size_t> CreateMap(std::vector<recob::PFParticle>
const& particles) {
319 pmap.resize(particles.size());
321 size_t const nParticles = particles.size();
322 for (
size_t iPart = 0; iPart < nParticles; ++iPart)
323 pmap[particles[iPart].Self()] = iPart;
331 auto const& daughters = particle.
Daughters();
332 return daughters.end()
333 != std::find(daughters.begin(), daughters.end(), partID);
338 class ParticleDumper {
342 struct PrintOptions_t {
343 bool hexFloats =
false;
347 std::string streamName;
352 ParticleDumper(std::vector<recob::PFParticle>
const& particle_list)
353 : ParticleDumper(particle_list, {})
358 std::vector<recob::PFParticle>
const& particle_list,
359 PrintOptions_t print_options
361 : particles(particle_list)
362 , options(print_options)
363 , visited(particles.size(), 0U)
364 , particle_map (CreateMap(particles))
370 { vertices = vtx_query; }
374 { tracks = trk_query; }
378 { clusters = cls_query; }
382 {
seeds = seed_query; }
386 { spacepoints = sp_query; }
390 { pcaxes = pca_query; }
395 template <
typename Stream>
397 Stream&& out,
size_t iPart, std::string indentstr =
"",
404 template <
typename Stream>
405 void DumpParticleWithID(
406 Stream&& out,
size_t pID, std::string indentstr =
"",
412 void DumpAllPrimaries(std::string indentstr =
"")
const;
416 void DumpAllParticles(std::string indentstr =
"")
const;
419 template <
typename Stream>
420 static void DumpPDGID(Stream&& out,
int ID);
424 std::vector<recob::PFParticle>
const& particles;
426 PrintOptions_t options;
447 mutable std::vector<unsigned int> visited;
449 int_map<size_t>
const particle_map;
452 template <
typename Stream>
453 void DumpPFParticleInfo(
457 std::string indentstr
460 template <
typename Stream>
463 cet::maybe_ref<recob::Vertex const> VertexRef,
464 std::string indentstr
467 template <
typename Stream>
468 void DumpPCAxisDirection
471 template <
typename Stream>
474 std::vector<recob::PCAxis const*>
const& myAxes,
475 std::string indentstr
478 template <
typename Stream>
481 template <
typename Stream>
484 std::vector<recob::Track const*>
const& myTracks,
485 std::string indentstr
488 template <
typename Stream>
492 template <
typename Stream>
495 std::vector<recob::Seed const*>
const& mySeeds,
496 std::string indentstr
499 template <
typename Stream>
502 template <
typename Stream>
505 std::vector<recob::SpacePoint const*>
const& mySpacePoints,
506 std::string indentstr
509 template <
typename Stream>
512 template <
typename Stream>
515 std::vector<recob::Cluster const*>
const& myClusters,
516 std::string indentstr
523 class PFParticleGraphMaker {
526 PFParticleGraphMaker() =
default;
528 template <
typename Stream>
530 (Stream&& out, std::vector<recob::PFParticle>
const& particles)
const;
532 template <
typename Stream>
533 void WriteGraphHeader(Stream&& out)
const;
535 template <
typename Stream>
536 void WriteParticleRelations
537 (Stream&& out, std::vector<recob::PFParticle>
const& particles)
const;
539 template <
typename Stream>
540 void WriteParticleNodes
541 (Stream&& out, std::vector<recob::PFParticle>
const& particles)
const;
543 template <
typename Stream>
544 void WriteParticleEdges
545 (Stream&& out, std::vector<recob::PFParticle>
const& particles)
const;
547 template <
typename Stream>
548 void WriteGraphFooter(Stream&& out)
const;
556 template <
typename Stream>
557 void ParticleDumper::DumpParticle(
558 Stream&& out,
size_t iPart, std::string indentstr ,
567 if (visited[iPart] > 1) {
568 out << indentstr <<
"particle " << part.
Self()
569 <<
" already printed!!!";
576 DumpPFParticleInfo(std::forward<Stream>(out), part, iPart, indentstr);
582 DumpVertex(std::forward<Stream>(out), vertices->at(iPart), indentstr);
588 out <<
" with no daughter";
594 DumpPCAxes(std::forward<Stream>(out), pcaxes->at(iPart), indentstr);
600 DumpTracks(std::forward<Stream>(out), tracks->at(iPart), indentstr);
606 DumpSeeds(std::forward<Stream>(out),
seeds->at(iPart), indentstr);
613 (std::forward<Stream>(out), spacepoints->at(iPart), indentstr);
621 (std::forward<Stream>(out), clusters->at(iPart), indentstr);
627 auto const PartID = part.
Self();
629 std::vector<size_t>
const& daughters = part.
Daughters();
630 out <<
"\n" << indentstr
634 for (
size_t DaughterID: daughters) {
635 if (DaughterID == PartID) {
636 out <<
"\n" << indentstr
637 <<
" oh, just great: this particle is its own daughter!";
641 DumpParticleWithID(out, DaughterID, indentstr +
" ", gen - 1);
646 out <<
" (further descend suppressed)";
653 if (visited[iPart] == 2) {
654 out <<
"\n" << indentstr <<
" WARNING: particle ID=" << PartID
655 <<
" connected more than once!";
666 template <
typename Stream>
667 void ParticleDumper::DumpParticleWithID(
668 Stream&& out,
size_t pID, std::string indentstr ,
671 size_t const pos = particle_map[pID];
672 if (particle_map.is_valid_value(pos)) {
673 DumpParticle(out, pos, indentstr, gen);
676 out << indentstr <<
"<ID=" << pID <<
" not found>";
682 void ParticleDumper::DumpAllPrimaries(std::string indentstr )
const 685 size_t const nParticles = particles.size();
686 unsigned int nPrimaries = 0;
687 for (
size_t iPart = 0; iPart < nParticles; ++iPart) {
688 if (!particles[iPart].IsPrimary())
continue;
691 iPart, indentstr, options.maxDepth
694 if (nPrimaries == 0) {
696 << indentstr <<
"No primary particle found";
702 void ParticleDumper::DumpAllParticles(std::string indentstr )
const 705 DumpAllPrimaries(indentstr);
707 unsigned int const nDisconnected
708 = std::count(visited.begin(), visited.end(), 0U);
711 << nDisconnected <<
" particles not coming from primary ones:";
712 size_t const nParticles = visited.size();
713 for (
size_t iPart = 0; iPart < nParticles; ++iPart) {
714 if (visited[iPart] > 0)
continue;
721 <<
"(end of " << nDisconnected <<
" particles not from primaries)";
729 template <
typename Stream>
730 void ParticleDumper::DumpPDGID(Stream&& out,
int ID) {
732 case -11: out <<
"e+";
break;
733 case 11: out <<
"e-";
break;
734 case -13: out <<
"mu+";
break;
735 case 13: out <<
"mu-";
break;
736 default: out <<
"MCID=" << ID;
break;
742 template <
typename Stream>
743 void ParticleDumper::DumpPFParticleInfo(
747 std::string indentstr
750 auto const PartID = part.
Self();
751 out << indentstr <<
"ID=" << PartID;
752 if (iPart != PartID) out <<
" [#" << iPart <<
"]";
754 DumpPDGID(out, part.
PdgCode());
756 if (part.
IsPrimary()) out <<
" (primary)";
757 else out <<
" from ID=" << part.
Parent();
761 template <
typename Stream>
762 void ParticleDumper::DumpVertex(
764 cet::maybe_ref<recob::Vertex const> VertexRef,
765 std::string indentstr
768 if (!VertexRef.isValid()) {
769 out <<
" [no vertex found!]";
773 std::array<double, 3> vtx_pos;
774 vertex.
XYZ(vtx_pos.data());
776 out <<
" [decay at (" 777 << hexfloat(vtx_pos[0]) <<
"," << hexfloat(vtx_pos[1])
778 <<
"," << hexfloat(vtx_pos[2])
779 <<
"), ID=" << vertex.
ID() <<
"]";
784 template <
typename Stream>
785 void ParticleDumper::DumpPCAxisDirection
789 out <<
"axis is invalid";
793 out <<
"axis ID=" << axis.
getID() <<
", principal: (" 799 template <
typename Stream>
800 void ParticleDumper::DumpPCAxes(
802 std::vector<recob::PCAxis const*>
const& myAxes,
803 std::string indentstr
806 out <<
"\n" << indentstr;
807 if (myAxes.empty()) {
808 out <<
" [no axis found!]";
811 if (myAxes.size() == 1) {
812 DumpPCAxisDirection(std::forward<Stream>(out), *(myAxes.front()));
815 out <<
" " << myAxes.size() <<
" axes present:";
817 out <<
"\n" << indentstr <<
" ";
818 DumpPCAxisDirection(std::forward<Stream>(out), *axis);
824 template <
typename Stream>
825 void ParticleDumper::DumpSeed
832 std::array<double, 3> start,
dir;
834 seed.
GetPoint(start.data(),
nullptr);
836 out <<
"\n" << indentstr
837 <<
" (" << hexfloat(start[0]) <<
"," << hexfloat(start[1])
838 <<
"," << hexfloat(start[2])
839 <<
")=>(" << hexfloat(dir[0]) <<
"," << hexfloat(dir[1])
840 <<
"," << hexfloat(dir[2])
841 <<
"), " << hexfloat(seed.
GetLength()) <<
" cm" 845 template <
typename Stream>
846 void ParticleDumper::DumpSeeds(
848 std::vector<recob::Seed const*>
const& mySeeds,
849 std::string indentstr
852 if (mySeeds.empty())
return;
853 out <<
"\n" << indentstr <<
" " 854 << mySeeds.size() <<
" seeds:";
856 DumpSeed(std::forward<Stream>(out), *seed, indentstr);
860 template <
typename Stream>
864 const double* pos = sp.
XYZ();
866 out <<
" ID=" << sp.
ID()
867 <<
" at (" << hexfloat(pos[0]) <<
"," << hexfloat(pos[1])
868 <<
"," << hexfloat(pos[2]) <<
") cm" 872 template <
typename Stream>
873 void ParticleDumper::DumpSpacePoints(
875 std::vector<recob::SpacePoint const*>
const& mySpacePoints,
876 std::string indentstr
879 out <<
"\n" << indentstr <<
" ";
880 if (mySpacePoints.empty()) {
881 out <<
"no space points";
884 constexpr
unsigned int PointsPerLine = 2;
885 out << mySpacePoints.size() <<
" space points:";
886 for (
size_t iSP = 0; iSP < mySpacePoints.size(); ++iSP) {
887 if ((iSP % PointsPerLine) == 0)
888 out <<
"\n" << indentstr <<
" ";
895 template <
typename Stream>
899 out <<
" length " << hexfloat(track.
Length())
900 <<
"cm from (" << hexfloat(track.
Vertex().X())
901 <<
";" << hexfloat(track.
Vertex().Y())
902 <<
";" << hexfloat(track.
Vertex().Z())
903 <<
") to (" << hexfloat(track.
End().X())
904 <<
";" << hexfloat(track.
End().Y())
905 <<
";" << hexfloat(track.
End().Z())
906 <<
") (ID=" << track.
ID() <<
")";
909 template <
typename Stream>
910 void ParticleDumper::DumpTracks(
912 std::vector<recob::Track const*>
const& myTracks,
913 std::string indentstr
916 if (myTracks.empty())
return;
917 out <<
"\n" << indentstr <<
" " 918 << myTracks.size() <<
" tracks:";
920 if (myTracks.size() > 1) out <<
"\n" << indentstr <<
" ";
921 DumpTrack(std::forward<Stream>(out), *track);
926 template <
typename Stream>
927 void ParticleDumper::DumpClusterSummary
930 out <<
" " << cluster.
NHits() <<
" hits on " << cluster.
Plane()
931 <<
" (ID=" << cluster.
ID() <<
")";
934 template <
typename Stream>
935 void ParticleDumper::DumpClusters(
937 std::vector<recob::Cluster const*>
const& myClusters,
938 std::string indentstr
941 if (myClusters.empty())
return;
942 out <<
"\n" << indentstr <<
" " 943 << myClusters.size() <<
" clusters:";
945 if (myClusters.size() > 1) out <<
"\n" << indentstr <<
" ";
946 DumpClusterSummary(std::forward<Stream>(out), *cluster);
954 template <
typename Stream>
955 void PFParticleGraphMaker::MakeGraph
956 (Stream&& out, std::vector<recob::PFParticle>
const& particles)
const 959 WriteGraphHeader (std::forward<Stream>(out));
960 WriteParticleRelations(std::forward<Stream>(out), particles);
961 WriteGraphFooter (std::forward<Stream>(out));
967 template <
typename Stream>
968 void PFParticleGraphMaker::WriteGraphHeader(Stream&& out)
const {
975 template <
typename Stream>
976 void PFParticleGraphMaker::WriteParticleNodes
977 (Stream&& out, std::vector<recob::PFParticle>
const& particles)
const 980 for (
auto const& particle: particles) {
982 std::ostringstream label;
983 label <<
"#" << particle.
Self();
986 ParticleDumper::DumpPDGID(label, particle.
PdgCode());
989 out <<
"\n P" << particle.
Self()
991 <<
" label = \"" << label.str() <<
"\"";
992 if (particle.
IsPrimary()) out <<
", style = bold";
999 template <
typename Stream>
1000 void PFParticleGraphMaker::WriteParticleEdges
1001 (Stream&& out, std::vector<recob::PFParticle>
const& particles)
const 1003 auto particle_map = CreateMap(particles);
1007 <<
"\n // relations" 1009 <<
"\n // the arrow is close to the information provider,;" 1010 <<
"\n // and it points from parent to daughter" 1016 for (
auto const& particle: particles) {
1017 auto const partID = particle.
Self();
1021 auto const parentID = particle.
Parent();
1022 size_t const iParent = particle_map[parentID];
1023 if (!particle_map.is_valid_value(iParent)) {
1026 <<
"\nP" << parentID
1027 <<
" [ style = dashed, color = red" 1028 <<
", label = \"(#" << parentID <<
")\" ] // ghost particle" 1029 <<
"\nP" << parentID <<
" -> P" << partID
1030 <<
" [ dir = both, arrowhead = empty, arrowtail = none ]";
1037 if (hasDaughter(parent, partID)) {
1039 <<
"\nP" << parentID <<
" -> P" << partID
1040 <<
" [ dir = both, arrowtail = inv ]";
1044 <<
"\nP" << parentID <<
" -> P" << partID
1045 <<
" [ dir = forward, color = red ]" 1046 <<
" // claimed parent";
1053 for (
auto daughterID: particle.
Daughters()) {
1054 size_t const iDaughter = particle_map[daughterID];
1055 if (!particle_map.is_valid_value(iDaughter)) {
1058 <<
"\nP" << daughterID
1059 <<
" [ style = dashed, color = red" 1060 <<
", label = \"(#" << daughterID <<
")\" ] // ghost daughter" 1061 <<
"\nP" << partID <<
" -> P" << daughterID
1062 <<
" [ dir = both, arrowhead = none, arrowtail = invempty ]";
1069 if (daughter.
Parent() != partID) {
1071 <<
"\nP" << partID <<
" -> P" << daughterID
1072 <<
" [ dir = both, arrowhead = none, arrowtail = inv, color = orange ]" 1073 <<
" // claimed daughter";
1086 template <
typename Stream>
1087 void PFParticleGraphMaker::WriteParticleRelations
1088 (Stream&& out, std::vector<recob::PFParticle>
const& particles)
const 1090 out <<
"\n // " << particles.size() <<
" particles (nodes)";
1091 WriteParticleNodes(std::forward<Stream>(out), particles);
1095 <<
"\n // parent/children relations";
1096 WriteParticleEdges(std::forward<Stream>(out), particles);
1101 template <
typename Stream>
1102 void PFParticleGraphMaker::WriteGraphFooter(Stream&& out)
const {
1155 std::string fileName =
DotFileName(eventID, *(handle.provenance()));
1156 std::ofstream outFile(fileName);
1159 <<
"// " << fileName
1161 <<
"\n// Created for run " << eventID.
run()
1162 <<
" subrun " << eventID.
subRun()
1163 <<
" event " << eventID.
event()
1165 <<
"\n// dump of " << handle->size() <<
" particles" 1169 PFParticleGraphMaker graphMaker;
1170 graphMaker.MakeGraph(outFile, *handle);
1201 size_t const nParticles = PFParticles->size();
1203 <<
" contains " << nParticles <<
" particles from '" 1207 ParticleDumper::PrintOptions_t options;
1211 ParticleDumper dumper(*PFParticles, options);
1212 if (ParticleVertices.isValid()) dumper.SetVertices(&ParticleVertices);
1213 else mf::LogPrint(
"DumpPFParticles") <<
"WARNING: vertex information not available";
1214 if (ParticleTracks.isValid()) dumper.SetTracks(&ParticleTracks);
1215 else mf::LogPrint(
"DumpPFParticles") <<
"WARNING: track information not available";
1216 if (ParticleClusters.isValid()) dumper.SetClusters(&ParticleClusters);
1217 else mf::LogPrint(
"DumpPFParticles") <<
"WARNING: cluster information not available";
1218 if (ParticleSeeds.isValid()) dumper.SetSeeds(&ParticleSeeds);
1219 else mf::LogPrint(
"DumpPFParticles") <<
"WARNING: seed information not avaialble";
1220 if (ParticleSpacePoints.isValid())
1221 dumper.SetSpacePoints(&ParticleSpacePoints);
1224 <<
"WARNING: space point information not available";
1226 if (ParticlePCAxes.isValid())
1227 dumper.SetPCAxes(&ParticlePCAxes);
1230 <<
"WARNING: principal component axis not available";
1232 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.
Reconstruction base classes.
size_t Self() const
Returns the index of this particle.
std::string const & productInstanceName() const
void GetPoint(double *Pt, double *Err) const
Prints the content of all the space points on screen.
std::string const & processName() const
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.
constexpr bool is_valid(IDNumber_t< L > const id)
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.
fhicl::OptionalAtom< unsigned int > MaxDepth
Definition of vertex object for LArSoft.
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
#define DEFINE_ART_MODULE(klass)
Provides recob::Track data product.
unsigned int fMaxDepth
maximum generation to print (0: only primaries)
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.
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
Point_t const & Vertex() const
Access to track position at different points.
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.
EDAnalyzer(Table< Config > const &config)
Declaration of cluster object.
Helper for formatting floats in base 16.
std::vector< TrajPoint > seeds
Prints the content of all the tracks on screen.
Hierarchical representation of particle flow.
std::string to_string(Flag_t< Storage > const flag)
Convert a flag into a stream (shows its index).
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
std::string const & moduleLabel() const
Prints the content of all the ParticleFlow particles on screen.
int ID() const
Return vertex id.
fhicl::Atom< std::string > OutputCategory
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
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
unsigned int NHits() const
Number of hits in the cluster.
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
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:
MaybeLogger_< ELseverityLevel::ELsev_warning, true > LogPrint
Event finding and building.