10 #include "art/Framework/Core/EDAnalyzer.h"
11 #include "art/Framework/Core/ModuleMacros.h"
12 #include "art/Framework/Principal/Event.h"
13 #include "art/Framework/Principal/Handle.h"
14 #include "art/Framework/Principal/Run.h"
15 #include "art/Framework/Principal/SubRun.h"
16 #include "canvas/Utilities/InputTag.h"
17 #include "fhiclcpp/ParameterSet.h"
18 #include "messagefacility/MessageLogger/MessageLogger.h"
20 #include "art/Framework/Services/Registry/ServiceHandle.h"
32 #include "art_root_io/TFileService.h"
49 #include "nusimdata/SimulationBase/MCParticle.h"
50 #include "nusimdata/SimulationBase/MCTruth.h"
81 float Completion(
const simb::MCParticle &particle,
float particleE,
const std::vector<std::pair<int, float>> &matches,
const std::vector<simb::MCParticle> &particles);
82 float Purity(
const simb::MCParticle &particle,
float totalE,
const std::vector<std::pair<int, float>> &matches,
const std::vector<simb::MCParticle> &particles);
84 const std::vector<geoalgo::AABox> &boxes);
99 void analyze(art::Event
const&
e)
override;
110 void InitReco(
unsigned i,
const std::string &prefix);
113 void FillReco(
unsigned i,
const simb::MCParticle &
muon,
const simb::MCParticle &proton,
float muon_completion,
float proton_completion,
float muon_purity,
float proton_purity);
116 void FillTrue(
const simb::MCParticle &
muon,
const simb::MCParticle &proton);
122 art::ServiceHandle<art::TFileService>
tfs;
130 art::ServiceHandle<art::TFileService>
tfs;
132 fTrackHistos[i].cos_open_angle = tfs->make<TH1D>((prefix +
"reco_CosOpenAngle").c_str(),
"", 64, -3.2, 3.2);
133 fTrackHistos[i].muon_length = tfs->make<TH1D>((prefix +
"reco_mu_length").c_str(),
"", 100, 0., 500.);
134 fTrackHistos[i].proton_length = tfs->make<TH1D>((prefix +
"reco_p_length").c_str(),
"", 100, 0., 200.);
136 fTrackHistos[i].muon_completion = tfs->make<TH1D>((prefix +
"reco_mu_completion").c_str(),
"", 100, 0., 1.);
137 fTrackHistos[i].proton_completion = tfs->make<TH1D>((prefix +
"reco_p_completion").c_str(),
"", 100, 0., 1.);
138 fTrackHistos[i].muon_purity = tfs->make<TH1D>((prefix +
"reco_mu_purity").c_str(),
"", 100, 0., 1.);
139 fTrackHistos[i].proton_purity = tfs->make<TH1D>((prefix +
"reco_p_purity").c_str(),
"", 100, 0., 1.);
143 art::ServiceHandle<art::TFileService>
tfs;
145 fVertexHistos.vertex_diff = tfs->make<TH1D>(
"vertex_diff",
"", 200, 0, 100.);
156 std::vector<std::string> prefixes {
"both",
"mu",
"p"};
157 for (
unsigned i = 0; i < 3; i++) {
158 InitReco(i, prefixes[i]);
166 tend = geometry->
end_TPC(cryo.ID());
167 std::vector<geo::BoxBoundedGeo> this_tpc_volumes;
168 while (iTPC != tend) {
173 fTPCVolumes.push_back(std::move(this_tpc_volumes));
177 for (
const std::vector<geo::BoxBoundedGeo> &tpcs: fTPCVolumes) {
178 double XMin = std::min_element(tpcs.begin(), tpcs.end(), [](
auto &lhs,
auto &rhs) {
return lhs.MinX() < rhs.MinX(); })->MinX();
179 double YMin = std::min_element(tpcs.begin(), tpcs.end(), [](
auto &lhs,
auto &rhs) {
return lhs.MinY() < rhs.MinY(); })->MinY();
180 double ZMin = std::min_element(tpcs.begin(), tpcs.end(), [](
auto &lhs,
auto &rhs) {
return lhs.MinZ() < rhs.MinZ(); })->MinZ();
182 double XMax = std::max_element(tpcs.begin(), tpcs.end(), [](
auto &lhs,
auto &rhs) {
return lhs.MaxX() < rhs.MaxX(); })->MaxX();
183 double YMax = std::max_element(tpcs.begin(), tpcs.end(), [](
auto &lhs,
auto &rhs) {
return lhs.MaxY() < rhs.MaxY(); })->MaxY();
184 double ZMax = std::max_element(tpcs.begin(), tpcs.end(), [](
auto &lhs,
auto &rhs) {
return lhs.MaxZ() < rhs.MaxZ(); })->MaxZ();
186 fActiveVolumes.emplace_back(XMin, XMax, YMin, YMax, ZMin, ZMax);
192 std::vector<geoalgo::AABox> aa_volumes;
194 if (AV.ContainsPosition(particle.Position().Vect())) {
195 aa_volumes.emplace_back(AV.MinX(), AV.MinY(), AV.MinZ(), AV.MaxX(), AV.MaxY(), AV.MaxZ());
201 for (
unsigned i = 1; i < particle.NumberTrajectoryPoints(); i++) {
202 length +=
ContainedLength(particle.Position(i-1).Vect(), particle.Position(i).Vect(), aa_volumes);
209 fTrueHistos.muon_length->Fill(ParticleLength(muon));
210 fTrueHistos.proton_length->Fill(ParticleLength(proton));
212 fTrueHistos.cos_open_angle->Fill(muon.Momentum().Vect().Dot(proton.Momentum().Vect()) / (muon.Momentum().Vect().Mag() * proton.Momentum().Vect().Mag()));
215 void numu::MuPVertexStudy::FillReco(
unsigned i,
const simb::MCParticle &
muon,
const simb::MCParticle &proton,
float muon_completion,
float proton_completion,
float muon_purity,
float proton_purity) {
217 fTrackHistos[i].muon_completion->Fill(muon_completion);
218 fTrackHistos[i].proton_completion->Fill(proton_completion);
219 fTrackHistos[i].muon_purity->Fill(muon_purity);
220 fTrackHistos[i].proton_purity->Fill(proton_purity);
222 fTrackHistos[i].muon_length->Fill(ParticleLength(muon));
223 fTrackHistos[i].proton_length->Fill(ParticleLength(proton));
225 fTrackHistos[i].cos_open_angle->Fill(muon.Momentum().Vect().Dot(proton.Momentum().Vect()) / (muon.Momentum().Vect().Mag() * proton.Momentum().Vect().Mag()));
230 TVector3 muon_start(muon->
Start().X(), muon->
Start().Y(), muon->
Start().Z());
231 TVector3 muon_end(muon->
End().X(), muon->
End().Y(), muon->
End().Z());
232 fVertexHistos.vertex_diff->Fill(std::min((vertex - muon_start).Mag(), (vertex - muon_end).Mag()));
237 auto const clock_data = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(ev);
238 art::ServiceHandle<cheat::BackTrackerService> backtracker;
240 const std::vector<simb::MCParticle> &mcparticle_list = *ev.getValidHandle<std::vector<simb::MCParticle>>(
"largeant");
242 const simb::MCParticle *
muon = NULL;
243 const simb::MCParticle *proton = NULL;
246 for (
unsigned i = 0; i < mcparticle_list.size(); i++) {
247 if (mcparticle_list[i].PdgCode() == 13 && mcparticle_list[i].Process() ==
"primary") {
248 assert(muon == NULL);
249 muon = &mcparticle_list[i];
251 if (mcparticle_list[i].PdgCode() == 2212 && mcparticle_list[i].Process() ==
"primary") {
252 assert(proton == NULL);
253 proton = &mcparticle_list[i];
257 assert(muon != NULL);
258 assert(proton != NULL);
260 FillTrue(*muon, *proton);
263 std::vector<const sim::IDE*> muon_ides(backtracker->TrackIdToSimIDEs_Ps(muon->TrackId()));
264 for (
const sim::IDE *ide: muon_ides) muonE += ide->energy;
267 std::vector<const sim::IDE*> proton_ides(backtracker->TrackIdToSimIDEs_Ps(proton->TrackId()));
268 for (
const sim::IDE *ide: proton_ides) protonE += ide->energy;
270 const auto &particle_handle = ev.getValidHandle<std::vector<recob::PFParticle>>(
"pandora");
271 const std::vector<recob::PFParticle> &particle_list = *particle_handle;
272 art::FindManyP<recob::Cluster> particles_to_clusters(particle_handle, ev,
"pandora");
273 art::FindManyP<recob::Track> particles_to_tracks(particle_handle, ev,
"pandoraTrack");
278 for (
unsigned i_part = 0; i_part < particle_list.size(); i_part++) {
279 const std::vector<art::Ptr<recob::Cluster>> clusters = particles_to_clusters.at(i_part);
280 art::FindManyP<recob::Hit> clusters_to_hits(clusters, ev,
"pandora");
282 std::vector<art::Ptr<recob::Hit>> hits;
283 for (
unsigned i_clus = 0; i_clus < clusters.size(); i_clus++) {
284 const std::vector<art::Ptr<recob::Hit>> &this_hits = clusters_to_hits.at(i_clus);
285 hits.insert(hits.end(), this_hits.begin(), this_hits.end());
291 float muon_completion =
Completion(*muon, muonE, matches, mcparticle_list);
292 float proton_completion =
Completion(*proton, protonE, matches, mcparticle_list);
294 float muon_purity =
Purity(*muon, totalE, matches, mcparticle_list);
295 float proton_purity =
Purity(*proton, totalE, matches, mcparticle_list);
297 const recob::Track *
track = particles_to_tracks.at(i_part).size() ? particles_to_tracks.at(i_part).at(0).get() : NULL;
299 if (muon_completion > 0.5 && proton_completion > 0.5) {
300 FillReco(0, *muon, *proton, muon_completion, proton_completion, muon_purity, proton_purity);
302 proton_track =
track;
304 else if (muon_completion > 0.5) {
305 FillReco(1, *muon, *proton, muon_completion, proton_completion, muon_purity, proton_purity);
308 else if (proton_completion > 0.5) {
309 FillReco(2, *muon, *proton, muon_completion, proton_completion, muon_purity, proton_purity);
310 proton_track =
track;
313 if (muon_track && proton_track && muon_track != proton_track) {
314 FillVertex(muon->Position().Vect(), muon_track, proton_track);
318 float Completion(
const simb::MCParticle &particle,
float particleE,
const std::vector<std::pair<int, float>> &matches,
const std::vector<simb::MCParticle> &particles) {
319 for (
auto const &pair: matches) {
320 if (pair.first == particle.TrackId()) {
321 return pair.second / particleE;
327 float Purity(
const simb::MCParticle &particle,
float totalE,
const std::vector<std::pair<int, float>> &matches,
const std::vector<simb::MCParticle> &particles) {
329 for (
auto const &pair: matches) {
330 bool matches =
false;
331 if (pair.first == particle.TrackId()) matches =
true;
333 for (
int i_d = 0; i_d < particle.NumberDaughters(); i_d++) {
334 if (pair.first == particle.Daughter(i_d)) {
335 bool showerDaughter =
true;
336 for (
unsigned i_p = 0; i_p < particles.size(); i_p++) {
337 if (pair.first == particles[i_p].TrackId()) {
338 showerDaughter = particles[i_p].Process() ==
"muIoni";
342 matches = showerDaughter;
347 if (matches) matchE += pair.second;
349 return matchE / totalE;
353 const std::vector<geoalgo::AABox> &boxes) {
357 if ((v0 - v1).Mag() < 1
e-6)
return 0;
370 for (
auto const &box: boxes) {
371 int n_contained = box.Contain(p0) + box.Contain(
p1);
373 if (n_contained == 2) {
374 length = (v1 - v0).Mag();
378 if (n_contained == 1) {
383 if (intersections.size() == 0) {
386 bool p0_edge = algo.
SqDist(p0, box) <
tol;
388 assert(p0_edge || p1_edge);
392 if ((p0_edge && box.Contain(p0)) || (box.Contain(
p1) && p1_edge))
395 else if ((p0_edge && box.Contain(
p1)) || (box.Contain(p0) && p1_edge)) {
396 length = (v1 - v0).Mag();
408 else if (intersections.size() == 2) {
409 length += (intersections.at(0).ToTLorentzVector().Vect() - intersections.at(1).ToTLorentzVector().Vect()).Mag();
413 else if (intersections.size() == 1) {
415 TVector3 int_tv(intersections.at(0).ToTLorentzVector().Vect());
416 length += ( box.Contain(p0) ? (v0 - int_tv).Mag() : (v1 - int_tv).Mag() );
421 if (n_contained == 0) {
423 if (!(intersections.size() == 0 || intersections.size() == 2)) {
428 bool p0_edge = algo.
SqDist(p0, box) <
tol;
431 TVector3 vint = intersections.at(0).ToTLorentzVector().Vect();
433 bool p0_int = (v0 - vint).Mag() <
tol;
434 bool p1_int = (v1 - vint).Mag() <
tol;
436 assert((p0_int && p0_edge) != (p1_int && p1_edge));
441 if (p0_edge && p1_edge) {
442 length += (v0 - v1).Mag();
448 else if (intersections.size() == 2) {
449 TVector3 start(intersections.at(0).ToTLorentzVector().Vect());
450 TVector3
end(intersections.at(1).ToTLorentzVector().Vect());
451 length += (start -
end).Mag();
Algorithm to compute various geometrical relation among geometrical objects. In particular functions ...
void InitReco(unsigned i, const std::string &prefix)
Utilities related to art service access.
double ContainedLength(const TVector3 &v0, const TVector3 &v1, const std::vector< geo::BoxBoundedGeo > &boxes)
void FillTrue(const simb::MCParticle &muon, const simb::MCParticle &proton)
const geo::GeometryCore * geometry
void FillReco(unsigned i, const simb::MCParticle &muon, const simb::MCParticle &proton, float muon_completion, float proton_completion, float muon_purity, float proton_purity)
double SqDist(const Line_t &line, const Point_t &pt) const
Declaration of signal hit object.
Representation of a simple 3D line segment Defines a finite 3D straight line by having the start and ...
Geometry information for a single TPC.
MuPVertexStudy(fhicl::ParameterSet const &p)
std::vector< geo::BoxBoundedGeo > fActiveVolumes
MuPVertexStudy & operator=(MuPVertexStudy const &)=delete
geo::BoxBoundedGeo const & ActiveBoundingBox() const
Returns the box of the active volume of this TPC.
process_name use argoneut_mc_hitfinder track
TPC_iterator begin_TPC() const
Returns an iterator pointing to the first TPC in the detector.
std::vector< std::pair< int, float > > AllTrueParticleIDEnergyMatches(const detinfo::DetectorClocksData &clockData, const std::vector< art::Ptr< recob::Hit > > &hits, bool rollup_unsaved_ids=1)
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Access the description of detector geometry.
Point_t const & Start() const
Access to track position at different points.
Ionization at a point of the TPC sensitive volume.
float ParticleLength(const simb::MCParticle &particle)
std::vector< std::vector< geo::BoxBoundedGeo > > fTPCVolumes
auto end(FixedBins< T, C > const &) noexcept
Description of geometry of one entire detector.
Declaration of cluster object.
Provides recob::Track data product.
Provides a base class aware of world box coordinates.
IteratorBox< cryostat_iterator,&GeometryCore::begin_cryostat,&GeometryCore::end_cryostat > IterateCryostats() const
Enables ranged-for loops on all cryostats of the detector.
process_name can override from command line with o or output muon
A base class aware of world box coordinatesAn object describing a simple shape can inherit from this ...
void analyze(art::Event const &e) override
VertexHistos fVertexHistos
Point_t const & End() const
std::array< TrackHistos, 3 > fTrackHistos
float Completion(const simb::MCParticle &particle, float particleE, const std::vector< std::pair< int, float >> &matches, const std::vector< simb::MCParticle > &particles)
float Purity(const simb::MCParticle &particle, float totalE, const std::vector< std::pair< int, float >> &matches, const std::vector< simb::MCParticle > &particles)
void FillVertex(const TVector3 vertex, const recob::Track *muon, const recob::Track *proton)
float TotalHitEnergy(const detinfo::DetectorClocksData &clockData, const std::vector< art::Ptr< recob::Hit > > &hits)
art::ServiceHandle< art::TFileService > tfs
std::vector< Point_t > Intersection(const AABox_t &box, const HalfLine_t &line, bool back=false) const
Intersection between a HalfLine and an AABox.
Forward iterator browsing all geometry elements in the detector.
physics associatedGroupsWithLeft p1
art framework interface to geometry description
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a "fitted" track:
TPC_iterator end_TPC() const
Returns an iterator pointing after the last TPC in the detector.