139 Name(
"PFModuleLabel"),
140 Comment(
"label of producer of the recob::PFParticle to be dumped")
144 Name(
"OutputCategory"),
145 Comment(
"message facility category used for output (for filtering)"),
150 Name(
"PrintHexFloats"),
151 Comment(
"print all the floating point numbers in base 16"),
157 Comment(
"at most this number of particle generations will be printed")
161 Name(
"MakeParticleGraphs"),
162 Comment(
"creates a DOT file with particle information for each event"),
212 #include "canvas/Persistency/Common/FindOne.h" 213 #include "canvas/Persistency/Common/FindMany.h" 231 template <
typename T>
233 using map_type = std::vector<T>;
235 using this_type = int_map<T>;
237 using typename map_type::value_type;
238 using typename map_type::reference;
239 using typename map_type::const_reference;
243 using typename map_type::size_type;
250 int_map(value_type invalid_value): invalid(invalid_value) {}
254 void resize(
size_t new_size)
255 { get_map().resize(new_size, invalid_value()); }
258 reference operator[] (
size_t pos)
259 {
if (pos >=
size())
resize(pos + 1);
return get_map()[
pos]; }
262 const_reference operator[] (
size_t pos)
const 263 {
return (pos >=
size())? invalid: get_map()[
pos]; }
272 using map_type::rbegin;
273 using map_type::rend;
274 using map_type::crbegin;
275 using map_type::crend;
286 size_type n_invalid()
const 290 size_type n_valid()
const {
return size() - n_invalid(); }
294 {
return (pos <
size())? is_valid_value(get_map()[pos]): false; }
297 bool is_valid_value(value_type
const& v)
const {
return v != invalid; }
300 value_type
const& invalid_value()
const {
return invalid; }
304 value_type
const invalid;
306 map_type& get_map() {
return static_cast<map_type&
>(*this); }
307 map_type
const& get_map()
const 308 {
return static_cast<map_type
const&
>(*this); }
314 int_map<size_t> CreateMap(std::vector<recob::PFParticle>
const& particles) {
317 pmap.resize(particles.size());
319 size_t const nParticles = particles.size();
320 for (
size_t iPart = 0; iPart < nParticles; ++iPart)
321 pmap[particles[iPart].Self()] = iPart;
329 auto const& daughters = particle.
Daughters();
330 return daughters.end()
331 != std::find(daughters.begin(), daughters.end(), partID);
336 class ParticleDumper {
340 struct PrintOptions_t {
341 bool hexFloats =
false;
350 ParticleDumper(std::vector<recob::PFParticle>
const& particle_list)
351 : ParticleDumper(particle_list, {})
356 std::vector<recob::PFParticle>
const& particle_list,
357 PrintOptions_t print_options
359 : particles(particle_list)
361 , visited(particles.
size(), 0U)
362 , particle_map (CreateMap(particles))
367 void SetVertices(art::FindOne<recob::Vertex>
const* vtx_query)
368 { vertices = vtx_query; }
371 void SetTracks(art::FindMany<recob::Track>
const* trk_query)
375 void SetClusters(art::FindMany<recob::Cluster>
const* cls_query)
376 { clusters = cls_query; }
379 void SetSeeds(art::FindMany<recob::Seed>
const* seed_query)
380 {
seeds = seed_query; }
383 void SetSpacePoints(art::FindMany<recob::SpacePoint>
const* sp_query)
384 { spacepoints = sp_query; }
387 void SetPCAxes(art::FindMany<recob::PCAxis>
const* pca_query)
388 { pcaxes = pca_query; }
393 template <
typename Stream>
395 Stream&& out,
size_t iPart,
std::string indentstr =
"",
402 template <
typename Stream>
403 void DumpParticleWithID(
404 Stream&& out,
size_t pID,
std::string indentstr =
"",
410 void DumpAllPrimaries(
std::string indentstr =
"")
const;
414 void DumpAllParticles(
std::string indentstr =
"")
const;
417 template <
typename Stream>
418 static void DumpPDGID(Stream&& out,
int ID);
422 std::vector<recob::PFParticle>
const& particles;
427 art::FindOne<recob::Vertex>
const* vertices =
nullptr;
430 art::FindMany<recob::Track>
const*
tracks =
nullptr;
433 art::FindMany<recob::Cluster>
const* clusters =
nullptr;
436 art::FindMany<recob::Seed>
const*
seeds =
nullptr;
439 art::FindMany<recob::SpacePoint>
const* spacepoints =
nullptr;
442 art::FindMany<recob::PCAxis>
const* pcaxes =
nullptr;
445 mutable std::vector<unsigned int> visited;
447 int_map<size_t>
const particle_map;
450 template <
typename Stream>
451 void DumpPFParticleInfo(
458 template <
typename Stream>
465 template <
typename Stream>
466 void DumpPCAxisDirection
469 template <
typename Stream>
472 std::vector<recob::PCAxis const*>
const& myAxes,
476 template <
typename Stream>
477 void DumpTrack(Stream&& out,
recob::Track const& track)
const;
479 template <
typename Stream>
482 std::vector<recob::Track const*>
const& myTracks,
486 template <
typename Stream>
490 template <
typename Stream>
493 std::vector<recob::Seed const*>
const& mySeeds,
497 template <
typename Stream>
500 template <
typename Stream>
503 std::vector<recob::SpacePoint const*>
const& mySpacePoints,
507 template <
typename Stream>
508 void DumpClusterSummary(Stream&& out,
recob::Cluster const& track)
const;
510 template <
typename Stream>
513 std::vector<recob::Cluster const*>
const& myClusters,
521 class PFParticleGraphMaker {
524 PFParticleGraphMaker() =
default;
526 template <
typename Stream>
528 (Stream&& out, std::vector<recob::PFParticle>
const& particles)
const;
530 template <
typename Stream>
531 void WriteGraphHeader(Stream&& out)
const;
533 template <
typename Stream>
534 void WriteParticleRelations
535 (Stream&& out, std::vector<recob::PFParticle>
const& particles)
const;
537 template <
typename Stream>
538 void WriteParticleNodes
539 (Stream&& out, std::vector<recob::PFParticle>
const& particles)
const;
541 template <
typename Stream>
542 void WriteParticleEdges
543 (Stream&& out, std::vector<recob::PFParticle>
const& particles)
const;
545 template <
typename Stream>
546 void WriteGraphFooter(Stream&& out)
const;
554 template <
typename Stream>
555 void ParticleDumper::DumpParticle(
556 Stream&& out,
size_t iPart,
std::string indentstr ,
565 if (visited[iPart] > 1) {
566 out << indentstr <<
"particle " << part.
Self()
567 <<
" already printed!!!";
574 DumpPFParticleInfo(std::forward<Stream>(out), part, iPart, indentstr);
580 DumpVertex(std::forward<Stream>(out), vertices->at(iPart), indentstr);
586 out <<
" with no daughter";
592 DumpPCAxes(std::forward<Stream>(out), pcaxes->at(iPart), indentstr);
604 DumpSeeds(std::forward<Stream>(out),
seeds->at(iPart), indentstr);
611 (std::forward<Stream>(out), spacepoints->at(iPart), indentstr);
619 (std::forward<Stream>(out), clusters->at(iPart), indentstr);
625 auto const PartID = part.
Self();
627 std::vector<size_t>
const& daughters = part.
Daughters();
628 out <<
"\n" << indentstr
632 for (
size_t DaughterID: daughters) {
633 if (DaughterID == PartID) {
634 out <<
"\n" << indentstr
635 <<
" oh, just great: this particle is its own daughter!";
639 DumpParticleWithID(out, DaughterID, indentstr +
" ", gen - 1);
644 out <<
" (further descend suppressed)";
651 if (visited[iPart] == 2) {
652 out <<
"\n" << indentstr <<
" WARNING: particle ID=" << PartID
653 <<
" connected more than once!";
664 template <
typename Stream>
665 void ParticleDumper::DumpParticleWithID(
669 size_t const pos = particle_map[pID];
670 if (particle_map.is_valid_value(pos)) {
671 DumpParticle(out, pos, indentstr, gen);
674 out << indentstr <<
"<ID=" << pID <<
" not found>";
680 void ParticleDumper::DumpAllPrimaries(
std::string indentstr )
const 683 size_t const nParticles = particles.size();
684 unsigned int nPrimaries = 0;
685 for (
size_t iPart = 0; iPart < nParticles; ++iPart) {
686 if (!particles[iPart].IsPrimary())
continue;
689 iPart, indentstr,
options.maxDepth
692 if (nPrimaries == 0) {
694 << indentstr <<
"No primary particle found";
700 void ParticleDumper::DumpAllParticles(
std::string indentstr )
const 703 DumpAllPrimaries(indentstr);
705 unsigned int const nDisconnected
706 =
std::count(visited.begin(), visited.end(), 0U);
709 << nDisconnected <<
" particles not coming from primary ones:";
710 size_t const nParticles = visited.size();
711 for (
size_t iPart = 0; iPart < nParticles; ++iPart) {
712 if (visited[iPart] > 0)
continue;
719 <<
"(end of " << nDisconnected <<
" particles not from primaries)";
727 template <
typename Stream>
728 void ParticleDumper::DumpPDGID(Stream&& out,
int ID) {
730 case -11: out <<
"e+";
break;
731 case 11: out <<
"e-";
break;
732 case -13: out <<
"mu+";
break;
733 case 13: out <<
"mu-";
break;
734 default: out <<
"MCID=" <<
ID;
break;
740 template <
typename Stream>
741 void ParticleDumper::DumpPFParticleInfo(
748 auto const PartID = part.
Self();
749 out << indentstr <<
"ID=" << PartID;
750 if (iPart != PartID) out <<
" [#" << iPart <<
"]";
752 DumpPDGID(out, part.
PdgCode());
754 if (part.
IsPrimary()) out <<
" (primary)";
755 else out <<
" from ID=" << part.
Parent();
759 template <
typename Stream>
760 void ParticleDumper::DumpVertex(
767 out <<
" [no vertex found!]";
771 std::array<double, 3> vtx_pos;
772 vertex.
XYZ(vtx_pos.data());
774 out <<
" [decay at (" 775 << hexfloat(vtx_pos[0]) <<
"," << hexfloat(vtx_pos[1])
776 <<
"," << hexfloat(vtx_pos[2])
777 <<
"), ID=" << vertex.
ID() <<
"]";
782 template <
typename Stream>
783 void ParticleDumper::DumpPCAxisDirection
787 out <<
"axis is invalid";
791 out <<
"axis ID=" << axis.
getID() <<
", principal: (" 797 template <
typename Stream>
798 void ParticleDumper::DumpPCAxes(
800 std::vector<recob::PCAxis const*>
const& myAxes,
804 out <<
"\n" << indentstr;
805 if (myAxes.empty()) {
806 out <<
" [no axis found!]";
809 if (myAxes.size() == 1) {
810 DumpPCAxisDirection(std::forward<Stream>(out), *(myAxes.front()));
813 out <<
" " << myAxes.size() <<
" axes present:";
815 out <<
"\n" << indentstr <<
" ";
816 DumpPCAxisDirection(std::forward<Stream>(out), *axis);
822 template <
typename Stream>
823 void ParticleDumper::DumpSeed
830 std::array<double, 3> start,
dir;
832 seed.
GetPoint(start.data(),
nullptr);
834 out <<
"\n" << indentstr
835 <<
" (" << hexfloat(start[0]) <<
"," << hexfloat(start[1])
836 <<
"," << hexfloat(start[2])
837 <<
")=>(" << hexfloat(dir[0]) <<
"," << hexfloat(dir[1])
838 <<
"," << hexfloat(dir[2])
839 <<
"), " << hexfloat(seed.
GetLength()) <<
" cm" 843 template <
typename Stream>
844 void ParticleDumper::DumpSeeds(
846 std::vector<recob::Seed const*>
const& mySeeds,
850 if (mySeeds.empty())
return;
851 out <<
"\n" << indentstr <<
" " 852 << mySeeds.size() <<
" seeds:";
854 DumpSeed(std::forward<Stream>(out), *seed, indentstr);
858 template <
typename Stream>
862 const double* pos = sp.
XYZ();
864 out <<
" ID=" << sp.
ID()
865 <<
" at (" << hexfloat(pos[0]) <<
"," << hexfloat(pos[1])
866 <<
"," << hexfloat(pos[2]) <<
") cm" 870 template <
typename Stream>
871 void ParticleDumper::DumpSpacePoints(
873 std::vector<recob::SpacePoint const*>
const& mySpacePoints,
877 out <<
"\n" << indentstr <<
" ";
878 if (mySpacePoints.empty()) {
879 out <<
"no space points";
882 constexpr
unsigned int PointsPerLine = 2;
883 out << mySpacePoints.size() <<
" space points:";
884 for (
size_t iSP = 0; iSP < mySpacePoints.size(); ++iSP) {
885 if ((iSP % PointsPerLine) == 0)
886 out <<
"\n" << indentstr <<
" ";
893 template <
typename Stream>
894 void ParticleDumper::DumpTrack(Stream&& out,
recob::Track const& track)
const 897 out <<
" length " << hexfloat(track.
Length())
898 <<
"cm from (" << hexfloat(track.
Vertex().X())
899 <<
";" << hexfloat(track.
Vertex().Y())
900 <<
";" << hexfloat(track.
Vertex().Z())
901 <<
") to (" << hexfloat(track.
End().X())
902 <<
";" << hexfloat(track.
End().Y())
903 <<
";" << hexfloat(track.
End().Z())
904 <<
") (ID=" << track.
ID() <<
")";
907 template <
typename Stream>
908 void ParticleDumper::DumpTracks(
910 std::vector<recob::Track const*>
const& myTracks,
914 if (myTracks.empty())
return;
915 out <<
"\n" << indentstr <<
" " 916 << myTracks.size() <<
" tracks:";
918 if (myTracks.size() > 1) out <<
"\n" << indentstr <<
" ";
919 DumpTrack(std::forward<Stream>(out), *track);
924 template <
typename Stream>
925 void ParticleDumper::DumpClusterSummary
928 out <<
" " << cluster.
NHits() <<
" hits on " << cluster.
Plane()
929 <<
" (ID=" << cluster.
ID() <<
")";
932 template <
typename Stream>
933 void ParticleDumper::DumpClusters(
935 std::vector<recob::Cluster const*>
const& myClusters,
939 if (myClusters.empty())
return;
940 out <<
"\n" << indentstr <<
" " 941 << myClusters.size() <<
" clusters:";
943 if (myClusters.size() > 1) out <<
"\n" << indentstr <<
" ";
944 DumpClusterSummary(std::forward<Stream>(out), *cluster);
952 template <
typename Stream>
953 void PFParticleGraphMaker::MakeGraph
954 (Stream&& out, std::vector<recob::PFParticle>
const& particles)
const 957 WriteGraphHeader (std::forward<Stream>(out));
958 WriteParticleRelations(std::forward<Stream>(out), particles);
959 WriteGraphFooter (std::forward<Stream>(out));
965 template <
typename Stream>
966 void PFParticleGraphMaker::WriteGraphHeader(Stream&& out)
const {
973 template <
typename Stream>
974 void PFParticleGraphMaker::WriteParticleNodes
975 (Stream&& out, std::vector<recob::PFParticle>
const& particles)
const 978 for (
auto const& particle: particles) {
980 std::ostringstream
label;
981 label <<
"#" << particle.
Self();
984 ParticleDumper::DumpPDGID(label, particle.
PdgCode());
987 out <<
"\n P" << particle.
Self()
989 <<
" label = \"" << label.str() <<
"\"";
990 if (particle.
IsPrimary()) out <<
", style = bold";
997 template <
typename Stream>
998 void PFParticleGraphMaker::WriteParticleEdges
999 (Stream&& out, std::vector<recob::PFParticle>
const& particles)
const 1001 auto particle_map = CreateMap(particles);
1005 <<
"\n // relations" 1007 <<
"\n // the arrow is close to the information provider,;" 1008 <<
"\n // and it points from parent to daughter" 1014 for (
auto const& particle: particles) {
1015 auto const partID = particle.
Self();
1019 auto const parentID = particle.
Parent();
1020 size_t const iParent = particle_map[parentID];
1021 if (!particle_map.is_valid_value(iParent)) {
1024 <<
"\nP" << parentID
1025 <<
" [ style = dashed, color = red" 1026 <<
", label = \"(#" << parentID <<
")\" ] // ghost particle" 1027 <<
"\nP" << parentID <<
" -> P" << partID
1028 <<
" [ dir = both, arrowhead = empty, arrowtail = none ]";
1035 if (hasDaughter(parent, partID)) {
1037 <<
"\nP" << parentID <<
" -> P" << partID
1038 <<
" [ dir = both, arrowtail = inv ]";
1042 <<
"\nP" << parentID <<
" -> P" << partID
1043 <<
" [ dir = forward, color = red ]" 1044 <<
" // claimed parent";
1051 for (
auto daughterID: particle.
Daughters()) {
1052 size_t const iDaughter = particle_map[daughterID];
1053 if (!particle_map.is_valid_value(iDaughter)) {
1056 <<
"\nP" << daughterID
1057 <<
" [ style = dashed, color = red" 1058 <<
", label = \"(#" << daughterID <<
")\" ] // ghost daughter" 1059 <<
"\nP" << partID <<
" -> P" << daughterID
1060 <<
" [ dir = both, arrowhead = none, arrowtail = invempty ]";
1067 if (daughter.
Parent() != partID) {
1069 <<
"\nP" << partID <<
" -> P" << daughterID
1070 <<
" [ dir = both, arrowhead = none, arrowtail = inv, color = orange ]" 1071 <<
" // claimed daughter";
1084 template <
typename Stream>
1085 void PFParticleGraphMaker::WriteParticleRelations
1086 (Stream&& out, std::vector<recob::PFParticle>
const& particles)
const 1088 out <<
"\n // " << particles.size() <<
" particles (nodes)";
1089 WriteParticleNodes(std::forward<Stream>(out), particles);
1093 <<
"\n // parent/children relations";
1094 WriteParticleEdges(std::forward<Stream>(out), particles);
1099 template <
typename Stream>
1100 void PFParticleGraphMaker::WriteGraphFooter(Stream&& out)
const {
1154 std::ofstream
outFile(fileName);
1157 <<
"// " << fileName
1159 <<
"\n// Created for run " << eventID.
run()
1160 <<
" subrun " << eventID.
subRun()
1161 <<
" event " << eventID.
event()
1163 <<
"\n// dump of " << handle->size() <<
" particles" 1167 PFParticleGraphMaker graphMaker;
1168 graphMaker.MakeGraph(outFile, *handle);
1186 art::FindOne<recob::Vertex>
const ParticleVertices
1188 art::FindMany<recob::Track>
const ParticleTracks
1190 art::FindMany<recob::Cluster>
const ParticleClusters
1192 art::FindMany<recob::Seed>
const ParticleSeeds
1194 art::FindMany<recob::SpacePoint>
const ParticleSpacePoints
1196 art::FindMany<recob::PCAxis>
const ParticlePCAxes
1199 size_t const nParticles = PFParticles->size();
1201 <<
" contains " << nParticles <<
" particles from '" 1205 ParticleDumper::PrintOptions_t
options;
1209 ParticleDumper dumper(*PFParticles, options);
1210 if (ParticleVertices.isValid()) dumper.SetVertices(&ParticleVertices);
1211 else mf::LogPrint(
"DumpPFParticles") <<
"WARNING: vertex information not available";
1212 if (ParticleTracks.isValid()) dumper.SetTracks(&ParticleTracks);
1213 else mf::LogPrint(
"DumpPFParticles") <<
"WARNING: track information not available";
1214 if (ParticleClusters.isValid()) dumper.SetClusters(&ParticleClusters);
1215 else mf::LogPrint(
"DumpPFParticles") <<
"WARNING: cluster information not available";
1216 if (ParticleSeeds.isValid()) dumper.SetSeeds(&ParticleSeeds);
1217 else mf::LogPrint(
"DumpPFParticles") <<
"WARNING: seed information not avaialble";
1218 if (ParticleSpacePoints.isValid())
1219 dumper.SetSpacePoints(&ParticleSpacePoints);
1222 <<
"WARNING: space point information not available";
1224 if (ParticlePCAxes.isValid())
1225 dumper.SetPCAxes(&ParticlePCAxes);
1228 <<
"WARNING: principal component axis not available";
1230 dumper.DumpAllParticles(
" ");
end
while True: pbar.update(maxval-len(onlies[E][S])) #print iS, "/", len(onlies[E][S]) found = False for...
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.
ChannelGroupService::Name Name
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)
void resize(Vector< T > &vec1, Index n1, const V &val)
fhicl::OptionalAtom< unsigned int > MaxDepth
Definition of vertex object for LArSoft.
std::string const & moduleLabel() const noexcept
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
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)
void swap(Handle< T > &a, Handle< T > &b)
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.
Point_t const & Vertex() const
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
bool IsPrimary() const
Returns whether the particle is the root of the flow.
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
static int max(int a, int b)
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.
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
Provides recob::Track data product.
decltype(auto) constexpr cbegin(T &&obj)
ADL-aware version of std::cbegin.
const Double32_t * XYZ() const
static std::string DotFileName(art::EventID const &evtID, art::Provenance const &prodInfo)
EventNumber_t event() const
Point_t const & End() const
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
std::string to_string(ModuleType const mt)
bool fPrintHexFloats
whether to print floats in base 16
SubRunNumber_t subRun() const
def parent(G, child, parent_type)
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a "fitted" track:
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
MaybeLogger_< ELseverityLevel::ELsev_warning, true > LogPrint
QTextStream & endl(QTextStream &s)
Event finding and building.