From 94c59df6e4d7797c25be05885b2973783e182069 Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Wed, 19 Oct 2022 10:15:26 -0500 Subject: [PATCH 01/52] first build + commit --- sbndcode/CMakeLists.txt | 2 + sbndcode/Calorimetry/CMakeLists.txt | 42 ++++++ sbndcode/Calorimetry/LightCaloAna_module.cc | 158 ++++++++++++++++++++ sbndcode/Calorimetry/lightcalo.fcl | 9 ++ sbndcode/Calorimetry/run_lightcalo.fcl | 19 +++ 5 files changed, 230 insertions(+) create mode 100644 sbndcode/Calorimetry/CMakeLists.txt create mode 100644 sbndcode/Calorimetry/LightCaloAna_module.cc create mode 100644 sbndcode/Calorimetry/lightcalo.fcl create mode 100644 sbndcode/Calorimetry/run_lightcalo.fcl diff --git a/sbndcode/CMakeLists.txt b/sbndcode/CMakeLists.txt index e28ee45d8..9ba8f903f 100644 --- a/sbndcode/CMakeLists.txt +++ b/sbndcode/CMakeLists.txt @@ -32,3 +32,5 @@ add_subdirectory(FlashMatch) add_subdirectory(Filters) add_subdirectory(ToFStudies) + +add_subdirectory(Calorimetry) diff --git a/sbndcode/Calorimetry/CMakeLists.txt b/sbndcode/Calorimetry/CMakeLists.txt new file mode 100644 index 000000000..8636e5820 --- /dev/null +++ b/sbndcode/Calorimetry/CMakeLists.txt @@ -0,0 +1,42 @@ + +art_make( + MODULE_LIBRARIES larcorealg_Geometry + larcore_Geometry_Geometry_service + larsim_Simulation lardataobj_Simulation + larsim_MCCheater_BackTrackerService_service + larsim_MCCheater_ParticleInventoryService_service + lardata_Utilities + larevt_Filters + lardataobj_RawData + lardataobj_RecoBase + larreco_Calorimetry + larreco_RecoAlg + lardata_RecoObjects + larpandora_LArPandoraInterface + sbndcode_CRTUtils + sbndcode_CRT + sbnobj_Common_CRT + nusimdata::SimulationBase + art::Framework_Core + art::Framework_Principal + art::Framework_Services_Registry + art_root_io::tfile_support ROOT::Core + art_root_io::TFileService_service + art::Persistency_Common canvas + art::Persistency_Provenance canvas + art::Utilities canvas + messagefacility::MF_MessageLogger + + fhiclcpp::fhiclcpp + ROOT::Geom + ROOT::XMLIO + ROOT::Gdml + ${ROOT_BASIC_LIB_LIST} + sbndcode_RecoUtils + sbndcode_OpDetSim + ) + +# install_headers() +install_fhicl() +install_source() + diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc new file mode 100644 index 000000000..5d8112bea --- /dev/null +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -0,0 +1,158 @@ +//////////////////////////////////////////////////////////////////////// +// Class: LightCaloAna +// Plugin Type: analyzer (Unknown Unknown) +// File: LightCaloAna_module.cc +// +// Generated at Fri Oct 14 13:43:49 2022 by Lynn Tung using cetskelgen +// from version . +//////////////////////////////////////////////////////////////////////// + +#include "art/Framework/Core/EDAnalyzer.h" +#include "art/Framework/Core/ModuleMacros.h" +#include "art/Framework/Principal/Event.h" +#include "art/Framework/Principal/Handle.h" +#include "art/Framework/Principal/Run.h" +#include "art/Framework/Principal/SubRun.h" +#include "canvas/Utilities/InputTag.h" +#include "fhiclcpp/ParameterSet.h" +#include "messagefacility/MessageLogger/MessageLogger.h" + +// Additional framework includes +#include "art_root_io/TFileService.h" + +#include "canvas/Persistency/Common/FindMany.h" +#include "canvas/Persistency/Common/FindManyP.h" +#include "canvas/Persistency/Common/FindOne.h" +#include "canvas/Persistency/Common/FindOneP.h" +#include "canvas/Persistency/Common/Ptr.h" +#include "canvas/Persistency/Common/PtrVector.h" + +// LArSoft includes +#include "lardataobj/RecoBase/PFParticle.h" +#include "lardataobj/RecoBase/Slice.h" +#include "lardataobj/RecoBase/OpHit.h" +#include "lardataobj/RecoBase/OpFlash.h" +#include "lardataobj/AnalysisBase/T0.h" +#include "lardataobj/RecoBase/PFParticleMetadata.h" + +// SBND includes +#include "sbnobj/Common/Reco/SimpleFlashMatchVars.h" + + +namespace sbnd { + class LightCaloAna; +} + + +class sbnd::LightCaloAna : public art::EDAnalyzer { +public: + explicit LightCaloAna(fhicl::ParameterSet const& p); + // The compiler-generated destructor is fine for non-base + // classes without bare pointers or other resource use. + + // Plugins should not be copied or assigned. + LightCaloAna(LightCaloAna const&) = delete; + LightCaloAna(LightCaloAna&&) = delete; + LightCaloAna& operator=(LightCaloAna const&) = delete; + LightCaloAna& operator=(LightCaloAna&&) = delete; + + // Required functions. + void analyze(art::Event const& e) override; + +private: + + std::vector _opflash_producer_v; ///< The OpFlash producers (to be set) + std::string _slice_producer; ///< The Slice producer (to be set) + std::string _flashmatch_producer; + + int _run, _subrun, _event; +}; + + +sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) + : EDAnalyzer{p} // , + // More initializers here. +{ + _opflash_producer_v = p.get>("OpFlashProducers"); + _slice_producer = p.get("SliceProducer"); + _flashmatch_producer = p.get("FlashMatchProducer"); + // Call appropriate consumes<>() for any products to be retrieved by this module. +} + +void sbnd::LightCaloAna::analyze(art::Event const& e) +{ + _run = e.id().run(); + _subrun = e.id().subRun(); + _event = e.id().event(); + std::cout << "run: " << _run << ", subrun: " << _subrun << ", event: " << _event << std::endl; + + // get slices + ::art::Handle> slice_h; + e.getByLabel(_slice_producer, slice_h); + if(!slice_h.isValid() || slice_h->empty()){ + std::cout << "dont have good slices!" << std::endl; + return; + } + + ::art::Handle> pfp_h; + e.getByLabel(_slice_producer, pfp_h); + if(!pfp_h.isValid() || pfp_h->empty()) { + std::cout << "don't have good PFParticle!" << std::endl; + return; + } + + auto const & flash0_h = e.getValidHandle>(_opflash_producer_v[0]); + auto const & flash1_h = e.getValidHandle>(_opflash_producer_v[1]); + if( (!flash0_h.isValid() || flash0_h->empty()) && (!flash1_h.isValid() || flash1_h->empty())) { + std::cout << "don't have good flashes from producer " << _opflash_producer_v[0] << " or " << _opflash_producer_v[1] << std::endl; + return; + } + + // Construct the vector of Slices + std::vector> slice_v; + art::fill_ptr_vector(slice_v, slice_h); + + // Get associations + art::FindManyP slice_to_pfps (slice_h, e, _slice_producer); + art::FindManyP pfp_to_meta(pfp_h, e, _slice_producer); + art::FindManyP pfps_to_sfm (pfp_h, e, _flashmatch_producer); + + std::vector> passed_slices_v; + + for (size_t n_slice=0; n_slice < slice_v.size(); n_slice++){ + float nu_score = -9999; + float fm_score = -9999; + auto slice = slice_v[n_slice]; + std::vector> pfp_v = slice_to_pfps.at(n_slice); + for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ + auto pfp = pfp_v[n_pfp]; + + // only select the PRIMARY pfp + if(!pfp->IsPrimary() && (abs(pfp->PdgCode()) == 12 || abs(pfp->PdgCode()) == 14|| abs(pfp->PdgCode()) == 16)) + continue; + + // if primary, get nu-score + const std::vector> pfpmeta_v = pfp_to_meta.at(pfp->Self()); + const art::Ptr pfpmeta = pfpmeta_v.front(); + larpandoraobj::PFParticleMetadata::PropertiesMap propmap = pfpmeta->GetPropertiesMap(); + if (propmap.count("NuScore")) nu_score = propmap.at("NuScore"); + else nu_score = -1; + // select slices that have nuscores > 0.4 + if (nu_score < 0.4) + continue; + + // get fm-score + std::vector> fm_v = pfps_to_sfm.at(pfp.key()); + std::cout << "fm_v size: " << fm_v.size() << std::endl; + for (size_t n_fm=0; n_fm < fm_v.size(); n_fm++){ + auto fm = fm_v.at(n_fm); + fm_score = fm->score.total; + std::cout << "fm_score: " << fm_score << std::endl; + } // end flashmatch loop + } // end pfp loop + if (fm_score < 7) + passed_slices_v.push_back(slice); + } // end slice loop +} // end analyze + +DEFINE_ART_MODULE(sbnd::LightCaloAna) diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl new file mode 100644 index 000000000..5a92cf499 --- /dev/null +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -0,0 +1,9 @@ +BEGIN_PROLOG +lightcalo_ana: +{ + module_type: "LightCaloAna" + OpFlashProducers: ["opflashtpc0", "opflashtpc1"] + SliceProducer: "pandora" + FlashMatchProducer: "fmatch" +} +END_PROLOG diff --git a/sbndcode/Calorimetry/run_lightcalo.fcl b/sbndcode/Calorimetry/run_lightcalo.fcl new file mode 100644 index 000000000..5284634e9 --- /dev/null +++ b/sbndcode/Calorimetry/run_lightcalo.fcl @@ -0,0 +1,19 @@ +#include "lightcalo.fcl" + +process_name: LightCaloAna + +source: +{ + module_type: RootInput + maxEvents: -1 +} + +physics: +{ + analyzers: + { + ana: @local::lightcalo_ana + } + path: [ana] + end_paths: [path] +} \ No newline at end of file From 08bd042de9b4555fd471c827a958a92e9f96accf Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Fri, 21 Oct 2022 16:05:32 -0500 Subject: [PATCH 02/52] added root tree, more explicit cut parameters, and opflashes --- sbndcode/Calorimetry/LightCaloAna_module.cc | 105 ++++++++++++++++++-- sbndcode/Calorimetry/lightcalo.fcl | 2 + sbndcode/Calorimetry/run_lightcalo.fcl | 15 +++ 3 files changed, 111 insertions(+), 11 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index 5d8112bea..58778666c 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -38,6 +38,9 @@ // SBND includes #include "sbnobj/Common/Reco/SimpleFlashMatchVars.h" +#include "TFile.h" +#include "TTree.h" + namespace sbnd { class LightCaloAna; @@ -61,11 +64,24 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { private: + // define functions + // art::Ptr SelectSlice(std::vector> slice_v, std::vector nuscore_v, std::vector fmscore_v + // std::vector> opflash_v); + + std::vector> MatchOpFlash(std::vector> fm_v, + std::vector> flash_v); std::vector _opflash_producer_v; ///< The OpFlash producers (to be set) std::string _slice_producer; ///< The Slice producer (to be set) std::string _flashmatch_producer; + float _nuscore_cut; + float _fmscore_cut; + TTree* _tree; int _run, _subrun, _event; + std::vector _slc_pfpid; + std::vector _slc_nuscore; + std::vector _slc_fmscore; + std::vector _slc_fmtime; }; @@ -76,7 +92,17 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _opflash_producer_v = p.get>("OpFlashProducers"); _slice_producer = p.get("SliceProducer"); _flashmatch_producer = p.get("FlashMatchProducer"); - // Call appropriate consumes<>() for any products to be retrieved by this module. + _nuscore_cut = p.get("nuScoreCut"); + _fmscore_cut = p.get("fmScoreCut"); + + art::ServiceHandle fs; + _tree = fs->make("slice_tree",""); + _tree->Branch("run", &_run, "run/I"); + _tree->Branch("subrun", &_subrun, "subrun/I"); + _tree->Branch("event", &_event, "event/I"); + _tree->Branch("slc_pfpid", "std::vector", &_slc_pfpid); + _tree->Branch("slc_nuscore", "std::vector", &_slc_nuscore); + _tree->Branch("slc_fmscore", "std::vector", &_slc_fmscore); } void sbnd::LightCaloAna::analyze(art::Event const& e) @@ -117,19 +143,27 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) art::FindManyP pfp_to_meta(pfp_h, e, _slice_producer); art::FindManyP pfps_to_sfm (pfp_h, e, _flashmatch_producer); - std::vector> passed_slices_v; + _slc_pfpid.clear(); + _slc_nuscore.clear(); + _slc_fmscore.clear(); + + std::vector> match_slices_v; + std::vector> match_fm_v; for (size_t n_slice=0; n_slice < slice_v.size(); n_slice++){ float nu_score = -9999; float fm_score = -9999; + float fm_time = -9999; auto slice = slice_v[n_slice]; + bool found_fm = false; std::vector> pfp_v = slice_to_pfps.at(n_slice); for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ auto pfp = pfp_v[n_pfp]; // only select the PRIMARY pfp - if(!pfp->IsPrimary() && (abs(pfp->PdgCode()) == 12 || abs(pfp->PdgCode()) == 14|| abs(pfp->PdgCode()) == 16)) + if(!pfp->IsPrimary() && !(abs(pfp->PdgCode()) == 12 || abs(pfp->PdgCode()) == 14|| abs(pfp->PdgCode()) == 16)) continue; + _slc_pfpid.push_back(pfp->Self()); // if primary, get nu-score const std::vector> pfpmeta_v = pfp_to_meta.at(pfp->Self()); @@ -137,22 +171,71 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) larpandoraobj::PFParticleMetadata::PropertiesMap propmap = pfpmeta->GetPropertiesMap(); if (propmap.count("NuScore")) nu_score = propmap.at("NuScore"); else nu_score = -1; - // select slices that have nuscores > 0.4 - if (nu_score < 0.4) - continue; - + _slc_nuscore.push_back(nu_score); + // get fm-score std::vector> fm_v = pfps_to_sfm.at(pfp.key()); - std::cout << "fm_v size: " << fm_v.size() << std::endl; + if (fm_v.empty()){ + _slc_fmscore.push_back(-999); + continue; + } + if (fm_v.size() > 1) + std::cout << "more than one match for one pfp?" << std::endl; for (size_t n_fm=0; n_fm < fm_v.size(); n_fm++){ auto fm = fm_v.at(n_fm); fm_score = fm->score.total; - std::cout << "fm_score: " << fm_score << std::endl; + fm_time = fm->time; + if (nu_score > _nuscore_cut && fm_score < _fmscore_cut && fm_score > 0){ + found_fm = true; + match_fm_v.push_back(fm); + } } // end flashmatch loop + if (found_fm ==true) match_slices_v.push_back(slice); + _slc_fmscore.push_back(fm_score); + _slc_fmtime.push_back(fm_time); } // end pfp loop - if (fm_score < 7) - passed_slices_v.push_back(slice); } // end slice loop + if (match_slices_v.size() != match_fm_v.size()){ + std::cout << "slice and flashmatch vector length mismatch!" << std::endl; + return; + } + + // tpc0 + std::vector> flash0_v; + art::fill_ptr_vector(flash0_v, flash0_h); + std::vector> match_op0 = MatchOpFlash(match_fm_v,flash0_v); + + // tpc1 + std::vector> flash1_v; + art::fill_ptr_vector(flash1_v, flash1_h); + std::vector> match_op1 = MatchOpFlash(match_fm_v,flash1_v); + + _tree->Fill(); } // end analyze + +// define functions + +std::vector> sbnd::LightCaloAna::MatchOpFlash(std::vector> fm_v, + std::vector> flash_v){ + std::vector> matched_opflashes; + for (size_t ifm=0; ifm nullOpFlash; + bool found_match = false; + auto match_time = fm->time; + for (size_t iop=0; iopTime() - match_time) < 0.01){ + found_match = true; + matched_opflashes.push_back(opflash); + break; + } + } + if (found_match == false) matched_opflashes.push_back(nullOpFlash); + } + if (matched_opflashes.size() != fm_v.size()) std::cout << "mismatched opflash and simpleflash vector sizes!" << std::endl; + return matched_opflashes; +} + DEFINE_ART_MODULE(sbnd::LightCaloAna) diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index 5a92cf499..dc6026881 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -5,5 +5,7 @@ lightcalo_ana: OpFlashProducers: ["opflashtpc0", "opflashtpc1"] SliceProducer: "pandora" FlashMatchProducer: "fmatch" + nuScoreCut: 0.4 # accep nusScore > 0.4, to analyze all slices, set = 0 + fmScoreCut: 7 # accept 0 < fm score < fmScoreCut, to analyze all slices, set = 1e3 } END_PROLOG diff --git a/sbndcode/Calorimetry/run_lightcalo.fcl b/sbndcode/Calorimetry/run_lightcalo.fcl index 5284634e9..af8a902f9 100644 --- a/sbndcode/Calorimetry/run_lightcalo.fcl +++ b/sbndcode/Calorimetry/run_lightcalo.fcl @@ -1,7 +1,22 @@ +#include "services_sbnd.fcl" +#include "simulationservices_sbnd.fcl" +#include "messages_sbnd.fcl" +#include "sam_sbnd.fcl" + #include "lightcalo.fcl" process_name: LightCaloAna +services: +{ + TFileService: { fileName: "lightcalo_tree.root" } + RandomNumberGenerator: {} + message: @local::sbnd_message_services_prod # from messages_sbnd.fcl + FileCatalogMetadata: @local::sbnd_file_catalog_mc # from sam_sbnd.fcl + @table::sbnd_services # from services_sbnd.fcl + @table::sbnd_g4_services +} + source: { module_type: RootInput From fa2b8a7fab089fc70e56b1a624a5cd92315d382c Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Mon, 24 Oct 2022 10:25:05 -0500 Subject: [PATCH 03/52] first commit of light reco attempt using visibility map --- sbndcode/Calorimetry/LightCaloAna_module.cc | 112 ++++++++++++++++++-- sbndcode/Calorimetry/lightcalo.fcl | 8 +- 2 files changed, 110 insertions(+), 10 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index 58778666c..a58688b77 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -19,7 +19,6 @@ // Additional framework includes #include "art_root_io/TFileService.h" - #include "canvas/Persistency/Common/FindMany.h" #include "canvas/Persistency/Common/FindManyP.h" #include "canvas/Persistency/Common/FindOne.h" @@ -28,19 +27,28 @@ #include "canvas/Persistency/Common/PtrVector.h" // LArSoft includes -#include "lardataobj/RecoBase/PFParticle.h" +#include "lardata/Utilities/AssociationUtil.h" #include "lardataobj/RecoBase/Slice.h" -#include "lardataobj/RecoBase/OpHit.h" +#include "lardataobj/RecoBase/PFParticle.h" +#include "lardataobj/RecoBase/PFParticleMetadata.h" +#include "lardataobj/RecoBase/SpacePoint.h" +#include "lardataobj/RecoBase/Hit.h" #include "lardataobj/RecoBase/OpFlash.h" #include "lardataobj/AnalysisBase/T0.h" -#include "lardataobj/RecoBase/PFParticleMetadata.h" +#include "larcore/CoreUtils/ServiceUtil.h" +#include "larsim/PhotonPropagation/SemiAnalyticalModel.h" // SBND includes #include "sbnobj/Common/Reco/SimpleFlashMatchVars.h" +#include "sbndcode/OpDetSim/sbndPDMapAlg.hh" +// ROOT includes #include "TFile.h" #include "TTree.h" +// C++ includes +#include +#include namespace sbnd { class LightCaloAna; @@ -70,12 +78,17 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { std::vector> MatchOpFlash(std::vector> fm_v, std::vector> flash_v); + // std::vector CalcVisibility(std::vector xyz_v, std::vector charge_v, std::string light_type); std::vector _opflash_producer_v; ///< The OpFlash producers (to be set) std::string _slice_producer; ///< The Slice producer (to be set) std::string _flashmatch_producer; float _nuscore_cut; float _fmscore_cut; + std::unique_ptr _semi_model; + fhicl::ParameterSet _vuv_params; + fhicl::ParameterSet _vis_params; + TTree* _tree; int _run, _subrun, _event; std::vector _slc_pfpid; @@ -89,6 +102,10 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) : EDAnalyzer{p} // , // More initializers here. { + _vuv_params = p.get("VUVHits"); + _vis_params = p.get("VIVHits"); + _semi_model = std::make_unique(_vuv_params, _vis_params, true, false); + _opflash_producer_v = p.get>("OpFlashProducers"); _slice_producer = p.get("SliceProducer"); _flashmatch_producer = p.get("FlashMatchProducer"); @@ -127,6 +144,13 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) return; } + ::art::Handle> spacepoint_h; + e.getByLabel(_slice_producer, spacepoint_h); + if(!spacepoint_h.isValid() || spacepoint_h->empty()) { + std::cout << "Don't have good SpacePoints!" << std::endl; + return; + } + auto const & flash0_h = e.getValidHandle>(_opflash_producer_v[0]); auto const & flash1_h = e.getValidHandle>(_opflash_producer_v[1]); if( (!flash0_h.isValid() || flash0_h->empty()) && (!flash1_h.isValid() || flash1_h->empty())) { @@ -139,9 +163,11 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) art::fill_ptr_vector(slice_v, slice_h); // Get associations - art::FindManyP slice_to_pfps (slice_h, e, _slice_producer); + art::FindManyP slice_to_pfp (slice_h, e, _slice_producer); art::FindManyP pfp_to_meta(pfp_h, e, _slice_producer); - art::FindManyP pfps_to_sfm (pfp_h, e, _flashmatch_producer); + art::FindManyP pfp_to_sfm (pfp_h, e, _flashmatch_producer); + art::FindManyP pfp_to_spacepoint(pfp_h, e, _slice_producer); + art::FindManyP spacepoint_to_hit(spacepoint_h, e, _slice_producer); _slc_pfpid.clear(); _slc_nuscore.clear(); @@ -156,7 +182,7 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) float fm_time = -9999; auto slice = slice_v[n_slice]; bool found_fm = false; - std::vector> pfp_v = slice_to_pfps.at(n_slice); + std::vector> pfp_v = slice_to_pfp.at(n_slice); for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ auto pfp = pfp_v[n_pfp]; @@ -174,7 +200,7 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) _slc_nuscore.push_back(nu_score); // get fm-score - std::vector> fm_v = pfps_to_sfm.at(pfp.key()); + std::vector> fm_v = pfp_to_sfm.at(pfp.key()); if (fm_v.empty()){ _slc_fmscore.push_back(-999); continue; @@ -199,7 +225,8 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) std::cout << "slice and flashmatch vector length mismatch!" << std::endl; return; } - + + // get relevant opflashes // tpc0 std::vector> flash0_v; art::fill_ptr_vector(flash0_v, flash0_h); @@ -210,6 +237,39 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) art::fill_ptr_vector(flash1_v, flash1_h); std::vector> match_op1 = MatchOpFlash(match_fm_v,flash1_v); + // calculate total Q + + // calculate total L + // first get the visibilities of each PMT for the relevant slice + + // get information to do charge-weighted average + std::vector slice_xyz; + std::vector slice_charge; + + for (size_t n_slice=0; n_slice < match_slices_v.size(); n_slice++){ + auto slice = match_slices_v[n_slice]; + std::vector> pfp_v = slice_to_pfp.at(slice.key()); + for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ + auto pfp = pfp_v[n_pfp]; + std::vector> sp_v = pfp_to_spacepoint.at(pfp.key()); + for (size_t n_sp=0; n_sp < sp_v.size(); n_sp++){ + auto sp = sp_v[n_sp]; + const auto &position(sp->XYZ()); + geo::Point_t xyz(position[0],position[1],position[2]); + slice_xyz.push_back(xyz); + + // get charge information + double sp_charge = 0; + std::vector> hit_v = spacepoint_to_hit.at(sp.key()); + for (size_t n_hit=0; n_hit < hit_v.size(); n_hit++){ + auto hit = hit_v[n_hit]; + sp_charge += (1/.0201293)*hit->Integral(); + } + slice_charge.push_back(sp_charge); + } + } + } // end slice loop + _tree->Fill(); } // end analyze @@ -238,4 +298,38 @@ std::vector> sbnd::LightCaloAna::MatchOpFlash(std::vect return matched_opflashes; } +/* +std::vector sbnd::LightCaloAna::CalcVisibility(std::vector xyz_v, + std::vector charge_v, + std::string light_type){ + // returns of a vector (len is # of opdet) for the visibility for every opdet + if (xyz_v.size() != charge_v.size()) std::cout << "spacepoint coord and charge vector size mismatch" << std::endl; + + std::vector visibility; + double sum_charge = std::accumulate(charge_v.begin(), charge_v.end(), 0.0); + + for (size_t i=0; i temp_visibility; + std::cout << light_type << std::endl; + _semi_model->detectedDirectVisibilities(temp_visibility, xyz); + // if (light_type == "reflected") + // _semi_model->detectedReflectedVisibilities(temp_visibility, xyz); + + // weight the temp visibility map by charge + std::transform(temp_visibility.begin(), temp_visibility.end(), + temp_visibility.begin(), [charge](double &k){ return charge*k; }); + + // add the visibility map for this spacepoint to the total + std::transform(visibility.begin(), visibility.end(), temp_visibility.begin(), + visibility.begin(), std::plus()); + } // end spacepoint loop + // normalize by the total charge + std::transform(visibility.begin(), visibility.end(), + visibility.begin(), [sum_charge](double &k){ return k/sum_charge; }); + return visibility; +} +*/ + DEFINE_ART_MODULE(sbnd::LightCaloAna) diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index dc6026881..dd8fb34ca 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -1,11 +1,17 @@ +#include "opticalsimparameterisations_sbnd.fcl" + BEGIN_PROLOG lightcalo_ana: { module_type: "LightCaloAna" + + VUVHits: @local::sbnd_vuv_RS100cm_hits_parameterization + VIVHits: @local::sbnd_vis_RS100cm_hits_parameterization + OpFlashProducers: ["opflashtpc0", "opflashtpc1"] SliceProducer: "pandora" FlashMatchProducer: "fmatch" - nuScoreCut: 0.4 # accep nusScore > 0.4, to analyze all slices, set = 0 + nuScoreCut: 0.4 # accept nusScore > 0.4, to analyze all slices, set = 0 fmScoreCut: 7 # accept 0 < fm score < fmScoreCut, to analyze all slices, set = 1e3 } END_PROLOG From ccea7c681404156584df288c8e2547e43f143cc5 Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Fri, 4 Nov 2022 11:38:01 -0500 Subject: [PATCH 04/52] working version with reco/true comparisons --- sbndcode/Calorimetry/CMakeLists.txt | 15 +- sbndcode/Calorimetry/LightCaloAna_module.cc | 251 ++++++++++++++++---- 2 files changed, 214 insertions(+), 52 deletions(-) diff --git a/sbndcode/Calorimetry/CMakeLists.txt b/sbndcode/Calorimetry/CMakeLists.txt index 8636e5820..05e490be1 100644 --- a/sbndcode/Calorimetry/CMakeLists.txt +++ b/sbndcode/Calorimetry/CMakeLists.txt @@ -1,6 +1,19 @@ art_make( - MODULE_LIBRARIES larcorealg_Geometry + LIB_LIBRARIES larsim_PhotonPropagation + larsim_PhotonPropagation_PhotonVisibilityService_service + larsim_LegacyLArG4 + larcorealg_GeoAlgo + sbncode_OpT0Finder_flashmatch_Base + lardataobj_Simulation + + MODULE_LIBRARIES + larsim_PhotonPropagation + larsim_PhotonPropagation_PhotonVisibilityService_service + larsim_LegacyLArG4 + larcorealg_GeoAlgo + sbncode_OpT0Finder_flashmatch_Base + larcorealg_Geometry larcore_Geometry_Geometry_service larsim_Simulation lardataobj_Simulation larsim_MCCheater_BackTrackerService_service diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index a58688b77..191243419 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -37,6 +37,10 @@ #include "lardataobj/AnalysisBase/T0.h" #include "larcore/CoreUtils/ServiceUtil.h" #include "larsim/PhotonPropagation/SemiAnalyticalModel.h" +#include "lardata/DetectorInfoServices/DetectorPropertiesService.h" +#include "lardata/DetectorInfoServices/DetectorClocksService.h" +#include "lardataobj/Simulation/SimPhotons.h" +#include "lardataobj/Simulation/SimEnergyDeposit.h" // SBND includes #include "sbnobj/Common/Reco/SimpleFlashMatchVars.h" @@ -75,12 +79,16 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { // define functions // art::Ptr SelectSlice(std::vector> slice_v, std::vector nuscore_v, std::vector fmscore_v // std::vector> opflash_v); - - std::vector> MatchOpFlash(std::vector> fm_v, - std::vector> flash_v); - // std::vector CalcVisibility(std::vector xyz_v, std::vector charge_v, std::string light_type); - std::vector _opflash_producer_v; ///< The OpFlash producers (to be set) - std::string _slice_producer; ///< The Slice producer (to be set) + opdet::sbndPDMapAlg _opdetmap; //map for photon detector types + unsigned int _nchan = _opdetmap.size(); + + bool MatchOpFlash(std::vector> fm_v, + std::vector> flash_v, + std::vector> &match_v); + std::vector CalcVisibility(std::vector xyz_v, std::vector charge_v); + void CalcLight(std::vector flash_pe_v, std::vector visibility, std::vector&total_pe_v); + std::vector _opflash_producer_v; + std::string _slice_producer; std::string _flashmatch_producer; float _nuscore_cut; float _fmscore_cut; @@ -95,6 +103,18 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { std::vector _slc_nuscore; std::vector _slc_fmscore; std::vector _slc_fmtime; + + TTree* _tree2; + int _nmatch=0; + std::vector _edep_time; + double _opflash_time; + + double _true_gamma; + double _true_charge; + double _true_energy; + double _slice_L; + double _slice_Q; + double _slice_E; }; @@ -120,6 +140,17 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _tree->Branch("slc_pfpid", "std::vector", &_slc_pfpid); _tree->Branch("slc_nuscore", "std::vector", &_slc_nuscore); _tree->Branch("slc_fmscore", "std::vector", &_slc_fmscore); + + _tree2 = fs->make("match_tree",""); + _tree2->Branch("nmatch", &_nmatch, "nmatch/I"); + _tree2->Branch("edep_time", "std::vector", &_edep_time); + _tree2->Branch("opflash_time", &_opflash_time, "opflash_time/D"); + _tree2->Branch("true_gamma", &_true_gamma, "true_gamma/D"); + _tree2->Branch("true_charge", &_true_charge, "true_charge/D"); + _tree2->Branch("true_energy", &_true_energy, "true_energy/D"); + _tree2->Branch("slice_L", &_slice_L, "slice_L/D"); + _tree2->Branch("slice_Q", &_slice_Q, "slice_Q/D"); + _tree2->Branch("slice_E", &_slice_E, "slice_E/D"); } void sbnd::LightCaloAna::analyze(art::Event const& e) @@ -164,6 +195,7 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) // Get associations art::FindManyP slice_to_pfp (slice_h, e, _slice_producer); + art::FindManyP slice_to_hit (slice_h, e, _slice_producer); art::FindManyP pfp_to_meta(pfp_h, e, _slice_producer); art::FindManyP pfp_to_sfm (pfp_h, e, _flashmatch_producer); art::FindManyP pfp_to_spacepoint(pfp_h, e, _slice_producer); @@ -221,64 +253,174 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) _slc_fmtime.push_back(fm_time); } // end pfp loop } // end slice loop + if (match_slices_v.empty() && !slice_v.empty()){ + std::cout << "no slices passed the cuts" << std::endl; + return; + } + if (match_slices_v.size() != match_fm_v.size()){ std::cout << "slice and flashmatch vector length mismatch!" << std::endl; return; } - + // get relevant opflashes // tpc0 std::vector> flash0_v; art::fill_ptr_vector(flash0_v, flash0_h); - std::vector> match_op0 = MatchOpFlash(match_fm_v,flash0_v); + std::vector> match_op0; + bool found_opflash0 = MatchOpFlash(match_fm_v,flash0_v, match_op0); // tpc1 std::vector> flash1_v; art::fill_ptr_vector(flash1_v, flash1_h); - std::vector> match_op1 = MatchOpFlash(match_fm_v,flash1_v); + std::vector> match_op1; + bool found_opflash1 = MatchOpFlash(match_fm_v,flash1_v, match_op1); - // calculate total Q + if (found_opflash0 == false && found_opflash1 == false){ + std::cout << "no opflashes matched to simpleflashes" << std::endl; + return; + } - // calculate total L - // first get the visibilities of each PMT for the relevant slice + const art::ValidHandle>& + energyDeps(e.getValidHandle>("ionandscint")); - // get information to do charge-weighted average - std::vector slice_xyz; - std::vector slice_charge; - for (size_t n_slice=0; n_slice < match_slices_v.size(); n_slice++){ + _nmatch++; + _edep_time.clear(); + + std::vector sp_xyz; + std::vector sp_charge; // vector of charge info for charge-weighting + + double flash_time = -999; + _slice_Q = 0; // total amount of charge + _slice_L = 0; // total amount of light + auto opflash0 = (match_op0.at(n_slice)); + auto opflash1 = (match_op1.at(n_slice)); + bool flash_in_0 = false; + bool flash_in_1 = false; + if (!opflash0.isNull() && opflash1.isNull()){ + flash_time = opflash0->Time(); + flash_in_0 = true; + } + else if ( opflash0.isNull() && !opflash1.isNull()){ + flash_time = opflash1->Time(); + flash_in_1 = true; + } + else if (!opflash0.isNull() && !opflash1.isNull()){ + flash_time = opflash0->Time(); + flash_in_0 = true; + flash_in_1 = true; + } + else if (opflash0.isNull() && opflash1.isNull()){ + std::cout << "err! no opflashes :(" << std::endl; + return; + } + auto slice = match_slices_v[n_slice]; + // find which plane has the most hits for this slice + std::vector> slice_hits_v = slice_to_hit.at(slice.key()); + int nhit0 = 0; + int nhit1 = 0; + int nhit2 = 0; + for (size_t i=0; i < slice_hits_v.size(); i++){ + auto hit = slice_hits_v[i]; + if (hit->View()==0) nhit0++; + if (hit->View()==1) nhit1++; + if (hit->View()==2) nhit2++; + } + uint plane = 2; + if ( nhit0 >= nhit1 && nhit0 >= nhit2) plane = 0; + else if ( nhit1 >= nhit0 && nhit1 >= nhit2) plane = 1; + else plane = 2; + + std::cout << "plane with most hits: " << plane << std::endl; + + // get charge information std::vector> pfp_v = slice_to_pfp.at(slice.key()); for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ auto pfp = pfp_v[n_pfp]; std::vector> sp_v = pfp_to_spacepoint.at(pfp.key()); for (size_t n_sp=0; n_sp < sp_v.size(); n_sp++){ auto sp = sp_v[n_sp]; - const auto &position(sp->XYZ()); - geo::Point_t xyz(position[0],position[1],position[2]); - slice_xyz.push_back(xyz); - - // get charge information - double sp_charge = 0; std::vector> hit_v = spacepoint_to_hit.at(sp.key()); for (size_t n_hit=0; n_hit < hit_v.size(); n_hit++){ auto hit = hit_v[n_hit]; - sp_charge += (1/.0201293)*hit->Integral(); + if (hit->View() !=plane) continue; + const auto &position(sp->XYZ()); + geo::Point_t xyz(position[0],position[1],position[2]); + // std::cout << "spacepoint pos: (" << position[0] << ", " << position[1] << ", " << position[2] << std::endl; + sp_xyz.push_back(xyz); + double drift_time = abs(200.0 - abs(position[0]))/(0.16); // in us, drift velocity = 0.16 cm/us + double atten_correction = std::exp(drift_time/10e3); // electron lifetime = 10e3 us, or 10 ms + double charge = (1/.0201293)*atten_correction*hit->Integral(); + sp_charge.push_back(charge); + _slice_Q += charge; } - slice_charge.push_back(sp_charge); + } // end spacepoint loop + } // end pfp loop + // get total L count + std::vector visibility_map = CalcVisibility(sp_xyz,sp_charge); + std::vector total_pe(_nchan, 0); + if (flash_in_0){ + auto flash_pe_v = opflash0->PEs(); + CalcLight(flash_pe_v, visibility_map, total_pe); + } + if (flash_in_1){ + auto flash_pe_v = opflash1->PEs(); + CalcLight(flash_pe_v, visibility_map, total_pe); + } + // calculate the average: + double sum_gamma = 0; + double counter = 0.0; + for (auto i : total_pe){ + if (i>0){ + counter+= 1.0; + sum_gamma += i; + } + } + // TO-DO: keep the amount of light as the average amount of light? + _slice_L = sum_gamma/counter; + _true_gamma = 0; + _true_charge = 0; + _true_energy = 0; + std::cout << "flash time: " << flash_time << std::endl; + for (const sim::SimEnergyDeposit& energyDep:*energyDeps){ + const double time = energyDep.Time() * 1e-3; + if (abs(time-flash_time) < 1){ + _true_gamma += energyDep.NumPhotons()/0.03; + _true_charge += energyDep.NumElectrons(); + _true_energy += energyDep.Energy(); + _edep_time.push_back(time); } } - } // end slice loop + _slice_E = (_slice_L + _slice_Q)*19.5*1e-6; + + std::cout << "true gamma: " << _true_gamma << std::endl; + std::cout << "calc gamma: " << _slice_L << std::endl; + std::cout << "true electrons: " << _true_charge << std::endl; + std::cout << "calc electrons: " << _slice_Q << std::endl; + std::cout << "true deposited energy: " << _true_energy << std::endl; + std::cout << "calc deposited energy: " << _slice_E << std::endl; + + std::cout << "ratio of gamma (calc/true): " << _slice_L/_true_gamma << std::endl; + std::cout << "ratio of electron (calc/true): " << _slice_Q/_true_charge << std::endl; + std::cout << "ratio of energy (calc/true): " << _slice_E/_true_energy << std::endl; + std::cout << "fractional energy difference: " << (_true_energy - _slice_E)/_true_energy << std::endl; + + _opflash_time = flash_time; + _tree2->Fill(); + } // end slice loop _tree->Fill(); } // end analyze // define functions -std::vector> sbnd::LightCaloAna::MatchOpFlash(std::vector> fm_v, - std::vector> flash_v){ - std::vector> matched_opflashes; +bool sbnd::LightCaloAna::MatchOpFlash(std::vector> fm_v, + std::vector> flash_v, + std::vector> &match_v){ + bool any_match = false; for (size_t ifm=0; ifm nullOpFlash; @@ -286,50 +428,57 @@ std::vector> sbnd::LightCaloAna::MatchOpFlash(std::vect auto match_time = fm->time; for (size_t iop=0; iopTime() - match_time) < 0.01){ + if (abs( opflash->Time() - match_time) < 0.05){ found_match = true; - matched_opflashes.push_back(opflash); + any_match = true; + match_v.push_back(opflash); break; } } - if (found_match == false) matched_opflashes.push_back(nullOpFlash); + if (found_match == false) match_v.push_back(nullOpFlash); } - if (matched_opflashes.size() != fm_v.size()) std::cout << "mismatched opflash and simpleflash vector sizes!" << std::endl; - return matched_opflashes; + if (match_v.size() != fm_v.size()) std::cout << "mismatched opflash and simpleflash vector sizes!" << std::endl; + return any_match; } -/* + std::vector sbnd::LightCaloAna::CalcVisibility(std::vector xyz_v, - std::vector charge_v, - std::string light_type){ + std::vector charge_v){ // returns of a vector (len is # of opdet) for the visibility for every opdet if (xyz_v.size() != charge_v.size()) std::cout << "spacepoint coord and charge vector size mismatch" << std::endl; - std::vector visibility; + std::vector visibility(_nchan, 0); double sum_charge = std::accumulate(charge_v.begin(), charge_v.end(), 0.0); for (size_t i=0; i temp_visibility; - std::cout << light_type << std::endl; - _semi_model->detectedDirectVisibilities(temp_visibility, xyz); - // if (light_type == "reflected") - // _semi_model->detectedReflectedVisibilities(temp_visibility, xyz); - - // weight the temp visibility map by charge - std::transform(temp_visibility.begin(), temp_visibility.end(), - temp_visibility.begin(), [charge](double &k){ return charge*k; }); - - // add the visibility map for this spacepoint to the total - std::transform(visibility.begin(), visibility.end(), temp_visibility.begin(), - visibility.begin(), std::plus()); + std::vector direct_visibility; + std::vector reflect_visibility; + _semi_model->detectedDirectVisibilities(direct_visibility, xyz); + _semi_model->detectedReflectedVisibilities(reflect_visibility, xyz); + if (visibility.size() != direct_visibility.size()) std::cout << "mismatch of visibility vector size" << std::endl; + + // sum direct and reflected, weight by charge, and add to total visibility map + for (size_t ivis=0; ivis flash_pe_v, + std::vector visibility, + std::vector &total_pe_v){ + for (size_t ichan = 0; ichan < flash_pe_v.size(); ichan++){ + auto pe = flash_pe_v[ichan]; + if(pe == 0) + continue; + total_pe_v[ichan] += (1/0.03)*pe*(1/visibility[ichan]); + } +} + DEFINE_ART_MODULE(sbnd::LightCaloAna) From afea365e8e3bc4e9ed4647835568776e0e6c6bc3 Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Fri, 11 Nov 2022 10:45:27 -0600 Subject: [PATCH 05/52] added backtracker info --- sbndcode/Calorimetry/CMakeLists.txt | 4 ++ sbndcode/Calorimetry/LightCaloAna_module.cc | 68 ++++++++++++--------- sbndcode/Calorimetry/run_lightcalo.fcl | 9 ++- 3 files changed, 50 insertions(+), 31 deletions(-) diff --git a/sbndcode/Calorimetry/CMakeLists.txt b/sbndcode/Calorimetry/CMakeLists.txt index 05e490be1..c317b4df2 100644 --- a/sbndcode/Calorimetry/CMakeLists.txt +++ b/sbndcode/Calorimetry/CMakeLists.txt @@ -6,8 +6,12 @@ art_make( larcorealg_GeoAlgo sbncode_OpT0Finder_flashmatch_Base lardataobj_Simulation + larsim_MCCheater_BackTrackerService_service + larsim_MCCheater_ParticleInventoryService_service + larsim_Utils MODULE_LIBRARIES + larsim_Utils larsim_PhotonPropagation larsim_PhotonPropagation_PhotonVisibilityService_service larsim_LegacyLArG4 diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index 191243419..03db64fe6 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -41,6 +41,9 @@ #include "lardata/DetectorInfoServices/DetectorClocksService.h" #include "lardataobj/Simulation/SimPhotons.h" #include "lardataobj/Simulation/SimEnergyDeposit.h" +#include "larcore/CoreUtils/ServiceUtil.h" +#include "larsim/MCCheater/BackTrackerService.h" +#include "lardata/DetectorInfoServices/DetectorClocksService.h" // SBND includes #include "sbnobj/Common/Reco/SimpleFlashMatchVars.h" @@ -98,11 +101,10 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { fhicl::ParameterSet _vis_params; TTree* _tree; - int _run, _subrun, _event; - std::vector _slc_pfpid; - std::vector _slc_nuscore; - std::vector _slc_fmscore; - std::vector _slc_fmtime; + // int _run, _subrun, _event; + std::vector _sp_x; + std::vector _sp_x_true; + std::vector _sp_peakT; TTree* _tree2; int _nmatch=0; @@ -134,15 +136,16 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) art::ServiceHandle fs; _tree = fs->make("slice_tree",""); - _tree->Branch("run", &_run, "run/I"); - _tree->Branch("subrun", &_subrun, "subrun/I"); - _tree->Branch("event", &_event, "event/I"); - _tree->Branch("slc_pfpid", "std::vector", &_slc_pfpid); - _tree->Branch("slc_nuscore", "std::vector", &_slc_nuscore); - _tree->Branch("slc_fmscore", "std::vector", &_slc_fmscore); + _tree->Branch("sp_x" , "std::vector", &_sp_x); + _tree->Branch("sp_x_true", "std::vector", &_sp_x_true); + _tree->Branch("sp_peakT", "std::vector", &_sp_peakT); + // _tree->Branch("run", &_run, "run/I"); + // _tree->Branch("subrun", &_subrun, "subrun/I"); + // _tree->Branch("event", &_event, "event/I"); + _tree2 = fs->make("match_tree",""); - _tree2->Branch("nmatch", &_nmatch, "nmatch/I"); + _tree2->Branch("nmatch", &_nmatch, "nmatch/I"); _tree2->Branch("edep_time", "std::vector", &_edep_time); _tree2->Branch("opflash_time", &_opflash_time, "opflash_time/D"); _tree2->Branch("true_gamma", &_true_gamma, "true_gamma/D"); @@ -155,10 +158,12 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) void sbnd::LightCaloAna::analyze(art::Event const& e) { - _run = e.id().run(); - _subrun = e.id().subRun(); - _event = e.id().event(); - std::cout << "run: " << _run << ", subrun: " << _subrun << ", event: " << _event << std::endl; + int run = e.id().run(); + int subrun = e.id().subRun(); + int event = e.id().event(); + std::cout << "run: " << run << ", subrun: " << subrun << ", event: " << event << std::endl; + + auto const clockData(art::ServiceHandle()->DataFor(e)); // get slices ::art::Handle> slice_h; @@ -201,17 +206,13 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) art::FindManyP pfp_to_spacepoint(pfp_h, e, _slice_producer); art::FindManyP spacepoint_to_hit(spacepoint_h, e, _slice_producer); - _slc_pfpid.clear(); - _slc_nuscore.clear(); - _slc_fmscore.clear(); - std::vector> match_slices_v; std::vector> match_fm_v; for (size_t n_slice=0; n_slice < slice_v.size(); n_slice++){ float nu_score = -9999; float fm_score = -9999; - float fm_time = -9999; + // float fm_time = -9999; auto slice = slice_v[n_slice]; bool found_fm = false; std::vector> pfp_v = slice_to_pfp.at(n_slice); @@ -221,7 +222,6 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) // only select the PRIMARY pfp if(!pfp->IsPrimary() && !(abs(pfp->PdgCode()) == 12 || abs(pfp->PdgCode()) == 14|| abs(pfp->PdgCode()) == 16)) continue; - _slc_pfpid.push_back(pfp->Self()); // if primary, get nu-score const std::vector> pfpmeta_v = pfp_to_meta.at(pfp->Self()); @@ -229,12 +229,10 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) larpandoraobj::PFParticleMetadata::PropertiesMap propmap = pfpmeta->GetPropertiesMap(); if (propmap.count("NuScore")) nu_score = propmap.at("NuScore"); else nu_score = -1; - _slc_nuscore.push_back(nu_score); // get fm-score std::vector> fm_v = pfp_to_sfm.at(pfp.key()); if (fm_v.empty()){ - _slc_fmscore.push_back(-999); continue; } if (fm_v.size() > 1) @@ -242,15 +240,13 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) for (size_t n_fm=0; n_fm < fm_v.size(); n_fm++){ auto fm = fm_v.at(n_fm); fm_score = fm->score.total; - fm_time = fm->time; + // fm_time = fm->time; if (nu_score > _nuscore_cut && fm_score < _fmscore_cut && fm_score > 0){ found_fm = true; match_fm_v.push_back(fm); } } // end flashmatch loop if (found_fm ==true) match_slices_v.push_back(slice); - _slc_fmscore.push_back(fm_score); - _slc_fmtime.push_back(fm_time); } // end pfp loop } // end slice loop if (match_slices_v.empty() && !slice_v.empty()){ @@ -283,9 +279,12 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) const art::ValidHandle>& energyDeps(e.getValidHandle>("ionandscint")); + + art::ServiceHandle bt_serv; for (size_t n_slice=0; n_slice < match_slices_v.size(); n_slice++){ _nmatch++; + _sp_x.clear(); _sp_x_true.clear(); _sp_peakT.clear(); _edep_time.clear(); std::vector sp_xyz; @@ -347,6 +346,8 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) auto hit = hit_v[n_hit]; if (hit->View() !=plane) continue; const auto &position(sp->XYZ()); + // get true position information + const std::vector xyz_true(bt_serv->HitToXYZ(clockData, hit)); geo::Point_t xyz(position[0],position[1],position[2]); // std::cout << "spacepoint pos: (" << position[0] << ", " << position[1] << ", " << position[2] << std::endl; sp_xyz.push_back(xyz); @@ -355,6 +356,9 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) double charge = (1/.0201293)*atten_correction*hit->Integral(); sp_charge.push_back(charge); _slice_Q += charge; + _sp_x.push_back(position[0]); + _sp_x_true.push_back(xyz_true[0]); + _sp_peakT.push_back(hit->PeakTime()); } } // end spacepoint loop } // end pfp loop @@ -379,7 +383,10 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) } } // TO-DO: keep the amount of light as the average amount of light? - _slice_L = sum_gamma/counter; + if (counter != 0) + _slice_L = sum_gamma/counter; + else + _slice_L = 0; _true_gamma = 0; _true_charge = 0; _true_energy = 0; @@ -409,9 +416,10 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) std::cout << "fractional energy difference: " << (_true_energy - _slice_E)/_true_energy << std::endl; _opflash_time = flash_time; + + _tree->Fill(); _tree2->Fill(); } // end slice loop - _tree->Fill(); } // end analyze @@ -474,7 +482,7 @@ void sbnd::LightCaloAna::CalcLight(std::vector flash_pe_v, std::vector &total_pe_v){ for (size_t ichan = 0; ichan < flash_pe_v.size(); ichan++){ auto pe = flash_pe_v[ichan]; - if(pe == 0) + if((pe == 0) || std::isinf(1/visibility[ichan])) continue; total_pe_v[ichan] += (1/0.03)*pe*(1/visibility[ichan]); } diff --git a/sbndcode/Calorimetry/run_lightcalo.fcl b/sbndcode/Calorimetry/run_lightcalo.fcl index af8a902f9..6e7e209cc 100644 --- a/sbndcode/Calorimetry/run_lightcalo.fcl +++ b/sbndcode/Calorimetry/run_lightcalo.fcl @@ -2,6 +2,8 @@ #include "simulationservices_sbnd.fcl" #include "messages_sbnd.fcl" #include "sam_sbnd.fcl" +#include "particleinventoryservice.fcl" +#include "backtrackerservice.fcl" #include "lightcalo.fcl" @@ -15,6 +17,9 @@ services: FileCatalogMetadata: @local::sbnd_file_catalog_mc # from sam_sbnd.fcl @table::sbnd_services # from services_sbnd.fcl @table::sbnd_g4_services + BackTrackerService: @local::standard_backtrackerservice + ParticleInventoryService: @local::standard_particleinventoryservice + } source: @@ -31,4 +36,6 @@ physics: } path: [ana] end_paths: [path] -} \ No newline at end of file +} + +services.BackTrackerService.BackTracker.SimChannelModuleLabel: "simdrift" \ No newline at end of file From 7ed0f0ebed4f3a51d1a5ec1b19c8fe14c7ac8480 Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Tue, 15 Nov 2022 13:36:25 -0600 Subject: [PATCH 06/52] cleaned up trees, added wire assn, gamma weighted avg, true hit info --- sbndcode/Calorimetry/LightCaloAna_module.cc | 232 +++++++++++++++----- sbndcode/Calorimetry/lightcalo.fcl | 1 + 2 files changed, 172 insertions(+), 61 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index 03db64fe6..fa432c511 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -33,6 +33,7 @@ #include "lardataobj/RecoBase/PFParticleMetadata.h" #include "lardataobj/RecoBase/SpacePoint.h" #include "lardataobj/RecoBase/Hit.h" +#include "lardataobj/RecoBase/Wire.h" #include "lardataobj/RecoBase/OpFlash.h" #include "lardataobj/AnalysisBase/T0.h" #include "larcore/CoreUtils/ServiceUtil.h" @@ -44,6 +45,8 @@ #include "larcore/CoreUtils/ServiceUtil.h" #include "larsim/MCCheater/BackTrackerService.h" #include "lardata/DetectorInfoServices/DetectorClocksService.h" +#include "lardataobj/Simulation/SimChannel.h" +#include "lardataobj/Simulation/sim.h" // SBND includes #include "sbnobj/Common/Reco/SimpleFlashMatchVars.h" @@ -95,20 +98,25 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { std::string _flashmatch_producer; float _nuscore_cut; float _fmscore_cut; + bool _light_wavg; std::unique_ptr _semi_model; fhicl::ParameterSet _vuv_params; fhicl::ParameterSet _vis_params; + + int _run, _subrun, _event; + TTree* _tree; - // int _run, _subrun, _event; - std::vector _sp_x; - std::vector _sp_x_true; - std::vector _sp_peakT; + int _match_type; + // std::vector _sp_x; + // std::vector _sp_x_true; + // std::vector _sp_peakT; TTree* _tree2; int _nmatch=0; - std::vector _edep_time; + int _pfpid; + // std::vector _edep_time; double _opflash_time; double _true_gamma; @@ -117,6 +125,20 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { double _slice_L; double _slice_Q; double _slice_E; + + double _frac_L; + double _frac_Q; + double _frac_E; + + // std::vector _reco_gamma; + // std::vector _meas_pe; + + TTree* _tree3; + double _rec_charge; + float _dep_charge; + float _dep_energy; + float _dep_photon; + }; @@ -133,35 +155,51 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _flashmatch_producer = p.get("FlashMatchProducer"); _nuscore_cut = p.get("nuScoreCut"); _fmscore_cut = p.get("fmScoreCut"); + _light_wavg = p.get ("LightWeightedAverage"); art::ServiceHandle fs; _tree = fs->make("slice_tree",""); - _tree->Branch("sp_x" , "std::vector", &_sp_x); - _tree->Branch("sp_x_true", "std::vector", &_sp_x_true); - _tree->Branch("sp_peakT", "std::vector", &_sp_peakT); - // _tree->Branch("run", &_run, "run/I"); - // _tree->Branch("subrun", &_subrun, "subrun/I"); - // _tree->Branch("event", &_event, "event/I"); - + // _tree->Branch("sp_x" , "std::vector", &_sp_x); + // _tree->Branch("sp_x_true", "std::vector", &_sp_x_true); + // _tree->Branch("sp_peakT", "std::vector", &_sp_peakT); + _tree->Branch("run", &_run, "run/I"); + _tree->Branch("subrun", &_subrun, "subrun/I"); + _tree->Branch("event", &_event, "event/I"); + _tree->Branch("match_type", &_match_type, "match_type/I"); _tree2 = fs->make("match_tree",""); + _tree2->Branch("run", &_run, "run/I"); + _tree2->Branch("subrun", &_subrun, "subrun/I"); + _tree2->Branch("event", &_event, "event/I"); _tree2->Branch("nmatch", &_nmatch, "nmatch/I"); - _tree2->Branch("edep_time", "std::vector", &_edep_time); + _tree2->Branch("pfpid", &_pfpid, "pfpid/I"); + // _tree2->Branch("edep_time", "std::vector", &_edep_time); _tree2->Branch("opflash_time", &_opflash_time, "opflash_time/D"); + // _tree2->Branch("reco_gamma", "std::vector", &_reco_gamma); + // _tree2->Branch("meas_pe", "std::vector", &_meas_pe); _tree2->Branch("true_gamma", &_true_gamma, "true_gamma/D"); _tree2->Branch("true_charge", &_true_charge, "true_charge/D"); _tree2->Branch("true_energy", &_true_energy, "true_energy/D"); _tree2->Branch("slice_L", &_slice_L, "slice_L/D"); _tree2->Branch("slice_Q", &_slice_Q, "slice_Q/D"); _tree2->Branch("slice_E", &_slice_E, "slice_E/D"); + _tree2->Branch("frac_L", &_frac_L, "frac_L/D"); + _tree2->Branch("frac_Q", &_frac_Q, "frac_Q/D"); + _tree2->Branch("frac_E", &_frac_E, "frac_E/D"); + + _tree3 = fs->make("dep_tree",""); + _tree3->Branch("rec_charge", &_rec_charge, "rec_charge/D"); + _tree3->Branch("dep_energy", &_dep_energy, "dep_energy/F"); + _tree3->Branch("dep_charge", &_dep_charge, "dep_charge/F"); + _tree3->Branch("dep_photon", &_dep_photon, "dep_photon/F"); } void sbnd::LightCaloAna::analyze(art::Event const& e) { - int run = e.id().run(); - int subrun = e.id().subRun(); - int event = e.id().event(); - std::cout << "run: " << run << ", subrun: " << subrun << ", event: " << event << std::endl; + _run = e.id().run(); + _subrun = e.id().subRun(); + _event = e.id().event(); + std::cout << "run: " << _run << ", subrun: " << _subrun << ", event: " << _event << std::endl; auto const clockData(art::ServiceHandle()->DataFor(e)); @@ -209,6 +247,13 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) std::vector> match_slices_v; std::vector> match_fm_v; + // std::string _hit_producer = "gaushit"; + // ::art::Handle> hit_h; + // e.getByLabel(_hit_producer, hit_h); + + // art::FindManyP hit_to_wire(hit_h, e, _hit_producer); + // std::vector> large_hits_v; + for (size_t n_slice=0; n_slice < slice_v.size(); n_slice++){ float nu_score = -9999; float fm_score = -9999; @@ -251,6 +296,8 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) } // end slice loop if (match_slices_v.empty() && !slice_v.empty()){ std::cout << "no slices passed the cuts" << std::endl; + _match_type = -1; + _tree->Fill(); return; } @@ -274,6 +321,8 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) if (found_opflash0 == false && found_opflash1 == false){ std::cout << "no opflashes matched to simpleflashes" << std::endl; + _match_type = -2; + _tree->Fill(); return; } @@ -282,17 +331,23 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) art::ServiceHandle bt_serv; + int nsuccessful_matches=0; for (size_t n_slice=0; n_slice < match_slices_v.size(); n_slice++){ + // initialize tree2 variables _nmatch++; - _sp_x.clear(); _sp_x_true.clear(); _sp_peakT.clear(); - _edep_time.clear(); + _pfpid = -1; + // _edep_time.clear(); + + _slice_Q = 0; // total amount of charge + _slice_L = 0; // total amount of light + _slice_E = 0; + + // _sp_x.clear(); _sp_x_true.clear(); _sp_peakT.clear(); std::vector sp_xyz; std::vector sp_charge; // vector of charge info for charge-weighting double flash_time = -999; - _slice_Q = 0; // total amount of charge - _slice_L = 0; // total amount of light auto opflash0 = (match_op0.at(n_slice)); auto opflash1 = (match_op1.at(n_slice)); bool flash_in_0 = false; @@ -312,32 +367,33 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) } else if (opflash0.isNull() && opflash1.isNull()){ std::cout << "err! no opflashes :(" << std::endl; + _match_type = -3; + _tree->Fill(); return; } auto slice = match_slices_v[n_slice]; - // find which plane has the most hits for this slice + // find which plane has the most integrated charge for this slice std::vector> slice_hits_v = slice_to_hit.at(slice.key()); - int nhit0 = 0; - int nhit1 = 0; - int nhit2 = 0; + double integral0 = 0; + double integral1 = 0; + double integral2 = 0; for (size_t i=0; i < slice_hits_v.size(); i++){ auto hit = slice_hits_v[i]; - if (hit->View()==0) nhit0++; - if (hit->View()==1) nhit1++; - if (hit->View()==2) nhit2++; + if (hit->View()==0) integral0+=hit->Integral(); + if (hit->View()==1) integral1+=hit->Integral(); + if (hit->View()==2) integral2+=hit->Integral(); } uint plane = 2; - if ( nhit0 >= nhit1 && nhit0 >= nhit2) plane = 0; - else if ( nhit1 >= nhit0 && nhit1 >= nhit2) plane = 1; + if ( integral0 >= integral1 && integral0 >= integral2) plane = 0; + else if ( integral1 >= integral0 && integral1 >= integral2) plane = 1; else plane = 2; - std::cout << "plane with most hits: " << plane << std::endl; - // get charge information std::vector> pfp_v = slice_to_pfp.at(slice.key()); for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ auto pfp = pfp_v[n_pfp]; + if (pfp->IsPrimary()) _pfpid = pfp->Self(); std::vector> sp_v = pfp_to_spacepoint.at(pfp.key()); for (size_t n_sp=0; n_sp < sp_v.size(); n_sp++){ auto sp = sp_v[n_sp]; @@ -345,70 +401,111 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) for (size_t n_hit=0; n_hit < hit_v.size(); n_hit++){ auto hit = hit_v[n_hit]; if (hit->View() !=plane) continue; - const auto &position(sp->XYZ()); + // std::cout << "plane: " << hit->View() << ", multiplicity: " << hit->Multiplicity() << std::endl; // get true position information - const std::vector xyz_true(bt_serv->HitToXYZ(clockData, hit)); + // const std::vector xyz_true(bt_serv->HitToXYZ(clockData, hit)); + // get reco position information + const auto &position(sp->XYZ()); geo::Point_t xyz(position[0],position[1],position[2]); - // std::cout << "spacepoint pos: (" << position[0] << ", " << position[1] << ", " << position[2] << std::endl; - sp_xyz.push_back(xyz); + // correct for e- attenuation double drift_time = abs(200.0 - abs(position[0]))/(0.16); // in us, drift velocity = 0.16 cm/us double atten_correction = std::exp(drift_time/10e3); // electron lifetime = 10e3 us, or 10 ms double charge = (1/.0201293)*atten_correction*hit->Integral(); + if (charge > 0){ + // large_hits_v.push_back(hit); + std::vector ide_v = bt_serv->HitToSimIDEs_Ps(clockData, hit); + float ide_energy = 0.0; + float ide_charge = 0.0; + for (auto const ide: ide_v){ + ide_energy += ide->energy; + ide_charge += ide->numElectrons; + } + // std::cout << "ide (deposit) energy: " << ide_energy << std::endl; + // std::cout << "ide (readout) charge: " << ide_charge << std::endl; + // std::cout << "ide (deposit) charge: " << ide_charge*atten_correction << std::endl; + // std::cout << "ide (deposit) light: " << ide_energy/(19.5*1e-6) - ide_charge*atten_correction << std::endl; + _rec_charge = charge; + _dep_energy = ide_energy; + _dep_charge = ide_charge*atten_correction; + _dep_photon = ide_energy/(19.5*1e-6) - ide_charge*atten_correction; + _tree3->Fill(); + } + sp_xyz.push_back(xyz); sp_charge.push_back(charge); + + // tree variables + // _sp_x.push_back(position[0]); + // _sp_x_true.push_back(xyz_true[0]); + // _sp_peakT.push_back(hit->PeakTime()); + _slice_Q += charge; - _sp_x.push_back(position[0]); - _sp_x_true.push_back(xyz_true[0]); - _sp_peakT.push_back(hit->PeakTime()); } } // end spacepoint loop } // end pfp loop // get total L count std::vector visibility_map = CalcVisibility(sp_xyz,sp_charge); - std::vector total_pe(_nchan, 0); + std::vector total_pe(_nchan,0); + std::vector total_gamma(_nchan, 0); + if (flash_in_0){ auto flash_pe_v = opflash0->PEs(); - CalcLight(flash_pe_v, visibility_map, total_pe); + for (size_t ich=0; ichPEs(); - CalcLight(flash_pe_v, visibility_map, total_pe); + for (size_t ich=0; ich0){ - counter+= 1.0; - sum_gamma += i; + // fill tree variables + // _reco_gamma = total_gamma; + // _meas_pe = total_pe; + + // calculate the weighted average: + double counter = 0.0; // counter of non-zero channels + double sum_gamma = 0.0; // normal sum of photons + double sum_pe = 0.0; // normal sum of photoelectrons + double wsum_gamma = 0.0; // weighted sum of photons + for (size_t ich=0; ich < total_pe.size(); ich++){ + auto gamma = total_gamma[ich]; + auto pe = total_pe[ich]; + if (gamma>0){ + counter += 1.0; + sum_gamma += gamma; + + sum_pe += pe; + wsum_gamma += gamma*pe; } } - // TO-DO: keep the amount of light as the average amount of light? - if (counter != 0) + // TO-DO: keep the amount of light as the weighted average amount of light? + if ((sum_pe != 0) & (_light_wavg==true)) + _slice_L = wsum_gamma/sum_pe; + if ((sum_pe != 0) & (_light_wavg==false)) _slice_L = sum_gamma/counter; else _slice_L = 0; _true_gamma = 0; _true_charge = 0; _true_energy = 0; - std::cout << "flash time: " << flash_time << std::endl; + // std::cout << "flash time: " << flash_time << std::endl; for (const sim::SimEnergyDeposit& energyDep:*energyDeps){ const double time = energyDep.Time() * 1e-3; if (abs(time-flash_time) < 1){ _true_gamma += energyDep.NumPhotons()/0.03; _true_charge += energyDep.NumElectrons(); _true_energy += energyDep.Energy(); - _edep_time.push_back(time); + // _edep_time.push_back(time); } } _slice_E = (_slice_L + _slice_Q)*19.5*1e-6; - std::cout << "true gamma: " << _true_gamma << std::endl; - std::cout << "calc gamma: " << _slice_L << std::endl; - std::cout << "true electrons: " << _true_charge << std::endl; - std::cout << "calc electrons: " << _slice_Q << std::endl; + // std::cout << "true gamma: " << _true_gamma << std::endl; + // std::cout << "calc gamma: " << _slice_L << std::endl; + // std::cout << "true electrons: " << _true_charge << std::endl; + // std::cout << "calc electrons: " << _slice_Q << std::endl; - std::cout << "true deposited energy: " << _true_energy << std::endl; - std::cout << "calc deposited energy: " << _slice_E << std::endl; + // std::cout << "true deposited energy: " << _true_energy << std::endl; + // std::cout << "calc deposited energy: " << _slice_E << std::endl; std::cout << "ratio of gamma (calc/true): " << _slice_L/_true_gamma << std::endl; std::cout << "ratio of electron (calc/true): " << _slice_Q/_true_charge << std::endl; @@ -416,10 +513,23 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) std::cout << "fractional energy difference: " << (_true_energy - _slice_E)/_true_energy << std::endl; _opflash_time = flash_time; - - _tree->Fill(); + + _frac_L = (_true_gamma - _slice_L)/_true_gamma; + _frac_Q = (_true_charge - _slice_Q)/_true_charge; + _frac_E = (_true_energy - _slice_E)/_true_energy; _tree2->Fill(); + nsuccessful_matches++; } // end slice loop + _match_type=nsuccessful_matches; + _tree->Fill(); + // do large hit stuff here : ) + // if (!large_hits_v.empty()){ + // for (auto hit : large_hits_v){ + // std::vector> wires_v = hit_to_wire.at(hit.key()); + // std::cout << "wire v size: " << wires_v.size() << std::endl; + // } + // } + } // end analyze diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index dd8fb34ca..f0209c02e 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -13,5 +13,6 @@ lightcalo_ana: FlashMatchProducer: "fmatch" nuScoreCut: 0.4 # accept nusScore > 0.4, to analyze all slices, set = 0 fmScoreCut: 7 # accept 0 < fm score < fmScoreCut, to analyze all slices, set = 1e3 + LightWeightedAverage: false } END_PROLOG From 31847f3c3701181a12c2404f30c0ab0860eeec7c Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Tue, 29 Nov 2022 15:02:57 -0600 Subject: [PATCH 07/52] clean up truth/reco hit information --- sbndcode/Calorimetry/LightCaloAna_module.cc | 116 ++++++++------------ 1 file changed, 46 insertions(+), 70 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index fa432c511..cd25e5342 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -44,7 +44,6 @@ #include "lardataobj/Simulation/SimEnergyDeposit.h" #include "larcore/CoreUtils/ServiceUtil.h" #include "larsim/MCCheater/BackTrackerService.h" -#include "lardata/DetectorInfoServices/DetectorClocksService.h" #include "lardataobj/Simulation/SimChannel.h" #include "lardataobj/Simulation/sim.h" @@ -109,16 +108,16 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { TTree* _tree; int _match_type; - // std::vector _sp_x; - // std::vector _sp_x_true; - // std::vector _sp_peakT; TTree* _tree2; int _nmatch=0; int _pfpid; - // std::vector _edep_time; double _opflash_time; + std::vector _rec_charge; + std::vector _dep_charge; + std::vector _dep_energy; + double _true_gamma; double _true_charge; double _true_energy; @@ -130,15 +129,11 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { double _frac_Q; double _frac_E; - // std::vector _reco_gamma; - // std::vector _meas_pe; - - TTree* _tree3; - double _rec_charge; - float _dep_charge; - float _dep_energy; - float _dep_photon; - + // TTree* _tree3; + // double _rec_charge; + // float _dep_charge; + // float _dep_energy; + // float _dep_photon; }; @@ -159,9 +154,6 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) art::ServiceHandle fs; _tree = fs->make("slice_tree",""); - // _tree->Branch("sp_x" , "std::vector", &_sp_x); - // _tree->Branch("sp_x_true", "std::vector", &_sp_x_true); - // _tree->Branch("sp_peakT", "std::vector", &_sp_peakT); _tree->Branch("run", &_run, "run/I"); _tree->Branch("subrun", &_subrun, "subrun/I"); _tree->Branch("event", &_event, "event/I"); @@ -173,10 +165,12 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _tree2->Branch("event", &_event, "event/I"); _tree2->Branch("nmatch", &_nmatch, "nmatch/I"); _tree2->Branch("pfpid", &_pfpid, "pfpid/I"); - // _tree2->Branch("edep_time", "std::vector", &_edep_time); _tree2->Branch("opflash_time", &_opflash_time, "opflash_time/D"); - // _tree2->Branch("reco_gamma", "std::vector", &_reco_gamma); - // _tree2->Branch("meas_pe", "std::vector", &_meas_pe); + + _tree2->Branch("rec_charge", "std::vector", &_rec_charge); + _tree2->Branch("dep_charge", "std::vector", &_dep_charge); + _tree2->Branch("dep_energy", "std::vector", &_dep_energy); + _tree2->Branch("true_gamma", &_true_gamma, "true_gamma/D"); _tree2->Branch("true_charge", &_true_charge, "true_charge/D"); _tree2->Branch("true_energy", &_true_energy, "true_energy/D"); @@ -187,11 +181,11 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _tree2->Branch("frac_Q", &_frac_Q, "frac_Q/D"); _tree2->Branch("frac_E", &_frac_E, "frac_E/D"); - _tree3 = fs->make("dep_tree",""); - _tree3->Branch("rec_charge", &_rec_charge, "rec_charge/D"); - _tree3->Branch("dep_energy", &_dep_energy, "dep_energy/F"); - _tree3->Branch("dep_charge", &_dep_charge, "dep_charge/F"); - _tree3->Branch("dep_photon", &_dep_photon, "dep_photon/F"); + // _tree3 = fs->make("dep_tree",""); + // _tree3->Branch("rec_charge", &_rec_charge, "rec_charge/D"); + // _tree3->Branch("dep_energy", &_dep_energy, "dep_energy/F"); + // _tree3->Branch("dep_charge", &_dep_charge, "dep_charge/F"); + // _tree3->Branch("dep_photon", &_dep_photon, "dep_photon/F"); } void sbnd::LightCaloAna::analyze(art::Event const& e) @@ -247,13 +241,6 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) std::vector> match_slices_v; std::vector> match_fm_v; - // std::string _hit_producer = "gaushit"; - // ::art::Handle> hit_h; - // e.getByLabel(_hit_producer, hit_h); - - // art::FindManyP hit_to_wire(hit_h, e, _hit_producer); - // std::vector> large_hits_v; - for (size_t n_slice=0; n_slice < slice_v.size(); n_slice++){ float nu_score = -9999; float fm_score = -9999; @@ -336,13 +323,14 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) // initialize tree2 variables _nmatch++; _pfpid = -1; - // _edep_time.clear(); _slice_Q = 0; // total amount of charge _slice_L = 0; // total amount of light _slice_E = 0; - // _sp_x.clear(); _sp_x_true.clear(); _sp_peakT.clear(); + _rec_charge.clear(); + _dep_charge.clear(); + _dep_energy.clear(); std::vector sp_xyz; std::vector sp_charge; // vector of charge info for charge-weighting @@ -389,6 +377,10 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) else if ( integral1 >= integral0 && integral1 >= integral2) plane = 1; else plane = 2; + _rec_charge.reserve(slice_hits_v.size()/2); // estimate the size of the vector to be between v.size()/3 and v.size()/2 + _dep_charge.reserve(slice_hits_v.size()/2); + _dep_energy.reserve(slice_hits_v.size()/2); + // get charge information std::vector> pfp_v = slice_to_pfp.at(slice.key()); for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ @@ -401,10 +393,6 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) for (size_t n_hit=0; n_hit < hit_v.size(); n_hit++){ auto hit = hit_v[n_hit]; if (hit->View() !=plane) continue; - // std::cout << "plane: " << hit->View() << ", multiplicity: " << hit->Multiplicity() << std::endl; - // get true position information - // const std::vector xyz_true(bt_serv->HitToXYZ(clockData, hit)); - // get reco position information const auto &position(sp->XYZ()); geo::Point_t xyz(position[0],position[1],position[2]); // correct for e- attenuation @@ -412,32 +400,31 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) double atten_correction = std::exp(drift_time/10e3); // electron lifetime = 10e3 us, or 10 ms double charge = (1/.0201293)*atten_correction*hit->Integral(); if (charge > 0){ - // large_hits_v.push_back(hit); - std::vector ide_v = bt_serv->HitToSimIDEs_Ps(clockData, hit); - float ide_energy = 0.0; - float ide_charge = 0.0; - for (auto const ide: ide_v){ - ide_energy += ide->energy; - ide_charge += ide->numElectrons; + // art::Ptr sim_chan_ptr = bt_serv->FindSimChannel(hit->Channel()); + // if (sim_chan_ptr.isNull()) std::cout << "null channel" << std::endl; + if (hit->Channel() != 8294 && hit->Channel() != 8327){ + std::vector ide_v = bt_serv->HitToSimIDEs_Ps(clockData, hit); + float ide_energy = 0.0; + float ide_charge = 0.0; + for (auto const ide: ide_v){ + ide_energy += ide->energy; + ide_charge += ide->numElectrons; + } + _rec_charge.push_back(charge); + _dep_charge.push_back(ide_charge*atten_correction); + _dep_energy.push_back(ide_energy); } - // std::cout << "ide (deposit) energy: " << ide_energy << std::endl; - // std::cout << "ide (readout) charge: " << ide_charge << std::endl; - // std::cout << "ide (deposit) charge: " << ide_charge*atten_correction << std::endl; - // std::cout << "ide (deposit) light: " << ide_energy/(19.5*1e-6) - ide_charge*atten_correction << std::endl; - _rec_charge = charge; - _dep_energy = ide_energy; - _dep_charge = ide_charge*atten_correction; - _dep_photon = ide_energy/(19.5*1e-6) - ide_charge*atten_correction; - _tree3->Fill(); + else{ + _rec_charge.push_back(charge); + _dep_charge.push_back(-1); + _dep_energy.push_back(-1); + } + // _dep_photon = ide_energy/(19.5*1e-6) - ide_charge*atten_correction; + // _tree3->Fill(); } sp_xyz.push_back(xyz); sp_charge.push_back(charge); - // tree variables - // _sp_x.push_back(position[0]); - // _sp_x_true.push_back(xyz_true[0]); - // _sp_peakT.push_back(hit->PeakTime()); - _slice_Q += charge; } } // end spacepoint loop @@ -457,9 +444,6 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) for (size_t ich=0; ichFill(); - // do large hit stuff here : ) - // if (!large_hits_v.empty()){ - // for (auto hit : large_hits_v){ - // std::vector> wires_v = hit_to_wire.at(hit.key()); - // std::cout << "wire v size: " << wires_v.size() << std::endl; - // } - // } } // end analyze From b1192733846b995957eafa2ae716cab507891007 Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Thu, 15 Dec 2022 11:02:02 -0600 Subject: [PATCH 08/52] add calibration constants for all planes --- sbndcode/Calorimetry/lightcalo.fcl | 1 + 1 file changed, 1 insertion(+) diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index f0209c02e..cae701f9d 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -13,6 +13,7 @@ lightcalo_ana: FlashMatchProducer: "fmatch" nuScoreCut: 0.4 # accept nusScore > 0.4, to analyze all slices, set = 0 fmScoreCut: 7 # accept 0 < fm score < fmScoreCut, to analyze all slices, set = 1e3 + CalAreaConstants: [ 0.0200906, 0.0200016, 0.0201293 ] LightWeightedAverage: false } END_PROLOG From 55032e68b23c571fa0ae2208aac4faaf397c9d54 Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Thu, 15 Dec 2022 11:02:37 -0600 Subject: [PATCH 09/52] use all hits instead of spacepoints->hits --- sbndcode/Calorimetry/LightCaloAna_module.cc | 91 +++++++++++++++++---- 1 file changed, 76 insertions(+), 15 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index cd25e5342..cbf49c887 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -58,6 +58,7 @@ // C++ includes #include #include +#include // sort namespace sbnd { class LightCaloAna; @@ -97,6 +98,7 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { std::string _flashmatch_producer; float _nuscore_cut; float _fmscore_cut; + std::vector _cal_area_const; bool _light_wavg; std::unique_ptr _semi_model; @@ -118,6 +120,9 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { std::vector _dep_charge; std::vector _dep_energy; + std::vector _dep_pe; + std::vector _rec_gamma; + double _true_gamma; double _true_charge; double _true_energy; @@ -150,6 +155,7 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _flashmatch_producer = p.get("FlashMatchProducer"); _nuscore_cut = p.get("nuScoreCut"); _fmscore_cut = p.get("fmScoreCut"); + _cal_area_const = p.get>("CalAreaConstants"); _light_wavg = p.get ("LightWeightedAverage"); art::ServiceHandle fs; @@ -171,6 +177,9 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _tree2->Branch("dep_charge", "std::vector", &_dep_charge); _tree2->Branch("dep_energy", "std::vector", &_dep_energy); + _tree2->Branch("rec_gamma", "std::vector", &_rec_gamma); + _tree2->Branch("dep_pe", "std::vector", &_dep_pe); + _tree2->Branch("true_gamma", &_true_gamma, "true_gamma/D"); _tree2->Branch("true_charge", &_true_charge, "true_charge/D"); _tree2->Branch("true_energy", &_true_energy, "true_energy/D"); @@ -361,27 +370,30 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) } auto slice = match_slices_v[n_slice]; + // sum charge information (without position info) for Q // find which plane has the most integrated charge for this slice std::vector> slice_hits_v = slice_to_hit.at(slice.key()); - double integral0 = 0; - double integral1 = 0; - double integral2 = 0; + std::vector plane_charge{0.,0.,0.}; for (size_t i=0; i < slice_hits_v.size(); i++){ auto hit = slice_hits_v[i]; - if (hit->View()==0) integral0+=hit->Integral(); - if (hit->View()==1) integral1+=hit->Integral(); - if (hit->View()==2) integral2+=hit->Integral(); + auto drift_time = (hit->PeakTime() - 500)*0.5; // us + double atten_correction = std::exp(drift_time/10e3); // electron lifetime = 10e3 us, or 10 ms + auto hit_plane = hit->View(); + plane_charge.at(hit_plane) += hit->Integral()*atten_correction*(1/_cal_area_const.at(hit_plane)); } - uint plane = 2; - if ( integral0 >= integral1 && integral0 >= integral2) plane = 0; - else if ( integral1 >= integral0 && integral1 >= integral2) plane = 1; - else plane = 2; + uint bestPlane = std::max_element(plane_charge.begin(), plane_charge.end()) - plane_charge.begin(); + std::cout << "best plane: " << bestPlane << std::endl; + // bestPlane = 2; + _slice_Q = plane_charge.at(bestPlane); + std::cout << "charge from hits: " << _slice_Q << std::endl; _rec_charge.reserve(slice_hits_v.size()/2); // estimate the size of the vector to be between v.size()/3 and v.size()/2 _dep_charge.reserve(slice_hits_v.size()/2); _dep_energy.reserve(slice_hits_v.size()/2); - // get charge information + double sps_Q = 0; + + // get charge information to create the weighted map std::vector> pfp_v = slice_to_pfp.at(slice.key()); for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ auto pfp = pfp_v[n_pfp]; @@ -392,7 +404,7 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) std::vector> hit_v = spacepoint_to_hit.at(sp.key()); for (size_t n_hit=0; n_hit < hit_v.size(); n_hit++){ auto hit = hit_v[n_hit]; - if (hit->View() !=plane) continue; + if (hit->View() !=bestPlane) continue; const auto &position(sp->XYZ()); geo::Point_t xyz(position[0],position[1],position[2]); // correct for e- attenuation @@ -425,14 +437,15 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) sp_xyz.push_back(xyz); sp_charge.push_back(charge); - _slice_Q += charge; + sps_Q += charge; } } // end spacepoint loop } // end pfp loop // get total L count + std::cout << "sps charge: " << sps_Q << std::endl; std::vector visibility_map = CalcVisibility(sp_xyz,sp_charge); - std::vector total_pe(_nchan,0); - std::vector total_gamma(_nchan, 0); + std::vector total_pe(_nchan,0.); + std::vector total_gamma(_nchan, 0.); if (flash_in_0){ auto flash_pe_v = opflash0->PEs(); @@ -445,6 +458,22 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) CalcLight(flash_pe_v, visibility_map, total_gamma); } + for (size_t i=0; i < total_gamma.size(); i++){ + std::cout << "PE: " << total_pe.at(i) << "Gamma:" << total_gamma.at(i) < idx(total_gamma.size()); + std::iota(idx.begin(), idx.end(), 0); + std::sort(idx.begin(), idx.end(), + [&](int A, int B) -> bool { + return total_gamma[A] < total_gamma[B]; + }); + for (auto i : idx){ + std::cout << "PE: " << total_pe.at(i) << "Gamma:" << total_gamma.at(i) < flash_pe_v, } } +// double sbnd::LightCaloAna::EqualizeLight(std::vector total_gamma, +// std::vector total_pe){ + +// for (size_t i=0; i < total_gamma.size(); i++){ +// std::cout << "PE: " << total_pe.at(i) << "Gamma:" << total_gamma.at(i) std::endl; +// } +// // get a map of sorted indices +// std::vector idx(total_gamma.size()); +// std::iota(idx.begin(), idx.end(), 0); +// std::sort(idx.begin(), idx.end(), +// [&](int A, int B) -> bool { +// return total_gamma[A] < total_gamma[B]; +// }); +// for (auto i : idx){ +// std::cout << "PE: " << total_pe.at(i) << "Gamma:" << total_gamma.at(i) std::endl; +// } + + // std::vector sorted_gamma = std::sort(total_gamma.begin(), total_gamma.end()); + // sorted_gamma.erase(std::remove(sorted_gamma.begin(), sorted_gamma.end(), 0.), sorted_gamma.end()); + // int nch = int(sorted_gamma.size()); // number of nonzero channels + // double gamma_median = sorted_gamma.at(int(nch/2)); + // double gamma_mean = std::accumulate(sorted_gamma.begin(), sorted_gamma.end(), 0.)/nch; + // // light estimate weighted by PE + // double gamma_wgt_sum = 0; + // double pe_sum = std::accumulate(total_pe.begin(), total_pe.end(), 0.); + // for (size_t i=0; i < total_gamma.size(); i++){ + // gamma_wgt_sum += total_gamma.at(i)*total_pe.at(i); + + // } + +// } + DEFINE_ART_MODULE(sbnd::LightCaloAna) From fea4bf4f7fe49766f7b75e9954994b53c11e42df Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Thu, 5 Jan 2023 23:50:33 -0600 Subject: [PATCH 10/52] clean up calorimetry cmakelists --- sbndcode/Calorimetry/CMakeLists.txt | 95 ++++++++++++----------------- 1 file changed, 39 insertions(+), 56 deletions(-) diff --git a/sbndcode/Calorimetry/CMakeLists.txt b/sbndcode/Calorimetry/CMakeLists.txt index c317b4df2..e3261cc9d 100644 --- a/sbndcode/Calorimetry/CMakeLists.txt +++ b/sbndcode/Calorimetry/CMakeLists.txt @@ -1,59 +1,42 @@ +set (MODULE_LIBRARIES + larsim::Utils + larsim::PhotonPropagation + larsim::PhotonPropagation_PhotonVisibilityService_service + larsim::LegacyLArG4 + larcorealg::GeoAlgo + sbncode_OpT0Finder_flashmatch_Base + larcorealg::Geometry + larcore::Geometry_Geometry_service + larsim::Simulation + lardataobj::Simulation + larsim::MCCheater_BackTrackerService_service + larsim::MCCheater_ParticleInventoryService_service + lardata::Utilities + lardataobj::RawData + lardataobj::RecoBase + larreco::Calorimetry + larreco::RecoAlg + lardata::RecoObjects + larpandora::LArPandoraInterface + nusimdata::SimulationBase + art::Framework_Core + art::Framework_Principal + art::Framework_Services_Registry + art_root_io::tfile_support ROOT::Core + art_root_io::TFileService_service + art::Utilities canvas::canvas + messagefacility::MF_MessageLogger + + fhiclcpp::fhiclcpp + ROOT::Geom + ROOT::XMLIO + ROOT::Gdml + ${ROOT_BASIC_LIB_LIST} + sbndcode_RecoUtils + sbndcode_OpDetSim +) +cet_build_plugin(LightCaloAna art::module SOURCE LightCaloAna_module.cc LIBRARIES ${MODULE_LIBRARIES}) -art_make( - LIB_LIBRARIES larsim_PhotonPropagation - larsim_PhotonPropagation_PhotonVisibilityService_service - larsim_LegacyLArG4 - larcorealg_GeoAlgo - sbncode_OpT0Finder_flashmatch_Base - lardataobj_Simulation - larsim_MCCheater_BackTrackerService_service - larsim_MCCheater_ParticleInventoryService_service - larsim_Utils - - MODULE_LIBRARIES - larsim_Utils - larsim_PhotonPropagation - larsim_PhotonPropagation_PhotonVisibilityService_service - larsim_LegacyLArG4 - larcorealg_GeoAlgo - sbncode_OpT0Finder_flashmatch_Base - larcorealg_Geometry - larcore_Geometry_Geometry_service - larsim_Simulation lardataobj_Simulation - larsim_MCCheater_BackTrackerService_service - larsim_MCCheater_ParticleInventoryService_service - lardata_Utilities - larevt_Filters - lardataobj_RawData - lardataobj_RecoBase - larreco_Calorimetry - larreco_RecoAlg - lardata_RecoObjects - larpandora_LArPandoraInterface - sbndcode_CRTUtils - sbndcode_CRT - sbnobj_Common_CRT - nusimdata::SimulationBase - art::Framework_Core - art::Framework_Principal - art::Framework_Services_Registry - art_root_io::tfile_support ROOT::Core - art_root_io::TFileService_service - art::Persistency_Common canvas - art::Persistency_Provenance canvas - art::Utilities canvas - messagefacility::MF_MessageLogger - - fhiclcpp::fhiclcpp - ROOT::Geom - ROOT::XMLIO - ROOT::Gdml - ${ROOT_BASIC_LIB_LIST} - sbndcode_RecoUtils - sbndcode_OpDetSim - ) - -# install_headers() +install_headers() install_fhicl() install_source() - From 477b63ae848dfe7bbac44e9c81a490e1388dd729 Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Wed, 11 Jan 2023 08:08:02 -0600 Subject: [PATCH 11/52] calculate median as light estimate --- sbndcode/Calorimetry/LightCaloAna_module.cc | 30 ++++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index cbf49c887..23335c5cc 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -393,6 +393,8 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) double sps_Q = 0; + bool hit_in_0 = false; + bool hit_in_1 = false; // get charge information to create the weighted map std::vector> pfp_v = slice_to_pfp.at(slice.key()); for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ @@ -408,6 +410,8 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) const auto &position(sp->XYZ()); geo::Point_t xyz(position[0],position[1],position[2]); // correct for e- attenuation + if (position[0] < 0) hit_in_0 = true; + if (position[0] > 0) hit_in_1 = true; double drift_time = abs(200.0 - abs(position[0]))/(0.16); // in us, drift velocity = 0.16 cm/us double atten_correction = std::exp(drift_time/10e3); // electron lifetime = 10e3 us, or 10 ms double charge = (1/.0201293)*atten_correction*hit->Integral(); @@ -447,6 +451,9 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) std::vector total_pe(_nchan,0.); std::vector total_gamma(_nchan, 0.); + if ( (flash_in_0 && !hit_in_0) || (!flash_in_0 && hit_in_0)) std::cout << "TPC 0 light and charge non-currence!" << std::endl; + if ( (flash_in_1 && !hit_in_1) || (!flash_in_1 && hit_in_1)) std::cout << "TPC 1 light and charge non-currence!" << std::endl; + if (flash_in_0){ auto flash_pe_v = opflash0->PEs(); for (size_t ich=0; ich bool { return total_gamma[A] < total_gamma[B]; }); - for (auto i : idx){ - std::cout << "PE: " << total_pe.at(i) << "Gamma:" << total_gamma.at(i) < Date: Mon, 23 Jan 2023 14:12:38 -0600 Subject: [PATCH 12/52] removed unweighted fcl, added arapucas and noise threshold --- sbndcode/Calorimetry/LightCaloAna_module.cc | 240 +++++++++++--------- sbndcode/Calorimetry/lightcalo.fcl | 3 +- 2 files changed, 132 insertions(+), 111 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index 23335c5cc..118a49c9b 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -44,6 +44,9 @@ #include "lardataobj/Simulation/SimEnergyDeposit.h" #include "larcore/CoreUtils/ServiceUtil.h" #include "larsim/MCCheater/BackTrackerService.h" +#include "larsim/MCCheater/ParticleInventoryService.h" +#include "nusimdata/SimulationBase/GTruth.h" +#include "nusimdata/SimulationBase/MCTruth.h" #include "lardataobj/Simulation/SimChannel.h" #include "lardataobj/Simulation/sim.h" @@ -83,8 +86,6 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { private: // define functions - // art::Ptr SelectSlice(std::vector> slice_v, std::vector nuscore_v, std::vector fmscore_v - // std::vector> opflash_v); opdet::sbndPDMapAlg _opdetmap; //map for photon detector types unsigned int _nchan = _opdetmap.size(); @@ -94,12 +95,13 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { std::vector CalcVisibility(std::vector xyz_v, std::vector charge_v); void CalcLight(std::vector flash_pe_v, std::vector visibility, std::vector&total_pe_v); std::vector _opflash_producer_v; + std::vector _opflash_ara_producer_v; std::string _slice_producer; std::string _flashmatch_producer; + bool _use_arapucas; float _nuscore_cut; float _fmscore_cut; std::vector _cal_area_const; - bool _light_wavg; std::unique_ptr _semi_model; fhicl::ParameterSet _vuv_params; @@ -116,16 +118,20 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { int _pfpid; double _opflash_time; - std::vector _rec_charge; - std::vector _dep_charge; - std::vector _dep_energy; - std::vector _dep_pe; std::vector _rec_gamma; double _true_gamma; double _true_charge; double _true_energy; + + double _median_gamma; + double _mean_gamma; + + double _mean_charge; + double _max_charge; + double _comp_charge; + double _slice_L; double _slice_Q; double _slice_E; @@ -134,11 +140,6 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { double _frac_Q; double _frac_E; - // TTree* _tree3; - // double _rec_charge; - // float _dep_charge; - // float _dep_energy; - // float _dep_photon; }; @@ -151,12 +152,13 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _semi_model = std::make_unique(_vuv_params, _vis_params, true, false); _opflash_producer_v = p.get>("OpFlashProducers"); + _opflash_ara_producer_v = p.get>("OpFlashAraProducers"); _slice_producer = p.get("SliceProducer"); _flashmatch_producer = p.get("FlashMatchProducer"); + _use_arapucas = p.get("UseArapucas"); _nuscore_cut = p.get("nuScoreCut"); _fmscore_cut = p.get("fmScoreCut"); _cal_area_const = p.get>("CalAreaConstants"); - _light_wavg = p.get ("LightWeightedAverage"); art::ServiceHandle fs; _tree = fs->make("slice_tree",""); @@ -173,16 +175,19 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _tree2->Branch("pfpid", &_pfpid, "pfpid/I"); _tree2->Branch("opflash_time", &_opflash_time, "opflash_time/D"); - _tree2->Branch("rec_charge", "std::vector", &_rec_charge); - _tree2->Branch("dep_charge", "std::vector", &_dep_charge); - _tree2->Branch("dep_energy", "std::vector", &_dep_energy); - _tree2->Branch("rec_gamma", "std::vector", &_rec_gamma); _tree2->Branch("dep_pe", "std::vector", &_dep_pe); _tree2->Branch("true_gamma", &_true_gamma, "true_gamma/D"); _tree2->Branch("true_charge", &_true_charge, "true_charge/D"); _tree2->Branch("true_energy", &_true_energy, "true_energy/D"); + + _tree2->Branch("median_gamma", &_median_gamma, "median_gamma/D"); + _tree2->Branch("mean_gamma", &_mean_gamma, "mean_gamma/D"); + _tree2->Branch("mean_charge", &_mean_charge, "mean_charge/D"); + _tree2->Branch("max_charge", &_max_charge, "max_charge/D"); + _tree2->Branch("comp_charge", &_comp_charge, "comp_charge/D"); + _tree2->Branch("slice_L", &_slice_L, "slice_L/D"); _tree2->Branch("slice_Q", &_slice_Q, "slice_Q/D"); _tree2->Branch("slice_E", &_slice_E, "slice_E/D"); @@ -190,11 +195,6 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _tree2->Branch("frac_Q", &_frac_Q, "frac_Q/D"); _tree2->Branch("frac_E", &_frac_E, "frac_E/D"); - // _tree3 = fs->make("dep_tree",""); - // _tree3->Branch("rec_charge", &_rec_charge, "rec_charge/D"); - // _tree3->Branch("dep_energy", &_dep_energy, "dep_energy/F"); - // _tree3->Branch("dep_charge", &_dep_charge, "dep_charge/F"); - // _tree3->Branch("dep_photon", &_dep_photon, "dep_photon/F"); } void sbnd::LightCaloAna::analyze(art::Event const& e) @@ -234,6 +234,12 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) std::cout << "don't have good flashes from producer " << _opflash_producer_v[0] << " or " << _opflash_producer_v[1] << std::endl; return; } + auto const & flash0_ara_h = e.getValidHandle>(_opflash_ara_producer_v[0]); + auto const & flash1_ara_h = e.getValidHandle>(_opflash_ara_producer_v[1]); + if( _use_arapucas && (!flash0_ara_h.isValid() || flash0_ara_h->empty()) && (!flash1_ara_h.isValid() || flash1_ara_h->empty())) { + std::cout << "don't have good flashes from producer " << _opflash_ara_producer_v[0] << " or " << _opflash_ara_producer_v[1] << std::endl; + return; + } // Construct the vector of Slices std::vector> slice_v; @@ -309,12 +315,18 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) std::vector> match_op0; bool found_opflash0 = MatchOpFlash(match_fm_v,flash0_v, match_op0); + std::vector> flash0_ara_v; + art::fill_ptr_vector(flash0_ara_v, flash0_ara_h); + // tpc1 std::vector> flash1_v; art::fill_ptr_vector(flash1_v, flash1_h); std::vector> match_op1; bool found_opflash1 = MatchOpFlash(match_fm_v,flash1_v, match_op1); + std::vector> flash1_ara_v; + art::fill_ptr_vector(flash1_ara_v, flash1_ara_h); + if (found_opflash0 == false && found_opflash1 == false){ std::cout << "no opflashes matched to simpleflashes" << std::endl; _match_type = -2; @@ -325,7 +337,7 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) const art::ValidHandle>& energyDeps(e.getValidHandle>("ionandscint")); - art::ServiceHandle bt_serv; + art::ServiceHandle pi_serv; int nsuccessful_matches=0; for (size_t n_slice=0; n_slice < match_slices_v.size(); n_slice++){ @@ -337,10 +349,6 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) _slice_L = 0; // total amount of light _slice_E = 0; - _rec_charge.clear(); - _dep_charge.clear(); - _dep_energy.clear(); - std::vector sp_xyz; std::vector sp_charge; // vector of charge info for charge-weighting @@ -349,21 +357,36 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) auto opflash1 = (match_op1.at(n_slice)); bool flash_in_0 = false; bool flash_in_1 = false; + // set threshold above noise PE levels for the flash + double noise_thresh = (_use_arapucas)? 2000 : 1000; + if (!opflash0.isNull() && opflash1.isNull()){ flash_time = opflash0->Time(); - flash_in_0 = true; + if (opflash0->TotalPE() > noise_thresh) + flash_in_0 = true; + else + std::cout << "Flash Total PE in TPC 0 too low ("<< opflash0->TotalPE() << ")... Skipping" << std::endl; } else if ( opflash0.isNull() && !opflash1.isNull()){ flash_time = opflash1->Time(); - flash_in_1 = true; + if (opflash1->TotalPE() > noise_thresh) + flash_in_1 = true; + else + std::cout << "Flash Total PE in TPC 1 too low(" << opflash1->TotalPE() << ")... Skipping" << std::endl; } else if (!opflash0.isNull() && !opflash1.isNull()){ flash_time = opflash0->Time(); - flash_in_0 = true; - flash_in_1 = true; + if (opflash0->TotalPE() > noise_thresh) + flash_in_0 = true; + else + std::cout << "Flash Total PE in TPC 0 too low ("<< opflash0->TotalPE() << ")... Skipping" << std::endl; + if (opflash1->TotalPE() > noise_thresh) + flash_in_1 = true; + else + std::cout << "Flash Total PE in TPC 1 too low(" << opflash1->TotalPE() << ")... Skipping" << std::endl; } else if (opflash0.isNull() && opflash1.isNull()){ - std::cout << "err! no opflashes :(" << std::endl; + std::cout << "No opflashes matched with SimpleFlash objects" << std::endl; _match_type = -3; _tree->Fill(); return; @@ -374,27 +397,27 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) // find which plane has the most integrated charge for this slice std::vector> slice_hits_v = slice_to_hit.at(slice.key()); std::vector plane_charge{0.,0.,0.}; + std::vector plane_hits{0,0,0}; for (size_t i=0; i < slice_hits_v.size(); i++){ auto hit = slice_hits_v[i]; auto drift_time = (hit->PeakTime() - 500)*0.5; // us double atten_correction = std::exp(drift_time/10e3); // electron lifetime = 10e3 us, or 10 ms auto hit_plane = hit->View(); plane_charge.at(hit_plane) += hit->Integral()*atten_correction*(1/_cal_area_const.at(hit_plane)); + plane_hits.at(hit_plane)++; } + std::cout << "charge: " << plane_charge[0] << ", " << plane_charge[1] << ", " << plane_charge[2] << std::endl; uint bestPlane = std::max_element(plane_charge.begin(), plane_charge.end()) - plane_charge.begin(); - std::cout << "best plane: " << bestPlane << std::endl; - // bestPlane = 2; + uint bestHits = std::max_element(plane_hits.begin(), plane_hits.end()) - plane_hits.begin(); + _slice_Q = plane_charge.at(bestPlane); - std::cout << "charge from hits: " << _slice_Q << std::endl; - _rec_charge.reserve(slice_hits_v.size()/2); // estimate the size of the vector to be between v.size()/3 and v.size()/2 - _dep_charge.reserve(slice_hits_v.size()/2); - _dep_energy.reserve(slice_hits_v.size()/2); + _mean_charge = (plane_charge[0] + plane_charge[1] + plane_charge[2])/3; + _max_charge = plane_charge.at(bestPlane); + _comp_charge = plane_charge.at(bestHits); double sps_Q = 0; - bool hit_in_0 = false; - bool hit_in_1 = false; // get charge information to create the weighted map std::vector> pfp_v = slice_to_pfp.at(slice.key()); for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ @@ -410,34 +433,9 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) const auto &position(sp->XYZ()); geo::Point_t xyz(position[0],position[1],position[2]); // correct for e- attenuation - if (position[0] < 0) hit_in_0 = true; - if (position[0] > 0) hit_in_1 = true; double drift_time = abs(200.0 - abs(position[0]))/(0.16); // in us, drift velocity = 0.16 cm/us double atten_correction = std::exp(drift_time/10e3); // electron lifetime = 10e3 us, or 10 ms double charge = (1/.0201293)*atten_correction*hit->Integral(); - if (charge > 0){ - // art::Ptr sim_chan_ptr = bt_serv->FindSimChannel(hit->Channel()); - // if (sim_chan_ptr.isNull()) std::cout << "null channel" << std::endl; - if (hit->Channel() != 8294 && hit->Channel() != 8327){ - std::vector ide_v = bt_serv->HitToSimIDEs_Ps(clockData, hit); - float ide_energy = 0.0; - float ide_charge = 0.0; - for (auto const ide: ide_v){ - ide_energy += ide->energy; - ide_charge += ide->numElectrons; - } - _rec_charge.push_back(charge); - _dep_charge.push_back(ide_charge*atten_correction); - _dep_energy.push_back(ide_energy); - } - else{ - _rec_charge.push_back(charge); - _dep_charge.push_back(-1); - _dep_energy.push_back(-1); - } - // _dep_photon = ide_energy/(19.5*1e-6) - ide_charge*atten_correction; - // _tree3->Fill(); - } sp_xyz.push_back(xyz); sp_charge.push_back(charge); @@ -445,29 +443,47 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) } } // end spacepoint loop } // end pfp loop + // get total L count - std::cout << "sps charge: " << sps_Q << std::endl; std::vector visibility_map = CalcVisibility(sp_xyz,sp_charge); std::vector total_pe(_nchan,0.); std::vector total_gamma(_nchan, 0.); - if ( (flash_in_0 && !hit_in_0) || (!flash_in_0 && hit_in_0)) std::cout << "TPC 0 light and charge non-currence!" << std::endl; - if ( (flash_in_1 && !hit_in_1) || (!flash_in_1 && hit_in_1)) std::cout << "TPC 1 light and charge non-currence!" << std::endl; - if (flash_in_0){ + std::cout << "Using OpFlash in TPC 0..." << std::endl; auto flash_pe_v = opflash0->PEs(); + flash_pe_v.insert(flash_pe_v.end(), {0,0,0,0,0,0}); + if (_use_arapucas){ + for (size_t nara=0; nara < flash0_ara_v.size(); nara++){ + auto const &flash0_ara = *flash0_ara_v[nara]; + if (flash0_ara.Time() - flash_time < 0.05){ + for (size_t ich=0; ich < (flash0_ara.PEs()).size(); ich++) + flash_pe_v.at(ich) += (flash0_ara.PEs()).at(ich); + break; + } + } + } for (size_t ich=0; ichPEs(); + std::cout << "Using OpFlash in TPC 1..." << std::endl; + flash_pe_v.insert(flash_pe_v.end(), {0,0,0,0,0,0}); + if (_use_arapucas){ + for (size_t nara=0; nara < flash0_ara_v.size(); nara++){ + auto const &flash0_ara = *flash0_ara_v[nara]; + if (flash0_ara.Time() - flash_time < 0.05){ + for (size_t ich=0; ich < (flash0_ara.PEs()).size(); ich++) + flash_pe_v.at(ich) += (flash0_ara.PEs()).at(ich); + break; + } + } + } for (size_t ich=0; ich0){ counter += 1.0; sum_gamma += gamma; - - sum_pe += pe; - wsum_gamma += gamma*pe; } } - // TO-DO: keep the amount of light as the weighted average amount of light? - if ((sum_pe != 0) & (_light_wavg==true)) - _slice_L = wsum_gamma/sum_pe; - if ((sum_pe != 0) & (_light_wavg==false)) - _slice_L = sum_gamma/counter; - else - _slice_L = 0; + if (sum_gamma !=0) _mean_gamma = sum_gamma/counter; + _slice_L = _median_gamma; + _slice_E = (_slice_L + _slice_Q)*19.5*1e-6; + + // get truth information _true_gamma = 0; _true_charge = 0; _true_energy = 0; - // std::cout << "flash time: " << flash_time << std::endl; + for (const sim::SimEnergyDeposit& energyDep:*energyDeps){ - const double time = energyDep.Time() * 1e-3; - if (abs(time-flash_time) < 1){ - _true_gamma += energyDep.NumPhotons()/0.03; + auto trackID = energyDep.TrackID(); + art::Ptr mctruth = pi_serv->TrackIdToMCTruth_P(trackID); + if (mctruth->Origin()==simb::kBeamNeutrino){ + _true_gamma += energyDep.NumPhotons()/0.03; // scint-prescale = 0.03 _true_charge += energyDep.NumElectrons(); _true_energy += energyDep.Energy(); } } - _slice_E = (_slice_L + _slice_Q)*19.5*1e-6; // std::cout << "true gamma: " << _true_gamma << std::endl; // std::cout << "calc gamma: " << _slice_L << std::endl; @@ -540,9 +543,13 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) // std::cout << "true deposited energy: " << _true_energy << std::endl; // std::cout << "calc deposited energy: " << _slice_E << std::endl; - std::cout << "ratio of gamma (median/true): " << med_gamma/_true_gamma << std::endl; - std::cout << "ratio of gamma (calc/true): " << _slice_L/_true_gamma << std::endl; - std::cout << "ratio of electron (calc/true): " << _slice_Q/_true_charge << std::endl; + std::cout << "ratio of gamma (median/true): " << _median_gamma/_true_gamma << std::endl; + std::cout << "ratio of gamma (mean/true): " << _mean_gamma/_true_gamma << std::endl; + + std::cout << "ratio of electron (mean/true): " << _mean_charge/_true_charge << std::endl; + std::cout << "ratio of electron (max/true): " << _max_charge/_true_charge << std::endl; + std::cout << "ratio of electron (comp/true): " << _comp_charge/_true_charge << std::endl; + std::cout << "ratio of energy (calc/true): " << _slice_E/_true_energy << std::endl; std::cout << "fractional energy difference: " << (_true_energy - _slice_E)/_true_energy << std::endl; @@ -573,7 +580,8 @@ bool sbnd::LightCaloAna::MatchOpFlash(std::vectortime; for (size_t iop=0; iopTime() - match_time) < 0.05){ + // only select opflashes that match the time and have total PE above noise levels + if (abs( opflash->Time() - match_time) < 0.17){ found_match = true; any_match = true; match_v.push_back(opflash); @@ -604,9 +612,14 @@ std::vector sbnd::LightCaloAna::CalcVisibility(std::vector _semi_model->detectedReflectedVisibilities(reflect_visibility, xyz); if (visibility.size() != direct_visibility.size()) std::cout << "mismatch of visibility vector size" << std::endl; - // sum direct and reflected, weight by charge, and add to total visibility map - for (size_t ivis=0; ivis sbnd::LightCaloAna::CalcVisibility(std::vector void sbnd::LightCaloAna::CalcLight(std::vector flash_pe_v, std::vector visibility, std::vector &total_pe_v){ - for (size_t ichan = 0; ichan < flash_pe_v.size(); ichan++){ - auto pe = flash_pe_v[ichan]; - if((pe == 0) || std::isinf(1/visibility[ichan])) + for (size_t ch = 0; ch < flash_pe_v.size(); ch++){ + auto pe = flash_pe_v[ch]; + double efficiency = 0.03; + if((pe == 0) || std::isinf(1/visibility[ch])) continue; - total_pe_v[ichan] += (1/0.03)*pe*(1/visibility[ichan]); + if (_opdetmap.isPDType(ch, "pmt_uncoated") || _opdetmap.isPDType(ch, "pmt_coated")) + efficiency = 0.03; + else if (_opdetmap.isPDType(ch, "xarapuca_vuv")) + efficiency = 0.021; + else if (_opdetmap.isPDType(ch, "xarapuca_vis")) + efficiency = 0.014; + total_pe_v[ch] += (1/efficiency)*pe*(1/visibility[ch]); } } diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index cae701f9d..f17c4711f 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -9,11 +9,12 @@ lightcalo_ana: VIVHits: @local::sbnd_vis_RS100cm_hits_parameterization OpFlashProducers: ["opflashtpc0", "opflashtpc1"] + OpFlashAraProducers: ["opflashtpc0xarapuca", "opflashtpc1xarapuca"] SliceProducer: "pandora" FlashMatchProducer: "fmatch" + UseArapucas: false nuScoreCut: 0.4 # accept nusScore > 0.4, to analyze all slices, set = 0 fmScoreCut: 7 # accept 0 < fm score < fmScoreCut, to analyze all slices, set = 1e3 CalAreaConstants: [ 0.0200906, 0.0200016, 0.0201293 ] - LightWeightedAverage: false } END_PROLOG From 081f01dccb1d03cb9963d7a2e2cc4a47914a6eae Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Tue, 24 Jan 2023 13:32:33 -0600 Subject: [PATCH 13/52] fix tpc split bug, comitting debugging couts, add mean+median functions --- sbndcode/Calorimetry/LightCaloAna_module.cc | 172 +++++++++++--------- 1 file changed, 95 insertions(+), 77 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index 118a49c9b..d47febb02 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -94,6 +94,8 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { std::vector> &match_v); std::vector CalcVisibility(std::vector xyz_v, std::vector charge_v); void CalcLight(std::vector flash_pe_v, std::vector visibility, std::vector&total_pe_v); + double CalcMedian(std::vector total_light); + double CalcMean(std::vector total_light); std::vector _opflash_producer_v; std::vector _opflash_ara_producer_v; std::string _slice_producer; @@ -410,12 +412,12 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) uint bestPlane = std::max_element(plane_charge.begin(), plane_charge.end()) - plane_charge.begin(); uint bestHits = std::max_element(plane_hits.begin(), plane_hits.end()) - plane_hits.begin(); - _slice_Q = plane_charge.at(bestPlane); - _mean_charge = (plane_charge[0] + plane_charge[1] + plane_charge[2])/3; _max_charge = plane_charge.at(bestPlane); _comp_charge = plane_charge.at(bestHits); + _slice_Q = _comp_charge; + double sps_Q = 0; // get charge information to create the weighted map @@ -484,40 +486,14 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) CalcLight(flash_pe_v, visibility_map, total_gamma); } + _median_gamma = CalcMedian(total_gamma); + _mean_gamma = CalcMean(total_gamma); + // protect against double flash outliers: + + // fill tree variables _dep_pe = total_pe; _rec_gamma = total_gamma; - // get a map of sorted indices - std::vector idx(total_gamma.size()); - std::iota(idx.begin(), idx.end(), 0); - std::sort(idx.begin(), idx.end(), - [&](int A, int B) -> bool { - return total_gamma[A] < total_gamma[B]; - }); - // count number of zero entries: - int zero_counter = 0; - for (size_t i=0; i < total_gamma.size(); i++){ - if (total_gamma.at(i) <= 0) zero_counter++; - } - int med_gamma_idx=0; - // double median_gamma=0; - if (zero_counter != int(total_gamma.size())){ - med_gamma_idx = idx.at(int((total_gamma.size()-zero_counter))/2 + zero_counter); - // std::cout << "med_gamma_idx: " << med_gamma_idx << std::endl; - // std::cout << "median gamma idx: " << med_gamma_idx << std::endl; - _median_gamma = total_gamma.at(med_gamma_idx); - // std::cout << "median gamma: " << med_gamma << std::endl; - } - - double counter = 0.0; // counter of non-zero channels - double sum_gamma = 0.0; // normal sum of photons - for (size_t ich=0; ich < total_pe.size(); ich++){ - auto gamma = total_gamma[ich]; - if (gamma>0){ - counter += 1.0; - sum_gamma += gamma; - } - } - if (sum_gamma !=0) _mean_gamma = sum_gamma/counter; + _slice_L = _median_gamma; _slice_E = (_slice_L + _slice_Q)*19.5*1e-6; @@ -526,32 +502,38 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) _true_charge = 0; _true_energy = 0; + double _true_gamma_0 = 0; + double _true_gamma_1 = 0; + for (const sim::SimEnergyDeposit& energyDep:*energyDeps){ auto trackID = energyDep.TrackID(); + auto start_x = energyDep.StartX(); + art::Ptr mctruth = pi_serv->TrackIdToMCTruth_P(trackID); if (mctruth->Origin()==simb::kBeamNeutrino){ + _true_gamma += energyDep.NumPhotons()/0.03; // scint-prescale = 0.03 _true_charge += energyDep.NumElectrons(); _true_energy += energyDep.Energy(); + if (start_x > 0) _true_gamma_1+= energyDep.NumPhotons()/0.03; + if (start_x < 0) _true_gamma_0+= energyDep.NumPhotons()/0.03; } } - // std::cout << "true gamma: " << _true_gamma << std::endl; - // std::cout << "calc gamma: " << _slice_L << std::endl; - // std::cout << "true electrons: " << _true_charge << std::endl; - // std::cout << "calc electrons: " << _slice_Q << std::endl; - - // std::cout << "true deposited energy: " << _true_energy << std::endl; - // std::cout << "calc deposited energy: " << _slice_E << std::endl; + // } std::cout << "ratio of gamma (median/true): " << _median_gamma/_true_gamma << std::endl; std::cout << "ratio of gamma (mean/true): " << _mean_gamma/_true_gamma << std::endl; + if (flash_in_0 && flash_in_1){ + std::cout << "ratio of gamma (mean/true) TPC 0: " << mean_gamma0/_true_gamma_0 << std::endl; + std::cout << "ratio of gamma (mean/true) TPC 1: " << mean_gamma1/_true_gamma_1 << std::endl; + } std::cout << "ratio of electron (mean/true): " << _mean_charge/_true_charge << std::endl; std::cout << "ratio of electron (max/true): " << _max_charge/_true_charge << std::endl; std::cout << "ratio of electron (comp/true): " << _comp_charge/_true_charge << std::endl; std::cout << "ratio of energy (calc/true): " << _slice_E/_true_energy << std::endl; - std::cout << "fractional energy difference: " << (_true_energy - _slice_E)/_true_energy << std::endl; + // std::cout << "fractional energy difference: " << (_true_energy - _slice_E)/_true_energy << std::endl; _opflash_time = flash_time; @@ -601,11 +583,16 @@ std::vector sbnd::LightCaloAna::CalcVisibility(std::vector if (xyz_v.size() != charge_v.size()) std::cout << "spacepoint coord and charge vector size mismatch" << std::endl; std::vector visibility(_nchan, 0); - double sum_charge = std::accumulate(charge_v.begin(), charge_v.end(), 0.0); + double sum_charge0 = 0; + double sum_charge1 = 0; for (size_t i=0; i direct_visibility; std::vector reflect_visibility; _semi_model->detectedDirectVisibilities(direct_visibility, xyz); @@ -620,11 +607,17 @@ std::vector sbnd::LightCaloAna::CalcVisibility(std::vector visibility[ch] += charge*direct_visibility[ch]; else if (_opdetmap.isPDType(ch, "pmt_coated")) visibility[ch] += charge*(direct_visibility[ch] + reflect_visibility[ch]); + + // std::cout << "x: " << xyz.X() << "vis: " << visibility[ch] << std::endl; } } // end spacepoint loop - // normalize by the total charge - std::transform(visibility.begin(), visibility.end(), - visibility.begin(), [sum_charge](double &k){ return k/sum_charge; }); + // normalize by the total charge in each TPC + for (size_t ch=0; ch < visibility.size(); ch++){ + if (ch%2 == 0) visibility[ch] /= sum_charge0; + if (ch%2 == 1) visibility[ch] /= sum_charge1; + } + // std::transform(visibility.begin(), visibility.end(), + // visibility.begin(), [sum_charge](double &k){ return k/sum_charge; }); return visibility; } void sbnd::LightCaloAna::CalcLight(std::vector flash_pe_v, @@ -645,37 +638,62 @@ void sbnd::LightCaloAna::CalcLight(std::vector flash_pe_v, } } -// double sbnd::LightCaloAna::EqualizeLight(std::vector total_gamma, -// std::vector total_pe){ - -// for (size_t i=0; i < total_gamma.size(); i++){ -// std::cout << "PE: " << total_pe.at(i) << "Gamma:" << total_gamma.at(i) std::endl; -// } -// // get a map of sorted indices -// std::vector idx(total_gamma.size()); -// std::iota(idx.begin(), idx.end(), 0); -// std::sort(idx.begin(), idx.end(), -// [&](int A, int B) -> bool { -// return total_gamma[A] < total_gamma[B]; -// }); -// for (auto i : idx){ -// std::cout << "PE: " << total_pe.at(i) << "Gamma:" << total_gamma.at(i) std::endl; -// } - - // std::vector sorted_gamma = std::sort(total_gamma.begin(), total_gamma.end()); - // sorted_gamma.erase(std::remove(sorted_gamma.begin(), sorted_gamma.end(), 0.), sorted_gamma.end()); - // int nch = int(sorted_gamma.size()); // number of nonzero channels - // double gamma_median = sorted_gamma.at(int(nch/2)); - // double gamma_mean = std::accumulate(sorted_gamma.begin(), sorted_gamma.end(), 0.)/nch; - // // light estimate weighted by PE - // double gamma_wgt_sum = 0; - // double pe_sum = std::accumulate(total_pe.begin(), total_pe.end(), 0.); - // for (size_t i=0; i < total_gamma.size(); i++){ - // gamma_wgt_sum += total_gamma.at(i)*total_pe.at(i); - - // } - -// } +double sbnd::LightCaloAna::CalcMedian(std::vector total_gamma){ + std::vector tpc0_gamma; + std::vector tpc1_gamma; + for (size_t i=0; i idx(gamma_v.size()); + std::iota(idx.begin(), idx.end(), 0); + std::sort(idx.begin(), idx.end(), + [&](int A, int B) -> bool { + return gamma_v[A] < gamma_v[B]; + }); + // count number of zero entries: + int zero_counter = 0; + for (size_t i=0; i < gamma_v.size(); i++){ + if (gamma_v.at(i) <= 0) zero_counter++; + } + int med_idx=0; + if (zero_counter != int(gamma_v.size())){ + med_idx = idx.at(int((gamma_v.size()-zero_counter))/2 + zero_counter); + median = gamma_v.at(med_idx); + } + median_gamma+=median; + } + return median_gamma; +} + +double sbnd::LightCaloAna::CalcMean(std::vector total_gamma){ + std::vector tpc0_gamma; + std::vector tpc1_gamma; + for (size_t i=0; i0){ + counter+=1.0; + sum+=gamma; + } + } + if (sum!=0) mean_gamma+= sum/counter; + } + return mean_gamma; +} DEFINE_ART_MODULE(sbnd::LightCaloAna) From 91ad09754e43a4e51fe5fec7cee4ecab280ae138 Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Wed, 25 Jan 2023 14:04:26 -0600 Subject: [PATCH 14/52] cleanup --- sbndcode/Calorimetry/LightCaloAna_module.cc | 46 +++++++-------------- 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index d47febb02..c844a5758 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -408,7 +408,7 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) plane_charge.at(hit_plane) += hit->Integral()*atten_correction*(1/_cal_area_const.at(hit_plane)); plane_hits.at(hit_plane)++; } - std::cout << "charge: " << plane_charge[0] << ", " << plane_charge[1] << ", " << plane_charge[2] << std::endl; + // std::cout << "charge: " << plane_charge[0] << ", " << plane_charge[1] << ", " << plane_charge[2] << std::endl; uint bestPlane = std::max_element(plane_charge.begin(), plane_charge.end()) - plane_charge.begin(); uint bestHits = std::max_element(plane_hits.begin(), plane_hits.end()) - plane_hits.begin(); @@ -485,16 +485,20 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) for (size_t ich=0; ich mctruth = pi_serv->TrackIdToMCTruth_P(trackID); if (mctruth->Origin()==simb::kBeamNeutrino){ @@ -515,32 +515,22 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) _true_gamma += energyDep.NumPhotons()/0.03; // scint-prescale = 0.03 _true_charge += energyDep.NumElectrons(); _true_energy += energyDep.Energy(); - if (start_x > 0) _true_gamma_1+= energyDep.NumPhotons()/0.03; - if (start_x < 0) _true_gamma_0+= energyDep.NumPhotons()/0.03; } } + + _frac_L = (_true_gamma - _slice_L)/_true_gamma; + _frac_Q = (_true_charge - _slice_Q)/_true_charge; + _frac_E = (_true_energy - _slice_E)/_true_energy; + _tree2->Fill(); - // } std::cout << "ratio of gamma (median/true): " << _median_gamma/_true_gamma << std::endl; std::cout << "ratio of gamma (mean/true): " << _mean_gamma/_true_gamma << std::endl; - if (flash_in_0 && flash_in_1){ - std::cout << "ratio of gamma (mean/true) TPC 0: " << mean_gamma0/_true_gamma_0 << std::endl; - std::cout << "ratio of gamma (mean/true) TPC 1: " << mean_gamma1/_true_gamma_1 << std::endl; - } std::cout << "ratio of electron (mean/true): " << _mean_charge/_true_charge << std::endl; std::cout << "ratio of electron (max/true): " << _max_charge/_true_charge << std::endl; std::cout << "ratio of electron (comp/true): " << _comp_charge/_true_charge << std::endl; std::cout << "ratio of energy (calc/true): " << _slice_E/_true_energy << std::endl; - // std::cout << "fractional energy difference: " << (_true_energy - _slice_E)/_true_energy << std::endl; - - _opflash_time = flash_time; - - _frac_L = (_true_gamma - _slice_L)/_true_gamma; - _frac_Q = (_true_charge - _slice_Q)/_true_charge; - _frac_E = (_true_energy - _slice_E)/_true_energy; - _tree2->Fill(); nsuccessful_matches++; } // end slice loop _match_type=nsuccessful_matches; @@ -607,8 +597,6 @@ std::vector sbnd::LightCaloAna::CalcVisibility(std::vector visibility[ch] += charge*direct_visibility[ch]; else if (_opdetmap.isPDType(ch, "pmt_coated")) visibility[ch] += charge*(direct_visibility[ch] + reflect_visibility[ch]); - - // std::cout << "x: " << xyz.X() << "vis: " << visibility[ch] << std::endl; } } // end spacepoint loop // normalize by the total charge in each TPC @@ -616,8 +604,6 @@ std::vector sbnd::LightCaloAna::CalcVisibility(std::vector if (ch%2 == 0) visibility[ch] /= sum_charge0; if (ch%2 == 1) visibility[ch] /= sum_charge1; } - // std::transform(visibility.begin(), visibility.end(), - // visibility.begin(), [sum_charge](double &k){ return k/sum_charge; }); return visibility; } void sbnd::LightCaloAna::CalcLight(std::vector flash_pe_v, From 2e972c0de584196b5ea227dcfff9023cb940ecdc Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Fri, 17 Feb 2023 16:11:38 -0600 Subject: [PATCH 15/52] cleanup: remove hardcoded values, add fcl params --- sbndcode/Calorimetry/LightCaloAna_module.cc | 278 ++++++++++++-------- sbndcode/Calorimetry/lightcalo.fcl | 28 +- 2 files changed, 187 insertions(+), 119 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index c844a5758..701cb6ab3 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -1,10 +1,11 @@ //////////////////////////////////////////////////////////////////////// // Class: LightCaloAna -// Plugin Type: analyzer (Unknown Unknown) +// Plugin Type: analyzer // File: LightCaloAna_module.cc // -// Generated at Fri Oct 14 13:43:49 2022 by Lynn Tung using cetskelgen -// from version . +// This module reconstructs the total visible energy in an event by +// combining charge (recob::Hit) and light (recob::OpFlash) information +// Authors: Lynn Tung //////////////////////////////////////////////////////////////////////// #include "art/Framework/Core/EDAnalyzer.h" @@ -36,20 +37,22 @@ #include "lardataobj/RecoBase/Wire.h" #include "lardataobj/RecoBase/OpFlash.h" #include "lardataobj/AnalysisBase/T0.h" -#include "larcore/CoreUtils/ServiceUtil.h" -#include "larsim/PhotonPropagation/SemiAnalyticalModel.h" -#include "lardata/DetectorInfoServices/DetectorPropertiesService.h" -#include "lardata/DetectorInfoServices/DetectorClocksService.h" + #include "lardataobj/Simulation/SimPhotons.h" #include "lardataobj/Simulation/SimEnergyDeposit.h" -#include "larcore/CoreUtils/ServiceUtil.h" -#include "larsim/MCCheater/BackTrackerService.h" -#include "larsim/MCCheater/ParticleInventoryService.h" #include "nusimdata/SimulationBase/GTruth.h" #include "nusimdata/SimulationBase/MCTruth.h" #include "lardataobj/Simulation/SimChannel.h" #include "lardataobj/Simulation/sim.h" +#include "larcore/CoreUtils/ServiceUtil.h" +#include "larcore/Geometry/Geometry.h" +#include "larsim/PhotonPropagation/SemiAnalyticalModel.h" +#include "larsim/Simulation/LArG4Parameters.h" +#include "larsim/MCCheater/ParticleInventoryService.h" +#include "lardata/DetectorInfoServices/DetectorClocksService.h" +#include "lardata/DetectorInfoServices/DetectorPropertiesService.h" + // SBND includes #include "sbnobj/Common/Reco/SimpleFlashMatchVars.h" #include "sbndcode/OpDetSim/sbndPDMapAlg.hh" @@ -67,7 +70,6 @@ namespace sbnd { class LightCaloAna; } - class sbnd::LightCaloAna : public art::EDAnalyzer { public: explicit LightCaloAna(fhicl::ParameterSet const& p); @@ -85,17 +87,28 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { private: - // define functions - opdet::sbndPDMapAlg _opdetmap; //map for photon detector types - unsigned int _nchan = _opdetmap.size(); - + // Matches SimpleFlash time to OpFlashes, fills match_v with succesfully matched OpFlashes + // returns true if match was found bool MatchOpFlash(std::vector> fm_v, std::vector> flash_v, std::vector> &match_v); - std::vector CalcVisibility(std::vector xyz_v, std::vector charge_v); - void CalcLight(std::vector flash_pe_v, std::vector visibility, std::vector&total_pe_v); + + // Returns visibility vector for all opdets given charge/position information + std::vector CalcVisibility(std::vector xyz_v, + std::vector charge_v); + + // Fills reconstructed photon count vector (total_gamma_v) for all opdets given charge/position information + void CalcLight(std::vector flash_pe_v, + std::vector visibility, + std::vector &total_gamma_v); + + // Returns the median of the light vector double CalcMedian(std::vector total_light); + + // Returns the mean of the light vector double CalcMean(std::vector total_light); + + // fcl parameters std::vector _opflash_producer_v; std::vector _opflash_ara_producer_v; std::string _slice_producer; @@ -103,45 +116,61 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { bool _use_arapucas; float _nuscore_cut; float _fmscore_cut; + + float _simple_op_offset; + float _pmt_ara_offset; + std::vector _noise_thresh; + std::vector _cal_area_const; + std::vector _opdet_eff; + float _scint_prescale; + + std::string _simenergy_producer; + bool _truth_neutrino; std::unique_ptr _semi_model; fhicl::ParameterSet _vuv_params; fhicl::ParameterSet _vis_params; + opdet::sbndPDMapAlg _opdetmap; //map for photon detector types + unsigned int _nchan = _opdetmap.size(); int _run, _subrun, _event; TTree* _tree; - int _match_type; + int _match_type; + // match_type key: + //// -1: no slices passed both the nuscore and flash match score cut + //// -2: no opflashes times found in coincidence with simpleflash time + //// -3: opflashes are empty or PE count too low TTree* _tree2; - int _nmatch=0; - int _pfpid; - double _opflash_time; - - std::vector _dep_pe; - std::vector _rec_gamma; + int _nmatch=0; // number of matches in an event + int _pfpid; // ID of the matched slice + double _opflash_time; // time of matched opflash - double _true_gamma; - double _true_charge; - double _true_energy; + std::vector _dep_pe; // vector of measured photo-electron (PE), one entry = one channel + std::vector _rec_gamma; // vector of reconstructed photon count, one entry = one channel - double _median_gamma; - double _mean_gamma; + double _true_gamma; // true photon count from all energy depositions + double _true_charge; // true electron count from all energy depositions + double _true_energy; // true deposited energy - double _mean_charge; - double _max_charge; - double _comp_charge; + double _median_gamma; // median of all reconstructed light estimates + double _mean_gamma; // mean of all reconstructed light estimates - double _slice_L; - double _slice_Q; - double _slice_E; + double _mean_charge; // avg charge from all three planes + double _max_charge; // charge from the plane with the highest amount of charge + double _comp_charge; // charge from the plane with the highest number of hits, "highest completeness" + double _coll_charge; // charge from collection plane only - double _frac_L; - double _frac_Q; - double _frac_E; + double _slice_L; // reconstructed photon count + double _slice_Q; // reconstructed electron count + double _slice_E; // reconstructed deposited energy + double _frac_L; // light fractional difference: (L_{true} - L_{reco})/(L_{true}) + double _frac_Q; // charge fractional difference: (Q_{true} - Q_{reco})/(Q_{true}) + double _frac_E; // energy fractional difference: (E_{true} - E_{reco})/(E_{true}) }; @@ -160,7 +189,17 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _use_arapucas = p.get("UseArapucas"); _nuscore_cut = p.get("nuScoreCut"); _fmscore_cut = p.get("fmScoreCut"); - _cal_area_const = p.get>("CalAreaConstants"); + + _simple_op_offset= p.get("SimpleOpFlashOffset"); + _pmt_ara_offset = p.get("PMTARAFlashOffset"); + _noise_thresh = p.get>("FlashNoiseThreshold"); + + _cal_area_const = p.get>("CalAreaConstants"); + _opdet_eff = p.get>("OpDetEfficiencies"); + _scint_prescale = p.get("ScintPreScale"); + + _simenergy_producer = p.get("SimEnergyProducer"); + _truth_neutrino = p.get("TruthNeutrino"); art::ServiceHandle fs; _tree = fs->make("slice_tree",""); @@ -189,6 +228,7 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _tree2->Branch("mean_charge", &_mean_charge, "mean_charge/D"); _tree2->Branch("max_charge", &_max_charge, "max_charge/D"); _tree2->Branch("comp_charge", &_comp_charge, "comp_charge/D"); + _tree2->Branch("coll_charge", &_coll_charge, "coll_charge/D"); _tree2->Branch("slice_L", &_slice_L, "slice_L/D"); _tree2->Branch("slice_Q", &_slice_Q, "slice_Q/D"); @@ -201,18 +241,25 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) void sbnd::LightCaloAna::analyze(art::Event const& e) { + // services + auto const clock_data = art::ServiceHandle()->DataFor(e); + auto const det_prop = art::ServiceHandle()->DataFor(e, clock_data); + + + art::ServiceHandle geom; + art::ServiceHandle g4param; + art::ServiceHandle piserv; + _run = e.id().run(); _subrun = e.id().subRun(); _event = e.id().event(); std::cout << "run: " << _run << ", subrun: " << _subrun << ", event: " << _event << std::endl; - auto const clockData(art::ServiceHandle()->DataFor(e)); - // get slices ::art::Handle> slice_h; e.getByLabel(_slice_producer, slice_h); if(!slice_h.isValid() || slice_h->empty()){ - std::cout << "dont have good slices!" << std::endl; + std::cout << "don't have good slices!" << std::endl; return; } @@ -226,23 +273,35 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) ::art::Handle> spacepoint_h; e.getByLabel(_slice_producer, spacepoint_h); if(!spacepoint_h.isValid() || spacepoint_h->empty()) { - std::cout << "Don't have good SpacePoints!" << std::endl; + std::cout << "don't have good SpacePoints!" << std::endl; return; } auto const & flash0_h = e.getValidHandle>(_opflash_producer_v[0]); auto const & flash1_h = e.getValidHandle>(_opflash_producer_v[1]); + if (!_use_arapucas) + std::cout << "Using PMT OpFlash only..." << std::endl; if( (!flash0_h.isValid() || flash0_h->empty()) && (!flash1_h.isValid() || flash1_h->empty())) { - std::cout << "don't have good flashes from producer " << _opflash_producer_v[0] << " or " << _opflash_producer_v[1] << std::endl; + std::cout << "don't have good PMT flashes from producer " << _opflash_producer_v[0] << " or " << _opflash_producer_v[1] << std::endl; return; } + // if using arapucas auto const & flash0_ara_h = e.getValidHandle>(_opflash_ara_producer_v[0]); auto const & flash1_ara_h = e.getValidHandle>(_opflash_ara_producer_v[1]); + if (_use_arapucas) + std::cout << "Using PMT OpFlash + X-ARAPUCA OpFlash..." << std::endl; if( _use_arapucas && (!flash0_ara_h.isValid() || flash0_ara_h->empty()) && (!flash1_ara_h.isValid() || flash1_ara_h->empty())) { - std::cout << "don't have good flashes from producer " << _opflash_ara_producer_v[0] << " or " << _opflash_ara_producer_v[1] << std::endl; + std::cout << "don't have good X-ARAPUCA flashes from producer " << _opflash_ara_producer_v[0] << " or " << _opflash_ara_producer_v[1] << std::endl; return; } + // get truth information + const art::ValidHandle>& + energyDeps(e.getValidHandle>(_simenergy_producer)); + if (!energyDeps.isValid() || energyDeps->empty()){ + std::cout << "Don't have good SimEnergyDeposits!" << std::endl; + } + // Construct the vector of Slices std::vector> slice_v; art::fill_ptr_vector(slice_v, slice_h); @@ -261,7 +320,6 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) for (size_t n_slice=0; n_slice < slice_v.size(); n_slice++){ float nu_score = -9999; float fm_score = -9999; - // float fm_time = -9999; auto slice = slice_v[n_slice]; bool found_fm = false; std::vector> pfp_v = slice_to_pfp.at(n_slice); @@ -269,9 +327,10 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) auto pfp = pfp_v[n_pfp]; // only select the PRIMARY pfp - if(!pfp->IsPrimary() && !(abs(pfp->PdgCode()) == 12 || abs(pfp->PdgCode()) == 14|| abs(pfp->PdgCode()) == 16)) + if(!pfp->IsPrimary()) + continue; + if(_truth_neutrino && !(abs(pfp->PdgCode()) == 12 || abs(pfp->PdgCode()) == 14|| abs(pfp->PdgCode()) == 16)) continue; - // if primary, get nu-score const std::vector> pfpmeta_v = pfp_to_meta.at(pfp->Self()); const art::Ptr pfpmeta = pfpmeta_v.front(); @@ -282,6 +341,7 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) // get fm-score std::vector> fm_v = pfp_to_sfm.at(pfp.key()); if (fm_v.empty()){ + std::cout << "No SimpleFlashMatch objects associated with this PFP!" << std::endl; continue; } if (fm_v.size() > 1) @@ -289,7 +349,6 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) for (size_t n_fm=0; n_fm < fm_v.size(); n_fm++){ auto fm = fm_v.at(n_fm); fm_score = fm->score.total; - // fm_time = fm->time; if (nu_score > _nuscore_cut && fm_score < _fmscore_cut && fm_score > 0){ found_fm = true; match_fm_v.push_back(fm); @@ -336,11 +395,6 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) return; } - const art::ValidHandle>& - energyDeps(e.getValidHandle>("ionandscint")); - - art::ServiceHandle pi_serv; - int nsuccessful_matches=0; for (size_t n_slice=0; n_slice < match_slices_v.size(); n_slice++){ // initialize tree2 variables @@ -360,7 +414,7 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) bool flash_in_0 = false; bool flash_in_1 = false; // set threshold above noise PE levels for the flash - double noise_thresh = (_use_arapucas)? 2000 : 1000; + float noise_thresh = (!_use_arapucas)? _noise_thresh[0] : _noise_thresh[1]; if (!opflash0.isNull() && opflash1.isNull()){ flash_time = opflash0->Time(); @@ -402,19 +456,20 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) std::vector plane_hits{0,0,0}; for (size_t i=0; i < slice_hits_v.size(); i++){ auto hit = slice_hits_v[i]; - auto drift_time = (hit->PeakTime() - 500)*0.5; // us - double atten_correction = std::exp(drift_time/10e3); // electron lifetime = 10e3 us, or 10 ms + auto drift_time = (hit->PeakTime() - 500)*0.5; // assuming TPC beam readout starts at 500 ticks, conversion = 0.5 us/tick + double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) auto hit_plane = hit->View(); plane_charge.at(hit_plane) += hit->Integral()*atten_correction*(1/_cal_area_const.at(hit_plane)); plane_hits.at(hit_plane)++; } - // std::cout << "charge: " << plane_charge[0] << ", " << plane_charge[1] << ", " << plane_charge[2] << std::endl; + uint bestPlane = std::max_element(plane_charge.begin(), plane_charge.end()) - plane_charge.begin(); uint bestHits = std::max_element(plane_hits.begin(), plane_hits.end()) - plane_hits.begin(); _mean_charge = (plane_charge[0] + plane_charge[1] + plane_charge[2])/3; _max_charge = plane_charge.at(bestPlane); _comp_charge = plane_charge.at(bestHits); + _coll_charge = plane_charge[2]; _slice_Q = _comp_charge; @@ -435,9 +490,9 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) const auto &position(sp->XYZ()); geo::Point_t xyz(position[0],position[1],position[2]); // correct for e- attenuation - double drift_time = abs(200.0 - abs(position[0]))/(0.16); // in us, drift velocity = 0.16 cm/us - double atten_correction = std::exp(drift_time/10e3); // electron lifetime = 10e3 us, or 10 ms - double charge = (1/.0201293)*atten_correction*hit->Integral(); + double drift_time = ((2.0*geom->DetHalfWidth()) - abs(position[0]))/(det_prop.DriftVelocity()); // cm / (cm/us) + double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) + double charge = (1/_cal_area_const.at(bestPlane))*atten_correction*hit->Integral(); sp_xyz.push_back(xyz); sp_charge.push_back(charge); @@ -451,40 +506,33 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) std::vector total_pe(_nchan,0.); std::vector total_gamma(_nchan, 0.); - if (flash_in_0){ - std::cout << "Using OpFlash in TPC 0..." << std::endl; - auto flash_pe_v = opflash0->PEs(); - flash_pe_v.insert(flash_pe_v.end(), {0,0,0,0,0,0}); - if (_use_arapucas){ - for (size_t nara=0; nara < flash0_ara_v.size(); nara++){ - auto const &flash0_ara = *flash0_ara_v[nara]; - if (flash0_ara.Time() - flash_time < 0.05){ - for (size_t ich=0; ich < (flash0_ara.PEs()).size(); ich++) - flash_pe_v.at(ich) += (flash0_ara.PEs()).at(ich); - break; - } - } + // combining flash PE information from separate TPCs into a single vector + for (int tpc=0; tpc<2; tpc++){ + bool found_flash = (tpc==0)? flash_in_0 : flash_in_1; + if (found_flash){ + auto flash_pe_v = (tpc==0)? opflash0->PEs() : opflash1->PEs(); + // if using arapucas, need to combine PMT and arapuca PE information into a single vector + if (_use_arapucas){ + auto flash_ara_v = (tpc==0)? flash0_ara_v : flash1_ara_v; + // for PMT flashes, the PE vector is shortened and don't include the last 6 entries for ARAPUCAs + if (flash_pe_v.size()!= _nchan) flash_pe_v.insert(flash_pe_v.end(), {0,0,0,0,0,0}); + for (size_t nara=0; nara < flash_ara_v.size(); nara++){ + auto const &flash_ara = *flash_ara_v[nara]; + if (abs(flash_time-flash_ara.Time()) < _pmt_ara_offset){ + std::cout << "Combining PMT+XARA Flashes with PMT time: " << flash_time << ", ARA time: " << flash_ara.Time() << std::endl; + for (size_t ich=0; ich < (flash_ara.PEs()).size(); ich++) + flash_pe_v.at(ich) += (flash_ara.PEs()).at(ich); + break; + } + } + } // end of arapuca if + for (size_t ich=0; ichPEs(); - std::cout << "Using OpFlash in TPC 1..." << std::endl; - flash_pe_v.insert(flash_pe_v.end(), {0,0,0,0,0,0}); - if (_use_arapucas){ - for (size_t nara=0; nara < flash0_ara_v.size(); nara++){ - auto const &flash0_ara = *flash0_ara_v[nara]; - if (flash0_ara.Time() - flash_time < 0.05){ - for (size_t ich=0; ich < (flash0_ara.PEs()).size(); ich++) - flash_pe_v.at(ich) += (flash0_ara.PEs()).at(ich); - break; - } - } - } - for (size_t ich=0; ichWph(); // MeV, Wph = 19.5 eV // get truth information _true_gamma = 0; @@ -507,15 +555,18 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) _true_energy = 0; for (const sim::SimEnergyDeposit& energyDep:*energyDeps){ - auto trackID = energyDep.TrackID(); + const auto trackID = energyDep.TrackID(); + const double time = energyDep.Time() * 1e-3; // us - art::Ptr mctruth = pi_serv->TrackIdToMCTruth_P(trackID); - if (mctruth->Origin()==simb::kBeamNeutrino){ - - _true_gamma += energyDep.NumPhotons()/0.03; // scint-prescale = 0.03 + art::Ptr mctruth = piserv->TrackIdToMCTruth_P(trackID); + + if ((_truth_neutrino && mctruth->Origin()==simb::kBeamNeutrino ) || + (!_truth_neutrino && abs(time-flash_time) < 1)){ + // note: we divide by the prescale because NumPhotons() stored in simulation has the scint prescale applied + _true_gamma += energyDep.NumPhotons()/_scint_prescale; _true_charge += energyDep.NumElectrons(); _true_energy += energyDep.Energy(); - } + } } _frac_L = (_true_gamma - _slice_L)/_true_gamma; @@ -552,8 +603,8 @@ bool sbnd::LightCaloAna::MatchOpFlash(std::vectortime; for (size_t iop=0; iopTime() - match_time) < 0.17){ + // only select opflashes that are coincident with the SimpleFlash t0 + if (abs(opflash->Time() - match_time) < _simple_op_offset){ found_match = true; any_match = true; match_v.push_back(opflash); @@ -608,25 +659,29 @@ std::vector sbnd::LightCaloAna::CalcVisibility(std::vector } void sbnd::LightCaloAna::CalcLight(std::vector flash_pe_v, std::vector visibility, - std::vector &total_pe_v){ + std::vector &total_gamma_v){ for (size_t ch = 0; ch < flash_pe_v.size(); ch++){ auto pe = flash_pe_v[ch]; double efficiency = 0.03; if((pe == 0) || std::isinf(1/visibility[ch])) continue; - if (_opdetmap.isPDType(ch, "pmt_uncoated") || _opdetmap.isPDType(ch, "pmt_coated")) - efficiency = 0.03; - else if (_opdetmap.isPDType(ch, "xarapuca_vuv")) - efficiency = 0.021; + if (_opdetmap.isPDType(ch, "pmt_uncoated")) + efficiency = _opdet_eff[0]; + else if (_opdetmap.isPDType(ch, "pmt_coated")) + efficiency = _opdet_eff[1]; else if (_opdetmap.isPDType(ch, "xarapuca_vis")) - efficiency = 0.014; - total_pe_v[ch] += (1/efficiency)*pe*(1/visibility[ch]); + efficiency = _opdet_eff[2]; + else if (_opdetmap.isPDType(ch, "xarapuca_vuv")) + efficiency = _opdet_eff[3]; + // deposited light is inverse of efficiency * inverse of visibility * PE count + total_gamma_v[ch] += (1/efficiency)*(1/visibility[ch])*pe; } } double sbnd::LightCaloAna::CalcMedian(std::vector total_gamma){ std::vector tpc0_gamma; std::vector tpc1_gamma; + // split into two TPCs for (size_t i=0; i total_gamma){ [&](int A, int B) -> bool { return gamma_v[A] < gamma_v[B]; }); - // count number of zero entries: + // count number of zero entries int zero_counter = 0; for (size_t i=0; i < gamma_v.size(); i++){ if (gamma_v.at(i) <= 0) zero_counter++; @@ -681,5 +736,4 @@ double sbnd::LightCaloAna::CalcMean(std::vector total_gamma){ return mean_gamma; } - DEFINE_ART_MODULE(sbnd::LightCaloAna) diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index f17c4711f..55bd12f41 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -8,13 +8,27 @@ lightcalo_ana: VUVHits: @local::sbnd_vuv_RS100cm_hits_parameterization VIVHits: @local::sbnd_vis_RS100cm_hits_parameterization - OpFlashProducers: ["opflashtpc0", "opflashtpc1"] + OpFlashProducers: ["opflashtpc0", "opflashtpc1"] OpFlashAraProducers: ["opflashtpc0xarapuca", "opflashtpc1xarapuca"] - SliceProducer: "pandora" - FlashMatchProducer: "fmatch" - UseArapucas: false - nuScoreCut: 0.4 # accept nusScore > 0.4, to analyze all slices, set = 0 - fmScoreCut: 7 # accept 0 < fm score < fmScoreCut, to analyze all slices, set = 1e3 - CalAreaConstants: [ 0.0200906, 0.0200016, 0.0201293 ] + SliceProducer: "pandora" + FlashMatchProducer: "fmatch" + UseArapucas: false + nuScoreCut: 0.4 # default: accept nusScore > 0.4, to analyze all slices, set nuScoreCut = -1 + fmScoreCut: 7 # default: accept 0 < fm score < fmScoreCut, to analyze all slices, set fmScoreCut = 1e3 + + # flash parameters + SimpleOpFlashOffset: 0.2 # the offset between the t0 from SimpleFlash and OpFlashes + PMTARAFlashOffset: 0.05 # the offset between the t0 of PMT OpFlashes and X-ARA OpFlashes + FlashNoiseThreshold: [ 600., 1500. ] # {PMT, xARAPUCA}, flash total PE threshold to ignore a flash + + # calibration constants & simulation parameters + ## shouldn't have to change this unless you change simulation parameters + CalAreaConstants: [ 0.0200906, 0.0200016, 0.0201293 ] # calibration constants for wire planes + OpDetEfficiencies: [ 0.03, 0.03, 0.014, 0.021 ] # efficiencies [uncoated PMT, coated PMT, vis ara, vuv ara + ScintPreScale: 0.03 # Scintillation Pre-Scale factor in simulation (set in ionandscint) + + # parameters for truth validation + SimEnergyProducer: "ionandscint" # only looking at energy deposits in the AV + TruthNeutrino: true # if analyzing cosmic sample (or non-beam neutrino), set to false } END_PROLOG From 5a0893ca2a83ccbe850c3498eab7d13943b2c993 Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Tue, 7 Mar 2023 17:39:03 -0600 Subject: [PATCH 16/52] added verbose + skip truth validation fcl - cleaned (but need to clean more) skipping products that aren't used (xarapuca flashes + truth products) for example to avoid nullptr --- sbndcode/Calorimetry/lightcalo.fcl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index 55bd12f41..c96babb0c 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -15,6 +15,7 @@ lightcalo_ana: UseArapucas: false nuScoreCut: 0.4 # default: accept nusScore > 0.4, to analyze all slices, set nuScoreCut = -1 fmScoreCut: 7 # default: accept 0 < fm score < fmScoreCut, to analyze all slices, set fmScoreCut = 1e3 + Verbose: false # flash parameters SimpleOpFlashOffset: 0.2 # the offset between the t0 from SimpleFlash and OpFlashes @@ -24,11 +25,12 @@ lightcalo_ana: # calibration constants & simulation parameters ## shouldn't have to change this unless you change simulation parameters CalAreaConstants: [ 0.0200906, 0.0200016, 0.0201293 ] # calibration constants for wire planes - OpDetEfficiencies: [ 0.03, 0.03, 0.014, 0.021 ] # efficiencies [uncoated PMT, coated PMT, vis ara, vuv ara + OpDetEfficiencies: [ 0.03, 0.03, 0.014, 0.021 ] # efficiencies [uncoated PMT, coated PMT, vis ara, vuv ara] ScintPreScale: 0.03 # Scintillation Pre-Scale factor in simulation (set in ionandscint) # parameters for truth validation + TruthValidation: false # can only set to true if the reco2 files have SimEnergyDeposits SimEnergyProducer: "ionandscint" # only looking at energy deposits in the AV - TruthNeutrino: true # if analyzing cosmic sample (or non-beam neutrino), set to false + TruthNeutrino: true # if validating anything other than simb::kBeamNeutrino, set to false } END_PROLOG From bd8b7602118af505ff21b02c4eb050f714eccb19 Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Tue, 7 Mar 2023 17:39:45 -0600 Subject: [PATCH 17/52] added verbose + skip truth validation fcl - cleaned (but need to clean more) skipping products that aren't used (xarapuca flashes + truth products) for example to avoid nullptr --- sbndcode/Calorimetry/LightCaloAna_module.cc | 146 ++++++++++++-------- 1 file changed, 90 insertions(+), 56 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index 701cb6ab3..c84d6978d 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -4,7 +4,9 @@ // File: LightCaloAna_module.cc // // This module reconstructs the total visible energy in an event by -// combining charge (recob::Hit) and light (recob::OpFlash) information +// combining charge (recob::Hit) and light (recob::OpFlash) information. +// Runs on reco2 files, requires flash-matching +// uses the Semi-Analytical Photon Model // Authors: Lynn Tung //////////////////////////////////////////////////////////////////////// @@ -116,6 +118,7 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { bool _use_arapucas; float _nuscore_cut; float _fmscore_cut; + bool _verbose; float _simple_op_offset; float _pmt_ara_offset; @@ -125,6 +128,7 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { std::vector _opdet_eff; float _scint_prescale; + bool _truth_validation; std::string _simenergy_producer; bool _truth_neutrino; @@ -189,6 +193,7 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _use_arapucas = p.get("UseArapucas"); _nuscore_cut = p.get("nuScoreCut"); _fmscore_cut = p.get("fmScoreCut"); + _verbose = p.get("Verbose"); _simple_op_offset= p.get("SimpleOpFlashOffset"); _pmt_ara_offset = p.get("PMTARAFlashOffset"); @@ -198,6 +203,7 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _opdet_eff = p.get>("OpDetEfficiencies"); _scint_prescale = p.get("ScintPreScale"); + _truth_validation = p.get("TruthValidation"); _simenergy_producer = p.get("SimEnergyProducer"); _truth_neutrino = p.get("TruthNeutrino"); @@ -279,28 +285,17 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) auto const & flash0_h = e.getValidHandle>(_opflash_producer_v[0]); auto const & flash1_h = e.getValidHandle>(_opflash_producer_v[1]); - if (!_use_arapucas) + if (!_use_arapucas && _verbose) std::cout << "Using PMT OpFlash only..." << std::endl; if( (!flash0_h.isValid() || flash0_h->empty()) && (!flash1_h.isValid() || flash1_h->empty())) { std::cout << "don't have good PMT flashes from producer " << _opflash_producer_v[0] << " or " << _opflash_producer_v[1] << std::endl; return; } - // if using arapucas - auto const & flash0_ara_h = e.getValidHandle>(_opflash_ara_producer_v[0]); - auto const & flash1_ara_h = e.getValidHandle>(_opflash_ara_producer_v[1]); - if (_use_arapucas) - std::cout << "Using PMT OpFlash + X-ARAPUCA OpFlash..." << std::endl; - if( _use_arapucas && (!flash0_ara_h.isValid() || flash0_ara_h->empty()) && (!flash1_ara_h.isValid() || flash1_ara_h->empty())) { - std::cout << "don't have good X-ARAPUCA flashes from producer " << _opflash_ara_producer_v[0] << " or " << _opflash_ara_producer_v[1] << std::endl; - return; - } - // get truth information - const art::ValidHandle>& - energyDeps(e.getValidHandle>(_simenergy_producer)); - if (!energyDeps.isValid() || energyDeps->empty()){ - std::cout << "Don't have good SimEnergyDeposits!" << std::endl; - } + // const art::ValidHandle>& + // energyDeps(e.getValidHandle>(_simenergy_producer)); + // if ( (!energyDeps.isValid() || energyDeps->empty()) && _truth_validation){ + // } // Construct the vector of Slices std::vector> slice_v; @@ -377,8 +372,18 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) bool found_opflash0 = MatchOpFlash(match_fm_v,flash0_v, match_op0); std::vector> flash0_ara_v; - art::fill_ptr_vector(flash0_ara_v, flash0_ara_h); - + // if using arapucas + if (_use_arapucas){ + ::art::Handle> flash0_ara_h; + e.getByLabel(_opflash_ara_producer_v[0],flash0_ara_h); + if (_verbose) std::cout << "Using PMT OpFlash + X-ARAPUCA OpFlash..." << std::endl; + if (!flash0_ara_h.isValid() || flash0_ara_h->empty()) { + std::cout << "don't have good X-ARAPUCA flashes from producer " << _opflash_ara_producer_v[0] << std::endl; + // return; + } + else + art::fill_ptr_vector(flash0_ara_v, flash0_ara_h); + } // tpc1 std::vector> flash1_v; art::fill_ptr_vector(flash1_v, flash1_h); @@ -386,8 +391,17 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) bool found_opflash1 = MatchOpFlash(match_fm_v,flash1_v, match_op1); std::vector> flash1_ara_v; - art::fill_ptr_vector(flash1_ara_v, flash1_ara_h); - + if (_use_arapucas){ + ::art::Handle> flash1_ara_h; + e.getByLabel(_opflash_ara_producer_v[1],flash1_ara_h); + if (_verbose) std::cout << "Using PMT OpFlash + X-ARAPUCA OpFlash..." << std::endl; + if (!flash1_ara_h.isValid() || flash1_ara_h->empty()) { + std::cout << "don't have good X-ARAPUCA flashes from producer " << _opflash_ara_producer_v[1] << std::endl; + // return; + } + else + art::fill_ptr_vector(flash1_ara_v, flash1_ara_h); + } if (found_opflash0 == false && found_opflash1 == false){ std::cout << "no opflashes matched to simpleflashes" << std::endl; _match_type = -2; @@ -420,26 +434,26 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) flash_time = opflash0->Time(); if (opflash0->TotalPE() > noise_thresh) flash_in_0 = true; - else - std::cout << "Flash Total PE in TPC 0 too low ("<< opflash0->TotalPE() << ")... Skipping" << std::endl; + else if (_verbose) + std::cout << "Flash Total PE in TPC 0 (" << opflash0->TotalPE() << ") below noise threshold ... Skipping" << std::endl; } else if ( opflash0.isNull() && !opflash1.isNull()){ flash_time = opflash1->Time(); if (opflash1->TotalPE() > noise_thresh) flash_in_1 = true; - else - std::cout << "Flash Total PE in TPC 1 too low(" << opflash1->TotalPE() << ")... Skipping" << std::endl; + else if (_verbose) + std::cout << "Flash Total PE in TPC 1 (" << opflash1->TotalPE() << ") below noise threshold ... Skipping" << std::endl; } else if (!opflash0.isNull() && !opflash1.isNull()){ flash_time = opflash0->Time(); if (opflash0->TotalPE() > noise_thresh) flash_in_0 = true; - else - std::cout << "Flash Total PE in TPC 0 too low ("<< opflash0->TotalPE() << ")... Skipping" << std::endl; + else if (_verbose) + std::cout << "Flash Total PE in TPC 0 (" << opflash0->TotalPE() << ") below noise threshold ... Skipping" << std::endl; if (opflash1->TotalPE() > noise_thresh) flash_in_1 = true; - else - std::cout << "Flash Total PE in TPC 1 too low(" << opflash1->TotalPE() << ")... Skipping" << std::endl; + else if (_verbose) + std::cout << "Flash Total PE in TPC 1 (" << opflash1->TotalPE() << ") below noise threshold ... Skipping" << std::endl; } else if (opflash0.isNull() && opflash1.isNull()){ std::cout << "No opflashes matched with SimpleFlash objects" << std::endl; @@ -519,7 +533,8 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) for (size_t nara=0; nara < flash_ara_v.size(); nara++){ auto const &flash_ara = *flash_ara_v[nara]; if (abs(flash_time-flash_ara.Time()) < _pmt_ara_offset){ - std::cout << "Combining PMT+XARA Flashes with PMT time: " << flash_time << ", ARA time: " << flash_ara.Time() << std::endl; + if (_verbose) + std::cout << "Combining PMT+XARA Flashes with PMT time: " << flash_time << ", ARA time: " << flash_ara.Time() << std::endl; for (size_t ich=0; ich < (flash_ara.PEs()).size(); ich++) flash_pe_v.at(ich) += (flash_ara.PEs()).at(ich); break; @@ -549,44 +564,63 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) _slice_E = (_slice_L + _slice_Q)*1e-6*g4param->Wph(); // MeV, Wph = 19.5 eV - // get truth information _true_gamma = 0; _true_charge = 0; _true_energy = 0; - for (const sim::SimEnergyDeposit& energyDep:*energyDeps){ - const auto trackID = energyDep.TrackID(); - const double time = energyDep.Time() * 1e-3; // us + if (_truth_validation){ + ::art::Handle> energyDeps_h; + e.getByLabel(_simenergy_producer, energyDeps_h); + std::vector> energyDeps; + + if (energyDeps_h.isValid() || energyDeps_h->empty()) + std::cout << "Don't have good SimEnergyDeposits!" << std::endl; + else + art::fill_ptr_vector(energyDeps, energyDeps_h); + + for (size_t n_dep=0; n_dep < energyDeps.size(); n_dep++){ + auto energyDep = energyDeps[n_dep]; + const auto trackID = energyDep->TrackID(); + const double time = energyDep->Time() * 1e-3; // us + + art::Ptr mctruth = piserv->TrackIdToMCTruth_P(trackID); + + if ((_truth_neutrino && mctruth->Origin()==simb::kBeamNeutrino ) || + (!_truth_neutrino && abs(time-flash_time) < 1)){ + // note: we divide by the prescale because NumPhotons() stored in simulation has the scint prescale applied + _true_gamma += energyDep->NumPhotons()/_scint_prescale; + _true_charge += energyDep->NumElectrons(); + _true_energy += energyDep->Energy(); + } + } + _frac_L = (_true_gamma - _slice_L)/_true_gamma; + _frac_Q = (_true_charge - _slice_Q)/_true_charge; + _frac_E = (_true_energy - _slice_E)/_true_energy; + + if (_verbose){ + std::cout << "ratio of gamma (median/true): " << _median_gamma/_true_gamma << std::endl; + std::cout << "ratio of gamma (mean/true): " << _mean_gamma/_true_gamma << std::endl; - art::Ptr mctruth = piserv->TrackIdToMCTruth_P(trackID); + std::cout << "ratio of electron (mean/true): " << _mean_charge/_true_charge << std::endl; + std::cout << "ratio of electron (max/true): " << _max_charge/_true_charge << std::endl; + std::cout << "ratio of electron (comp/true): " << _comp_charge/_true_charge << std::endl; - if ((_truth_neutrino && mctruth->Origin()==simb::kBeamNeutrino ) || - (!_truth_neutrino && abs(time-flash_time) < 1)){ - // note: we divide by the prescale because NumPhotons() stored in simulation has the scint prescale applied - _true_gamma += energyDep.NumPhotons()/_scint_prescale; - _true_charge += energyDep.NumElectrons(); - _true_energy += energyDep.Energy(); - } + std::cout << "ratio of energy (calc/true): " << _slice_E/_true_energy << std::endl; + } } - - _frac_L = (_true_gamma - _slice_L)/_true_gamma; - _frac_Q = (_true_charge - _slice_Q)/_true_charge; - _frac_E = (_true_energy - _slice_E)/_true_energy; + else{ + _true_gamma = -9999; + _true_charge = -9999; + _true_energy = -9999; + _frac_L = -9999; + _frac_Q = -9999; + _frac_E = -9999; + } _tree2->Fill(); - - std::cout << "ratio of gamma (median/true): " << _median_gamma/_true_gamma << std::endl; - std::cout << "ratio of gamma (mean/true): " << _mean_gamma/_true_gamma << std::endl; - - std::cout << "ratio of electron (mean/true): " << _mean_charge/_true_charge << std::endl; - std::cout << "ratio of electron (max/true): " << _max_charge/_true_charge << std::endl; - std::cout << "ratio of electron (comp/true): " << _comp_charge/_true_charge << std::endl; - - std::cout << "ratio of energy (calc/true): " << _slice_E/_true_energy << std::endl; nsuccessful_matches++; } // end slice loop _match_type=nsuccessful_matches; _tree->Fill(); - } // end analyze From bf0b0cca4add6e10d8acd6e1072aec7a7f714898 Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Thu, 20 Apr 2023 17:10:08 -0500 Subject: [PATCH 18/52] initial commit of producer module --- sbndcode/Calorimetry/CMakeLists.txt | 2 + sbndcode/Calorimetry/LightCaloAna_module.cc | 6 +- .../Calorimetry/LightCaloProducer_module.cc | 816 ++++++++++++++++++ sbndcode/Calorimetry/lightcalo.fcl | 4 +- sbndcode/Calorimetry/lightcalo_ana.fcl | 36 + sbndcode/Calorimetry/run_lightcalo.fcl | 39 +- 6 files changed, 893 insertions(+), 10 deletions(-) create mode 100644 sbndcode/Calorimetry/LightCaloProducer_module.cc create mode 100644 sbndcode/Calorimetry/lightcalo_ana.fcl diff --git a/sbndcode/Calorimetry/CMakeLists.txt b/sbndcode/Calorimetry/CMakeLists.txt index e3261cc9d..6b4fb70af 100644 --- a/sbndcode/Calorimetry/CMakeLists.txt +++ b/sbndcode/Calorimetry/CMakeLists.txt @@ -26,6 +26,7 @@ set (MODULE_LIBRARIES art_root_io::TFileService_service art::Utilities canvas::canvas messagefacility::MF_MessageLogger + sbnobj::Common_Reco fhiclcpp::fhiclcpp ROOT::Geom @@ -36,6 +37,7 @@ set (MODULE_LIBRARIES sbndcode_OpDetSim ) cet_build_plugin(LightCaloAna art::module SOURCE LightCaloAna_module.cc LIBRARIES ${MODULE_LIBRARIES}) +cet_build_plugin(LightCaloProducer art::module SOURCE LightCaloProducer_module.cc LIBRARIES ${MODULE_LIBRARIES}) install_headers() install_fhicl() diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index c84d6978d..1a9397f9f 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -144,9 +144,9 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { TTree* _tree; int _match_type; // match_type key: - //// -1: no slices passed both the nuscore and flash match score cut - //// -2: no opflashes times found in coincidence with simpleflash time - //// -3: opflashes are empty or PE count too low + /// -1: no slices passed both the nuscore and flash match score cut + /// -2: no opflashes times found in coincidence with simpleflash time + /// -3: opflashes are empty or PE count too low TTree* _tree2; int _nmatch=0; // number of matches in an event diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc new file mode 100644 index 000000000..c861472a9 --- /dev/null +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -0,0 +1,816 @@ +//////////////////////////////////////////////////////////////////////// +// Class: LightCaloProducer +// Plugin Type: producer (Unknown Unknown) +// File: LightCaloProducer_module.cc +// +// Generated at Wed Apr 19 16:49:20 2023 by Lynn Tung using cetskelgen +// from version . +//////////////////////////////////////////////////////////////////////// + +#include "art/Framework/Core/EDProducer.h" +#include "art/Framework/Core/ModuleMacros.h" +#include "art/Framework/Principal/Event.h" +#include "art/Framework/Principal/Handle.h" +#include "art/Framework/Principal/Run.h" +#include "art/Framework/Principal/SubRun.h" +#include "canvas/Utilities/InputTag.h" +#include "fhiclcpp/ParameterSet.h" +#include "messagefacility/MessageLogger/MessageLogger.h" + +// Additional framework includes +#include "art_root_io/TFileService.h" +#include "canvas/Persistency/Common/FindMany.h" +#include "canvas/Persistency/Common/FindManyP.h" +#include "canvas/Persistency/Common/FindOne.h" +#include "canvas/Persistency/Common/FindOneP.h" +#include "canvas/Persistency/Common/Ptr.h" +#include "canvas/Persistency/Common/PtrVector.h" + +// LArSoft includes +#include "lardata/Utilities/AssociationUtil.h" +#include "lardataobj/RecoBase/Slice.h" +#include "lardataobj/RecoBase/PFParticle.h" +#include "lardataobj/RecoBase/PFParticleMetadata.h" +#include "lardataobj/RecoBase/SpacePoint.h" +#include "lardataobj/RecoBase/Hit.h" +#include "lardataobj/RecoBase/Wire.h" +#include "lardataobj/RecoBase/OpFlash.h" +#include "lardataobj/AnalysisBase/T0.h" + +#include "lardataobj/Simulation/SimPhotons.h" +#include "lardataobj/Simulation/SimEnergyDeposit.h" +#include "nusimdata/SimulationBase/GTruth.h" +#include "nusimdata/SimulationBase/MCTruth.h" +#include "lardataobj/Simulation/SimChannel.h" +#include "lardataobj/Simulation/sim.h" + +#include "larcore/CoreUtils/ServiceUtil.h" +#include "larcore/Geometry/Geometry.h" +#include "larsim/PhotonPropagation/SemiAnalyticalModel.h" +#include "larsim/Simulation/LArG4Parameters.h" +#include "larsim/MCCheater/ParticleInventoryService.h" +#include "lardata/DetectorInfoServices/DetectorClocksService.h" +#include "lardata/DetectorInfoServices/DetectorPropertiesService.h" + +// SBND includes +#include "sbnobj/Common/Reco/SimpleFlashMatchVars.h" +#include "sbndcode/OpDetSim/sbndPDMapAlg.hh" +#include "sbnobj/Common/Reco/LightCaloInfo.h" + +// ROOT includes +#include "TFile.h" +#include "TTree.h" + +// C++ includes +#include +#include +#include // sort + +namespace sbnd { + class LightCaloProducer; +} + + +class sbnd::LightCaloProducer : public art::EDProducer { +public: + explicit LightCaloProducer(fhicl::ParameterSet const& p); + // The compiler-generated destructor is fine for non-base + // classes without bare pointers or other resource use. + + // Plugins should not be copied or assigned. + LightCaloProducer(LightCaloProducer const&) = delete; + LightCaloProducer(LightCaloProducer&&) = delete; + LightCaloProducer& operator=(LightCaloProducer const&) = delete; + LightCaloProducer& operator=(LightCaloProducer&&) = delete; + + // Required functions. + void produce(art::Event& e) override; + + // Selected optional functions. + void beginJob() override; + void endJob() override; + +private: + + // Matches SimpleFlash time to OpFlashes, fills match_v with succesfully matched OpFlashes + // returns true if match was found + bool MatchOpFlash(std::vector> fm_v, + std::vector> flash_v, + std::vector> &match_v); + + // Returns visibility vector for all opdets given charge/position information + std::vector CalcVisibility(std::vector xyz_v, + std::vector charge_v); + + // Fills reconstructed photon count vector (total_gamma_v) for all opdets given charge/position information + void CalcLight(std::vector flash_pe_v, + std::vector visibility, + std::vector &total_gamma_v); + + // Returns the median of the light vector + double CalcMedian(std::vector total_light); + + // Returns the mean of the light vector + double CalcMean(std::vector total_light); + + // fcl parameters + std::vector _opflash_producer_v; + std::vector _opflash_ara_producer_v; + std::string _slice_producer; + std::string _flashmatch_producer; + bool _use_arapucas; + float _nuscore_cut; + float _fmscore_cut; + bool _verbose; + + float _simple_op_offset; + float _pmt_ara_offset; + std::vector _noise_thresh; + + std::vector _cal_area_const; + std::vector _opdet_eff; + float _scint_prescale; + + bool _truth_validation; + std::string _simenergy_producer; + bool _truth_neutrino; + + std::unique_ptr _semi_model; + fhicl::ParameterSet _vuv_params; + fhicl::ParameterSet _vis_params; + + opdet::sbndPDMapAlg _opdetmap; //map for photon detector types + unsigned int _nchan = _opdetmap.size(); + + int _run, _subrun, _event; + + TTree* _tree; + int _match_type; + // match_type key: + /// -1: no slices passed both the nuscore and flash match score cut + /// -2: no opflashes times found in coincidence with simpleflash time + /// -3: opflashes are empty or PE count too low + + TTree* _tree2; + int _nmatch=0; // number of matches in an event + int _pfpid; // ID of the matched slice + double _opflash_time; // time of matched opflash + + std::vector _dep_pe; // vector of measured photo-electron (PE), one entry = one channel + std::vector _rec_gamma; // vector of reconstructed photon counts, one entry = one channel (plane with most hits) + + double _true_gamma; // true photon count from all energy depositions + double _true_charge; // true electron count from all energy depositions + double _true_energy; // true deposited energy + + std::vector _charge; // reconstructed electron count per plane + std::vector _light_med; // median reconstructed photon count per plane + std::vector _light_avg; // average reconstructed photon count per plane + std::vector _energy; + + double _slice_L; // reconstructed photon count (plane with most hits) + double _slice_Q; // reconstructed electron count for plane with the most hits + double _slice_E; // reconstructed deposited energy, sum of slice_L and slice_Q + + double _frac_L; // light fractional difference: (L_{true} - L_{reco})/(L_{true}) + double _frac_Q; // charge fractional difference: (Q_{true} - Q_{reco})/(Q_{true}) + double _frac_E; // energy fractional difference: (E_{true} - E_{reco})/(E_{true}) +}; + + +sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) + : EDProducer{p} // , + // More initializers here. +{ + _vuv_params = p.get("VUVHits"); + _vis_params = p.get("VIVHits"); + _semi_model = std::make_unique(_vuv_params, _vis_params, true, false); + + _opflash_producer_v = p.get>("OpFlashProducers"); + _opflash_ara_producer_v = p.get>("OpFlashAraProducers"); + _slice_producer = p.get("SliceProducer"); + _flashmatch_producer = p.get("FlashMatchProducer"); + _use_arapucas = p.get("UseArapucas"); + _nuscore_cut = p.get("nuScoreCut"); + _fmscore_cut = p.get("fmScoreCut"); + _verbose = p.get("Verbose"); + + _simple_op_offset= p.get("SimpleOpFlashOffset"); + _pmt_ara_offset = p.get("PMTARAFlashOffset"); + _noise_thresh = p.get>("FlashNoiseThreshold"); + + _cal_area_const = p.get>("CalAreaConstants"); + _opdet_eff = p.get>("OpDetEfficiencies"); + _scint_prescale = p.get("ScintPreScale"); + + _truth_validation = p.get("TruthValidation"); + _simenergy_producer = p.get("SimEnergyProducer"); + _truth_neutrino = p.get("TruthNeutrino"); + + // Call appropriate produces<>() functions here. + produces>(); + produces>(); + // Call appropriate consumes<>() for any products to be retrieved by this module. + +} + +void sbnd::LightCaloProducer::produce(art::Event& e) +{ + + std::unique_ptr> lightcalo_v (new std::vector); + std::unique_ptr> slice_lightcalo_assn_v (new art::Assns); + + // services + auto const clock_data = art::ServiceHandle()->DataFor(e); + auto const det_prop = art::ServiceHandle()->DataFor(e, clock_data); + + art::ServiceHandle geom; + art::ServiceHandle g4param; + art::ServiceHandle piserv; + + _run = e.id().run(); + _subrun = e.id().subRun(); + _event = e.id().event(); + std::cout << "run: " << _run << ", subrun: " << _subrun << ", event: " << _event << std::endl; + + // get slices + ::art::Handle> slice_h; + e.getByLabel(_slice_producer, slice_h); + if(!slice_h.isValid() || slice_h->empty()){ + std::cout << "don't have good slices!" << std::endl; + return; + } + + ::art::Handle> pfp_h; + e.getByLabel(_slice_producer, pfp_h); + if(!pfp_h.isValid() || pfp_h->empty()) { + std::cout << "don't have good PFParticle!" << std::endl; + return; + } + + ::art::Handle> spacepoint_h; + e.getByLabel(_slice_producer, spacepoint_h); + if(!spacepoint_h.isValid() || spacepoint_h->empty()) { + std::cout << "don't have good SpacePoints!" << std::endl; + return; + } + + auto const & flash0_h = e.getValidHandle>(_opflash_producer_v[0]); + auto const & flash1_h = e.getValidHandle>(_opflash_producer_v[1]); + if (!_use_arapucas && _verbose) + std::cout << "Using PMT OpFlash only..." << std::endl; + if( (!flash0_h.isValid() || flash0_h->empty()) && (!flash1_h.isValid() || flash1_h->empty())) { + std::cout << "don't have good PMT flashes from producer " << _opflash_producer_v[0] << " or " << _opflash_producer_v[1] << std::endl; + return; + } + + // const art::ValidHandle>& + // energyDeps(e.getValidHandle>(_simenergy_producer)); + // if ( (!energyDeps.isValid() || energyDeps->empty()) && _truth_validation){ + // } + + // Construct the vector of Slices + std::vector> slice_v; + art::fill_ptr_vector(slice_v, slice_h); + + // Get associations + art::FindManyP slice_to_pfp (slice_h, e, _slice_producer); + art::FindManyP slice_to_hit (slice_h, e, _slice_producer); + art::FindManyP pfp_to_meta(pfp_h, e, _slice_producer); + art::FindManyP pfp_to_sfm (pfp_h, e, _flashmatch_producer); + art::FindManyP pfp_to_spacepoint(pfp_h, e, _slice_producer); + art::FindManyP spacepoint_to_hit(spacepoint_h, e, _slice_producer); + + std::vector> match_slices_v; + std::vector> match_fm_v; + + for (size_t n_slice=0; n_slice < slice_v.size(); n_slice++){ + float nu_score = -9999; + float fm_score = -9999; + auto slice = slice_v[n_slice]; + bool found_fm = false; + std::vector> pfp_v = slice_to_pfp.at(n_slice); + for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ + auto pfp = pfp_v[n_pfp]; + + // only select the PRIMARY pfp + if(!pfp->IsPrimary()) + continue; + if(_truth_neutrino && !(abs(pfp->PdgCode()) == 12 || abs(pfp->PdgCode()) == 14|| abs(pfp->PdgCode()) == 16)) + continue; + // if primary, get nu-score + const std::vector> pfpmeta_v = pfp_to_meta.at(pfp->Self()); + const art::Ptr pfpmeta = pfpmeta_v.front(); + larpandoraobj::PFParticleMetadata::PropertiesMap propmap = pfpmeta->GetPropertiesMap(); + if (propmap.count("NuScore")) nu_score = propmap.at("NuScore"); + else nu_score = -1; + + // get fm-score + std::vector> fm_v = pfp_to_sfm.at(pfp.key()); + if (fm_v.empty()){ + std::cout << "No SimpleFlashMatch objects associated with this PFP!" << std::endl; + continue; + } + if (fm_v.size() > 1) + std::cout << "more than one match for one pfp?" << std::endl; + for (size_t n_fm=0; n_fm < fm_v.size(); n_fm++){ + auto fm = fm_v.at(n_fm); + fm_score = fm->score.total; + if (nu_score > _nuscore_cut && fm_score < _fmscore_cut && fm_score > 0){ + found_fm = true; + match_fm_v.push_back(fm); + } + } // end flashmatch loop + if (found_fm ==true) match_slices_v.push_back(slice); + } // end pfp loop + } // end slice loop + if (match_slices_v.empty() && !slice_v.empty()){ + std::cout << "no slices passed the cuts" << std::endl; + _match_type = -1; + _tree->Fill(); + return; + } + + if (match_slices_v.size() != match_fm_v.size()){ + std::cout << "slice and flashmatch vector length mismatch!" << std::endl; + return; + } + + // get relevant opflashes + // tpc0 + std::vector> flash0_v; + art::fill_ptr_vector(flash0_v, flash0_h); + std::vector> match_op0; + bool found_opflash0 = MatchOpFlash(match_fm_v,flash0_v, match_op0); + + std::vector> flash0_ara_v; + // if using arapucas + if (_use_arapucas){ + ::art::Handle> flash0_ara_h; + e.getByLabel(_opflash_ara_producer_v[0],flash0_ara_h); + if (_verbose) std::cout << "Using PMT OpFlash + X-ARAPUCA OpFlash..." << std::endl; + if (!flash0_ara_h.isValid() || flash0_ara_h->empty()) { + std::cout << "don't have good X-ARAPUCA flashes from producer " << _opflash_ara_producer_v[0] << std::endl; + // return; + } + else + art::fill_ptr_vector(flash0_ara_v, flash0_ara_h); + } + // tpc1 + std::vector> flash1_v; + art::fill_ptr_vector(flash1_v, flash1_h); + std::vector> match_op1; + bool found_opflash1 = MatchOpFlash(match_fm_v,flash1_v, match_op1); + + std::vector> flash1_ara_v; + if (_use_arapucas){ + ::art::Handle> flash1_ara_h; + e.getByLabel(_opflash_ara_producer_v[1],flash1_ara_h); + if (_verbose) std::cout << "Using PMT OpFlash + X-ARAPUCA OpFlash..." << std::endl; + if (!flash1_ara_h.isValid() || flash1_ara_h->empty()) { + std::cout << "don't have good X-ARAPUCA flashes from producer " << _opflash_ara_producer_v[1] << std::endl; + // return; + } + else + art::fill_ptr_vector(flash1_ara_v, flash1_ara_h); + } + if (found_opflash0 == false && found_opflash1 == false){ + std::cout << "no opflashes matched to simpleflashes" << std::endl; + _match_type = -2; + _tree->Fill(); + return; + } + + int nsuccessful_matches=0; + for (size_t n_slice=0; n_slice < match_slices_v.size(); n_slice++){ + // initialize tree2 variables + _nmatch++; + _pfpid = -1; + + _slice_Q = 0; // total amount of charge + _slice_L = 0; // total amount of light + _slice_E = 0; + + std::vector> sp_xyz; // position info of each spacepoint per plane + std::vector> sp_charge; // vector of charge info for charge-weighting for each plane + + double flash_time = -999; + auto opflash0 = (match_op0.at(n_slice)); + auto opflash1 = (match_op1.at(n_slice)); + bool flash_in_0 = false; + bool flash_in_1 = false; + // set threshold above noise PE levels for the flash + float noise_thresh = (!_use_arapucas)? _noise_thresh[0] : _noise_thresh[1]; + + if (!opflash0.isNull() && opflash1.isNull()){ + flash_time = opflash0->Time(); + if (opflash0->TotalPE() > noise_thresh) + flash_in_0 = true; + else if (_verbose) + std::cout << "Flash Total PE in TPC 0 (" << opflash0->TotalPE() << ") below noise threshold ... Skipping" << std::endl; + } + else if ( opflash0.isNull() && !opflash1.isNull()){ + flash_time = opflash1->Time(); + if (opflash1->TotalPE() > noise_thresh) + flash_in_1 = true; + else if (_verbose) + std::cout << "Flash Total PE in TPC 1 (" << opflash1->TotalPE() << ") below noise threshold ... Skipping" << std::endl; + } + else if (!opflash0.isNull() && !opflash1.isNull()){ + flash_time = opflash0->Time(); + if (opflash0->TotalPE() > noise_thresh) + flash_in_0 = true; + else if (_verbose) + std::cout << "Flash Total PE in TPC 0 (" << opflash0->TotalPE() << ") below noise threshold ... Skipping" << std::endl; + if (opflash1->TotalPE() > noise_thresh) + flash_in_1 = true; + else if (_verbose) + std::cout << "Flash Total PE in TPC 1 (" << opflash1->TotalPE() << ") below noise threshold ... Skipping" << std::endl; + } + else if (opflash0.isNull() && opflash1.isNull()){ + std::cout << "No opflashes matched with SimpleFlash objects" << std::endl; + _match_type = -3; + _tree->Fill(); + return; + } + + auto slice = match_slices_v[n_slice]; + // sum charge information (without position info) for Q + // find which plane has the most integrated charge for this slice + std::vector> slice_hits_v = slice_to_hit.at(slice.key()); + std::vector plane_charge{0.,0.,0.}; + std::vector plane_hits{0,0,0}; + for (size_t i=0; i < slice_hits_v.size(); i++){ + auto hit = slice_hits_v[i]; + auto drift_time = (hit->PeakTime() - 500)*0.5; // assuming TPC beam readout starts at 500 ticks, conversion = 0.5 us/tick + double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) + auto hit_plane = hit->View(); + plane_charge.at(hit_plane) += hit->Integral()*atten_correction*(1/_cal_area_const.at(hit_plane)); + plane_hits.at(hit_plane)++; + } + int bestPlane = std::max_element(plane_hits.begin(), plane_hits.end()) - plane_hits.begin(); + _slice_Q = plane_charge.at(bestPlane); + _charge = plane_charge; + + // get charge information to create the weighted map + std::vector> pfp_v = slice_to_pfp.at(slice.key()); + for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ + auto pfp = pfp_v[n_pfp]; + if (pfp->IsPrimary()) _pfpid = pfp->Self(); + std::vector> sp_v = pfp_to_spacepoint.at(pfp.key()); + for (size_t n_sp=0; n_sp < sp_v.size(); n_sp++){ + auto sp = sp_v[n_sp]; + std::vector> hit_v = spacepoint_to_hit.at(sp.key()); + for (size_t n_hit=0; n_hit < hit_v.size(); n_hit++){ + auto hit = hit_v[n_hit]; + auto hit_plane = hit->View(); + // get position + const auto &position(sp->XYZ()); + geo::Point_t xyz(position[0],position[1],position[2]); + // correct for e- attenuation + double drift_time = ((2.0*geom->DetHalfWidth()) - abs(position[0]))/(det_prop.DriftVelocity()); // cm / (cm/us) + double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) + double charge = (1/_cal_area_const.at(hit_plane))*atten_correction*hit->Integral(); + + sp_xyz.at(hit_plane).push_back(xyz); + sp_charge.at(hit_plane).push_back(charge); + } + } // end spacepoint loop + } // end pfp loop + + std::vector total_pe(_nchan,0.); // contains PE info from both TPCs, PMTs, and ARA (if applicable) + // combining flash PE information from separate TPCs into a single vector + for (int tpc=0; tpc<2; tpc++){ + bool found_flash = (tpc==0)? flash_in_0 : flash_in_1; + if (found_flash){ + auto flash_pe_v = (tpc==0)? opflash0->PEs() : opflash1->PEs(); + // if using arapucas, need to combine PMT and arapuca PE information into a single vector + if (_use_arapucas){ + auto flash_ara_v = (tpc==0)? flash0_ara_v : flash1_ara_v; + // for PMT flashes, the PE vector is shortened and don't include the last 6 entries for ARAPUCAs + if (flash_pe_v.size()!= _nchan) flash_pe_v.insert(flash_pe_v.end(), {0,0,0,0,0,0}); + for (size_t nara=0; nara < flash_ara_v.size(); nara++){ + auto const &flash_ara = *flash_ara_v[nara]; + if (abs(flash_time-flash_ara.Time()) < _pmt_ara_offset){ + if (_verbose) + std::cout << "Combining PMT+XARA Flashes with PMT time: " << flash_time << ", ARA time: " << flash_ara.Time() << std::endl; + for (size_t ich=0; ich < (flash_ara.PEs()).size(); ich++) + flash_pe_v.at(ich) += (flash_ara.PEs()).at(ich); + break; + } + } + } // end of arapuca if + for (size_t ich=0; ich lightcalo_charge; + std::vector lightcalo_light; + std::vector lightcalo_energy; + std::vector lightcalo_plane; + + std::vector> total_gamma(3, std::vector(_nchan,0.)); + for (int nplane = 0; nplane<3; nplane++){ + // get total L count + std::vector visibility_map = CalcVisibility(sp_xyz.at(nplane),sp_charge.at(nplane)); + // calculate the photon estimates for every entry in total_pe + CalcLight(total_pe, visibility_map, total_gamma.at(nplane)); + _light_med.at(nplane) = CalcMedian(total_gamma.at(nplane)); + _light_avg.at(nplane) = CalcMedian(total_gamma.at(nplane)); + + _energy.at(nplane) = (_charge.at(nplane) + _light_med.at(nplane))*1e-6*g4param->Wph(); + + gamma_avg = _light_avg.at(nplane); + gamma_med = _light_med.at(nplane); + int planeID = nplane; + if (nplane==bestPlane){ + _rec_gamma = total_gamma.at(nplane); + if (gamma_med!=0 && !std::isnan(gamma_med)) + _slice_L = gamma_med; + else + _slice_L = gamma_avg; + lightcalo_charge.insert(lightcalo_charge.begin(),_charge.at(nplane)); + lightcalo_light.insert(lightcalo_light.begin(),gamma_med); + lightcalo_energy.insert(lightcalo_energy.begin(),_energy.at(nplane)); + lightcalo_plane.insert(lightcalo_plane.begin(),planeID); + } + else{ + lightcalo_charge.push_back(_charge.at(nplane)); + lightcalo_light.push_back(gamma_med); + lightcalo_energy.push_back(_energy.at(nplane)); + lightcalo_plane.push_back(planeID); + } + } + _slice_E = _energy.at(bestPlane); + + sbn::LightCalo lightcalo(lightcalo_charge, + lightcalo_light, + lightcalo_energy, + lightcalo_plane, + flash_time); + + lightcalo_v->push_back(lightcalo); + + _true_gamma = 0; + _true_charge = 0; + _true_energy = 0; + + //* start truth validation section *// + if (_truth_validation){ + ::art::Handle> energyDeps_h; + e.getByLabel(_simenergy_producer, energyDeps_h); + std::vector> energyDeps; + + if (energyDeps_h.isValid() || energyDeps_h->empty()) + std::cout << "Don't have good SimEnergyDeposits!" << std::endl; + else + art::fill_ptr_vector(energyDeps, energyDeps_h); + + for (size_t n_dep=0; n_dep < energyDeps.size(); n_dep++){ + auto energyDep = energyDeps[n_dep]; + const auto trackID = energyDep->TrackID(); + const double time = energyDep->Time() * 1e-3; // us + + art::Ptr mctruth = piserv->TrackIdToMCTruth_P(trackID); + + if ((_truth_neutrino && mctruth->Origin()==simb::kBeamNeutrino ) || + (!_truth_neutrino && abs(time-flash_time) < 1)){ + // note: we divide by the prescale because NumPhotons() stored in simulation has the scint prescale applied + _true_gamma += energyDep->NumPhotons()/_scint_prescale; + _true_charge += energyDep->NumElectrons(); + _true_energy += energyDep->Energy(); + } + } + //* end truth validation section *// + + _frac_L = (_true_gamma - _slice_L)/_true_gamma; + _frac_Q = (_true_charge - _slice_Q)/_true_charge; + _frac_E = (_true_energy - _slice_E)/_true_energy; + + if (_verbose){ + std::cout << "ratio of gamma (median/true): " << _slice_L/_true_gamma << std::endl; + std::cout << "ratio of electron (comp/true): " << _slice_Q/_true_charge << std::endl; + std::cout << "ratio of energy (calc/true): " << _slice_E/_true_energy << std::endl; + } + } + else{ + _true_gamma = -9999; + _true_charge = -9999; + _true_energy = -9999; + _frac_L = -9999; + _frac_Q = -9999; + _frac_E = -9999; + } + + util::CreateAssn(*this, e, *lightcalo_v, slice, *slice_lightcalo_assn_v); + + _tree2->Fill(); + nsuccessful_matches++; + } // end slice loop + _match_type=nsuccessful_matches; + _tree->Fill(); + e.put(std::move(lightcalo_v)); + e.put(std::move(slice_lightcalo_assn_v)); +} + +void sbnd::LightCaloProducer::beginJob() +{ + art::ServiceHandle fs; + _tree = fs->make("slice_tree",""); + _tree->Branch("run", &_run, "run/I"); + _tree->Branch("subrun", &_subrun, "subrun/I"); + _tree->Branch("event", &_event, "event/I"); + _tree->Branch("match_type", &_match_type, "match_type/I"); + + _tree2 = fs->make("match_tree",""); + _tree2->Branch("run", &_run, "run/I"); + _tree2->Branch("subrun", &_subrun, "subrun/I"); + _tree2->Branch("event", &_event, "event/I"); + _tree2->Branch("nmatch", &_nmatch, "nmatch/I"); + _tree2->Branch("pfpid", &_pfpid, "pfpid/I"); + _tree2->Branch("opflash_time", &_opflash_time, "opflash_time/D"); + + _tree2->Branch("rec_gamma", "std::vector", &_rec_gamma); + _tree2->Branch("dep_pe", "std::vector", &_dep_pe); + + _tree2->Branch("true_gamma", &_true_gamma, "true_gamma/D"); + _tree2->Branch("true_charge", &_true_charge, "true_charge/D"); + _tree2->Branch("true_energy", &_true_energy, "true_energy/D"); + + _tree2->Branch("charge_plane0", &_charge[0], "charge_plane0/D"); + _tree2->Branch("charge_plane1", &_charge[1], "charge_plane1/D"); + _tree2->Branch("charge_plane2", &_charge[2], "charge_plane2/D"); + + _tree2->Branch("light_med_plane0", &_light_med[0] ,"light_med_plane0/D"); + _tree2->Branch("light_med_plane1", &_light_med[1] ,"light_med_plane1/D"); + _tree2->Branch("light_med_plane2", &_light_med[2] ,"light_med_plane2/D"); + + _tree2->Branch("light_avg_plane0", &_light_avg[0] ,"light_avg_plane0/D"); + _tree2->Branch("light_avg_plane1", &_light_avg[1] ,"light_avg_plane1/D"); + _tree2->Branch("light_avg_plane2", &_light_avg[2] ,"light_avg_plane2/D"); + + _tree2->Branch("slice_L", &_slice_L, "slice_L/D"); + _tree2->Branch("slice_Q", &_slice_Q, "slice_Q/D"); + _tree2->Branch("slice_E", &_slice_E, "slice_E/D"); + _tree2->Branch("frac_L", &_frac_L, "frac_L/D"); + _tree2->Branch("frac_Q", &_frac_Q, "frac_Q/D"); + _tree2->Branch("frac_E", &_frac_E, "frac_E/D"); +} + +void sbnd::LightCaloProducer::endJob() +{ + // Implementation of optional member function here. +} + +// define functions + +bool sbnd::LightCaloProducer::MatchOpFlash(std::vector> fm_v, + std::vector> flash_v, + std::vector> &match_v){ + bool any_match = false; + for (size_t ifm=0; ifm nullOpFlash; + bool found_match = false; + auto match_time = fm->time; + for (size_t iop=0; iopTime() - match_time) < _simple_op_offset){ + found_match = true; + any_match = true; + match_v.push_back(opflash); + break; + } + } + if (found_match == false) match_v.push_back(nullOpFlash); + } + if (match_v.size() != fm_v.size()) std::cout << "mismatched opflash and simpleflash vector sizes!" << std::endl; + return any_match; +} + + +std::vector sbnd::LightCaloProducer::CalcVisibility(std::vector xyz_v, + std::vector charge_v){ + // returns of a vector (len is # of opdet) for the visibility for every opdet + if (xyz_v.size() != charge_v.size()) std::cout << "spacepoint coord and charge vector size mismatch" << std::endl; + + std::vector visibility(_nchan, 0); + double sum_charge0 = 0; + double sum_charge1 = 0; + + for (size_t i=0; i direct_visibility; + std::vector reflect_visibility; + _semi_model->detectedDirectVisibilities(direct_visibility, xyz); + _semi_model->detectedReflectedVisibilities(reflect_visibility, xyz); + if (visibility.size() != direct_visibility.size()) std::cout << "mismatch of visibility vector size" << std::endl; + + // weight by charge + for (size_t ch=0; ch flash_pe_v, + std::vector visibility, + std::vector &total_gamma_v){ + for (size_t ch = 0; ch < flash_pe_v.size(); ch++){ + auto pe = flash_pe_v[ch]; + double efficiency = 0.03; + if((pe == 0) || std::isinf(1/visibility[ch])) + continue; + if (_opdetmap.isPDType(ch, "pmt_uncoated")) + efficiency = _opdet_eff[0]; + else if (_opdetmap.isPDType(ch, "pmt_coated")) + efficiency = _opdet_eff[1]; + else if (_opdetmap.isPDType(ch, "xarapuca_vis")) + efficiency = _opdet_eff[2]; + else if (_opdetmap.isPDType(ch, "xarapuca_vuv")) + efficiency = _opdet_eff[3]; + // deposited light is inverse of efficiency * inverse of visibility * PE count + total_gamma_v[ch] += (1/efficiency)*(1/visibility[ch])*pe; + } +} + +double sbnd::LightCaloProducer::CalcMedian(std::vector total_gamma){ + std::vector tpc0_gamma; + std::vector tpc1_gamma; + // split into two TPCs + for (size_t i=0; i idx(gamma_v.size()); + std::iota(idx.begin(), idx.end(), 0); + std::sort(idx.begin(), idx.end(), + [&](int A, int B) -> bool { + return gamma_v[A] < gamma_v[B]; + }); + // count number of zero entries + int zero_counter = 0; + for (size_t i=0; i < gamma_v.size(); i++){ + if (gamma_v.at(i) <= 0) zero_counter++; + } + int med_idx=0; + if (zero_counter != int(gamma_v.size())){ + med_idx = idx.at(int((gamma_v.size()-zero_counter))/2 + zero_counter); + median = gamma_v.at(med_idx); + } + median_gamma+=median; + } + return median_gamma; +} + +double sbnd::LightCaloProducer::CalcMean(std::vector total_gamma){ + std::vector tpc0_gamma; + std::vector tpc1_gamma; + for (size_t i=0; i0){ + counter+=1.0; + sum+=gamma; + } + } + if (sum!=0) mean_gamma+= sum/counter; + } + return mean_gamma; +} + +DEFINE_ART_MODULE(sbnd::LightCaloProducer) diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index c96babb0c..038560ba0 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -1,9 +1,9 @@ #include "opticalsimparameterisations_sbnd.fcl" BEGIN_PROLOG -lightcalo_ana: +lightcalo: { - module_type: "LightCaloAna" + module_type: "LightCaloProducer" VUVHits: @local::sbnd_vuv_RS100cm_hits_parameterization VIVHits: @local::sbnd_vis_RS100cm_hits_parameterization diff --git a/sbndcode/Calorimetry/lightcalo_ana.fcl b/sbndcode/Calorimetry/lightcalo_ana.fcl new file mode 100644 index 000000000..c96babb0c --- /dev/null +++ b/sbndcode/Calorimetry/lightcalo_ana.fcl @@ -0,0 +1,36 @@ +#include "opticalsimparameterisations_sbnd.fcl" + +BEGIN_PROLOG +lightcalo_ana: +{ + module_type: "LightCaloAna" + + VUVHits: @local::sbnd_vuv_RS100cm_hits_parameterization + VIVHits: @local::sbnd_vis_RS100cm_hits_parameterization + + OpFlashProducers: ["opflashtpc0", "opflashtpc1"] + OpFlashAraProducers: ["opflashtpc0xarapuca", "opflashtpc1xarapuca"] + SliceProducer: "pandora" + FlashMatchProducer: "fmatch" + UseArapucas: false + nuScoreCut: 0.4 # default: accept nusScore > 0.4, to analyze all slices, set nuScoreCut = -1 + fmScoreCut: 7 # default: accept 0 < fm score < fmScoreCut, to analyze all slices, set fmScoreCut = 1e3 + Verbose: false + + # flash parameters + SimpleOpFlashOffset: 0.2 # the offset between the t0 from SimpleFlash and OpFlashes + PMTARAFlashOffset: 0.05 # the offset between the t0 of PMT OpFlashes and X-ARA OpFlashes + FlashNoiseThreshold: [ 600., 1500. ] # {PMT, xARAPUCA}, flash total PE threshold to ignore a flash + + # calibration constants & simulation parameters + ## shouldn't have to change this unless you change simulation parameters + CalAreaConstants: [ 0.0200906, 0.0200016, 0.0201293 ] # calibration constants for wire planes + OpDetEfficiencies: [ 0.03, 0.03, 0.014, 0.021 ] # efficiencies [uncoated PMT, coated PMT, vis ara, vuv ara] + ScintPreScale: 0.03 # Scintillation Pre-Scale factor in simulation (set in ionandscint) + + # parameters for truth validation + TruthValidation: false # can only set to true if the reco2 files have SimEnergyDeposits + SimEnergyProducer: "ionandscint" # only looking at energy deposits in the AV + TruthNeutrino: true # if validating anything other than simb::kBeamNeutrino, set to false +} +END_PROLOG diff --git a/sbndcode/Calorimetry/run_lightcalo.fcl b/sbndcode/Calorimetry/run_lightcalo.fcl index 6e7e209cc..567cdbf30 100644 --- a/sbndcode/Calorimetry/run_lightcalo.fcl +++ b/sbndcode/Calorimetry/run_lightcalo.fcl @@ -6,8 +6,9 @@ #include "backtrackerservice.fcl" #include "lightcalo.fcl" +#include "lightcalo_ana.fcl" -process_name: LightCaloAna +process_name: LightCaloProducer services: { @@ -28,14 +29,42 @@ source: maxEvents: -1 } -physics: +outputs: { + out1: + { + module_type: RootOutput + fileName: "lightcalo-art.root" + dataTier: "reconstructed" + compressionLevel:1 + SelectEvents: ["reco"] + } +} + +physics: +{ + producers: + { + lightcalo: @local::lightcalo + } analyzers: { - ana: @local::lightcalo_ana + lightcaloana: @local::lightcalo_ana } - path: [ana] - end_paths: [path] + #define the producer and filter modules for this path, order matters, + reco: [lightcalo] + ana: [lightcaloana] + + # define the output stream, there could be more than one if using filters + stream1: [out1] + + # trigger_paths is a keyword and contains the paths that modify the art::event, + # ie filters and producers + trigger_paths: [reco] + + # end_paths is a keyword and contains the paths that do not modify the art::Event, + # ie analyzers and output streams. these all run simultaneously + end_paths: [stream1] } services.BackTrackerService.BackTracker.SimChannelModuleLabel: "simdrift" \ No newline at end of file From 8411be859464f91cbe40aee7175733d86fd1147b Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Fri, 21 Apr 2023 11:12:34 -0500 Subject: [PATCH 19/52] working version of producer module --- .../Calorimetry/LightCaloProducer_module.cc | 134 ++++++++++-------- sbndcode/Calorimetry/lightcalo_ana.fcl | 2 +- 2 files changed, 79 insertions(+), 57 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index c861472a9..7f7b0ae69 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -163,10 +163,10 @@ class sbnd::LightCaloProducer : public art::EDProducer { double _true_charge; // true electron count from all energy depositions double _true_energy; // true deposited energy - std::vector _charge; // reconstructed electron count per plane - std::vector _light_med; // median reconstructed photon count per plane - std::vector _light_avg; // average reconstructed photon count per plane - std::vector _energy; + std::vector _charge = std::vector(3); // reconstructed electron count per plane + std::vector _light_med = std::vector(3); // median reconstructed photon count per plane + std::vector _light_avg = std::vector(3); // average reconstructed photon count per plane + std::vector _energy = std::vector(3); double _slice_L; // reconstructed photon count (plane with most hits) double _slice_Q; // reconstructed electron count for plane with the most hits @@ -209,7 +209,7 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) // Call appropriate produces<>() functions here. produces>(); - produces>(); + produces>(); // Call appropriate consumes<>() for any products to be retrieved by this module. } @@ -238,6 +238,8 @@ void sbnd::LightCaloProducer::produce(art::Event& e) e.getByLabel(_slice_producer, slice_h); if(!slice_h.isValid() || slice_h->empty()){ std::cout << "don't have good slices!" << std::endl; + e.put(std::move(lightcalo_v)); + e.put(std::move(slice_lightcalo_assn_v)); return; } @@ -245,6 +247,8 @@ void sbnd::LightCaloProducer::produce(art::Event& e) e.getByLabel(_slice_producer, pfp_h); if(!pfp_h.isValid() || pfp_h->empty()) { std::cout << "don't have good PFParticle!" << std::endl; + e.put(std::move(lightcalo_v)); + e.put(std::move(slice_lightcalo_assn_v)); return; } @@ -252,6 +256,8 @@ void sbnd::LightCaloProducer::produce(art::Event& e) e.getByLabel(_slice_producer, spacepoint_h); if(!spacepoint_h.isValid() || spacepoint_h->empty()) { std::cout << "don't have good SpacePoints!" << std::endl; + e.put(std::move(lightcalo_v)); + e.put(std::move(slice_lightcalo_assn_v)); return; } @@ -261,14 +267,11 @@ void sbnd::LightCaloProducer::produce(art::Event& e) std::cout << "Using PMT OpFlash only..." << std::endl; if( (!flash0_h.isValid() || flash0_h->empty()) && (!flash1_h.isValid() || flash1_h->empty())) { std::cout << "don't have good PMT flashes from producer " << _opflash_producer_v[0] << " or " << _opflash_producer_v[1] << std::endl; + e.put(std::move(lightcalo_v)); + e.put(std::move(slice_lightcalo_assn_v)); return; } - // const art::ValidHandle>& - // energyDeps(e.getValidHandle>(_simenergy_producer)); - // if ( (!energyDeps.isValid() || energyDeps->empty()) && _truth_validation){ - // } - // Construct the vector of Slices std::vector> slice_v; art::fill_ptr_vector(slice_v, slice_h); @@ -328,11 +331,15 @@ void sbnd::LightCaloProducer::produce(art::Event& e) std::cout << "no slices passed the cuts" << std::endl; _match_type = -1; _tree->Fill(); + e.put(std::move(lightcalo_v)); + e.put(std::move(slice_lightcalo_assn_v)); return; } if (match_slices_v.size() != match_fm_v.size()){ std::cout << "slice and flashmatch vector length mismatch!" << std::endl; + e.put(std::move(lightcalo_v)); + e.put(std::move(slice_lightcalo_assn_v)); return; } @@ -351,7 +358,6 @@ void sbnd::LightCaloProducer::produce(art::Event& e) if (_verbose) std::cout << "Using PMT OpFlash + X-ARAPUCA OpFlash..." << std::endl; if (!flash0_ara_h.isValid() || flash0_ara_h->empty()) { std::cout << "don't have good X-ARAPUCA flashes from producer " << _opflash_ara_producer_v[0] << std::endl; - // return; } else art::fill_ptr_vector(flash0_ara_v, flash0_ara_h); @@ -369,7 +375,6 @@ void sbnd::LightCaloProducer::produce(art::Event& e) if (_verbose) std::cout << "Using PMT OpFlash + X-ARAPUCA OpFlash..." << std::endl; if (!flash1_ara_h.isValid() || flash1_ara_h->empty()) { std::cout << "don't have good X-ARAPUCA flashes from producer " << _opflash_ara_producer_v[1] << std::endl; - // return; } else art::fill_ptr_vector(flash1_ara_v, flash1_ara_h); @@ -378,6 +383,8 @@ void sbnd::LightCaloProducer::produce(art::Event& e) std::cout << "no opflashes matched to simpleflashes" << std::endl; _match_type = -2; _tree->Fill(); + e.put(std::move(lightcalo_v)); + e.put(std::move(slice_lightcalo_assn_v)); return; } @@ -391,8 +398,8 @@ void sbnd::LightCaloProducer::produce(art::Event& e) _slice_L = 0; // total amount of light _slice_E = 0; - std::vector> sp_xyz; // position info of each spacepoint per plane - std::vector> sp_charge; // vector of charge info for charge-weighting for each plane + std::vector> sp_xyz(3); // position info of each spacepoint per plane + std::vector> sp_charge(3); // vector of charge info for charge-weighting for each plane double flash_time = -999; auto opflash0 = (match_op0.at(n_slice)); @@ -431,6 +438,8 @@ void sbnd::LightCaloProducer::produce(art::Event& e) std::cout << "No opflashes matched with SimpleFlash objects" << std::endl; _match_type = -3; _tree->Fill(); + e.put(std::move(lightcalo_v)); + e.put(std::move(slice_lightcalo_assn_v)); return; } @@ -471,7 +480,7 @@ void sbnd::LightCaloProducer::produce(art::Event& e) double drift_time = ((2.0*geom->DetHalfWidth()) - abs(position[0]))/(det_prop.DriftVelocity()); // cm / (cm/us) double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) double charge = (1/_cal_area_const.at(hit_plane))*atten_correction*hit->Integral(); - + sp_xyz.at(hit_plane).push_back(xyz); sp_charge.at(hit_plane).push_back(charge); } @@ -487,17 +496,22 @@ void sbnd::LightCaloProducer::produce(art::Event& e) // if using arapucas, need to combine PMT and arapuca PE information into a single vector if (_use_arapucas){ auto flash_ara_v = (tpc==0)? flash0_ara_v : flash1_ara_v; - // for PMT flashes, the PE vector is shortened and don't include the last 6 entries for ARAPUCAs - if (flash_pe_v.size()!= _nchan) flash_pe_v.insert(flash_pe_v.end(), {0,0,0,0,0,0}); - for (size_t nara=0; nara < flash_ara_v.size(); nara++){ - auto const &flash_ara = *flash_ara_v[nara]; - if (abs(flash_time-flash_ara.Time()) < _pmt_ara_offset){ - if (_verbose) - std::cout << "Combining PMT+XARA Flashes with PMT time: " << flash_time << ", ARA time: " << flash_ara.Time() << std::endl; - for (size_t ich=0; ich < (flash_ara.PEs()).size(); ich++) - flash_pe_v.at(ich) += (flash_ara.PEs()).at(ich); - break; - } + if (flash_ara_v.empty()) + // if there are no valid arapuca flashes + std::cout << "Using PMT information Only..." << std::endl; + else{ + // for PMT flashes, the PE vector is shortened and don't include the last 6 entries for ARAPUCAs + if (flash_pe_v.size()!= _nchan) flash_pe_v.insert(flash_pe_v.end(), {0,0,0,0,0,0}); + for (size_t nara=0; nara < flash_ara_v.size(); nara++){ + auto const &flash_ara = *flash_ara_v[nara]; + if (abs(flash_time-flash_ara.Time()) < _pmt_ara_offset){ + if (_verbose) + std::cout << "Combining PMT+XARA Flashes with PMT time: " << flash_time << ", ARA time: " << flash_ara.Time() << std::endl; + for (size_t ich=0; ich < (flash_ara.PEs()).size(); ich++) + flash_pe_v.at(ich) += (flash_ara.PEs()).at(ich); + break; + } + } } } // end of arapuca if for (size_t ich=0; ich lightcalo_charge; std::vector lightcalo_light; std::vector lightcalo_energy; @@ -517,36 +531,46 @@ void sbnd::LightCaloProducer::produce(art::Event& e) std::vector> total_gamma(3, std::vector(_nchan,0.)); for (int nplane = 0; nplane<3; nplane++){ // get total L count - std::vector visibility_map = CalcVisibility(sp_xyz.at(nplane),sp_charge.at(nplane)); - // calculate the photon estimates for every entry in total_pe - CalcLight(total_pe, visibility_map, total_gamma.at(nplane)); - _light_med.at(nplane) = CalcMedian(total_gamma.at(nplane)); - _light_avg.at(nplane) = CalcMedian(total_gamma.at(nplane)); - - _energy.at(nplane) = (_charge.at(nplane) + _light_med.at(nplane))*1e-6*g4param->Wph(); - - gamma_avg = _light_avg.at(nplane); - gamma_med = _light_med.at(nplane); - int planeID = nplane; - if (nplane==bestPlane){ - _rec_gamma = total_gamma.at(nplane); - if (gamma_med!=0 && !std::isnan(gamma_med)) - _slice_L = gamma_med; - else - _slice_L = gamma_avg; - lightcalo_charge.insert(lightcalo_charge.begin(),_charge.at(nplane)); - lightcalo_light.insert(lightcalo_light.begin(),gamma_med); - lightcalo_energy.insert(lightcalo_energy.begin(),_energy.at(nplane)); - lightcalo_plane.insert(lightcalo_plane.begin(),planeID); + if (!sp_xyz.at(nplane).empty()){ + std::vector visibility_map = CalcVisibility(sp_xyz.at(nplane),sp_charge.at(nplane)); + // calculate the photon estimates for every entry in total_pe + CalcLight(total_pe, visibility_map, total_gamma.at(nplane)); + _light_med.at(nplane) = CalcMedian(total_gamma.at(nplane)); + _light_avg.at(nplane) = CalcMedian(total_gamma.at(nplane)); + + _energy.at(nplane) = (_charge.at(nplane) + _light_med.at(nplane))*1e-6*g4param->Wph(); + + double gamma_avg = _light_avg.at(nplane); + double gamma_med = _light_med.at(nplane); + if (nplane==bestPlane){ + _rec_gamma = total_gamma.at(nplane); + if (gamma_med!=0 && !std::isnan(gamma_med)) + _slice_L = gamma_med; + else + _slice_L = gamma_avg; + lightcalo_charge.insert(lightcalo_charge.begin(),_charge.at(nplane)); + lightcalo_light.insert(lightcalo_light.begin(),gamma_med); + lightcalo_energy.insert(lightcalo_energy.begin(),_energy.at(nplane)); + lightcalo_plane.insert(lightcalo_plane.begin(),nplane); + } + else{ + lightcalo_charge.push_back(_charge.at(nplane)); + lightcalo_light.push_back(gamma_med); + lightcalo_energy.push_back(_energy.at(nplane)); + lightcalo_plane.push_back(nplane); + } } else{ - lightcalo_charge.push_back(_charge.at(nplane)); - lightcalo_light.push_back(gamma_med); - lightcalo_energy.push_back(_energy.at(nplane)); - lightcalo_plane.push_back(planeID); + _light_med.at(nplane) = -1.; + _light_avg.at(nplane) = -1.; + _energy.at(nplane) = -1.; + lightcalo_charge.push_back(-1.); + lightcalo_light.push_back(-1.); + lightcalo_energy.push_back(-1.); + lightcalo_plane.push_back(-1); } } - _slice_E = _energy.at(bestPlane); + _slice_E = _energy.at(bestPlane); sbn::LightCalo lightcalo(lightcalo_charge, lightcalo_light, @@ -555,6 +579,7 @@ void sbnd::LightCaloProducer::produce(art::Event& e) flash_time); lightcalo_v->push_back(lightcalo); + util::CreateAssn(*this, e, *lightcalo_v, slice, *slice_lightcalo_assn_v); _true_gamma = 0; _true_charge = 0; @@ -606,9 +631,6 @@ void sbnd::LightCaloProducer::produce(art::Event& e) _frac_Q = -9999; _frac_E = -9999; } - - util::CreateAssn(*this, e, *lightcalo_v, slice, *slice_lightcalo_assn_v); - _tree2->Fill(); nsuccessful_matches++; } // end slice loop diff --git a/sbndcode/Calorimetry/lightcalo_ana.fcl b/sbndcode/Calorimetry/lightcalo_ana.fcl index c96babb0c..5a43f94f7 100644 --- a/sbndcode/Calorimetry/lightcalo_ana.fcl +++ b/sbndcode/Calorimetry/lightcalo_ana.fcl @@ -1,7 +1,7 @@ #include "opticalsimparameterisations_sbnd.fcl" BEGIN_PROLOG -lightcalo_ana: +lightcaloana: { module_type: "LightCaloAna" From 52c18df17cd92649d7114c3d5c5e85db014897d8 Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Wed, 26 Apr 2023 16:22:01 -0500 Subject: [PATCH 20/52] cleanup, new functions, fcl parameters: - moved truth validation to a separate function - added lower/upper threshold for PE per channel - added fcl param to turn on/off evaluating all planes - option to add dir/refl efficiencies; NOTE: not really accounted for in the code yet --- sbndcode/Calorimetry/LightCaloAna_module.cc | 2 +- .../Calorimetry/LightCaloProducer_module.cc | 328 ++++++++++-------- sbndcode/Calorimetry/lightcalo.fcl | 8 +- 3 files changed, 185 insertions(+), 153 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index 1a9397f9f..203346093 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -573,7 +573,7 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) e.getByLabel(_simenergy_producer, energyDeps_h); std::vector> energyDeps; - if (energyDeps_h.isValid() || energyDeps_h->empty()) + if (!energyDeps_h.isValid() || energyDeps_h->empty()) std::cout << "Don't have good SimEnergyDeposits!" << std::endl; else art::fill_ptr_vector(energyDeps, energyDeps_h); diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 7f7b0ae69..aa5bd6ae2 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -99,12 +99,15 @@ class sbnd::LightCaloProducer : public art::EDProducer { std::vector> &match_v); // Returns visibility vector for all opdets given charge/position information - std::vector CalcVisibility(std::vector xyz_v, - std::vector charge_v); + void CalcVisibility(std::vector xyz_v, + std::vector charge_v, + std::vector &dir_vis_v, + std::vector &ref_vis_v); // Fills reconstructed photon count vector (total_gamma_v) for all opdets given charge/position information void CalcLight(std::vector flash_pe_v, - std::vector visibility, + std::vector dir_visibility, + std::vector ref_visibility, std::vector &total_gamma_v); // Returns the median of the light vector @@ -113,6 +116,9 @@ class sbnd::LightCaloProducer : public art::EDProducer { // Returns the mean of the light vector double CalcMean(std::vector total_light); + // Performs truth validation, saves info to TTree + void TruthValidation(art::Event& e, art::ServiceHandle piserv, double flash_time); + // fcl parameters std::vector _opflash_producer_v; std::vector _opflash_ara_producer_v; @@ -121,14 +127,17 @@ class sbnd::LightCaloProducer : public art::EDProducer { bool _use_arapucas; float _nuscore_cut; float _fmscore_cut; + bool _use_all_planes; bool _verbose; float _simple_op_offset; float _pmt_ara_offset; - std::vector _noise_thresh; + float _noise_thresh; + std::vector _pmt_pe_range; std::vector _cal_area_const; - std::vector _opdet_eff; + std::vector _opdet_dir_eff; + std::vector _opdet_ref_eff; float _scint_prescale; bool _truth_validation; @@ -193,14 +202,17 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) _use_arapucas = p.get("UseArapucas"); _nuscore_cut = p.get("nuScoreCut"); _fmscore_cut = p.get("fmScoreCut"); + _use_all_planes = p.get("UseAllPlanes"); _verbose = p.get("Verbose"); _simple_op_offset= p.get("SimpleOpFlashOffset"); _pmt_ara_offset = p.get("PMTARAFlashOffset"); - _noise_thresh = p.get>("FlashNoiseThreshold"); + _noise_thresh = p.get("FlashNoiseThreshold"); + _pmt_pe_range = p.get>("PMTPERange"); _cal_area_const = p.get>("CalAreaConstants"); - _opdet_eff = p.get>("OpDetEfficiencies"); + _opdet_dir_eff = p.get>("OpDetDirectEff"); + _opdet_ref_eff = p.get>("OpDetReflectEff"); _scint_prescale = p.get("ScintPreScale"); _truth_validation = p.get("TruthValidation"); @@ -224,6 +236,7 @@ void sbnd::LightCaloProducer::produce(art::Event& e) auto const clock_data = art::ServiceHandle()->DataFor(e); auto const det_prop = art::ServiceHandle()->DataFor(e, clock_data); + // std::cout<< "trigger offset TPC: " << clock_data.TriggerOffsetTPC() * 1.6 / 10 << std::endl; art::ServiceHandle geom; art::ServiceHandle g4param; art::ServiceHandle piserv; @@ -287,6 +300,10 @@ void sbnd::LightCaloProducer::produce(art::Event& e) std::vector> match_slices_v; std::vector> match_fm_v; + //------------------------------// + + //* OBTAINING VALID SLICES BEGIN *// + for (size_t n_slice=0; n_slice < slice_v.size(); n_slice++){ float nu_score = -9999; float fm_score = -9999; @@ -314,8 +331,7 @@ void sbnd::LightCaloProducer::produce(art::Event& e) std::cout << "No SimpleFlashMatch objects associated with this PFP!" << std::endl; continue; } - if (fm_v.size() > 1) - std::cout << "more than one match for one pfp?" << std::endl; + if (fm_v.size() > 1) std::cout << "WARNING: more than one SimpleFlashMatch for one pfp?" << std::endl; for (size_t n_fm=0; n_fm < fm_v.size(); n_fm++){ auto fm = fm_v.at(n_fm); fm_score = fm->score.total; @@ -343,12 +359,16 @@ void sbnd::LightCaloProducer::produce(art::Event& e) return; } - // get relevant opflashes + //* OBTAINING VALID SLICES END *// + + //------------------------------// + + //* OBTAINING OPFLASH INFORMATION BEGIN*// // tpc0 std::vector> flash0_v; art::fill_ptr_vector(flash0_v, flash0_h); - std::vector> match_op0; - bool found_opflash0 = MatchOpFlash(match_fm_v,flash0_v, match_op0); + std::vector> match_op0_v; + bool found_opflash0 = MatchOpFlash(match_fm_v,flash0_v, match_op0_v); std::vector> flash0_ara_v; // if using arapucas @@ -365,8 +385,8 @@ void sbnd::LightCaloProducer::produce(art::Event& e) // tpc1 std::vector> flash1_v; art::fill_ptr_vector(flash1_v, flash1_h); - std::vector> match_op1; - bool found_opflash1 = MatchOpFlash(match_fm_v,flash1_v, match_op1); + std::vector> match_op1_v; + bool found_opflash1 = MatchOpFlash(match_fm_v,flash1_v, match_op1_v); std::vector> flash1_ara_v; if (_use_arapucas){ @@ -379,14 +399,16 @@ void sbnd::LightCaloProducer::produce(art::Event& e) else art::fill_ptr_vector(flash1_ara_v, flash1_ara_h); } + // if no opflashes found in either TPC if (found_opflash0 == false && found_opflash1 == false){ - std::cout << "no opflashes matched to simpleflashes" << std::endl; + std::cout << "No OpFlashes matched to SimpleFlashes (for the entire event)" << std::endl; _match_type = -2; _tree->Fill(); e.put(std::move(lightcalo_v)); e.put(std::move(slice_lightcalo_assn_v)); return; } + //* OBTAINING OPFLASH INFORMATION END *// int nsuccessful_matches=0; for (size_t n_slice=0; n_slice < match_slices_v.size(); n_slice++){ @@ -402,55 +424,41 @@ void sbnd::LightCaloProducer::produce(art::Event& e) std::vector> sp_charge(3); // vector of charge info for charge-weighting for each plane double flash_time = -999; - auto opflash0 = (match_op0.at(n_slice)); - auto opflash1 = (match_op1.at(n_slice)); + auto opflash0 = (match_op0_v.at(n_slice)); + auto opflash1 = (match_op1_v.at(n_slice)); bool flash_in_0 = false; bool flash_in_1 = false; - // set threshold above noise PE levels for the flash - float noise_thresh = (!_use_arapucas)? _noise_thresh[0] : _noise_thresh[1]; - - if (!opflash0.isNull() && opflash1.isNull()){ - flash_time = opflash0->Time(); - if (opflash0->TotalPE() > noise_thresh) + if (!opflash0.isNull()){ + if (opflash0->TotalPE() > _noise_thresh) flash_in_0 = true; else if (_verbose) std::cout << "Flash Total PE in TPC 0 (" << opflash0->TotalPE() << ") below noise threshold ... Skipping" << std::endl; } - else if ( opflash0.isNull() && !opflash1.isNull()){ - flash_time = opflash1->Time(); - if (opflash1->TotalPE() > noise_thresh) - flash_in_1 = true; - else if (_verbose) - std::cout << "Flash Total PE in TPC 1 (" << opflash1->TotalPE() << ") below noise threshold ... Skipping" << std::endl; - } - else if (!opflash0.isNull() && !opflash1.isNull()){ - flash_time = opflash0->Time(); - if (opflash0->TotalPE() > noise_thresh) - flash_in_0 = true; - else if (_verbose) - std::cout << "Flash Total PE in TPC 0 (" << opflash0->TotalPE() << ") below noise threshold ... Skipping" << std::endl; - if (opflash1->TotalPE() > noise_thresh) + if (!opflash1.isNull()){ + if (opflash1->TotalPE() > _noise_thresh) flash_in_1 = true; else if (_verbose) std::cout << "Flash Total PE in TPC 1 (" << opflash1->TotalPE() << ") below noise threshold ... Skipping" << std::endl; - } - else if (opflash0.isNull() && opflash1.isNull()){ - std::cout << "No opflashes matched with SimpleFlash objects" << std::endl; + } + if (!flash_in_0 && !flash_in_1){ + std::cout << "No OpFlashes matched with SimpleFlash objects (for this slice)" << std::endl; _match_type = -3; _tree->Fill(); - e.put(std::move(lightcalo_v)); - e.put(std::move(slice_lightcalo_assn_v)); - return; + continue; } + + if (flash_in_0) flash_time = opflash0->Time(); + else if (flash_in_1) flash_time = opflash1->Time(); auto slice = match_slices_v[n_slice]; - // sum charge information (without position info) for Q + // sum charge information (without position info) for Q, higher completeness // find which plane has the most integrated charge for this slice std::vector> slice_hits_v = slice_to_hit.at(slice.key()); std::vector plane_charge{0.,0.,0.}; std::vector plane_hits{0,0,0}; for (size_t i=0; i < slice_hits_v.size(); i++){ auto hit = slice_hits_v[i]; + // TODO: fix hardcoded beam readout time auto drift_time = (hit->PeakTime() - 500)*0.5; // assuming TPC beam readout starts at 500 ticks, conversion = 0.5 us/tick double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) auto hit_plane = hit->View(); @@ -472,50 +480,53 @@ void sbnd::LightCaloProducer::produce(art::Event& e) std::vector> hit_v = spacepoint_to_hit.at(sp.key()); for (size_t n_hit=0; n_hit < hit_v.size(); n_hit++){ auto hit = hit_v[n_hit]; - auto hit_plane = hit->View(); - // get position - const auto &position(sp->XYZ()); - geo::Point_t xyz(position[0],position[1],position[2]); - // correct for e- attenuation - double drift_time = ((2.0*geom->DetHalfWidth()) - abs(position[0]))/(det_prop.DriftVelocity()); // cm / (cm/us) - double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) - double charge = (1/_cal_area_const.at(hit_plane))*atten_correction*hit->Integral(); - - sp_xyz.at(hit_plane).push_back(xyz); - sp_charge.at(hit_plane).push_back(charge); + auto hit_plane = hit->View(); + // if not the best plane and we're only using the best plane + if ( hit_plane != bestPlane && !_use_all_planes) + continue; + else{ + // get position + const auto &position(sp->XYZ()); + geo::Point_t xyz(position[0],position[1],position[2]); + // correct for e- attenuation + double drift_time = ((2.0*geom->DetHalfWidth()) - abs(position[0]))/(det_prop.DriftVelocity()); // cm / (cm/us) + double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) + double charge = (1/_cal_area_const.at(hit_plane))*atten_correction*hit->Integral(); + + sp_xyz.at(hit_plane).push_back(xyz); + sp_charge.at(hit_plane).push_back(charge); + } } } // end spacepoint loop } // end pfp loop std::vector total_pe(_nchan,0.); // contains PE info from both TPCs, PMTs, and ARA (if applicable) + // combining flash PE information from separate TPCs into a single vector for (int tpc=0; tpc<2; tpc++){ bool found_flash = (tpc==0)? flash_in_0 : flash_in_1; if (found_flash){ - auto flash_pe_v = (tpc==0)? opflash0->PEs() : opflash1->PEs(); + auto opflash_pe = (tpc==0)? opflash0->PEs() : opflash1->PEs(); + for (size_t ich=0; ich < opflash_pe.size(); ich++) total_pe[ich] += opflash_pe[ich]; // if using arapucas, need to combine PMT and arapuca PE information into a single vector if (_use_arapucas){ auto flash_ara_v = (tpc==0)? flash0_ara_v : flash1_ara_v; - if (flash_ara_v.empty()) - // if there are no valid arapuca flashes + if (flash_ara_v.empty()) // if there are no valid arapuca flashes std::cout << "Using PMT information Only..." << std::endl; else{ - // for PMT flashes, the PE vector is shortened and don't include the last 6 entries for ARAPUCAs - if (flash_pe_v.size()!= _nchan) flash_pe_v.insert(flash_pe_v.end(), {0,0,0,0,0,0}); for (size_t nara=0; nara < flash_ara_v.size(); nara++){ auto const &flash_ara = *flash_ara_v[nara]; if (abs(flash_time-flash_ara.Time()) < _pmt_ara_offset){ if (_verbose) std::cout << "Combining PMT+XARA Flashes with PMT time: " << flash_time << ", ARA time: " << flash_ara.Time() << std::endl; for (size_t ich=0; ich < (flash_ara.PEs()).size(); ich++) - flash_pe_v.at(ich) += (flash_ara.PEs()).at(ich); + total_pe.at(ich) += (flash_ara.PEs()).at(ich); break; - } - } + } // end if arapuca and pmt flash time match + } // end of arapuca flash loop } } // end of arapuca if - for (size_t ich=0; ich visibility_map = CalcVisibility(sp_xyz.at(nplane),sp_charge.at(nplane)); + std::vector dir_vis_v(_nchan, 0.); // direct visibility + std::vector ref_vis_v(_nchan, 0.); // reflected visibility + CalcVisibility(sp_xyz.at(nplane),sp_charge.at(nplane), dir_vis_v, ref_vis_v); // calculate the photon estimates for every entry in total_pe - CalcLight(total_pe, visibility_map, total_gamma.at(nplane)); + CalcLight(total_pe, dir_vis_v, ref_vis_v, total_gamma.at(nplane)); _light_med.at(nplane) = CalcMedian(total_gamma.at(nplane)); _light_avg.at(nplane) = CalcMedian(total_gamma.at(nplane)); @@ -548,6 +561,7 @@ void sbnd::LightCaloProducer::produce(art::Event& e) _slice_L = gamma_med; else _slice_L = gamma_avg; + // if the plane is the bestPlane, insert it at the front lightcalo_charge.insert(lightcalo_charge.begin(),_charge.at(nplane)); lightcalo_light.insert(lightcalo_light.begin(),gamma_med); lightcalo_energy.insert(lightcalo_energy.begin(),_energy.at(nplane)); @@ -561,76 +575,32 @@ void sbnd::LightCaloProducer::produce(art::Event& e) } } else{ - _light_med.at(nplane) = -1.; - _light_avg.at(nplane) = -1.; - _energy.at(nplane) = -1.; - lightcalo_charge.push_back(-1.); - lightcalo_light.push_back(-1.); - lightcalo_energy.push_back(-1.); + _light_med.at(nplane) = -1.; _light_avg.at(nplane) = -1.; _energy.at(nplane) = -1.; + lightcalo_charge.push_back(-1.); lightcalo_light.push_back(-1.); lightcalo_energy.push_back(-1.); lightcalo_plane.push_back(-1); } } _slice_E = _energy.at(bestPlane); sbn::LightCalo lightcalo(lightcalo_charge, - lightcalo_light, - lightcalo_energy, - lightcalo_plane, - flash_time); + lightcalo_light, + lightcalo_energy, + lightcalo_plane, + flash_time); lightcalo_v->push_back(lightcalo); util::CreateAssn(*this, e, *lightcalo_v, slice, *slice_lightcalo_assn_v); - _true_gamma = 0; - _true_charge = 0; - _true_energy = 0; - - //* start truth validation section *// - if (_truth_validation){ - ::art::Handle> energyDeps_h; - e.getByLabel(_simenergy_producer, energyDeps_h); - std::vector> energyDeps; - - if (energyDeps_h.isValid() || energyDeps_h->empty()) - std::cout << "Don't have good SimEnergyDeposits!" << std::endl; - else - art::fill_ptr_vector(energyDeps, energyDeps_h); - - for (size_t n_dep=0; n_dep < energyDeps.size(); n_dep++){ - auto energyDep = energyDeps[n_dep]; - const auto trackID = energyDep->TrackID(); - const double time = energyDep->Time() * 1e-3; // us - - art::Ptr mctruth = piserv->TrackIdToMCTruth_P(trackID); - - if ((_truth_neutrino && mctruth->Origin()==simb::kBeamNeutrino ) || - (!_truth_neutrino && abs(time-flash_time) < 1)){ - // note: we divide by the prescale because NumPhotons() stored in simulation has the scint prescale applied - _true_gamma += energyDep->NumPhotons()/_scint_prescale; - _true_charge += energyDep->NumElectrons(); - _true_energy += energyDep->Energy(); - } - } - //* end truth validation section *// - - _frac_L = (_true_gamma - _slice_L)/_true_gamma; - _frac_Q = (_true_charge - _slice_Q)/_true_charge; - _frac_E = (_true_energy - _slice_E)/_true_energy; - - if (_verbose){ - std::cout << "ratio of gamma (median/true): " << _slice_L/_true_gamma << std::endl; - std::cout << "ratio of electron (comp/true): " << _slice_Q/_true_charge << std::endl; - std::cout << "ratio of energy (calc/true): " << _slice_E/_true_energy << std::endl; - } - } + ::art::Handle> energyDeps_h; + e.getByLabel(_simenergy_producer, energyDeps_h); + std::vector> energyDeps; + + if (_truth_validation) TruthValidation(e, piserv, flash_time); else{ - _true_gamma = -9999; - _true_charge = -9999; - _true_energy = -9999; - _frac_L = -9999; - _frac_Q = -9999; - _frac_E = -9999; - } + _true_gamma = -9999; _true_charge = -9999; _true_energy = -9999; + _frac_L = -9999; _frac_Q = -9999; _frac_E = -9999; + } + _tree2->Fill(); nsuccessful_matches++; } // end slice loop @@ -717,12 +687,12 @@ bool sbnd::LightCaloProducer::MatchOpFlash(std::vector sbnd::LightCaloProducer::CalcVisibility(std::vector xyz_v, - std::vector charge_v){ +void sbnd::LightCaloProducer::CalcVisibility(std::vector xyz_v, + std::vector charge_v, + std::vector &dir_vis_v, + std::vector &ref_vis_v){ // returns of a vector (len is # of opdet) for the visibility for every opdet if (xyz_v.size() != charge_v.size()) std::cout << "spacepoint coord and charge vector size mismatch" << std::endl; - - std::vector visibility(_nchan, 0); double sum_charge0 = 0; double sum_charge1 = 0; @@ -737,43 +707,56 @@ std::vector sbnd::LightCaloProducer::CalcVisibility(std::vector reflect_visibility; _semi_model->detectedDirectVisibilities(direct_visibility, xyz); _semi_model->detectedReflectedVisibilities(reflect_visibility, xyz); - if (visibility.size() != direct_visibility.size()) std::cout << "mismatch of visibility vector size" << std::endl; + if (dir_vis_v.size() != direct_visibility.size() || ref_vis_v.size() != direct_visibility.size() ) + std::cout << "mismatch of visibility vector size" << std::endl; // weight by charge for (size_t ch=0; ch flash_pe_v, - std::vector visibility, + std::vector dir_visibility, + std::vector ref_visibility, std::vector &total_gamma_v){ for (size_t ch = 0; ch < flash_pe_v.size(); ch++){ auto pe = flash_pe_v[ch]; double efficiency = 0.03; - if((pe == 0) || std::isinf(1/visibility[ch])) + if((pe == 0) || std::isinf(abs(1/(dir_visibility[ch]+ref_visibility[ch])))) + continue; + if ( pe < _pmt_pe_range.at(0) || pe > _pmt_pe_range.at(1)) continue; if (_opdetmap.isPDType(ch, "pmt_uncoated")) - efficiency = _opdet_eff[0]; + efficiency = _opdet_dir_eff[0]; else if (_opdetmap.isPDType(ch, "pmt_coated")) - efficiency = _opdet_eff[1]; + efficiency = _opdet_dir_eff[1]; else if (_opdetmap.isPDType(ch, "xarapuca_vis")) - efficiency = _opdet_eff[2]; + efficiency = _opdet_dir_eff[2]; else if (_opdetmap.isPDType(ch, "xarapuca_vuv")) - efficiency = _opdet_eff[3]; + efficiency = _opdet_dir_eff[3]; // deposited light is inverse of efficiency * inverse of visibility * PE count - total_gamma_v[ch] += (1/efficiency)*(1/visibility[ch])*pe; + total_gamma_v[ch] += (1/efficiency)*(1/(dir_visibility[ch]+ref_visibility[ch]))*pe; } } @@ -805,7 +788,7 @@ double sbnd::LightCaloProducer::CalcMedian(std::vector total_gamma){ med_idx = idx.at(int((gamma_v.size()-zero_counter))/2 + zero_counter); median = gamma_v.at(med_idx); } - median_gamma+=median; + median_gamma+=median; // sum the two tpc median light } return median_gamma; } @@ -830,9 +813,54 @@ double sbnd::LightCaloProducer::CalcMean(std::vector total_gamma){ sum+=gamma; } } - if (sum!=0) mean_gamma+= sum/counter; + if (counter!=0) mean_gamma+= sum/counter; } return mean_gamma; } +void sbnd::LightCaloProducer::TruthValidation(art::Event& e, art::ServiceHandle piserv, double flash_time){ + _true_gamma = 0; + _true_charge = 0; + _true_energy = 0; + + ::art::Handle> energyDeps_h; + e.getByLabel(_simenergy_producer, energyDeps_h); + std::vector> energyDeps; + + if (!energyDeps_h.isValid() || energyDeps_h->empty()){ + std::cout << "Don't have good SimEnergyDeposits!" << std::endl; + _true_gamma = -9999; _true_charge = -9999; _true_energy = -9999; + _frac_L = -9999; _frac_Q = -9999; _frac_E = -9999; + return; + } + else art::fill_ptr_vector(energyDeps, energyDeps_h); + + for (size_t n_dep=0; n_dep < energyDeps.size(); n_dep++){ + auto energyDep = energyDeps[n_dep]; + const auto trackID = energyDep->TrackID(); + const double time = energyDep->Time() * 1e-3; // us + + art::Ptr mctruth = piserv->TrackIdToMCTruth_P(trackID); + + // if validating a neutrino event, check that the origin of the deposit is from a beam neutrino + // if validating a non-neutrino event (e.g. cosmics), match the deposit time with the flash time (may not be complete) + if ((_truth_neutrino && mctruth->Origin()==simb::kBeamNeutrino ) || + (!_truth_neutrino && abs(time-flash_time) < 1)){ + // note: we divide by the prescale because NumPhotons() stored in simulation has the scint prescale applied + _true_gamma += energyDep->NumPhotons()/_scint_prescale; + _true_charge += energyDep->NumElectrons(); + _true_energy += energyDep->Energy(); + } + } + _frac_L = (_true_gamma - _slice_L)/_true_gamma; + _frac_Q = (_true_charge - _slice_Q)/_true_charge; + _frac_E = (_true_energy - _slice_E)/_true_energy; + + if (_verbose){ + std::cout << "ratio of gamma (median/true): " << _slice_L/_true_gamma << std::endl; + std::cout << "ratio of electron (comp/true): " << _slice_Q/_true_charge << std::endl; + std::cout << "ratio of energy (calc/true): " << _slice_E/_true_energy << std::endl; + } +} + DEFINE_ART_MODULE(sbnd::LightCaloProducer) diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index 038560ba0..450c591a4 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -15,17 +15,21 @@ lightcalo: UseArapucas: false nuScoreCut: 0.4 # default: accept nusScore > 0.4, to analyze all slices, set nuScoreCut = -1 fmScoreCut: 7 # default: accept 0 < fm score < fmScoreCut, to analyze all slices, set fmScoreCut = 1e3 + UseAllPlanes: false # if true: Q, L, E will be calculated separately for each plane (increases computational time) + # if false: Q, L, E will be calculated for best plane only (highest # of hits) Verbose: false # flash parameters SimpleOpFlashOffset: 0.2 # the offset between the t0 from SimpleFlash and OpFlashes PMTARAFlashOffset: 0.05 # the offset between the t0 of PMT OpFlashes and X-ARA OpFlashes - FlashNoiseThreshold: [ 600., 1500. ] # {PMT, xARAPUCA}, flash total PE threshold to ignore a flash + FlashNoiseThreshold: 600. # for PMTS, flash total PE threshold to ignore a flash (below thresh = noise) + PMTPERange: [10,300] # the lower and upper PE thresholds to evaluate a flash. Below lower -> noise, above upper -> non-linearity # calibration constants & simulation parameters ## shouldn't have to change this unless you change simulation parameters CalAreaConstants: [ 0.0200906, 0.0200016, 0.0201293 ] # calibration constants for wire planes - OpDetEfficiencies: [ 0.03, 0.03, 0.014, 0.021 ] # efficiencies [uncoated PMT, coated PMT, vis ara, vuv ara] + OpDetDirectEff: [ 0.03, 0.03, 0.014, 0.021 ] # direct efficiencies [uncoated PMT, coated PMT, vis ara, vuv ara] + OpDetReflectEff: [ 0.03, 0.03, 0.014, 0.021 ] # reflected efficiencies ScintPreScale: 0.03 # Scintillation Pre-Scale factor in simulation (set in ionandscint) # parameters for truth validation From a1df52b34b797aeaca2e5bdf74948eb6ba33f10c Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Tue, 16 May 2023 09:26:22 -0500 Subject: [PATCH 21/52] update output ttree, fix initialized/dummy ttree variables - merge the two previous trees into one - match-type can now differentiate between event/slice level easily --- .../Calorimetry/LightCaloProducer_module.cc | 183 ++++++++++-------- 1 file changed, 98 insertions(+), 85 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index aa5bd6ae2..d8b21d512 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -151,17 +151,16 @@ class sbnd::LightCaloProducer : public art::EDProducer { opdet::sbndPDMapAlg _opdetmap; //map for photon detector types unsigned int _nchan = _opdetmap.size(); - int _run, _subrun, _event; - TTree* _tree; - int _match_type; + int _run, _subrun, _event; + int _match_type; // match_type key: - /// -1: no slices passed both the nuscore and flash match score cut - /// -2: no opflashes times found in coincidence with simpleflash time - /// -3: opflashes are empty or PE count too low + /// -1: no slices passed both the nuscore and flash match score cut (in the entire event) + /// -2: no opflashes times found in coincidence with simpleflash time (in the entire event) + /// -3: no opflashes in coincidence with simpleflash (for this slice) + /// -4: opflashes are below the noise threshold (for this slice) + /// 1: successful match - TTree* _tree2; - int _nmatch=0; // number of matches in an event int _pfpid; // ID of the matched slice double _opflash_time; // time of matched opflash @@ -245,6 +244,14 @@ void sbnd::LightCaloProducer::produce(art::Event& e) _subrun = e.id().subRun(); _event = e.id().event(); std::cout << "run: " << _run << ", subrun: " << _subrun << ", event: " << _event << std::endl; + + // initialize tree variables + _match_type=0; _pfpid = -1; _opflash_time=-9999; + _dep_pe.clear(); _rec_gamma.clear(); + _true_gamma = -9999; _true_charge = -9999; _true_energy = -9999; + _charge.assign(3,0); _light_med.assign(3,0); _light_avg.assign(3,0); _energy.assign(3,0); + _slice_L = -1; _slice_Q = -1; _slice_E = -1; + _frac_L = -9999; _frac_Q = -9999; _frac_E = -9999; // get slices ::art::Handle> slice_h; @@ -298,6 +305,7 @@ void sbnd::LightCaloProducer::produce(art::Event& e) art::FindManyP spacepoint_to_hit(spacepoint_h, e, _slice_producer); std::vector> match_slices_v; + std::vector match_pfpid_v; std::vector> match_fm_v; //------------------------------// @@ -340,12 +348,15 @@ void sbnd::LightCaloProducer::produce(art::Event& e) match_fm_v.push_back(fm); } } // end flashmatch loop - if (found_fm ==true) match_slices_v.push_back(slice); + if (found_fm ==true){ + match_slices_v.push_back(slice); + match_pfpid_v.push_back(pfp->Self()); + } } // end pfp loop } // end slice loop if (match_slices_v.empty() && !slice_v.empty()){ std::cout << "no slices passed the cuts" << std::endl; - _match_type = -1; + _match_type = -1; _pfpid = -1; _tree->Fill(); e.put(std::move(lightcalo_v)); e.put(std::move(slice_lightcalo_assn_v)); @@ -402,27 +413,27 @@ void sbnd::LightCaloProducer::produce(art::Event& e) // if no opflashes found in either TPC if (found_opflash0 == false && found_opflash1 == false){ std::cout << "No OpFlashes matched to SimpleFlashes (for the entire event)" << std::endl; - _match_type = -2; - _tree->Fill(); + for (size_t n_slice=0; n_slice < match_pfpid_v.size(); n_slice++){ + _match_type = -2; + _pfpid = match_pfpid_v.at(n_slice); + _tree->Fill(); + } e.put(std::move(lightcalo_v)); e.put(std::move(slice_lightcalo_assn_v)); return; } //* OBTAINING OPFLASH INFORMATION END *// - int nsuccessful_matches=0; for (size_t n_slice=0; n_slice < match_slices_v.size(); n_slice++){ - // initialize tree2 variables - _nmatch++; - _pfpid = -1; - - _slice_Q = 0; // total amount of charge - _slice_L = 0; // total amount of light - _slice_E = 0; + // initialize tree variables + _pfpid = match_pfpid_v.at(n_slice); std::vector> sp_xyz(3); // position info of each spacepoint per plane - std::vector> sp_charge(3); // vector of charge info for charge-weighting for each plane - + std::vector> sp_charge(3); // vector of charge info for charge-weighting for each plane + + if (_verbose) + std::cout << "Reconstructing slice " << n_slice << std::endl; + double flash_time = -999; auto opflash0 = (match_op0_v.at(n_slice)); auto opflash1 = (match_op1_v.at(n_slice)); @@ -432,7 +443,7 @@ void sbnd::LightCaloProducer::produce(art::Event& e) if (opflash0->TotalPE() > _noise_thresh) flash_in_0 = true; else if (_verbose) - std::cout << "Flash Total PE in TPC 0 (" << opflash0->TotalPE() << ") below noise threshold ... Skipping" << std::endl; + std::cout << "Flash Total PE in TPC 0 (" << opflash0->TotalPE() << ") below noise threshold ..." << std::endl; } if (!opflash1.isNull()){ if (opflash1->TotalPE() > _noise_thresh) @@ -441,14 +452,30 @@ void sbnd::LightCaloProducer::produce(art::Event& e) std::cout << "Flash Total PE in TPC 1 (" << opflash1->TotalPE() << ") below noise threshold ... Skipping" << std::endl; } if (!flash_in_0 && !flash_in_1){ - std::cout << "No OpFlashes matched with SimpleFlash objects (for this slice)" << std::endl; - _match_type = -3; + if (opflash0.isNull() || opflash1.isNull()){ + std::cout << "No OpFlashes matched with SimpleFlash objects (for this slice)" << std::endl; + _match_type = -3; + } + else if (opflash0->TotalPE() < _noise_thresh|| opflash1->TotalPE() < _noise_thresh){ + std::cout << "All OpFlashes are below noise threshold..." << std::endl; + _match_type = -4; + } + _opflash_time=-9999; + _dep_pe.clear(); _rec_gamma.clear(); + _true_gamma = -9999; _true_charge = -9999; _true_energy = -9999; + _charge.assign(3,0); _light_med.assign(3,0); _light_avg.assign(3,0); _energy.assign(3,0); + _slice_L = -1; _slice_Q = -1; _slice_E = -1; + _frac_L = -9999; _frac_Q = -9999; _frac_E = -9999; _tree->Fill(); continue; } if (flash_in_0) flash_time = opflash0->Time(); else if (flash_in_1) flash_time = opflash1->Time(); + + _slice_Q = 0; // total amount of charge + _slice_L = 0; // total amount of light + _slice_E = 0; auto slice = match_slices_v[n_slice]; // sum charge information (without position info) for Q, higher completeness @@ -468,7 +495,6 @@ void sbnd::LightCaloProducer::produce(art::Event& e) int bestPlane = std::max_element(plane_hits.begin(), plane_hits.end()) - plane_hits.begin(); _slice_Q = plane_charge.at(bestPlane); _charge = plane_charge; - // get charge information to create the weighted map std::vector> pfp_v = slice_to_pfp.at(slice.key()); for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ @@ -499,8 +525,7 @@ void sbnd::LightCaloProducer::produce(art::Event& e) } } // end spacepoint loop } // end pfp loop - - std::vector total_pe(_nchan,0.); // contains PE info from both TPCs, PMTs, and ARA (if applicable) + std::vector total_pe(_nchan,0.); // contains PE info from both TPCs: PMTs and ARA (if applicable) // combining flash PE information from separate TPCs into a single vector for (int tpc=0; tpc<2; tpc++){ @@ -528,7 +553,6 @@ void sbnd::LightCaloProducer::produce(art::Event& e) } // end of arapuca if } // end of found flash if } // end of TPC loop - // fill tree variables _opflash_time = flash_time; _dep_pe = total_pe; @@ -550,17 +574,13 @@ void sbnd::LightCaloProducer::produce(art::Event& e) CalcLight(total_pe, dir_vis_v, ref_vis_v, total_gamma.at(nplane)); _light_med.at(nplane) = CalcMedian(total_gamma.at(nplane)); _light_avg.at(nplane) = CalcMedian(total_gamma.at(nplane)); - _energy.at(nplane) = (_charge.at(nplane) + _light_med.at(nplane))*1e-6*g4param->Wph(); - double gamma_avg = _light_avg.at(nplane); double gamma_med = _light_med.at(nplane); if (nplane==bestPlane){ _rec_gamma = total_gamma.at(nplane); - if (gamma_med!=0 && !std::isnan(gamma_med)) - _slice_L = gamma_med; - else - _slice_L = gamma_avg; + if (gamma_med!=0 && !std::isnan(gamma_med)) _slice_L = gamma_med; + else _slice_L = gamma_avg; // if the plane is the bestPlane, insert it at the front lightcalo_charge.insert(lightcalo_charge.begin(),_charge.at(nplane)); lightcalo_light.insert(lightcalo_light.begin(),gamma_med); @@ -582,11 +602,8 @@ void sbnd::LightCaloProducer::produce(art::Event& e) } _slice_E = _energy.at(bestPlane); - sbn::LightCalo lightcalo(lightcalo_charge, - lightcalo_light, - lightcalo_energy, - lightcalo_plane, - flash_time); + sbn::LightCalo lightcalo(lightcalo_charge, lightcalo_light,lightcalo_energy, + lightcalo_plane,flash_time); lightcalo_v->push_back(lightcalo); util::CreateAssn(*this, e, *lightcalo_v, slice, *slice_lightcalo_assn_v); @@ -600,12 +617,9 @@ void sbnd::LightCaloProducer::produce(art::Event& e) _true_gamma = -9999; _true_charge = -9999; _true_energy = -9999; _frac_L = -9999; _frac_Q = -9999; _frac_E = -9999; } - - _tree2->Fill(); - nsuccessful_matches++; + _match_type = 1; + _tree->Fill(); } // end slice loop - _match_type=nsuccessful_matches; - _tree->Fill(); e.put(std::move(lightcalo_v)); e.put(std::move(slice_lightcalo_assn_v)); } @@ -614,44 +628,43 @@ void sbnd::LightCaloProducer::beginJob() { art::ServiceHandle fs; _tree = fs->make("slice_tree",""); - _tree->Branch("run", &_run, "run/I"); - _tree->Branch("subrun", &_subrun, "subrun/I"); - _tree->Branch("event", &_event, "event/I"); - _tree->Branch("match_type", &_match_type, "match_type/I"); - - _tree2 = fs->make("match_tree",""); - _tree2->Branch("run", &_run, "run/I"); - _tree2->Branch("subrun", &_subrun, "subrun/I"); - _tree2->Branch("event", &_event, "event/I"); - _tree2->Branch("nmatch", &_nmatch, "nmatch/I"); - _tree2->Branch("pfpid", &_pfpid, "pfpid/I"); - _tree2->Branch("opflash_time", &_opflash_time, "opflash_time/D"); - - _tree2->Branch("rec_gamma", "std::vector", &_rec_gamma); - _tree2->Branch("dep_pe", "std::vector", &_dep_pe); - - _tree2->Branch("true_gamma", &_true_gamma, "true_gamma/D"); - _tree2->Branch("true_charge", &_true_charge, "true_charge/D"); - _tree2->Branch("true_energy", &_true_energy, "true_energy/D"); - - _tree2->Branch("charge_plane0", &_charge[0], "charge_plane0/D"); - _tree2->Branch("charge_plane1", &_charge[1], "charge_plane1/D"); - _tree2->Branch("charge_plane2", &_charge[2], "charge_plane2/D"); + + _tree->Branch("run", &_run, "run/I"); + _tree->Branch("subrun", &_subrun, "subrun/I"); + _tree->Branch("event", &_event, "event/I"); + _tree->Branch("match_type", &_match_type, "match_type/I"); + _tree->Branch("pfpid", &_pfpid, "pfpid/I"); + _tree->Branch("opflash_time", &_opflash_time, "opflash_time/D"); + + _tree->Branch("rec_gamma", "std::vector", &_rec_gamma); + _tree->Branch("dep_pe", "std::vector", &_dep_pe); + + _tree->Branch("true_gamma", &_true_gamma, "true_gamma/D"); + _tree->Branch("true_charge", &_true_charge, "true_charge/D"); + _tree->Branch("true_energy", &_true_energy, "true_energy/D"); + + _tree->Branch("charge_plane0", &_charge[0], "charge_plane0/D"); + _tree->Branch("charge_plane1", &_charge[1], "charge_plane1/D"); + _tree->Branch("charge_plane2", &_charge[2], "charge_plane2/D"); - _tree2->Branch("light_med_plane0", &_light_med[0] ,"light_med_plane0/D"); - _tree2->Branch("light_med_plane1", &_light_med[1] ,"light_med_plane1/D"); - _tree2->Branch("light_med_plane2", &_light_med[2] ,"light_med_plane2/D"); - - _tree2->Branch("light_avg_plane0", &_light_avg[0] ,"light_avg_plane0/D"); - _tree2->Branch("light_avg_plane1", &_light_avg[1] ,"light_avg_plane1/D"); - _tree2->Branch("light_avg_plane2", &_light_avg[2] ,"light_avg_plane2/D"); - - _tree2->Branch("slice_L", &_slice_L, "slice_L/D"); - _tree2->Branch("slice_Q", &_slice_Q, "slice_Q/D"); - _tree2->Branch("slice_E", &_slice_E, "slice_E/D"); - _tree2->Branch("frac_L", &_frac_L, "frac_L/D"); - _tree2->Branch("frac_Q", &_frac_Q, "frac_Q/D"); - _tree2->Branch("frac_E", &_frac_E, "frac_E/D"); + _tree->Branch("light_med_plane0", &_light_med[0] ,"light_med_plane0/D"); + _tree->Branch("light_med_plane1", &_light_med[1] ,"light_med_plane1/D"); + _tree->Branch("light_med_plane2", &_light_med[2] ,"light_med_plane2/D"); + + _tree->Branch("light_avg_plane0", &_light_avg[0] ,"light_avg_plane0/D"); + _tree->Branch("light_avg_plane1", &_light_avg[1] ,"light_avg_plane1/D"); + _tree->Branch("light_avg_plane2", &_light_avg[2] ,"light_avg_plane2/D"); + + _tree->Branch("energy_plane0", &_energy[0], "energy_plane0/D"); + _tree->Branch("energy_plane1", &_energy[1], "energy_plane1/D"); + _tree->Branch("energy_plane2", &_energy[2], "energy_plane2/D"); + + _tree->Branch("slice_L", &_slice_L, "slice_L/D"); + _tree->Branch("slice_Q", &_slice_Q, "slice_Q/D"); + _tree->Branch("slice_E", &_slice_E, "slice_E/D"); + _tree->Branch("frac_L", &_frac_L, "frac_L/D"); + _tree->Branch("frac_Q", &_frac_Q, "frac_Q/D"); + _tree->Branch("frac_E", &_frac_E, "frac_E/D"); } void sbnd::LightCaloProducer::endJob() @@ -852,9 +865,9 @@ void sbnd::LightCaloProducer::TruthValidation(art::Event& e, art::ServiceHandle< _true_energy += energyDep->Energy(); } } - _frac_L = (_true_gamma - _slice_L)/_true_gamma; - _frac_Q = (_true_charge - _slice_Q)/_true_charge; - _frac_E = (_true_energy - _slice_E)/_true_energy; + _frac_L = _true_gamma > 0? (_true_gamma - _slice_L)/_true_gamma : -9999; + _frac_Q = _true_charge > 0? (_true_charge - _slice_Q)/_true_charge : -9999; + _frac_E = _true_energy > 0? (_true_energy - _slice_E)/_true_energy : -9999; if (_verbose){ std::cout << "ratio of gamma (median/true): " << _slice_L/_true_gamma << std::endl; From 16ce24109207e2840d65cd9b2bccb678f6664372 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 16 May 2024 13:26:48 -0500 Subject: [PATCH 22/52] switch to correct namespace for photon model, cleanup --- sbndcode/Calorimetry/CMakeLists.txt | 1 - sbndcode/Calorimetry/LightCaloAna_module.cc | 4 ++-- sbndcode/Calorimetry/LightCaloProducer_module.cc | 12 ++++++------ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/sbndcode/Calorimetry/CMakeLists.txt b/sbndcode/Calorimetry/CMakeLists.txt index 6b4fb70af..131e5f278 100644 --- a/sbndcode/Calorimetry/CMakeLists.txt +++ b/sbndcode/Calorimetry/CMakeLists.txt @@ -4,7 +4,6 @@ set (MODULE_LIBRARIES larsim::PhotonPropagation_PhotonVisibilityService_service larsim::LegacyLArG4 larcorealg::GeoAlgo - sbncode_OpT0Finder_flashmatch_Base larcorealg::Geometry larcore::Geometry_Geometry_service larsim::Simulation diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index 203346093..8e0bfede6 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -132,7 +132,7 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { std::string _simenergy_producer; bool _truth_neutrino; - std::unique_ptr _semi_model; + std::unique_ptr _semi_model; fhicl::ParameterSet _vuv_params; fhicl::ParameterSet _vis_params; @@ -184,7 +184,7 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) { _vuv_params = p.get("VUVHits"); _vis_params = p.get("VIVHits"); - _semi_model = std::make_unique(_vuv_params, _vis_params, true, false); + _semi_model = std::make_unique(_vuv_params, _vis_params, true, false); _opflash_producer_v = p.get>("OpFlashProducers"); _opflash_ara_producer_v = p.get>("OpFlashAraProducers"); diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index d8b21d512..b2b82e538 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -144,7 +144,7 @@ class sbnd::LightCaloProducer : public art::EDProducer { std::string _simenergy_producer; bool _truth_neutrino; - std::unique_ptr _semi_model; + std::unique_ptr _semi_model; fhicl::ParameterSet _vuv_params; fhicl::ParameterSet _vis_params; @@ -192,7 +192,7 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) { _vuv_params = p.get("VUVHits"); _vis_params = p.get("VIVHits"); - _semi_model = std::make_unique(_vuv_params, _vis_params, true, false); + _semi_model = std::make_unique(_vuv_params, _vis_params, true, false); _opflash_producer_v = p.get>("OpFlashProducers"); _opflash_ara_producer_v = p.get>("OpFlashAraProducers"); @@ -602,11 +602,11 @@ void sbnd::LightCaloProducer::produce(art::Event& e) } _slice_E = _energy.at(bestPlane); - sbn::LightCalo lightcalo(lightcalo_charge, lightcalo_light,lightcalo_energy, - lightcalo_plane,flash_time); + // sbn::LightCalo lightcalo(lightcalo_charge, lightcalo_light,lightcalo_energy, + // lightcalo_plane,flash_time); - lightcalo_v->push_back(lightcalo); - util::CreateAssn(*this, e, *lightcalo_v, slice, *slice_lightcalo_assn_v); + // lightcalo_v->push_back(lightcalo); + // util::CreateAssn(*this, e, *lightcalo_v, slice, *slice_lightcalo_assn_v); ::art::Handle> energyDeps_h; e.getByLabel(_simenergy_producer, energyDeps_h); From b791b51523f3b1c4bae77a2bacff29d1177b727d Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 16 May 2024 14:22:31 -0500 Subject: [PATCH 23/52] update opdet efficiencies and simulation values --- sbndcode/Calorimetry/lightcalo.fcl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index 450c591a4..aa8d0dcf6 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -28,9 +28,9 @@ lightcalo: # calibration constants & simulation parameters ## shouldn't have to change this unless you change simulation parameters CalAreaConstants: [ 0.0200906, 0.0200016, 0.0201293 ] # calibration constants for wire planes - OpDetDirectEff: [ 0.03, 0.03, 0.014, 0.021 ] # direct efficiencies [uncoated PMT, coated PMT, vis ara, vuv ara] - OpDetReflectEff: [ 0.03, 0.03, 0.014, 0.021 ] # reflected efficiencies - ScintPreScale: 0.03 # Scintillation Pre-Scale factor in simulation (set in ionandscint) + OpDetDirectEff: [ 0.152, 0.096, 0.01264, 0.01752 ] # direct efficiencies ... uncoated PMT, coated PMT, vis ara, vuv ara + OpDetReflectEff: [ 0.152, 0.104, 0.01264, 0.00271 ] # reflected efficiencies + ScintPreScale: 0.152 # Scintillation Pre-Scale factor in simulation (set in ionandscint) # parameters for truth validation TruthValidation: false # can only set to true if the reco2 files have SimEnergyDeposits From 543c337f3f98f352a61bb893c826c7acb96f36d0 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 16 May 2024 15:42:21 -0500 Subject: [PATCH 24/52] make working version of fcl without the analyzer --- sbndcode/Calorimetry/run_lightcalo.fcl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sbndcode/Calorimetry/run_lightcalo.fcl b/sbndcode/Calorimetry/run_lightcalo.fcl index 567cdbf30..3ffcee9e0 100644 --- a/sbndcode/Calorimetry/run_lightcalo.fcl +++ b/sbndcode/Calorimetry/run_lightcalo.fcl @@ -6,7 +6,7 @@ #include "backtrackerservice.fcl" #include "lightcalo.fcl" -#include "lightcalo_ana.fcl" +##include "lightcalo_ana.fcl" process_name: LightCaloProducer @@ -49,11 +49,11 @@ physics: } analyzers: { - lightcaloana: @local::lightcalo_ana + # lightcaloana: @local::lightcalo_ana } #define the producer and filter modules for this path, order matters, reco: [lightcalo] - ana: [lightcaloana] + # ana: [lightcaloana] # define the output stream, there could be more than one if using filters stream1: [out1] From 2fc9be1e487df7792fb9305196278d664e017c3a Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 16 May 2024 15:43:12 -0500 Subject: [PATCH 25/52] update noise/non-linearity thresholds --- sbndcode/Calorimetry/lightcalo.fcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index aa8d0dcf6..ccba9ab6a 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -23,7 +23,7 @@ lightcalo: SimpleOpFlashOffset: 0.2 # the offset between the t0 from SimpleFlash and OpFlashes PMTARAFlashOffset: 0.05 # the offset between the t0 of PMT OpFlashes and X-ARA OpFlashes FlashNoiseThreshold: 600. # for PMTS, flash total PE threshold to ignore a flash (below thresh = noise) - PMTPERange: [10,300] # the lower and upper PE thresholds to evaluate a flash. Below lower -> noise, above upper -> non-linearity + PMTPERange: [200,3000] # the lower and upper PE thresholds to evaluate a flash. Below lower -> noise, above upper -> non-linearity # calibration constants & simulation parameters ## shouldn't have to change this unless you change simulation parameters From 6b59f8e499eb5e68b3d9b85bc67a3c3077e198fc Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Wed, 12 Feb 2025 15:09:25 -0600 Subject: [PATCH 26/52] small cleanup --- sbndcode/Calorimetry/LightCaloProducer_module.cc | 14 +++++++++----- sbndcode/Calorimetry/lightcalo.fcl | 8 ++++---- sbndcode/Calorimetry/run_lightcalo.fcl | 8 ++------ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index b2b82e538..3b4bab102 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -327,11 +327,14 @@ void sbnd::LightCaloProducer::produce(art::Event& e) if(_truth_neutrino && !(abs(pfp->PdgCode()) == 12 || abs(pfp->PdgCode()) == 14|| abs(pfp->PdgCode()) == 16)) continue; // if primary, get nu-score - const std::vector> pfpmeta_v = pfp_to_meta.at(pfp->Self()); + const std::vector> pfpmeta_v = pfp_to_meta.at(pfp.key()); const art::Ptr pfpmeta = pfpmeta_v.front(); - larpandoraobj::PFParticleMetadata::PropertiesMap propmap = pfpmeta->GetPropertiesMap(); - if (propmap.count("NuScore")) nu_score = propmap.at("NuScore"); - else nu_score = -1; + std::map propmap = pfpmeta->GetPropertiesMap(); + auto propertiesMapIter = propmap.find("NuScore"); + if (propertiesMapIter == propmap.end()){ + nu_score = -1; + } + else{nu_score = propertiesMapIter->second;} // get fm-score std::vector> fm_v = pfp_to_sfm.at(pfp.key()); @@ -343,9 +346,10 @@ void sbnd::LightCaloProducer::produce(art::Event& e) for (size_t n_fm=0; n_fm < fm_v.size(); n_fm++){ auto fm = fm_v.at(n_fm); fm_score = fm->score.total; - if (nu_score > _nuscore_cut && fm_score < _fmscore_cut && fm_score > 0){ + if (nu_score >= _nuscore_cut && fm_score < _fmscore_cut && fm_score > 0){ found_fm = true; match_fm_v.push_back(fm); + if (_verbose) std::cout << "Nuscore: " << nu_score << ", FmScore: " << fm_score << std::endl; } } // end flashmatch loop if (found_fm ==true){ diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index ccba9ab6a..6f0a235d9 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -22,15 +22,15 @@ lightcalo: # flash parameters SimpleOpFlashOffset: 0.2 # the offset between the t0 from SimpleFlash and OpFlashes PMTARAFlashOffset: 0.05 # the offset between the t0 of PMT OpFlashes and X-ARA OpFlashes - FlashNoiseThreshold: 600. # for PMTS, flash total PE threshold to ignore a flash (below thresh = noise) + FlashNoiseThreshold: 600. # for PMTS, flash total PE threshold to ignore a flash (below thresh = noise), equivalent to 10 PE per PMT PMTPERange: [200,3000] # the lower and upper PE thresholds to evaluate a flash. Below lower -> noise, above upper -> non-linearity # calibration constants & simulation parameters ## shouldn't have to change this unless you change simulation parameters CalAreaConstants: [ 0.0200906, 0.0200016, 0.0201293 ] # calibration constants for wire planes - OpDetDirectEff: [ 0.152, 0.096, 0.01264, 0.01752 ] # direct efficiencies ... uncoated PMT, coated PMT, vis ara, vuv ara - OpDetReflectEff: [ 0.152, 0.104, 0.01264, 0.00271 ] # reflected efficiencies - ScintPreScale: 0.152 # Scintillation Pre-Scale factor in simulation (set in ionandscint) + OpDetDirectEff: [ 0.152, 0.096, 0.01264, 0.01752 ] # direct (VUV) efficiencies ... uncoated PMT, coated PMT, vis ara, vuv ara + OpDetReflectEff: [ 0.152, 0.104, 0.01264, 0.00271 ] # reflected (VIS) efficiencies + ScintPreScale: 0.152 # Scintillation Pre-Scale factor in simulation (set in ionandscint, should be equal to the maximum efficiency above) # parameters for truth validation TruthValidation: false # can only set to true if the reco2 files have SimEnergyDeposits diff --git a/sbndcode/Calorimetry/run_lightcalo.fcl b/sbndcode/Calorimetry/run_lightcalo.fcl index 3ffcee9e0..13e256158 100644 --- a/sbndcode/Calorimetry/run_lightcalo.fcl +++ b/sbndcode/Calorimetry/run_lightcalo.fcl @@ -3,7 +3,6 @@ #include "messages_sbnd.fcl" #include "sam_sbnd.fcl" #include "particleinventoryservice.fcl" -#include "backtrackerservice.fcl" #include "lightcalo.fcl" ##include "lightcalo_ana.fcl" @@ -18,7 +17,6 @@ services: FileCatalogMetadata: @local::sbnd_file_catalog_mc # from sam_sbnd.fcl @table::sbnd_services # from services_sbnd.fcl @table::sbnd_g4_services - BackTrackerService: @local::standard_backtrackerservice ParticleInventoryService: @local::standard_particleinventoryservice } @@ -34,7 +32,7 @@ outputs: out1: { module_type: RootOutput - fileName: "lightcalo-art.root" + # fileName: "lightcalo-art.root" dataTier: "reconstructed" compressionLevel:1 SelectEvents: ["reco"] @@ -65,6 +63,4 @@ physics: # end_paths is a keyword and contains the paths that do not modify the art::Event, # ie analyzers and output streams. these all run simultaneously end_paths: [stream1] -} - -services.BackTrackerService.BackTracker.SimChannelModuleLabel: "simdrift" \ No newline at end of file +} \ No newline at end of file From 30cf079c35b40950aa6501df6681983bcc9b41e7 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Mon, 28 Apr 2025 15:03:18 -0500 Subject: [PATCH 27/52] update geometry service to compile with v10_04_07 --- sbndcode/Calorimetry/LightCaloAna_module.cc | 9 +++++++-- sbndcode/Calorimetry/LightCaloProducer_module.cc | 11 ++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index 8e0bfede6..1683d02ce 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -49,6 +49,7 @@ #include "larcore/CoreUtils/ServiceUtil.h" #include "larcore/Geometry/Geometry.h" +#include "larcorealg/Geometry/GeometryCore.h" #include "larsim/PhotonPropagation/SemiAnalyticalModel.h" #include "larsim/Simulation/LArG4Parameters.h" #include "larsim/MCCheater/ParticleInventoryService.h" @@ -139,6 +140,8 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { opdet::sbndPDMapAlg _opdetmap; //map for photon detector types unsigned int _nchan = _opdetmap.size(); + geo::GeometryCore const* geom; + int _run, _subrun, _event; TTree* _tree; @@ -207,6 +210,8 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _simenergy_producer = p.get("SimEnergyProducer"); _truth_neutrino = p.get("TruthNeutrino"); + geom = lar::providerFrom(); + art::ServiceHandle fs; _tree = fs->make("slice_tree",""); _tree->Branch("run", &_run, "run/I"); @@ -252,7 +257,6 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) auto const det_prop = art::ServiceHandle()->DataFor(e, clock_data); - art::ServiceHandle geom; art::ServiceHandle g4param; art::ServiceHandle piserv; @@ -504,7 +508,8 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) const auto &position(sp->XYZ()); geo::Point_t xyz(position[0],position[1],position[2]); // correct for e- attenuation - double drift_time = ((2.0*geom->DetHalfWidth()) - abs(position[0]))/(det_prop.DriftVelocity()); // cm / (cm/us) + geo::TPCGeo const& tpcGeo = geom->TPC({0, 0}); + double drift_time = (2.0*tpcGeo.HalfWidth() - abs(position[0]))/(det_prop.DriftVelocity()); // cm / (cm/us) double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) double charge = (1/_cal_area_const.at(bestPlane))*atten_correction*hit->Integral(); sp_xyz.push_back(xyz); diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 3b4bab102..4591450df 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -46,6 +46,7 @@ #include "larcore/CoreUtils/ServiceUtil.h" #include "larcore/Geometry/Geometry.h" +#include "larcorealg/Geometry/GeometryCore.h" #include "larsim/PhotonPropagation/SemiAnalyticalModel.h" #include "larsim/Simulation/LArG4Parameters.h" #include "larsim/MCCheater/ParticleInventoryService.h" @@ -151,6 +152,8 @@ class sbnd::LightCaloProducer : public art::EDProducer { opdet::sbndPDMapAlg _opdetmap; //map for photon detector types unsigned int _nchan = _opdetmap.size(); + geo::GeometryCore const* geom; + TTree* _tree; int _run, _subrun, _event; int _match_type; @@ -218,6 +221,8 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) _simenergy_producer = p.get("SimEnergyProducer"); _truth_neutrino = p.get("TruthNeutrino"); + geom = lar::providerFrom(); + // Call appropriate produces<>() functions here. produces>(); produces>(); @@ -236,7 +241,6 @@ void sbnd::LightCaloProducer::produce(art::Event& e) auto const det_prop = art::ServiceHandle()->DataFor(e, clock_data); // std::cout<< "trigger offset TPC: " << clock_data.TriggerOffsetTPC() * 1.6 / 10 << std::endl; - art::ServiceHandle geom; art::ServiceHandle g4param; art::ServiceHandle piserv; @@ -519,8 +523,9 @@ void sbnd::LightCaloProducer::produce(art::Event& e) const auto &position(sp->XYZ()); geo::Point_t xyz(position[0],position[1],position[2]); // correct for e- attenuation - double drift_time = ((2.0*geom->DetHalfWidth()) - abs(position[0]))/(det_prop.DriftVelocity()); // cm / (cm/us) - double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) + geo::TPCGeo const& tpcGeo = geom->TPC({0, 0}); + double drift_time = (2.0*tpcGeo.HalfWidth() - abs(position[0]))/(det_prop.DriftVelocity()); // cm / (cm/us) + double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) double charge = (1/_cal_area_const.at(hit_plane))*atten_correction*hit->Integral(); sp_xyz.at(hit_plane).push_back(xyz); From 22c27ad74a388f237d2a1e76e68dfbf33f596106 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Mon, 28 Apr 2025 17:14:05 -0500 Subject: [PATCH 28/52] intermediate commit for first lines that include opt0finder (compiles) --- sbndcode/Calorimetry/LightCaloAna_module.cc | 95 ++++++++++++++++++--- sbndcode/Calorimetry/lightcalo_ana.fcl | 9 +- 2 files changed, 89 insertions(+), 15 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index 1683d02ce..12038ad74 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -58,6 +58,7 @@ // SBND includes #include "sbnobj/Common/Reco/SimpleFlashMatchVars.h" +#include "sbnobj/Common/Reco/OpT0FinderResult.h" #include "sbndcode/OpDetSim/sbndPDMapAlg.hh" // ROOT includes @@ -115,13 +116,20 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { std::vector _opflash_producer_v; std::vector _opflash_ara_producer_v; std::string _slice_producer; + std::string _opt0_producer; std::string _flashmatch_producer; bool _use_arapucas; float _nuscore_cut; float _fmscore_cut; + float _fopt0score_cut; bool _verbose; float _simple_op_offset; + + float _fopt0_flash_min; + float _fopt0_flash_max; + float _fopt0_frac_diff_cut; + float _pmt_ara_offset; std::vector _noise_thresh; @@ -192,13 +200,20 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _opflash_producer_v = p.get>("OpFlashProducers"); _opflash_ara_producer_v = p.get>("OpFlashAraProducers"); _slice_producer = p.get("SliceProducer"); + _opt0_producer = p.get("OpT0FinderProducer"); _flashmatch_producer = p.get("FlashMatchProducer"); _use_arapucas = p.get("UseArapucas"); _nuscore_cut = p.get("nuScoreCut"); _fmscore_cut = p.get("fmScoreCut"); + _fopt0score_cut = p.get("opt0ScoreCut"); _verbose = p.get("Verbose"); _simple_op_offset= p.get("SimpleOpFlashOffset"); + + _fopt0_flash_min = p.get("OpT0FlashMin"); + _fopt0_flash_max = p.get("OpT0FlashMax"); + _fopt0_frac_diff_cut = p.get("OpT0FractionalCut"); + _pmt_ara_offset = p.get("PMTARAFlashOffset"); _noise_thresh = p.get>("FlashNoiseThreshold"); @@ -287,6 +302,15 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) return; } + ::art::Handle> opt0_h; + e.getByLabel(_opt0_producer, opt0_h); + if(!opt0_h.isValid() || opt0_h->empty()) { + std::cout << "don't have good OpT0Finder matches!" << std::endl; + return; + } + std::vector> opt0_v; + art::fill_ptr_vector(opt0_v, opt0_h); + auto const & flash0_h = e.getValidHandle>(_opflash_producer_v[0]); auto const & flash1_h = e.getValidHandle>(_opflash_producer_v[1]); if (!_use_arapucas && _verbose) @@ -301,11 +325,66 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) // if ( (!energyDeps.isValid() || energyDeps->empty()) && _truth_validation){ // } + std::vector> match_slices_v; + std::vector> match_fm_v; + + // tpc0 + std::vector> flash0_v; + art::fill_ptr_vector(flash0_v, flash0_h); + std::vector> match_op0; + + // tpc1 + std::vector> flash1_v; + art::fill_ptr_vector(flash1_v, flash1_h); + std::vector> match_op1; + + + // * START OPT0FINDER + std::map, std::vector>> match_slice_opflash_map; + art::FindManyP opt0_to_slice(opt0_h, e, _opt0_producer); + art::FindManyP opt0_to_flash(opt0_h, e, _opt0_producer); + + for (size_t n_opt0=0; n_opt0 < opt0_v.size(); n_opt0++){ + auto opt0 = opt0_v[n_opt0]; + std::vector> slice_v = opt0_to_slice.at(opt0.key()); + std::vector> flash_v = opt0_to_flash.at(opt0.key()); + + assert(slice_v.size() == 1); + assert(flash_v.size() == 1); + + auto slice = slice_v.front(); + auto flash = flash_v.front(); + + auto opt0_score = opt0->score; + auto opt0_time = opt0->time; + auto opt0_measPE = opt0->measPE; + auto opt0_hypoPE = opt0->hypoPE; + + auto opt0_frac_diff = std::abs((opt0_hypoPE - opt0_measPE)/opt0_measPE); + + if (opt0_time < _fopt0_flash_min || opt0_time > _fopt0_flash_max) continue; + if (opt0_score < _fopt0score_cut) continue; + if (opt0_frac_diff > _fopt0_frac_diff_cut) continue; + + // check that slice is not already in the map + auto it = match_slice_opflash_map.find(slice); + if (it == match_slice_opflash_map.end()){ + std::vector> flash_v; + flash_v.push_back(flash); + match_slice_opflash_map.insert(std::pair, std::vector>>(slice, flash_v)); + } + else{ + it->second.push_back(flash); + } + } + + // * END OPT0FINDER + + // * START SLICE & SimpleFlash // Construct the vector of Slices std::vector> slice_v; art::fill_ptr_vector(slice_v, slice_h); - // Get associations art::FindManyP slice_to_pfp (slice_h, e, _slice_producer); art::FindManyP slice_to_hit (slice_h, e, _slice_producer); art::FindManyP pfp_to_meta(pfp_h, e, _slice_producer); @@ -313,9 +392,6 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) art::FindManyP pfp_to_spacepoint(pfp_h, e, _slice_producer); art::FindManyP spacepoint_to_hit(spacepoint_h, e, _slice_producer); - std::vector> match_slices_v; - std::vector> match_fm_v; - for (size_t n_slice=0; n_slice < slice_v.size(); n_slice++){ float nu_score = -9999; float fm_score = -9999; @@ -369,12 +445,7 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) } // get relevant opflashes - // tpc0 - std::vector> flash0_v; - art::fill_ptr_vector(flash0_v, flash0_h); - std::vector> match_op0; bool found_opflash0 = MatchOpFlash(match_fm_v,flash0_v, match_op0); - std::vector> flash0_ara_v; // if using arapucas if (_use_arapucas){ @@ -388,12 +459,7 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) else art::fill_ptr_vector(flash0_ara_v, flash0_ara_h); } - // tpc1 - std::vector> flash1_v; - art::fill_ptr_vector(flash1_v, flash1_h); - std::vector> match_op1; bool found_opflash1 = MatchOpFlash(match_fm_v,flash1_v, match_op1); - std::vector> flash1_ara_v; if (_use_arapucas){ ::art::Handle> flash1_ara_h; @@ -412,6 +478,7 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) _tree->Fill(); return; } + // * END SLICE & SimpleFlash int nsuccessful_matches=0; for (size_t n_slice=0; n_slice < match_slices_v.size(); n_slice++){ diff --git a/sbndcode/Calorimetry/lightcalo_ana.fcl b/sbndcode/Calorimetry/lightcalo_ana.fcl index 5a43f94f7..7dfc73f15 100644 --- a/sbndcode/Calorimetry/lightcalo_ana.fcl +++ b/sbndcode/Calorimetry/lightcalo_ana.fcl @@ -15,10 +15,17 @@ lightcaloana: UseArapucas: false nuScoreCut: 0.4 # default: accept nusScore > 0.4, to analyze all slices, set nuScoreCut = -1 fmScoreCut: 7 # default: accept 0 < fm score < fmScoreCut, to analyze all slices, set fmScoreCut = 1e3 + opt0ScoreCut: 200 # default: accept opt0 match > opt0ScoreCut + Verbose: false - # flash parameters SimpleOpFlashOffset: 0.2 # the offset between the t0 from SimpleFlash and OpFlashes + + OpT0FlashMin: 0.0 # simulation [0.0], light-triggered data [-0.8] + OpT0FlashMax: 2.0 # simulation [2.0], light-triggered data [2.0] + OpT0FractionalCut: 0.5 + + # flash parameters PMTARAFlashOffset: 0.05 # the offset between the t0 of PMT OpFlashes and X-ARA OpFlashes FlashNoiseThreshold: [ 600., 1500. ] # {PMT, xARAPUCA}, flash total PE threshold to ignore a flash From 82222e30f694278f127f30021fea514c1c6d0154 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Tue, 29 Apr 2025 11:33:46 -0500 Subject: [PATCH 29/52] update efficiency, visibility configs, and add channel mask - all opdets may have non-zero direct/reflected visibility and different efficiencies - add option to mask specific channels --- sbndcode/Calorimetry/LightCaloAna_module.cc | 82 ++++++++++++--------- sbndcode/Calorimetry/lightcalo_ana.fcl | 7 +- 2 files changed, 51 insertions(+), 38 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index 12038ad74..ae4625e8f 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -38,7 +38,6 @@ #include "lardataobj/RecoBase/Hit.h" #include "lardataobj/RecoBase/Wire.h" #include "lardataobj/RecoBase/OpFlash.h" -#include "lardataobj/AnalysisBase/T0.h" #include "lardataobj/Simulation/SimPhotons.h" #include "lardataobj/Simulation/SimEnergyDeposit.h" @@ -98,12 +97,13 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { std::vector> &match_v); // Returns visibility vector for all opdets given charge/position information - std::vector CalcVisibility(std::vector xyz_v, - std::vector charge_v); + std::vector> CalcVisibility(std::vector xyz_v, + std::vector charge_v); // Fills reconstructed photon count vector (total_gamma_v) for all opdets given charge/position information void CalcLight(std::vector flash_pe_v, - std::vector visibility, + std::vector dir_visibility, + std::vector ref_visibility, std::vector &total_gamma_v); // Returns the median of the light vector @@ -134,7 +134,9 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { std::vector _noise_thresh; std::vector _cal_area_const; - std::vector _opdet_eff; + std::vector _opdet_vuv_eff; + std::vector _opdet_vis_eff; + std::vector _opdet_mask; float _scint_prescale; bool _truth_validation; @@ -218,7 +220,9 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _noise_thresh = p.get>("FlashNoiseThreshold"); _cal_area_const = p.get>("CalAreaConstants"); - _opdet_eff = p.get>("OpDetEfficiencies"); + _opdet_vuv_eff = p.get>("OpDetVUVEfficiencies"); + _opdet_vis_eff = p.get>("OpDetVISEfficiencies"); + _opdet_mask = p.get>("OpDetMask"); _scint_prescale = p.get("ScintPreScale"); _truth_validation = p.get("TruthValidation"); @@ -588,7 +592,10 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) } // end pfp loop // get total L count - std::vector visibility_map = CalcVisibility(sp_xyz,sp_charge); + std::vector> visibility_maps = CalcVisibility(sp_xyz,sp_charge); + auto dir_visibility_map = visibility_maps[0]; + auto ref_visibility_map = visibility_maps[1]; + std::vector total_pe(_nchan,0.); std::vector total_gamma(_nchan, 0.); @@ -617,8 +624,13 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) } } // end of TPC loop + // mask out specific channels in opdet mask + for (size_t imask=0; imask<_opdet_mask.size(); imask++){ + total_pe.at(_opdet_mask.at(imask)) = 0; + } + // calculate the photon estimates for every entry in total_pe - CalcLight(total_pe, visibility_map, total_gamma); + CalcLight(total_pe, dir_visibility_map, ref_visibility_map, total_gamma); // fill tree variables _opflash_time = flash_time; @@ -724,12 +736,13 @@ bool sbnd::LightCaloAna::MatchOpFlash(std::vector sbnd::LightCaloAna::CalcVisibility(std::vector xyz_v, - std::vector charge_v){ - // returns of a vector (len is # of opdet) for the visibility for every opdet +std::vector> sbnd::LightCaloAna::CalcVisibility(std::vector xyz_v, + std::vector charge_v){ + // returns of two vectors (len is # of opdet) for the visibility for every opdet if (xyz_v.size() != charge_v.size()) std::cout << "spacepoint coord and charge vector size mismatch" << std::endl; - std::vector visibility(_nchan, 0); + std::vector dir_visibility_map(_nchan, 0); + std::vector ref_visibility_map(_nchan, 0); double sum_charge0 = 0; double sum_charge1 = 0; @@ -744,43 +757,40 @@ std::vector sbnd::LightCaloAna::CalcVisibility(std::vector std::vector reflect_visibility; _semi_model->detectedDirectVisibilities(direct_visibility, xyz); _semi_model->detectedReflectedVisibilities(reflect_visibility, xyz); - if (visibility.size() != direct_visibility.size()) std::cout << "mismatch of visibility vector size" << std::endl; + // if (dir_visibility_map.size() != direct_visibility.size()) std::cout << "mismatch of visibility vector size" << std::endl; // weight by charge for (size_t ch=0; ch flash_pe_v, - std::vector visibility, + std::vector dir_visibility, + std::vector ref_visibility, std::vector &total_gamma_v){ for (size_t ch = 0; ch < flash_pe_v.size(); ch++){ auto pe = flash_pe_v[ch]; - double efficiency = 0.03; - if((pe == 0) || std::isinf(1/visibility[ch])) + auto vuv_eff = _opdet_vuv_eff.at(ch); + auto vis_eff = _opdet_vis_eff.at(ch); + auto visibility = 1/(vuv_eff*dir_visibility[ch] + vis_eff*ref_visibility[ch]); + if((pe == 0) || std::isinf(1/visibility)) continue; - if (_opdetmap.isPDType(ch, "pmt_uncoated")) - efficiency = _opdet_eff[0]; - else if (_opdetmap.isPDType(ch, "pmt_coated")) - efficiency = _opdet_eff[1]; - else if (_opdetmap.isPDType(ch, "xarapuca_vis")) - efficiency = _opdet_eff[2]; - else if (_opdetmap.isPDType(ch, "xarapuca_vuv")) - efficiency = _opdet_eff[3]; - // deposited light is inverse of efficiency * inverse of visibility * PE count - total_gamma_v[ch] += (1/efficiency)*(1/visibility[ch])*pe; + // deposited light is inverse of visibility * PE count + total_gamma_v[ch] += (1/visibility)*pe; } } diff --git a/sbndcode/Calorimetry/lightcalo_ana.fcl b/sbndcode/Calorimetry/lightcalo_ana.fcl index 7dfc73f15..e834353e9 100644 --- a/sbndcode/Calorimetry/lightcalo_ana.fcl +++ b/sbndcode/Calorimetry/lightcalo_ana.fcl @@ -31,8 +31,11 @@ lightcaloana: # calibration constants & simulation parameters ## shouldn't have to change this unless you change simulation parameters - CalAreaConstants: [ 0.0200906, 0.0200016, 0.0201293 ] # calibration constants for wire planes - OpDetEfficiencies: [ 0.03, 0.03, 0.014, 0.021 ] # efficiencies [uncoated PMT, coated PMT, vis ara, vuv ara] + CalAreaConstants: [ 0.0200906, 0.0200016, 0.0201293 ] # calibration constants for wire planes + OpDetVUVEfficiencies: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021]; + OpDetVISEfficiencies: [0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]; + OpDetMask : [39, 66, 67, 71, 85, 86, 87, 92, 115, 138, 141, 170, 197, 217, 218, 221, 222, 223, 226, 245, 248, 249, 302] + ScintPreScale: 0.03 # Scintillation Pre-Scale factor in simulation (set in ionandscint) # parameters for truth validation From 6ad380a9bb6f69682fd895105b4cc4a9d9b37c10 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Tue, 29 Apr 2025 12:16:51 -0500 Subject: [PATCH 30/52] add fcl config to choose between flash matchers - finish separating opt0finder and simpleflash blocks --- sbndcode/Calorimetry/LightCaloAna_module.cc | 311 +++++++++++--------- sbndcode/Calorimetry/lightcalo_ana.fcl | 1 + 2 files changed, 166 insertions(+), 146 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index ae4625e8f..aa7be901b 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -119,6 +119,7 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { std::string _opt0_producer; std::string _flashmatch_producer; bool _use_arapucas; + bool _use_opt0; float _nuscore_cut; float _fmscore_cut; float _fopt0score_cut; @@ -205,6 +206,7 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _opt0_producer = p.get("OpT0FinderProducer"); _flashmatch_producer = p.get("FlashMatchProducer"); _use_arapucas = p.get("UseArapucas"); + _use_opt0 = p.get("UseOpT0Finder"); _nuscore_cut = p.get("nuScoreCut"); _fmscore_cut = p.get("fmScoreCut"); _fopt0score_cut = p.get("opt0ScoreCut"); @@ -275,7 +277,6 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) auto const clock_data = art::ServiceHandle()->DataFor(e); auto const det_prop = art::ServiceHandle()->DataFor(e, clock_data); - art::ServiceHandle g4param; art::ServiceHandle piserv; @@ -306,15 +307,6 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) return; } - ::art::Handle> opt0_h; - e.getByLabel(_opt0_producer, opt0_h); - if(!opt0_h.isValid() || opt0_h->empty()) { - std::cout << "don't have good OpT0Finder matches!" << std::endl; - return; - } - std::vector> opt0_v; - art::fill_ptr_vector(opt0_v, opt0_h); - auto const & flash0_h = e.getValidHandle>(_opflash_producer_v[0]); auto const & flash1_h = e.getValidHandle>(_opflash_producer_v[1]); if (!_use_arapucas && _verbose) @@ -324,165 +316,192 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) return; } - // const art::ValidHandle>& - // energyDeps(e.getValidHandle>(_simenergy_producer)); - // if ( (!energyDeps.isValid() || energyDeps->empty()) && _truth_validation){ - // } + art::FindManyP slice_to_pfp (slice_h, e, _slice_producer); + art::FindManyP slice_to_hit (slice_h, e, _slice_producer); + art::FindManyP pfp_to_spacepoint(pfp_h, e, _slice_producer); + art::FindManyP spacepoint_to_hit(spacepoint_h, e, _slice_producer); std::vector> match_slices_v; - std::vector> match_fm_v; - - // tpc0 - std::vector> flash0_v; - art::fill_ptr_vector(flash0_v, flash0_h); std::vector> match_op0; - - // tpc1 - std::vector> flash1_v; - art::fill_ptr_vector(flash1_v, flash1_h); std::vector> match_op1; - - // * START OPT0FINDER - std::map, std::vector>> match_slice_opflash_map; - art::FindManyP opt0_to_slice(opt0_h, e, _opt0_producer); - art::FindManyP opt0_to_flash(opt0_h, e, _opt0_producer); - - for (size_t n_opt0=0; n_opt0 < opt0_v.size(); n_opt0++){ - auto opt0 = opt0_v[n_opt0]; - std::vector> slice_v = opt0_to_slice.at(opt0.key()); - std::vector> flash_v = opt0_to_flash.at(opt0.key()); - - assert(slice_v.size() == 1); - assert(flash_v.size() == 1); - - auto slice = slice_v.front(); - auto flash = flash_v.front(); - - auto opt0_score = opt0->score; - auto opt0_time = opt0->time; - auto opt0_measPE = opt0->measPE; - auto opt0_hypoPE = opt0->hypoPE; - - auto opt0_frac_diff = std::abs((opt0_hypoPE - opt0_measPE)/opt0_measPE); - - if (opt0_time < _fopt0_flash_min || opt0_time > _fopt0_flash_max) continue; - if (opt0_score < _fopt0score_cut) continue; - if (opt0_frac_diff > _fopt0_frac_diff_cut) continue; - - // check that slice is not already in the map - auto it = match_slice_opflash_map.find(slice); - if (it == match_slice_opflash_map.end()){ - std::vector> flash_v; - flash_v.push_back(flash); - match_slice_opflash_map.insert(std::pair, std::vector>>(slice, flash_v)); - } - else{ - it->second.push_back(flash); + if (_use_opt0){ + ::art::Handle> opt0_h; + e.getByLabel(_opt0_producer, opt0_h); + if(!opt0_h.isValid() || opt0_h->empty()) { + std::cout << "don't have good OpT0Finder matches!" << std::endl; + return; } - } - - // * END OPT0FINDER + std::vector> opt0_v; + art::fill_ptr_vector(opt0_v, opt0_h); - // * START SLICE & SimpleFlash - // Construct the vector of Slices - std::vector> slice_v; - art::fill_ptr_vector(slice_v, slice_h); + std::map, std::vector>> match_slice_opflash_map; + art::FindManyP opt0_to_slice(opt0_h, e, _opt0_producer); + art::FindManyP opt0_to_flash(opt0_h, e, _opt0_producer); - art::FindManyP slice_to_pfp (slice_h, e, _slice_producer); - art::FindManyP slice_to_hit (slice_h, e, _slice_producer); - art::FindManyP pfp_to_meta(pfp_h, e, _slice_producer); - art::FindManyP pfp_to_sfm (pfp_h, e, _flashmatch_producer); - art::FindManyP pfp_to_spacepoint(pfp_h, e, _slice_producer); - art::FindManyP spacepoint_to_hit(spacepoint_h, e, _slice_producer); - - for (size_t n_slice=0; n_slice < slice_v.size(); n_slice++){ - float nu_score = -9999; - float fm_score = -9999; - auto slice = slice_v[n_slice]; - bool found_fm = false; - std::vector> pfp_v = slice_to_pfp.at(n_slice); - for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ - auto pfp = pfp_v[n_pfp]; + for (size_t n_opt0=0; n_opt0 < opt0_v.size(); n_opt0++){ + auto opt0 = opt0_v[n_opt0]; + std::vector> slice_v = opt0_to_slice.at(opt0.key()); + std::vector> flash_v = opt0_to_flash.at(opt0.key()); + + assert(slice_v.size() == 1); + assert(flash_v.size() == 1); + + auto slice = slice_v.front(); + auto flash = flash_v.front(); + + auto opt0_score = opt0->score; + auto opt0_time = opt0->time; + auto opt0_measPE = opt0->measPE; + auto opt0_hypoPE = opt0->hypoPE; + auto opt0_frac_diff = std::abs((opt0_hypoPE - opt0_measPE)/opt0_measPE); + + if (opt0_time < _fopt0_flash_min || opt0_time > _fopt0_flash_max) continue; + if (opt0_score < _fopt0score_cut) continue; + if (opt0_frac_diff > _fopt0_frac_diff_cut) continue; + + // check that slice is not already in the map + auto it = match_slice_opflash_map.find(slice); + if (it == match_slice_opflash_map.end()){ + std::vector> flash_v; + flash_v.push_back(flash); + match_slice_opflash_map.insert(std::pair, std::vector>>(slice, flash_v)); + } + else{ + it->second.push_back(flash); + } + } - // only select the PRIMARY pfp - if(!pfp->IsPrimary()) - continue; - if(_truth_neutrino && !(abs(pfp->PdgCode()) == 12 || abs(pfp->PdgCode()) == 14|| abs(pfp->PdgCode()) == 16)) + for (auto it = match_slice_opflash_map.begin(); it != match_slice_opflash_map.end(); ++it){ + auto slice = it->first; + auto flash_v = it->second; + if (flash_v.size() > 2){ + std::cout << "more than one opflash matched to this slice!" << std::endl; continue; - // if primary, get nu-score - const std::vector> pfpmeta_v = pfp_to_meta.at(pfp->Self()); - const art::Ptr pfpmeta = pfpmeta_v.front(); - larpandoraobj::PFParticleMetadata::PropertiesMap propmap = pfpmeta->GetPropertiesMap(); - if (propmap.count("NuScore")) nu_score = propmap.at("NuScore"); - else nu_score = -1; - - // get fm-score - std::vector> fm_v = pfp_to_sfm.at(pfp.key()); - if (fm_v.empty()){ - std::cout << "No SimpleFlashMatch objects associated with this PFP!" << std::endl; + } + bool found_opflash0 = false; + bool found_opflash1 = false; + + for (size_t n_flash=0; n_flash < flash_v.size(); n_flash++){ + auto flash = flash_v[n_flash]; + if (flash->XCenter() > 0){ + found_opflash1 = true; + match_op1.push_back(flash); + } + else if (flash->XCenter() < 0){ + found_opflash0 = true; + match_op0.push_back(flash); + } + } // end opflash loop + if (found_opflash0 == false && found_opflash1 == false){ + std::cout << "no opflashes matched to this slice" << std::endl; continue; } - if (fm_v.size() > 1) - std::cout << "more than one match for one pfp?" << std::endl; - for (size_t n_fm=0; n_fm < fm_v.size(); n_fm++){ - auto fm = fm_v.at(n_fm); - fm_score = fm->score.total; - if (nu_score > _nuscore_cut && fm_score < _fmscore_cut && fm_score > 0){ - found_fm = true; - match_fm_v.push_back(fm); + else if (found_opflash0 || found_opflash1){ + match_slices_v.push_back(slice); + art::Ptr nullOpFlash; + if (found_opflash0==false) { + match_op0.push_back(nullOpFlash); + } + else if (found_opflash1==false){ + match_op1.push_back(nullOpFlash); } - } // end flashmatch loop - if (found_fm ==true) match_slices_v.push_back(slice); - } // end pfp loop - } // end slice loop - if (match_slices_v.empty() && !slice_v.empty()){ - std::cout << "no slices passed the cuts" << std::endl; - _match_type = -1; - _tree->Fill(); - return; - } - if (match_slices_v.size() != match_fm_v.size()){ - std::cout << "slice and flashmatch vector length mismatch!" << std::endl; - return; + } + } // end opt0finder loop } + else { // using SimpleFlash + std::vector> slice_v; + art::fill_ptr_vector(slice_v, slice_h); + + art::FindManyP pfp_to_meta(pfp_h, e, _slice_producer); + art::FindManyP pfp_to_sfm (pfp_h, e, _flashmatch_producer); + + std::vector> match_fm_v; + std::vector> flash0_v; + art::fill_ptr_vector(flash0_v, flash0_h); + std::vector> flash1_v; + art::fill_ptr_vector(flash1_v, flash1_h); + + for (size_t n_slice=0; n_slice < slice_v.size(); n_slice++){ + float nu_score = -9999; + float fm_score = -9999; + auto slice = slice_v[n_slice]; + bool found_fm = false; + std::vector> pfp_v = slice_to_pfp.at(n_slice); + for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ + auto pfp = pfp_v[n_pfp]; + + // only select the PRIMARY pfp + if(!pfp->IsPrimary()) + continue; + if(_truth_neutrino && !(abs(pfp->PdgCode()) == 12 || abs(pfp->PdgCode()) == 14|| abs(pfp->PdgCode()) == 16)) + continue; + // if primary, get nu-score + const std::vector> pfpmeta_v = pfp_to_meta.at(pfp->Self()); + const art::Ptr pfpmeta = pfpmeta_v.front(); + larpandoraobj::PFParticleMetadata::PropertiesMap propmap = pfpmeta->GetPropertiesMap(); + if (propmap.count("NuScore")) nu_score = propmap.at("NuScore"); + else nu_score = -1; + + // get fm-score + std::vector> fm_v = pfp_to_sfm.at(pfp.key()); + if (fm_v.empty()){ + std::cout << "No SimpleFlashMatch objects associated with this PFP!" << std::endl; + continue; + } + if (fm_v.size() > 1) + std::cout << "more than one match for one pfp?" << std::endl; + for (size_t n_fm=0; n_fm < fm_v.size(); n_fm++){ + auto fm = fm_v.at(n_fm); + fm_score = fm->score.total; + if (nu_score > _nuscore_cut && fm_score < _fmscore_cut && fm_score > 0){ + found_fm = true; + match_fm_v.push_back(fm); + } + } // end flashmatch loop + if (found_fm ==true) match_slices_v.push_back(slice); + } // end pfp loop + } // end slice loop + if (match_slices_v.empty() && !slice_v.empty()){ + std::cout << "no slices passed the cuts" << std::endl; + _match_type = -1; + _tree->Fill(); + return; + } - // get relevant opflashes - bool found_opflash0 = MatchOpFlash(match_fm_v,flash0_v, match_op0); - std::vector> flash0_ara_v; - // if using arapucas - if (_use_arapucas){ - ::art::Handle> flash0_ara_h; - e.getByLabel(_opflash_ara_producer_v[0],flash0_ara_h); - if (_verbose) std::cout << "Using PMT OpFlash + X-ARAPUCA OpFlash..." << std::endl; - if (!flash0_ara_h.isValid() || flash0_ara_h->empty()) { - std::cout << "don't have good X-ARAPUCA flashes from producer " << _opflash_ara_producer_v[0] << std::endl; - // return; + if (match_slices_v.size() != match_fm_v.size()){ + std::cout << "slice and flashmatch vector length mismatch!" << std::endl; + return; + } + + // get relevant opflashes + bool found_opflash0 = MatchOpFlash(match_fm_v,flash0_v, match_op0); + bool found_opflash1 = MatchOpFlash(match_fm_v,flash1_v, match_op1); + + if (found_opflash0 == false && found_opflash1 == false){ + std::cout << "no opflashes matched to simpleflashes" << std::endl; + _match_type = -2; + _tree->Fill(); + return; } - else - art::fill_ptr_vector(flash0_ara_v, flash0_ara_h); } - bool found_opflash1 = MatchOpFlash(match_fm_v,flash1_v, match_op1); + + std::vector> flash0_ara_v; std::vector> flash1_ara_v; if (_use_arapucas){ + ::art::Handle> flash0_ara_h; ::art::Handle> flash1_ara_h; - e.getByLabel(_opflash_ara_producer_v[1],flash1_ara_h); - if (_verbose) std::cout << "Using PMT OpFlash + X-ARAPUCA OpFlash..." << std::endl; - if (!flash1_ara_h.isValid() || flash1_ara_h->empty()) { - std::cout << "don't have good X-ARAPUCA flashes from producer " << _opflash_ara_producer_v[1] << std::endl; - // return; + + for (size_t i=0; i<2; i++){ + ::art::Handle> flash_ara_h; + e.getByLabel(_opflash_ara_producer_v[i], flash_ara_h); + if (!flash_ara_h.isValid() || flash_ara_h->empty()) { + std::cout << "don't have good X-ARAPUCA flashes from producer " << _opflash_ara_producer_v[i] << std::endl; + } + else art::fill_ptr_vector((i==0)? flash0_ara_v : flash1_ara_v, flash_ara_h); } - else - art::fill_ptr_vector(flash1_ara_v, flash1_ara_h); - } - if (found_opflash0 == false && found_opflash1 == false){ - std::cout << "no opflashes matched to simpleflashes" << std::endl; - _match_type = -2; - _tree->Fill(); - return; } - // * END SLICE & SimpleFlash int nsuccessful_matches=0; for (size_t n_slice=0; n_slice < match_slices_v.size(); n_slice++){ diff --git a/sbndcode/Calorimetry/lightcalo_ana.fcl b/sbndcode/Calorimetry/lightcalo_ana.fcl index e834353e9..87de48ac1 100644 --- a/sbndcode/Calorimetry/lightcalo_ana.fcl +++ b/sbndcode/Calorimetry/lightcalo_ana.fcl @@ -13,6 +13,7 @@ lightcaloana: SliceProducer: "pandora" FlashMatchProducer: "fmatch" UseArapucas: false + UseOpT0Finder: true nuScoreCut: 0.4 # default: accept nusScore > 0.4, to analyze all slices, set nuScoreCut = -1 fmScoreCut: 7 # default: accept 0 < fm score < fmScoreCut, to analyze all slices, set fmScoreCut = 1e3 opt0ScoreCut: 200 # default: accept opt0 match > opt0ScoreCut From c1dd6705573d5705bb7d67ffe7c79b94a41a7db9 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Tue, 29 Apr 2025 16:47:44 -0500 Subject: [PATCH 31/52] fix bug with visibility/efficiency --- sbndcode/Calorimetry/LightCaloAna_module.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index aa7be901b..42343ed60 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -805,11 +805,11 @@ void sbnd::LightCaloAna::CalcLight(std::vector flash_pe_v, auto pe = flash_pe_v[ch]; auto vuv_eff = _opdet_vuv_eff.at(ch); auto vis_eff = _opdet_vis_eff.at(ch); - auto visibility = 1/(vuv_eff*dir_visibility[ch] + vis_eff*ref_visibility[ch]); - if((pe == 0) || std::isinf(1/visibility)) + auto tot_visibility = vuv_eff*dir_visibility[ch] + vis_eff*ref_visibility[ch]; + if((pe == 0) || std::isinf(1/tot_visibility)) continue; // deposited light is inverse of visibility * PE count - total_gamma_v[ch] += (1/visibility)*pe; + total_gamma_v[ch] += (1/tot_visibility)*pe; } } From dd103101b2c81536ca5c1d2c7238c7b53f1d0a5f Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Tue, 29 Apr 2025 16:48:06 -0500 Subject: [PATCH 32/52] fcl syntax fix, adding `OpT0FinderProducer` value to fcl --- sbndcode/Calorimetry/lightcalo_ana.fcl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sbndcode/Calorimetry/lightcalo_ana.fcl b/sbndcode/Calorimetry/lightcalo_ana.fcl index 87de48ac1..4924945be 100644 --- a/sbndcode/Calorimetry/lightcalo_ana.fcl +++ b/sbndcode/Calorimetry/lightcalo_ana.fcl @@ -12,6 +12,7 @@ lightcaloana: OpFlashAraProducers: ["opflashtpc0xarapuca", "opflashtpc1xarapuca"] SliceProducer: "pandora" FlashMatchProducer: "fmatch" + OpT0FinderProducer: "opt0finder" UseArapucas: false UseOpT0Finder: true nuScoreCut: 0.4 # default: accept nusScore > 0.4, to analyze all slices, set nuScoreCut = -1 @@ -33,8 +34,8 @@ lightcaloana: # calibration constants & simulation parameters ## shouldn't have to change this unless you change simulation parameters CalAreaConstants: [ 0.0200906, 0.0200016, 0.0201293 ] # calibration constants for wire planes - OpDetVUVEfficiencies: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021]; - OpDetVISEfficiencies: [0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]; + OpDetVUVEfficiencies: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021] + OpDetVISEfficiencies: [0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] OpDetMask : [39, 66, 67, 71, 85, 86, 87, 92, 115, 138, 141, 170, 197, 217, 218, 221, 222, 223, 226, 245, 248, 249, 302] ScintPreScale: 0.03 # Scintillation Pre-Scale factor in simulation (set in ionandscint) From c8561f821050d3da55fd6f39470a0723deb6404a Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Tue, 29 Apr 2025 16:49:19 -0500 Subject: [PATCH 33/52] add simple analyzer to scrape mc sim energy depo information after g4 stage --- sbndcode/Calorimetry/CMakeLists.txt | 1 + sbndcode/Calorimetry/MCCaloAna_module.cc | 137 +++++++++++++++++++++++ sbndcode/Calorimetry/run_mcana.fcl | 46 ++++++++ 3 files changed, 184 insertions(+) create mode 100644 sbndcode/Calorimetry/MCCaloAna_module.cc create mode 100644 sbndcode/Calorimetry/run_mcana.fcl diff --git a/sbndcode/Calorimetry/CMakeLists.txt b/sbndcode/Calorimetry/CMakeLists.txt index 131e5f278..b4c264484 100644 --- a/sbndcode/Calorimetry/CMakeLists.txt +++ b/sbndcode/Calorimetry/CMakeLists.txt @@ -37,6 +37,7 @@ set (MODULE_LIBRARIES ) cet_build_plugin(LightCaloAna art::module SOURCE LightCaloAna_module.cc LIBRARIES ${MODULE_LIBRARIES}) cet_build_plugin(LightCaloProducer art::module SOURCE LightCaloProducer_module.cc LIBRARIES ${MODULE_LIBRARIES}) +cet_build_plugin(MCCaloAna art::module SOURCE MCCaloAna_module.cc LIBRARIES ${MODULE_LIBRARIES}) install_headers() install_fhicl() diff --git a/sbndcode/Calorimetry/MCCaloAna_module.cc b/sbndcode/Calorimetry/MCCaloAna_module.cc new file mode 100644 index 000000000..f16c755a8 --- /dev/null +++ b/sbndcode/Calorimetry/MCCaloAna_module.cc @@ -0,0 +1,137 @@ +//////////////////////////////////////////////////////////////////////// +// Class: MCCaloAna +// Plugin Type: analyzer (Unknown Unknown) +// File: MCCaloAna_module.cc +// +// Generated at Tue Apr 29 12:33:40 2025 by Lynn Tung using cetskelgen +// from cetlib version 3.18.02. +//////////////////////////////////////////////////////////////////////// + +#include "art/Framework/Core/EDAnalyzer.h" +#include "art/Framework/Core/ModuleMacros.h" +#include "art/Framework/Principal/Event.h" +#include "art/Framework/Principal/Handle.h" +#include "art/Framework/Principal/Run.h" +#include "art/Framework/Principal/SubRun.h" +#include "canvas/Utilities/InputTag.h" +#include "fhiclcpp/ParameterSet.h" +#include "messagefacility/MessageLogger/MessageLogger.h" + +#include "larsim/MCCheater/ParticleInventoryService.h" +#include "lardataobj/Simulation/SimEnergyDeposit.h" +#include "nusimdata/SimulationBase/MCTruth.h" + +#include "art_root_io/TFileService.h" +#include "TFile.h" +#include "TTree.h" + +#include + +namespace sbnd { + class MCCaloAna; +} + + +class sbnd::MCCaloAna : public art::EDAnalyzer { +public: + explicit MCCaloAna(fhicl::ParameterSet const& p); + // The compiler-generated destructor is fine for non-base + // classes without bare pointers or other resource use. + + // Plugins should not be copied or assigned. + MCCaloAna(MCCaloAna const&) = delete; + MCCaloAna(MCCaloAna&&) = delete; + MCCaloAna& operator=(MCCaloAna const&) = delete; + MCCaloAna& operator=(MCCaloAna&&) = delete; + + // Required functions. + void analyze(art::Event const& e) override; + +private: + TTree* _tree; + + int _run; + int _subrun; + int _event; + + std::vector _nu_E; + std::vector _nu_CCNC; + std::vector _true_gamma; + std::vector _true_charge; + std::vector _true_energy; + + // Declare member data here. + +}; + + +sbnd::MCCaloAna::MCCaloAna(fhicl::ParameterSet const& p) + : EDAnalyzer{p} // , + // More initializers here. +{ + art::ServiceHandle fs; + _tree = fs->make("mccalo_tree",""); + _tree->Branch("run", &_run, "run/I"); + _tree->Branch("subrun", &_subrun, "subrun/I"); + _tree->Branch("event", &_event, "event/I"); + _tree->Branch("nu_E", "std::vector", &_nu_E); + _tree->Branch("nu_CCNC", "std::vector", &_nu_CCNC); + _tree->Branch("true_gamma", "std::vector", &_true_gamma); + _tree->Branch("true_charge", "std::vector", &_true_charge); + _tree->Branch("true_energy", "std::vector", &_true_energy); +} + +void sbnd::MCCaloAna::analyze(art::Event const& e) +{ + + _run = e.id().run(); + _subrun = e.id().subRun(); + _event = e.id().event(); + + _nu_E.clear(); + _nu_CCNC.clear(); + _true_gamma.clear(); + _true_charge.clear(); + _true_energy.clear(); + + art::ServiceHandle piserv; + + ::art::Handle> energyDeps_h; + e.getByLabel("ionandscint", energyDeps_h); + std::vector> energyDeps; + + if (!energyDeps_h.isValid() || energyDeps_h->empty()) + std::cout << "Don't have good SimEnergyDeposits!" << std::endl; + else + art::fill_ptr_vector(energyDeps, energyDeps_h); + + std::unordered_set> mctruth_set; + + for (size_t n_dep=0; n_dep < energyDeps.size(); n_dep++){ + auto energyDep = energyDeps[n_dep]; + const auto trackID = energyDep->TrackID(); + + art::Ptr mctruth = piserv->TrackIdToMCTruth_P(trackID); + if (mctruth->Origin() != simb::kBeamNeutrino) continue; + if (auto it = mctruth_set.find(mctruth); it == mctruth_set.end()) { + mctruth_set.insert(mctruth); + + auto neutrino = mctruth->GetNeutrino(); + _nu_E.push_back(neutrino.Nu().E()); + _nu_CCNC.push_back(neutrino.CCNC()); + + _true_gamma.push_back(0); + _true_charge.push_back(0); + _true_energy.push_back(0); + } + // get the index of the mctruth in the set + auto mctruth_index = std::distance(mctruth_set.begin(), mctruth_set.find(mctruth)); + + _true_gamma[mctruth_index] += energyDep->NumPhotons(); + _true_charge[mctruth_index] += energyDep->NumElectrons(); + _true_energy[mctruth_index] += energyDep->Energy(); + } + _tree->Fill(); +} + +DEFINE_ART_MODULE(sbnd::MCCaloAna) diff --git a/sbndcode/Calorimetry/run_mcana.fcl b/sbndcode/Calorimetry/run_mcana.fcl new file mode 100644 index 000000000..5642f2cbc --- /dev/null +++ b/sbndcode/Calorimetry/run_mcana.fcl @@ -0,0 +1,46 @@ +#include "particleinventoryservice.fcl" + +process_name: MCCaloAna + +services: { + TFileService : {fileName: "mcanacalo.root"} + ParticleInventoryService: @local::standard_particleinventoryservice + +} + +source: +{ + module_type: RootInput + maxEvents: -1 # Number of events to create +} + +outputs: +{ + dataTier: 'simulated' +} + +physics: +{ + + producers:{ + } + + filters:{} + + analyzers:{ + mccaloana: { + module_type: MCCaloAna + } + } + + # define the output stream, there could be more than one if using filters + stream1: [mccaloana] + + # trigger_paths is a keyword and contains the paths that modify the art::event, + # ie filters and producers + trigger_paths: [] + + # end_paths is a keyword and contains the paths that do not modify the art::Event, + # ie analyzers and output streams. these all run simultaneously + end_paths: [stream1] +} \ No newline at end of file From b83e549a853bd5ce5b0f39906fbeade7f50ff8be Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Tue, 29 Apr 2025 16:49:28 -0500 Subject: [PATCH 34/52] add lightcalo ana only fcl --- sbndcode/Calorimetry/run_lightcaloana.fcl | 48 +++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 sbndcode/Calorimetry/run_lightcaloana.fcl diff --git a/sbndcode/Calorimetry/run_lightcaloana.fcl b/sbndcode/Calorimetry/run_lightcaloana.fcl new file mode 100644 index 000000000..a3c37cede --- /dev/null +++ b/sbndcode/Calorimetry/run_lightcaloana.fcl @@ -0,0 +1,48 @@ +#include "lightcalo_ana.fcl" +#include "particleinventoryservice.fcl" +#include "services_sbnd.fcl" +#include "simulationservices_sbnd.fcl" + +process_name: LightCaloAna + +services: { + TFileService : {fileName: "lightcaloana.root"} + ParticleInventoryService: @local::standard_particleinventoryservice + @table::sbnd_services # from services_sbnd.fcl + @table::sbnd_g4_services + +} + +source: +{ + module_type: RootInput + maxEvents: -1 # Number of events to create +} + +outputs: +{ +} + +physics: +{ + + producers:{ + } + + filters:{} + + analyzers:{ + lightcaloana: @local::lightcaloana + } + + # define the output stream, there could be more than one if using filters + stream1: [lightcaloana] + + # trigger_paths is a keyword and contains the paths that modify the art::event, + # ie filters and producers + trigger_paths: [] + + # end_paths is a keyword and contains the paths that do not modify the art::Event, + # ie analyzers and output streams. these all run simultaneously + end_paths: [stream1] +} \ No newline at end of file From b2f560c3769253aee1a0531bca9c21308cba4c15 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Mon, 4 Aug 2025 12:43:39 -0500 Subject: [PATCH 35/52] update running fcls --- sbndcode/Calorimetry/run_lightcaloana.fcl | 3 +- .../Calorimetry/run_lightcaloana_data.fcl | 53 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 sbndcode/Calorimetry/run_lightcaloana_data.fcl diff --git a/sbndcode/Calorimetry/run_lightcaloana.fcl b/sbndcode/Calorimetry/run_lightcaloana.fcl index a3c37cede..fce6beecb 100644 --- a/sbndcode/Calorimetry/run_lightcaloana.fcl +++ b/sbndcode/Calorimetry/run_lightcaloana.fcl @@ -2,11 +2,12 @@ #include "particleinventoryservice.fcl" #include "services_sbnd.fcl" #include "simulationservices_sbnd.fcl" +#include "rootoutput_sbnd.fcl" process_name: LightCaloAna services: { - TFileService : {fileName: "lightcaloana.root"} + TFileService : {fileName: @local::sbnd_tfileoutput.fileName} ParticleInventoryService: @local::standard_particleinventoryservice @table::sbnd_services # from services_sbnd.fcl @table::sbnd_g4_services diff --git a/sbndcode/Calorimetry/run_lightcaloana_data.fcl b/sbndcode/Calorimetry/run_lightcaloana_data.fcl new file mode 100644 index 000000000..4490e6205 --- /dev/null +++ b/sbndcode/Calorimetry/run_lightcaloana_data.fcl @@ -0,0 +1,53 @@ +#include "lightcalo_ana.fcl" +#include "particleinventoryservice.fcl" +#include "services_sbnd.fcl" +#include "simulationservices_sbnd.fcl" +#include "rootoutput_sbnd.fcl" + +process_name: LightCaloAna + +services: { + TFileService : {fileName: @local::sbnd_tfileoutput.fileName} + ParticleInventoryService: @local::standard_particleinventoryservice + @table::sbnd_services # from services_sbnd.fcl + @table::sbnd_g4_services +} + +source: +{ + module_type: RootInput + maxEvents: -1 # Number of events to create +} + +outputs: +{ +} + +physics: +{ + + producers:{ + } + + filters:{} + + analyzers:{ + lightcaloana: @local::lightcaloana + } + + # define the output stream, there could be more than one if using filters + stream1: [lightcaloana] + + # trigger_paths is a keyword and contains the paths that modify the art::event, + # ie filters and producers + trigger_paths: [] + + # end_paths is a keyword and contains the paths that do not modify the art::Event, + # ie analyzers and output streams. these all run simultaneously + end_paths: [stream1] +} + +physics.analyzers.lightcaloana.OpT0FlashMin: -1 +physics.analyzers.lightcaloana.OpT0FlashMax: 5 +# physics.analyzers.lightcaloana.Verbose: false +physics.analyzers.lightcaloana.CalAreaConstants: [0.0211 , 0.0209, 0.0204] From 6a6a6f62e8f786c1c0c609c898b0f28588e5c60f Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Mon, 4 Aug 2025 12:44:30 -0500 Subject: [PATCH 36/52] use vector instead of unordered set --- sbndcode/Calorimetry/MCCaloAna_module.cc | 34 ++++++++++++++---------- sbndcode/Calorimetry/run_mcana.fcl | 2 +- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/sbndcode/Calorimetry/MCCaloAna_module.cc b/sbndcode/Calorimetry/MCCaloAna_module.cc index f16c755a8..68d4dbdc1 100644 --- a/sbndcode/Calorimetry/MCCaloAna_module.cc +++ b/sbndcode/Calorimetry/MCCaloAna_module.cc @@ -25,7 +25,7 @@ #include "TFile.h" #include "TTree.h" -#include +#include namespace sbnd { class MCCaloAna; @@ -83,7 +83,6 @@ sbnd::MCCaloAna::MCCaloAna(fhicl::ParameterSet const& p) void sbnd::MCCaloAna::analyze(art::Event const& e) { - _run = e.id().run(); _subrun = e.id().subRun(); _event = e.id().event(); @@ -96,6 +95,13 @@ void sbnd::MCCaloAna::analyze(art::Event const& e) art::ServiceHandle piserv; + art::Handle> mctruth_handle; + e.getByLabel("generator", mctruth_handle); + + std::vector> mctruths; + if (mctruth_handle.isValid()) + art::fill_ptr_vector(mctruths, mctruth_handle); + ::art::Handle> energyDeps_h; e.getByLabel("ionandscint", energyDeps_h); std::vector> energyDeps; @@ -105,7 +111,11 @@ void sbnd::MCCaloAna::analyze(art::Event const& e) else art::fill_ptr_vector(energyDeps, energyDeps_h); - std::unordered_set> mctruth_set; + _nu_E.resize(mctruths.size(), 0); + _nu_CCNC.resize(mctruths.size(), 0); + _true_gamma.resize(mctruths.size(), 0); + _true_charge.resize(mctruths.size(), 0); + _true_energy.resize(mctruths.size(), 0); for (size_t n_dep=0; n_dep < energyDeps.size(); n_dep++){ auto energyDep = energyDeps[n_dep]; @@ -113,19 +123,15 @@ void sbnd::MCCaloAna::analyze(art::Event const& e) art::Ptr mctruth = piserv->TrackIdToMCTruth_P(trackID); if (mctruth->Origin() != simb::kBeamNeutrino) continue; - if (auto it = mctruth_set.find(mctruth); it == mctruth_set.end()) { - mctruth_set.insert(mctruth); - - auto neutrino = mctruth->GetNeutrino(); - _nu_E.push_back(neutrino.Nu().E()); - _nu_CCNC.push_back(neutrino.CCNC()); - - _true_gamma.push_back(0); - _true_charge.push_back(0); - _true_energy.push_back(0); + + auto it = std::find(mctruths.begin(), mctruths.end(), mctruth); + if (it == mctruths.end()) { + std::cout << "No matching MCTruth found for trackID: " << trackID << std::endl; + continue; } + // get the index of the mctruth in the set - auto mctruth_index = std::distance(mctruth_set.begin(), mctruth_set.find(mctruth)); + auto mctruth_index = std::distance(mctruths.begin(), it); _true_gamma[mctruth_index] += energyDep->NumPhotons(); _true_charge[mctruth_index] += energyDep->NumElectrons(); diff --git a/sbndcode/Calorimetry/run_mcana.fcl b/sbndcode/Calorimetry/run_mcana.fcl index 5642f2cbc..0b800f03a 100644 --- a/sbndcode/Calorimetry/run_mcana.fcl +++ b/sbndcode/Calorimetry/run_mcana.fcl @@ -16,7 +16,7 @@ source: outputs: { - dataTier: 'simulated' + dataTier: "simulated" } physics: From 37d4683e6beec84c7ec05bf370aef331b6359030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20S=C3=A1nchez=20Castillo?= Date: Mon, 28 Jul 2025 05:32:22 -0500 Subject: [PATCH 37/52] Add pmt variations fcls --- .../pmt_variations/standard_detsim_sbnd_PMTGainFluct.fcl | 2 ++ .../standard_detsim_sbnd_PMTGainFluct_HighNoise.fcl | 3 +++ ...tandard_detsim_sbnd_PMTGainFluct_HighNoise_LowEff.fcl | 9 +++++++++ .../standard_detsim_sbnd_PMTGainFluct_LowEff.fcl | 8 ++++++++ .../pmt_variations/standard_detsim_sbnd_PMTHighNoise.fcl | 2 ++ .../standard_detsim_sbnd_PMTHighNoise_LowEff.fcl | 8 ++++++++ .../pmt_variations/standard_detsim_sbnd_PMTLowEff.fcl | 7 +++++++ 7 files changed, 39 insertions(+) create mode 100644 sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTGainFluct.fcl create mode 100644 sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTGainFluct_HighNoise.fcl create mode 100644 sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTGainFluct_HighNoise_LowEff.fcl create mode 100644 sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTGainFluct_LowEff.fcl create mode 100644 sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTHighNoise.fcl create mode 100644 sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTHighNoise_LowEff.fcl create mode 100644 sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTLowEff.fcl diff --git a/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTGainFluct.fcl b/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTGainFluct.fcl new file mode 100644 index 000000000..8db6961e9 --- /dev/null +++ b/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTGainFluct.fcl @@ -0,0 +1,2 @@ +#include "standard_detsim_sbnd.fcl" +physics.producers.opdaq.GainFluctuationsParams.DynodeK: 0.25 \ No newline at end of file diff --git a/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTGainFluct_HighNoise.fcl b/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTGainFluct_HighNoise.fcl new file mode 100644 index 000000000..efa572693 --- /dev/null +++ b/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTGainFluct_HighNoise.fcl @@ -0,0 +1,3 @@ +#include "standard_detsim_sbnd.fcl" +physics.producers.opdaq.GainFluctuationsParams.DynodeK: 0.25 +physics.producers.opdaq.PMTBaselineRMS: 3.5 \ No newline at end of file diff --git a/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTGainFluct_HighNoise_LowEff.fcl b/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTGainFluct_HighNoise_LowEff.fcl new file mode 100644 index 000000000..a0e579154 --- /dev/null +++ b/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTGainFluct_HighNoise_LowEff.fcl @@ -0,0 +1,9 @@ +#include "standard_detsim_sbnd.fcl" +physics.producers.opdaq.GainFluctuationsParams.DynodeK: 0.25 +physics.producers.opdaq.PMTBaselineRMS: 3.5 +physics.producers.opdaq.PMTCoatedVUVEff_tpc0: 0.021 +physics.producers.opdaq.PMTCoatedVISEff_tpc0: 0.02329 +physics.producers.opdaq.PMTUncoatedEff_tpc0: 0.0225 +physics.producers.opdaq.PMTCoatedVUVEff_tpc1: 0.018 +physics.producers.opdaq.PMTCoatedVISEff_tpc1: 0.02329 +physics.producers.opdaq.PMTUncoatedEff_tpc1: 0.0225 \ No newline at end of file diff --git a/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTGainFluct_LowEff.fcl b/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTGainFluct_LowEff.fcl new file mode 100644 index 000000000..85241bc89 --- /dev/null +++ b/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTGainFluct_LowEff.fcl @@ -0,0 +1,8 @@ +#include "standard_detsim_sbnd.fcl" +physics.producers.opdaq.GainFluctuationsParams.DynodeK: 0.25 +physics.producers.opdaq.PMTCoatedVUVEff_tpc0: 0.021 +physics.producers.opdaq.PMTCoatedVISEff_tpc0: 0.02329 +physics.producers.opdaq.PMTUncoatedEff_tpc0: 0.0225 +physics.producers.opdaq.PMTCoatedVUVEff_tpc1: 0.018 +physics.producers.opdaq.PMTCoatedVISEff_tpc1: 0.02329 +physics.producers.opdaq.PMTUncoatedEff_tpc1: 0.0225 \ No newline at end of file diff --git a/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTHighNoise.fcl b/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTHighNoise.fcl new file mode 100644 index 000000000..83eb95ee3 --- /dev/null +++ b/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTHighNoise.fcl @@ -0,0 +1,2 @@ +#include "standard_detsim_sbnd.fcl" +physics.producers.opdaq.PMTBaselineRMS: 3.5 \ No newline at end of file diff --git a/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTHighNoise_LowEff.fcl b/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTHighNoise_LowEff.fcl new file mode 100644 index 000000000..047e7d9cf --- /dev/null +++ b/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTHighNoise_LowEff.fcl @@ -0,0 +1,8 @@ +#include "standard_detsim_sbnd.fcl" +physics.producers.opdaq.PMTBaselineRMS: 3.5 +physics.producers.opdaq.PMTCoatedVUVEff_tpc0: 0.021 +physics.producers.opdaq.PMTCoatedVISEff_tpc0: 0.02329 +physics.producers.opdaq.PMTUncoatedEff_tpc0: 0.0225 +physics.producers.opdaq.PMTCoatedVUVEff_tpc1: 0.018 +physics.producers.opdaq.PMTCoatedVISEff_tpc1: 0.02329 +physics.producers.opdaq.PMTUncoatedEff_tpc1: 0.0225 \ No newline at end of file diff --git a/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTLowEff.fcl b/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTLowEff.fcl new file mode 100644 index 000000000..ddb999453 --- /dev/null +++ b/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTLowEff.fcl @@ -0,0 +1,7 @@ +#include "standard_detsim_sbnd.fcl" +physics.producers.opdaq.PMTCoatedVUVEff_tpc0: 0.021 +physics.producers.opdaq.PMTCoatedVISEff_tpc0: 0.02329 +physics.producers.opdaq.PMTUncoatedEff_tpc0: 0.0225 +physics.producers.opdaq.PMTCoatedVUVEff_tpc1: 0.018 +physics.producers.opdaq.PMTCoatedVISEff_tpc1: 0.02329 +physics.producers.opdaq.PMTUncoatedEff_tpc1: 0.0225 \ No newline at end of file From 6447cf1fa6f4021d7279157a380fbf1a57d59100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20S=C3=A1nchez=20Castillo?= Date: Mon, 28 Jul 2025 05:32:22 -0500 Subject: [PATCH 38/52] add more feaetures to mccaloana - store simphotons at each opdet - calculate true light/charge based spatial-correction maps - calculate various versions of L1 reco --- sbndcode/Calorimetry/MCCaloAna_config.fcl | 14 ++ sbndcode/Calorimetry/MCCaloAna_module.cc | 263 +++++++++++++++++++++- sbndcode/Calorimetry/run_mcana.fcl | 17 +- 3 files changed, 285 insertions(+), 9 deletions(-) create mode 100644 sbndcode/Calorimetry/MCCaloAna_config.fcl diff --git a/sbndcode/Calorimetry/MCCaloAna_config.fcl b/sbndcode/Calorimetry/MCCaloAna_config.fcl new file mode 100644 index 000000000..a53a9b26b --- /dev/null +++ b/sbndcode/Calorimetry/MCCaloAna_config.fcl @@ -0,0 +1,14 @@ +#include "opticalsimparameterisations_sbnd.fcl" + +BEGIN_PROLOG +mccaloana: +{ + module_type: "MCCaloAna" + + VUVHits: @local::sbnd_vuv_RS100cm_hits_parameterization + VIVHits: @local::sbnd_vis_RS100cm_hits_parameterization + OpDetVUVEfficiencies: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021] + OpDetVISEfficiencies: [0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + +} +END_PROLOG \ No newline at end of file diff --git a/sbndcode/Calorimetry/MCCaloAna_module.cc b/sbndcode/Calorimetry/MCCaloAna_module.cc index 68d4dbdc1..6b70b2ddf 100644 --- a/sbndcode/Calorimetry/MCCaloAna_module.cc +++ b/sbndcode/Calorimetry/MCCaloAna_module.cc @@ -19,8 +19,14 @@ #include "larsim/MCCheater/ParticleInventoryService.h" #include "lardataobj/Simulation/SimEnergyDeposit.h" +#include "lardataobj/Simulation/SimPhotons.h" #include "nusimdata/SimulationBase/MCTruth.h" +#include "larsim/PhotonPropagation/SemiAnalyticalModel.h" +#include "larcore/Geometry/Geometry.h" +#include "larcorealg/Geometry/GeometryCore.h" +#include "sbndcode/OpDetSim/sbndPDMapAlg.hh" + #include "art_root_io/TFileService.h" #include "TFile.h" #include "TTree.h" @@ -60,15 +66,48 @@ class sbnd::MCCaloAna : public art::EDAnalyzer { std::vector _true_charge; std::vector _true_energy; - // Declare member data here. + std::vector _true_gamma_tpc; + std::vector _true_measphotons; + std::vector _true_resimphotons; -}; + std::vector _chargecorr_gamma; + std::vector _chargecorr_visibility; + std::vector _lightcorr_gamma; + std::vector _lightcorr_gamma_resim; + std::vector _lightcorr_visibility; + + std::vector _opdet_vuv_eff; + std::vector _opdet_vis_eff; + + std::unique_ptr _semi_model; + fhicl::ParameterSet _vuv_params; + fhicl::ParameterSet _vis_params; + opdet::sbndPDMapAlg _opdetmap; //map for photon detector types + unsigned int _nchan = _opdetmap.size(); + std::vector> CalcVisibility(std::vector xyz_v, + std::vector charge_v); + std::vector> CalcPE(std::vector xyz_v, + std::vector light_v); + std::vector> FillSimPhotonsLite(std::vector >> photonHandle_list); + void CalcLight(std::vector flash_pe_v, + std::vector dir_visibility, + std::vector ref_visibility, + std::vector &total_gamma_v, + std::vector &total_visibility_v); +}; + sbnd::MCCaloAna::MCCaloAna(fhicl::ParameterSet const& p) : EDAnalyzer{p} // , // More initializers here. { + _vuv_params = p.get("VUVHits"); + _vis_params = p.get("VIVHits"); + _semi_model = std::make_unique(_vuv_params, _vis_params, true, false); + _opdet_vuv_eff = p.get>("OpDetVUVEfficiencies"); + _opdet_vis_eff = p.get>("OpDetVISEfficiencies"); + art::ServiceHandle fs; _tree = fs->make("mccalo_tree",""); _tree->Branch("run", &_run, "run/I"); @@ -79,6 +118,14 @@ sbnd::MCCaloAna::MCCaloAna(fhicl::ParameterSet const& p) _tree->Branch("true_gamma", "std::vector", &_true_gamma); _tree->Branch("true_charge", "std::vector", &_true_charge); _tree->Branch("true_energy", "std::vector", &_true_energy); + _tree->Branch("true_gamma_tpc", "std::vector", &_true_gamma_tpc); + _tree->Branch("true_measphotons","std::vector", &_true_measphotons); + _tree->Branch("true_resimphotons","std::vector", &_true_resimphotons); + _tree->Branch("chargecorr_gamma", "std::vector", &_chargecorr_gamma); + _tree->Branch("chargecorr_visibility","std::vector", &_chargecorr_visibility); + _tree->Branch("lightcorr_gamma", "std::vector", &_lightcorr_gamma); + _tree->Branch("lightcorr_gamma_resim","std::vector",&_lightcorr_gamma_resim); + _tree->Branch("lightcorr_visibility","std::vector", &_lightcorr_visibility); } void sbnd::MCCaloAna::analyze(art::Event const& e) @@ -93,6 +140,16 @@ void sbnd::MCCaloAna::analyze(art::Event const& e) _true_charge.clear(); _true_energy.clear(); + _true_gamma_tpc.clear(); + _true_measphotons.clear(); + _true_resimphotons.clear(); + + _chargecorr_gamma.clear(); + _chargecorr_visibility.clear(); + _lightcorr_gamma.clear(); + _lightcorr_gamma_resim.clear(); + _lightcorr_visibility.clear(); + art::ServiceHandle piserv; art::Handle> mctruth_handle; @@ -110,12 +167,31 @@ void sbnd::MCCaloAna::analyze(art::Event const& e) std::cout << "Don't have good SimEnergyDeposits!" << std::endl; else art::fill_ptr_vector(energyDeps, energyDeps_h); - + + std::vector >> fLitePhotonHandle_list; + fLitePhotonHandle_list = e.getMany>(); + auto opdet_simphotons = FillSimPhotonsLite(fLitePhotonHandle_list); + + std::vector> edep_photons; + std::vector> edep_electrons; + std::vector> edep_energy; + std::vector> edep_points; + // std::vector> edep_x, edep_y, edep_z; + _nu_E.resize(mctruths.size(), 0); _nu_CCNC.resize(mctruths.size(), 0); _true_gamma.resize(mctruths.size(), 0); _true_charge.resize(mctruths.size(), 0); _true_energy.resize(mctruths.size(), 0); + _true_measphotons.resize(_nchan,0); + _true_resimphotons.resize(_nchan,0); + + _true_gamma_tpc.resize(2,0); + + edep_photons.resize(mctruths.size()); + edep_electrons.resize(mctruths.size()); + edep_energy.resize(mctruths.size()); + edep_points.resize(mctruths.size()); for (size_t n_dep=0; n_dep < energyDeps.size(); n_dep++){ auto energyDep = energyDeps[n_dep]; @@ -136,8 +212,187 @@ void sbnd::MCCaloAna::analyze(art::Event const& e) _true_gamma[mctruth_index] += energyDep->NumPhotons(); _true_charge[mctruth_index] += energyDep->NumElectrons(); _true_energy[mctruth_index] += energyDep->Energy(); - } + + edep_photons.at(mctruth_index).push_back(energyDep->NumPhotons()); + edep_electrons.at(mctruth_index).push_back(energyDep->NumElectrons()); + edep_energy.at(mctruth_index).push_back(energyDep->Energy()); + edep_points.at(mctruth_index).push_back(energyDep->Start()); + + if (energyDep->Start().X() < 0) + _true_gamma_tpc.at(0) += energyDep->NumPhotons(); + else + _true_gamma_tpc.at(1) += energyDep->NumPhotons(); + } + + + auto resim_pe = CalcPE(edep_points.at(0),edep_photons.at(0)); + + for (size_t ich=0; ich < opdet_simphotons.at(0).size(); ich++){ + std::string pd_type = _opdetmap.pdType(ich); + if(pd_type=="xarapuca_vis" || pd_type=="xarapuca_vuv") continue; + _true_measphotons.at(ich) = opdet_simphotons.at(0).at(ich) + opdet_simphotons.at(1).at(ich); + _true_resimphotons.at(ich) = resim_pe.at(0).at(ich) + resim_pe.at(1).at(ich); + // std::cout << "ich " << ich << " (dir sim/resim): " << opdet_simphotons.at(0).at(ich) << ", " << resim_pe.at(0).at(ich) << std::endl; + // std::cout << "ich " << ich << " (ref sim/resim): " << opdet_simphotons.at(1).at(ich) << ", " << resim_pe.at(1).at(ich) << std::endl; + } + + for (size_t nnu; nnu < mctruths.size(); nnu++){ + auto true_vis_charge = CalcVisibility(edep_points.at(nnu),edep_electrons.at(nnu)); + auto true_vis_light = CalcVisibility(edep_points.at(nnu),edep_photons.at(nnu)); + + _chargecorr_gamma.resize(_nchan,0); + _chargecorr_visibility.resize(_nchan,0); + _lightcorr_gamma.resize(_nchan,0); + _lightcorr_gamma_resim.resize(_nchan,0); + _lightcorr_visibility.resize(_nchan,0); + CalcLight(_true_measphotons, true_vis_charge.at(0), true_vis_charge.at(1),_chargecorr_gamma,_chargecorr_visibility); + CalcLight(_true_measphotons, true_vis_light.at(0), true_vis_light.at(1),_lightcorr_gamma,_lightcorr_visibility); + CalcLight(_true_resimphotons, true_vis_light.at(0), true_vis_light.at(1),_lightcorr_gamma_resim,_lightcorr_visibility); + } + _tree->Fill(); } +std::vector> sbnd::MCCaloAna::CalcVisibility(std::vector xyz_v, + std::vector charge_v){ + // returns of two vectors (len is # of opdet) for the visibility for every opdet + if (xyz_v.size() != charge_v.size()) std::cout << "spacepoint coord and charge vector size mismatch" << std::endl; + + std::vector dir_visibility_map(_nchan, 0); + std::vector ref_visibility_map(_nchan, 0); + double sum_charge0 = 0; + double sum_charge1 = 0; + + for (size_t i=0; i direct_visibility; + std::vector reflect_visibility; + _semi_model->detectedDirectVisibilities(direct_visibility, xyz); + _semi_model->detectedReflectedVisibilities(reflect_visibility, xyz); + // if (dir_visibility_map.size() != direct_visibility.size()) std::cout << "mismatch of visibility vector size" << std::endl; + + // weight by charge + for (size_t ch=0; ch> sbnd::MCCaloAna::CalcPE(std::vector xyz_v, + std::vector light_v){ + // returns of two vectors (len is # of opdet) for the visibility for every opdet + + std::vector> pe_v(2); + for (size_t i=0; i<2;i++){ + pe_v.at(i).resize(_nchan,0); + } + + for (size_t i=0; i direct_visibility; + std::vector reflect_visibility; + _semi_model->detectedDirectVisibilities(direct_visibility, xyz); + _semi_model->detectedReflectedVisibilities(reflect_visibility, xyz); + + for (size_t ich=0;ich<_nchan;ich++){ + pe_v.at(0).at(ich) += light*direct_visibility.at(ich); + pe_v.at(1).at(ich) += light*reflect_visibility.at(ich); + } + } + return pe_v; +} + +std::vector> sbnd::MCCaloAna::FillSimPhotonsLite(std::vector >> photonHandle_list){ + std::vector fPDTypes{"pmt_coated", "pmt_uncoated"}; + std::vector> opdet_simphotons; + opdet_simphotons.resize(2); + for (size_t i=0; i<2; i++){ + opdet_simphotons.at(i).resize(_nchan,0); + } + + for ( const art::Handle>& litePhotonHandle: (photonHandle_list) ){ + + std::string spLabel = litePhotonHandle.provenance()->moduleLabel(); + std::vector fSimPhotonsModuleLabel{"pdfastsim"}; + if(std::find(fSimPhotonsModuleLabel.begin(), fSimPhotonsModuleLabel.end(), spLabel)==fSimPhotonsModuleLabel.end()) continue; + + // Reflected light + bool reflected = (litePhotonHandle.provenance()->productInstanceName() == "Reflected"); + + // Loop over the SimPhotonsLite + for ( auto const& fLitePhotons : (*litePhotonHandle) ){ + + int opch=fLitePhotons.OpChannel; + + std::string pd_type = _opdetmap.pdType(opch); + // Channels not sensitive to reflected light + if(reflected && pd_type=="xarapuca_vuv") continue; + // Channels not sensitive to direct light + if(!reflected && (pd_type=="xarapuca_vis" || pd_type=="pmt_uncoated")) continue; + + // Only save the PD types specified in the fhicl list + if(std::find(fPDTypes.begin(), fPDTypes.end(), pd_type ) != fPDTypes.end() ){ + + std::map fLitePhotons_map = fLitePhotons.DetectedPhotons; + int nphotons=0; + + for(auto fphoton = fLitePhotons_map.begin(); fphoton!= fLitePhotons_map.end(); fphoton++){ + nphotons+=fphoton->second; + } + + // Fill #photons per OpChannel + if(reflected){ + opdet_simphotons.at(1).at(opch)+=nphotons; + } + else{ + opdet_simphotons.at(0).at(opch)+=nphotons; + } + } + } + } + + return opdet_simphotons; +} + + +void sbnd::MCCaloAna::CalcLight(std::vector flash_pe_v, + std::vector dir_visibility, + std::vector ref_visibility, + std::vector &total_gamma_v, + std::vector &tot_visibility_v){ + for (size_t ch = 0; ch < flash_pe_v.size(); ch++){ + auto pe = flash_pe_v[ch]; + // auto vuv_eff = _opdet_vuv_eff.at(ch); + // auto vis_eff = _opdet_vis_eff.at(ch); + auto vuv_eff = 1.0; + auto vis_eff = 1.0; + auto tot_visibility = vuv_eff*dir_visibility[ch] + vis_eff*ref_visibility[ch]; + tot_visibility_v.at(ch) = tot_visibility; + if((pe == 0) || std::isinf(1/tot_visibility)) + continue; + // deposited light is inverse of visibility * PE count + total_gamma_v[ch] += (1/tot_visibility)*pe; + } +} + DEFINE_ART_MODULE(sbnd::MCCaloAna) diff --git a/sbndcode/Calorimetry/run_mcana.fcl b/sbndcode/Calorimetry/run_mcana.fcl index 0b800f03a..55de8b041 100644 --- a/sbndcode/Calorimetry/run_mcana.fcl +++ b/sbndcode/Calorimetry/run_mcana.fcl @@ -1,11 +1,16 @@ #include "particleinventoryservice.fcl" +#include "services_sbnd.fcl" +#include "simulationservices_sbnd.fcl" +#include "rootoutput_sbnd.fcl" +#include "MCCaloAna_config.fcl" process_name: MCCaloAna services: { TFileService : {fileName: "mcanacalo.root"} ParticleInventoryService: @local::standard_particleinventoryservice - + @table::sbnd_services # from services_sbnd.fcl + @table::sbnd_g4_services } source: @@ -16,7 +21,11 @@ source: outputs: { - dataTier: "simulated" + out1: + { + @table::sbnd_rootoutput + dataTier: "simulated" + } } physics: @@ -28,9 +37,7 @@ physics: filters:{} analyzers:{ - mccaloana: { - module_type: MCCaloAna - } + mccaloana: @local::mccaloana } # define the output stream, there could be more than one if using filters From b27bf1ab4670f8cac3787432d49343ce37ee5667 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 13 Nov 2025 12:58:22 -0600 Subject: [PATCH 39/52] add more features to lightcaloana - update drift time correction with call to clocks - split by shower/track - add more tree branches --- sbndcode/Calorimetry/LightCaloAna_module.cc | 122 +++++++++++++++++++- sbndcode/Calorimetry/lightcalo_ana.fcl | 2 +- sbndcode/Calorimetry/run_lightcaloana.fcl | 3 +- 3 files changed, 119 insertions(+), 8 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index 42343ed60..8d3511b8b 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -38,6 +38,9 @@ #include "lardataobj/RecoBase/Hit.h" #include "lardataobj/RecoBase/Wire.h" #include "lardataobj/RecoBase/OpFlash.h" +#include "lardataobj/RecoBase/Shower.h" +#include "lardataobj/RecoBase/Track.h" +#include "larpandora/LArPandoraInterface/LArPandoraHelper.h" #include "lardataobj/Simulation/SimPhotons.h" #include "lardataobj/Simulation/SimEnergyDeposit.h" @@ -174,6 +177,15 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { double _true_charge; // true electron count from all energy depositions double _true_energy; // true deposited energy + std::vector _visibility; + + double _sp_max_x; + double _sp_min_x; + double _sp_max_y; + double _sp_min_y; + double _sp_max_z; + double _sp_min_z; + double _median_gamma; // median of all reconstructed light estimates double _mean_gamma; // mean of all reconstructed light estimates @@ -182,6 +194,13 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { double _comp_charge; // charge from the plane with the highest number of hits, "highest completeness" double _coll_charge; // charge from collection plane only + double _sp_charge; + double _trk_charge; + double _shw_charge; + + double _trk_sp_charge; + double _shw_sp_charge; + double _slice_L; // reconstructed photon count double _slice_Q; // reconstructed electron count double _slice_E; // reconstructed deposited energy @@ -255,6 +274,14 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _tree2->Branch("true_charge", &_true_charge, "true_charge/D"); _tree2->Branch("true_energy", &_true_energy, "true_energy/D"); + _tree2->Branch("visibility", "std::vector", &_visibility); + _tree2->Branch("sp_max_x", &_sp_max_x, "sp_x_max/D"); + _tree2->Branch("sp_min_x", &_sp_min_x, "sp_x_min/D"); + _tree2->Branch("sp_max_y", &_sp_max_y, "sp_y_max/D"); + _tree2->Branch("sp_min_y", &_sp_min_y, "sp_y_min/D"); + _tree2->Branch("sp_max_z", &_sp_max_z, "sp_z_max/D"); + _tree2->Branch("sp_min_z", &_sp_min_z, "sp_z_min/D"); + _tree2->Branch("median_gamma", &_median_gamma, "median_gamma/D"); _tree2->Branch("mean_gamma", &_mean_gamma, "mean_gamma/D"); _tree2->Branch("mean_charge", &_mean_charge, "mean_charge/D"); @@ -262,6 +289,12 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) _tree2->Branch("comp_charge", &_comp_charge, "comp_charge/D"); _tree2->Branch("coll_charge", &_coll_charge, "coll_charge/D"); + _tree2->Branch("sp_charge", &_sp_charge, "sp_charge/D"); + _tree2->Branch("trk_charge", &_trk_charge, "trk_charge/D"); + _tree2->Branch("shw_charge", &_shw_charge, "shw_charge/D"); + _tree2->Branch("trk_sp_charge", &_trk_sp_charge,"trk_sp_charge/D"); + _tree2->Branch("shw_sp_charge", &_shw_sp_charge,"shw_sp_charge/D"); + _tree2->Branch("slice_L", &_slice_L, "slice_L/D"); _tree2->Branch("slice_Q", &_slice_Q, "slice_Q/D"); _tree2->Branch("slice_E", &_slice_E, "slice_E/D"); @@ -307,6 +340,20 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) return; } + ::art::Handle> shower_h; + e.getByLabel("pandoraShowerSBN", shower_h); + if(!shower_h.isValid() || shower_h->empty()) { + std::cout << "don't have good Showers!" << std::endl; + return; + } + + ::art::Handle> track_h; + e.getByLabel("pandoraTrack", track_h); + if(!track_h.isValid() || track_h->empty()) { + std::cout << "don't have good Tracks!" << std::endl; + return; + } + auto const & flash0_h = e.getValidHandle>(_opflash_producer_v[0]); auto const & flash1_h = e.getValidHandle>(_opflash_producer_v[1]); if (!_use_arapucas && _verbose) @@ -319,6 +366,11 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) art::FindManyP slice_to_pfp (slice_h, e, _slice_producer); art::FindManyP slice_to_hit (slice_h, e, _slice_producer); art::FindManyP pfp_to_spacepoint(pfp_h, e, _slice_producer); + art::FindManyP pfp_to_shower (pfp_h, e, "pandoraShowerSBN"); + art::FindManyP pfp_to_track (pfp_h, e, "pandoraTrack"); + art::FindManyP shower_to_hit (shower_h, e, "pandoraShowerSBN"); + art::FindManyP track_to_hit (track_h, e, "pandoraTrack"); + art::FindManyP spacepoint_to_hit(spacepoint_h, e, _slice_producer); std::vector> match_slices_v; @@ -564,7 +616,7 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) std::vector plane_hits{0,0,0}; for (size_t i=0; i < slice_hits_v.size(); i++){ auto hit = slice_hits_v[i]; - auto drift_time = (hit->PeakTime() - 500)*0.5; // assuming TPC beam readout starts at 500 ticks, conversion = 0.5 us/tick + auto drift_time = hit->PeakTime()*0.5 - clock_data.TriggerOffsetTPC(); double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) auto hit_plane = hit->View(); plane_charge.at(hit_plane) += hit->Integral()*atten_correction*(1/_cal_area_const.at(hit_plane)); @@ -581,31 +633,84 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) _slice_Q = _comp_charge; - double sps_Q = 0; + _sp_charge = 0; + _shw_sp_charge = 0; + _trk_sp_charge = 0; + + _trk_charge = 0; + _shw_charge = 0; + + _sp_max_x = -1e9; _sp_max_y = -1e9; _sp_max_z = -1e9; + _sp_min_x = 1e9; _sp_min_y = 1e9; _sp_min_z = 1e9; // get charge information to create the weighted map std::vector> pfp_v = slice_to_pfp.at(slice.key()); for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ auto pfp = pfp_v[n_pfp]; if (pfp->IsPrimary()) _pfpid = pfp->Self(); + auto pfpistrack = ::lar_pandora::LArPandoraHelper::IsTrack(pfp); + auto pfpisshower = ::lar_pandora::LArPandoraHelper::IsShower(pfp); + + if (pfpistrack){ + std::vector> trk_v = pfp_to_track.at(pfp.key()); + for (size_t n_trk=0; n_trk < trk_v.size(); n_trk++){ + auto trk = trk_v[n_trk]; + std::vector> hit_v = track_to_hit.at(trk.key()); + for (size_t n_hit=0; n_hit < hit_v.size(); n_hit++){ + auto hit = hit_v[n_hit]; + if (hit->View() !=bestHits) continue; + auto drift_time = hit->PeakTime()*0.5 - clock_data.TriggerOffsetTPC(); + double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) + double charge = (1/_cal_area_const.at(bestPlane))*atten_correction*hit->Integral(); + _trk_charge += charge; + } + } + } + if (pfpisshower){ + std::vector> shw_v = pfp_to_shower.at(pfp.key()); + for (size_t n_shw=0; n_shw < shw_v.size(); n_shw++){ + auto shw = shw_v[n_shw]; + std::vector> hit_v = shower_to_hit.at(shw.key()); + for (size_t n_hit=0; n_hit < hit_v.size(); n_hit++){ + auto hit = hit_v[n_hit]; + if (hit->View() !=bestHits) continue; + auto drift_time = hit->PeakTime()*0.5 - clock_data.TriggerOffsetTPC(); + double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) + double charge = (1/_cal_area_const.at(bestPlane))*atten_correction*hit->Integral(); + _shw_charge += charge; + } + } + } std::vector> sp_v = pfp_to_spacepoint.at(pfp.key()); for (size_t n_sp=0; n_sp < sp_v.size(); n_sp++){ auto sp = sp_v[n_sp]; std::vector> hit_v = spacepoint_to_hit.at(sp.key()); for (size_t n_hit=0; n_hit < hit_v.size(); n_hit++){ auto hit = hit_v[n_hit]; - if (hit->View() !=bestPlane) continue; + // + if (hit->View() !=bestHits) continue; const auto &position(sp->XYZ()); geo::Point_t xyz(position[0],position[1],position[2]); // correct for e- attenuation - geo::TPCGeo const& tpcGeo = geom->TPC({0, 0}); - double drift_time = (2.0*tpcGeo.HalfWidth() - abs(position[0]))/(det_prop.DriftVelocity()); // cm / (cm/us) + // geo::TPCGeo const& tpcGeo = geom->TPC({0, 0}); + // double drift_time1 = (abs(tpcGeo.MaxX()) - abs(position[0]))/(det_prop.DriftVelocity()); // cm / (cm/us) + auto drift_time = hit->PeakTime()*0.5 - clock_data.TriggerOffsetTPC(); double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) double charge = (1/_cal_area_const.at(bestPlane))*atten_correction*hit->Integral(); sp_xyz.push_back(xyz); sp_charge.push_back(charge); - sps_Q += charge; + _sp_charge += charge; + if (pfpistrack) _trk_sp_charge +=charge; + if (pfpisshower) _shw_sp_charge +=charge; + + if (xyz.X() > _sp_max_x) _sp_max_x = xyz.X(); + if (xyz.X() < _sp_min_x) _sp_min_x = xyz.X(); + if (xyz.Y() > _sp_max_y) _sp_max_y = xyz.Y(); + if (xyz.Y() < _sp_min_y) _sp_min_y = xyz.Y(); + if (xyz.Z() > _sp_max_z) _sp_max_z = xyz.Z(); + if (xyz.Z() < _sp_min_z) _sp_min_z = xyz.Z(); + } } // end spacepoint loop } // end pfp loop @@ -648,6 +753,7 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) total_pe.at(_opdet_mask.at(imask)) = 0; } + _visibility.resize(_nchan,0); // calculate the photon estimates for every entry in total_pe CalcLight(total_pe, dir_visibility_map, ref_visibility_map, total_gamma); @@ -657,6 +763,8 @@ void sbnd::LightCaloAna::analyze(art::Event const& e) _rec_gamma = total_gamma; // calculate final light estimate + // ! TODO: final light estimate should be weighted average + // ! where the weights are 1/poisson_err _median_gamma = CalcMedian(total_gamma); _mean_gamma = CalcMean(total_gamma); @@ -768,6 +876,7 @@ std::vector> sbnd::LightCaloAna::CalcVisibility(std::vector< for (size_t i=0; i flash_pe_v, auto vuv_eff = _opdet_vuv_eff.at(ch); auto vis_eff = _opdet_vis_eff.at(ch); auto tot_visibility = vuv_eff*dir_visibility[ch] + vis_eff*ref_visibility[ch]; + _visibility.at(ch) = tot_visibility; if((pe == 0) || std::isinf(1/tot_visibility)) continue; // deposited light is inverse of visibility * PE count diff --git a/sbndcode/Calorimetry/lightcalo_ana.fcl b/sbndcode/Calorimetry/lightcalo_ana.fcl index 4924945be..0619b9e4c 100644 --- a/sbndcode/Calorimetry/lightcalo_ana.fcl +++ b/sbndcode/Calorimetry/lightcalo_ana.fcl @@ -38,7 +38,7 @@ lightcaloana: OpDetVISEfficiencies: [0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] OpDetMask : [39, 66, 67, 71, 85, 86, 87, 92, 115, 138, 141, 170, 197, 217, 218, 221, 222, 223, 226, 245, 248, 249, 302] - ScintPreScale: 0.03 # Scintillation Pre-Scale factor in simulation (set in ionandscint) + ScintPreScale: 0.039 # Scintillation Pre-Scale factor in simulation (set in ionandscint) # parameters for truth validation TruthValidation: false # can only set to true if the reco2 files have SimEnergyDeposits diff --git a/sbndcode/Calorimetry/run_lightcaloana.fcl b/sbndcode/Calorimetry/run_lightcaloana.fcl index fce6beecb..23cc9070a 100644 --- a/sbndcode/Calorimetry/run_lightcaloana.fcl +++ b/sbndcode/Calorimetry/run_lightcaloana.fcl @@ -7,7 +7,8 @@ process_name: LightCaloAna services: { - TFileService : {fileName: @local::sbnd_tfileoutput.fileName} + # TFileService : {fileName: @local::sbnd_tfileoutput.fileName} + TFileService: {fileName: "lightcalo_tree.root"} ParticleInventoryService: @local::standard_particleinventoryservice @table::sbnd_services # from services_sbnd.fcl @table::sbnd_g4_services From a149a0c71854ace492709e3790d70143df79d133 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 13 Nov 2025 12:59:17 -0600 Subject: [PATCH 40/52] update producer module to be aligned with analyzer --- .../Calorimetry/LightCaloProducer_module.cc | 775 +++++++----------- sbndcode/Calorimetry/lightcalo.fcl | 26 +- 2 files changed, 318 insertions(+), 483 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 4591450df..653074851 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -54,9 +54,9 @@ #include "lardata/DetectorInfoServices/DetectorPropertiesService.h" // SBND includes -#include "sbnobj/Common/Reco/SimpleFlashMatchVars.h" #include "sbndcode/OpDetSim/sbndPDMapAlg.hh" #include "sbnobj/Common/Reco/LightCaloInfo.h" +#include "sbnobj/Common/Reco/OpT0FinderResult.h" // ROOT includes #include "TFile.h" @@ -87,23 +87,11 @@ class sbnd::LightCaloProducer : public art::EDProducer { // Required functions. void produce(art::Event& e) override; - // Selected optional functions. - void beginJob() override; - void endJob() override; - private: - // Matches SimpleFlash time to OpFlashes, fills match_v with succesfully matched OpFlashes - // returns true if match was found - bool MatchOpFlash(std::vector> fm_v, - std::vector> flash_v, - std::vector> &match_v); - // Returns visibility vector for all opdets given charge/position information - void CalcVisibility(std::vector xyz_v, - std::vector charge_v, - std::vector &dir_vis_v, - std::vector &ref_vis_v); + std::vector> CalcVisibility(std::vector xyz_v, + std::vector charge_v); // Fills reconstructed photon count vector (total_gamma_v) for all opdets given charge/position information void CalcLight(std::vector flash_pe_v, @@ -124,21 +112,24 @@ class sbnd::LightCaloProducer : public art::EDProducer { std::vector _opflash_producer_v; std::vector _opflash_ara_producer_v; std::string _slice_producer; - std::string _flashmatch_producer; + std::string _opt0_producer; bool _use_arapucas; + bool _use_opt0; float _nuscore_cut; - float _fmscore_cut; - bool _use_all_planes; + float _fopt0score_cut; bool _verbose; - float _simple_op_offset; + float _fopt0_flash_min; + float _fopt0_flash_max; + float _fopt0_frac_diff_cut; + float _pmt_ara_offset; - float _noise_thresh; - std::vector _pmt_pe_range; + std::vector _noise_thresh; std::vector _cal_area_const; - std::vector _opdet_dir_eff; - std::vector _opdet_ref_eff; + std::vector _opdet_vuv_eff; + std::vector _opdet_vis_eff; + std::vector _opdet_mask; float _scint_prescale; bool _truth_validation; @@ -164,28 +155,35 @@ class sbnd::LightCaloProducer : public art::EDProducer { /// -4: opflashes are below the noise threshold (for this slice) /// 1: successful match + TTree* _tree2; + int _nmatch=0; // number of matches in an event int _pfpid; // ID of the matched slice double _opflash_time; // time of matched opflash std::vector _dep_pe; // vector of measured photo-electron (PE), one entry = one channel - std::vector _rec_gamma; // vector of reconstructed photon counts, one entry = one channel (plane with most hits) + std::vector _rec_gamma; // vector of reconstructed photon count, one entry = one channel double _true_gamma; // true photon count from all energy depositions double _true_charge; // true electron count from all energy depositions double _true_energy; // true deposited energy + std::vector _visibility; + + double _median_gamma; // median of all reconstructed light estimates + double _mean_gamma; // mean of all reconstructed light estimates + + double _mean_charge; // avg charge from all three planes + double _max_charge; // charge from the plane with the highest amount of charge + double _comp_charge; // charge from the plane with the highest number of hits, "highest completeness" + + double _slice_L; // reconstructed photon count + double _slice_Q; // reconstructed electron count + double _slice_E; // reconstructed deposited energy + std::vector _charge = std::vector(3); // reconstructed electron count per plane std::vector _light_med = std::vector(3); // median reconstructed photon count per plane std::vector _light_avg = std::vector(3); // average reconstructed photon count per plane std::vector _energy = std::vector(3); - - double _slice_L; // reconstructed photon count (plane with most hits) - double _slice_Q; // reconstructed electron count for plane with the most hits - double _slice_E; // reconstructed deposited energy, sum of slice_L and slice_Q - - double _frac_L; // light fractional difference: (L_{true} - L_{reco})/(L_{true}) - double _frac_Q; // charge fractional difference: (Q_{true} - Q_{reco})/(Q_{true}) - double _frac_E; // energy fractional difference: (E_{true} - E_{reco})/(E_{true}) }; @@ -200,21 +198,24 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) _opflash_producer_v = p.get>("OpFlashProducers"); _opflash_ara_producer_v = p.get>("OpFlashAraProducers"); _slice_producer = p.get("SliceProducer"); - _flashmatch_producer = p.get("FlashMatchProducer"); + _opt0_producer = p.get("OpT0FinderProducer"); _use_arapucas = p.get("UseArapucas"); + _use_opt0 = p.get("UseOpT0Finder"); _nuscore_cut = p.get("nuScoreCut"); - _fmscore_cut = p.get("fmScoreCut"); - _use_all_planes = p.get("UseAllPlanes"); + _fopt0score_cut = p.get("opt0ScoreCut"); _verbose = p.get("Verbose"); - _simple_op_offset= p.get("SimpleOpFlashOffset"); + _fopt0_flash_min = p.get("OpT0FlashMin"); + _fopt0_flash_max = p.get("OpT0FlashMax"); + _fopt0_frac_diff_cut = p.get("OpT0FractionalCut"); + _pmt_ara_offset = p.get("PMTARAFlashOffset"); - _noise_thresh = p.get("FlashNoiseThreshold"); - _pmt_pe_range = p.get>("PMTPERange"); + _noise_thresh = p.get>("FlashNoiseThreshold"); _cal_area_const = p.get>("CalAreaConstants"); - _opdet_dir_eff = p.get>("OpDetDirectEff"); - _opdet_ref_eff = p.get>("OpDetReflectEff"); + _opdet_vuv_eff = p.get>("OpDetVUVEfficiencies"); + _opdet_vis_eff = p.get>("OpDetVISEfficiencies"); + _opdet_mask = p.get>("OpDetMask"); _scint_prescale = p.get("ScintPreScale"); _truth_validation = p.get("TruthValidation"); @@ -232,15 +233,10 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) void sbnd::LightCaloProducer::produce(art::Event& e) { - - std::unique_ptr> lightcalo_v (new std::vector); - std::unique_ptr> slice_lightcalo_assn_v (new art::Assns); - // services auto const clock_data = art::ServiceHandle()->DataFor(e); auto const det_prop = art::ServiceHandle()->DataFor(e, clock_data); - // std::cout<< "trigger offset TPC: " << clock_data.TriggerOffsetTPC() * 1.6 / 10 << std::endl; art::ServiceHandle g4param; art::ServiceHandle piserv; @@ -248,22 +244,12 @@ void sbnd::LightCaloProducer::produce(art::Event& e) _subrun = e.id().subRun(); _event = e.id().event(); std::cout << "run: " << _run << ", subrun: " << _subrun << ", event: " << _event << std::endl; - - // initialize tree variables - _match_type=0; _pfpid = -1; _opflash_time=-9999; - _dep_pe.clear(); _rec_gamma.clear(); - _true_gamma = -9999; _true_charge = -9999; _true_energy = -9999; - _charge.assign(3,0); _light_med.assign(3,0); _light_avg.assign(3,0); _energy.assign(3,0); - _slice_L = -1; _slice_Q = -1; _slice_E = -1; - _frac_L = -9999; _frac_Q = -9999; _frac_E = -9999; // get slices ::art::Handle> slice_h; e.getByLabel(_slice_producer, slice_h); if(!slice_h.isValid() || slice_h->empty()){ std::cout << "don't have good slices!" << std::endl; - e.put(std::move(lightcalo_v)); - e.put(std::move(slice_lightcalo_assn_v)); return; } @@ -271,8 +257,6 @@ void sbnd::LightCaloProducer::produce(art::Event& e) e.getByLabel(_slice_producer, pfp_h); if(!pfp_h.isValid() || pfp_h->empty()) { std::cout << "don't have good PFParticle!" << std::endl; - e.put(std::move(lightcalo_v)); - e.put(std::move(slice_lightcalo_assn_v)); return; } @@ -280,8 +264,6 @@ void sbnd::LightCaloProducer::produce(art::Event& e) e.getByLabel(_slice_producer, spacepoint_h); if(!spacepoint_h.isValid() || spacepoint_h->empty()) { std::cout << "don't have good SpacePoints!" << std::endl; - e.put(std::move(lightcalo_v)); - e.put(std::move(slice_lightcalo_assn_v)); return; } @@ -291,436 +273,341 @@ void sbnd::LightCaloProducer::produce(art::Event& e) std::cout << "Using PMT OpFlash only..." << std::endl; if( (!flash0_h.isValid() || flash0_h->empty()) && (!flash1_h.isValid() || flash1_h->empty())) { std::cout << "don't have good PMT flashes from producer " << _opflash_producer_v[0] << " or " << _opflash_producer_v[1] << std::endl; - e.put(std::move(lightcalo_v)); - e.put(std::move(slice_lightcalo_assn_v)); return; } - // Construct the vector of Slices - std::vector> slice_v; - art::fill_ptr_vector(slice_v, slice_h); - - // Get associations art::FindManyP slice_to_pfp (slice_h, e, _slice_producer); art::FindManyP slice_to_hit (slice_h, e, _slice_producer); - art::FindManyP pfp_to_meta(pfp_h, e, _slice_producer); - art::FindManyP pfp_to_sfm (pfp_h, e, _flashmatch_producer); art::FindManyP pfp_to_spacepoint(pfp_h, e, _slice_producer); art::FindManyP spacepoint_to_hit(spacepoint_h, e, _slice_producer); std::vector> match_slices_v; - std::vector match_pfpid_v; - std::vector> match_fm_v; - - //------------------------------// + std::vector> match_op0; + std::vector> match_op1; + + if (_use_opt0){ + ::art::Handle> opt0_h; + e.getByLabel(_opt0_producer, opt0_h); + if(!opt0_h.isValid() || opt0_h->empty()) { + std::cout << "don't have good OpT0Finder matches!" << std::endl; + return; + } + std::vector> opt0_v; + art::fill_ptr_vector(opt0_v, opt0_h); - //* OBTAINING VALID SLICES BEGIN *// + std::map, std::vector>> match_slice_opflash_map; + art::FindManyP opt0_to_slice(opt0_h, e, _opt0_producer); + art::FindManyP opt0_to_flash(opt0_h, e, _opt0_producer); - for (size_t n_slice=0; n_slice < slice_v.size(); n_slice++){ - float nu_score = -9999; - float fm_score = -9999; - auto slice = slice_v[n_slice]; - bool found_fm = false; - std::vector> pfp_v = slice_to_pfp.at(n_slice); - for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ - auto pfp = pfp_v[n_pfp]; + for (size_t n_opt0=0; n_opt0 < opt0_v.size(); n_opt0++){ + auto opt0 = opt0_v[n_opt0]; + std::vector> slice_v = opt0_to_slice.at(opt0.key()); + std::vector> flash_v = opt0_to_flash.at(opt0.key()); + + assert(slice_v.size() == 1); + assert(flash_v.size() == 1); + + auto slice = slice_v.front(); + auto flash = flash_v.front(); + + auto opt0_score = opt0->score; + auto opt0_time = opt0->time; + auto opt0_measPE = opt0->measPE; + auto opt0_hypoPE = opt0->hypoPE; + auto opt0_frac_diff = std::abs((opt0_hypoPE - opt0_measPE)/opt0_measPE); + + if (opt0_time < _fopt0_flash_min || opt0_time > _fopt0_flash_max) continue; + if (opt0_score < _fopt0score_cut) continue; + if (opt0_frac_diff > _fopt0_frac_diff_cut) continue; + + // check that slice is not already in the map + auto it = match_slice_opflash_map.find(slice); + if (it == match_slice_opflash_map.end()){ + std::vector> flash_v; + flash_v.push_back(flash); + match_slice_opflash_map.insert(std::pair, std::vector>>(slice, flash_v)); + } + else{ + it->second.push_back(flash); + } + } - // only select the PRIMARY pfp - if(!pfp->IsPrimary()) + for (auto it = match_slice_opflash_map.begin(); it != match_slice_opflash_map.end(); ++it){ + auto slice = it->first; + auto flash_v = it->second; + if (flash_v.size() > 2){ + std::cout << "more than one opflash matched to this slice!" << std::endl; continue; - if(_truth_neutrino && !(abs(pfp->PdgCode()) == 12 || abs(pfp->PdgCode()) == 14|| abs(pfp->PdgCode()) == 16)) - continue; - // if primary, get nu-score - const std::vector> pfpmeta_v = pfp_to_meta.at(pfp.key()); - const art::Ptr pfpmeta = pfpmeta_v.front(); - std::map propmap = pfpmeta->GetPropertiesMap(); - auto propertiesMapIter = propmap.find("NuScore"); - if (propertiesMapIter == propmap.end()){ - nu_score = -1; } - else{nu_score = propertiesMapIter->second;} - - // get fm-score - std::vector> fm_v = pfp_to_sfm.at(pfp.key()); - if (fm_v.empty()){ - std::cout << "No SimpleFlashMatch objects associated with this PFP!" << std::endl; + bool found_opflash0 = false; + bool found_opflash1 = false; + + for (size_t n_flash=0; n_flash < flash_v.size(); n_flash++){ + auto flash = flash_v[n_flash]; + if (flash->XCenter() > 0){ + found_opflash1 = true; + match_op1.push_back(flash); + } + else if (flash->XCenter() < 0){ + found_opflash0 = true; + match_op0.push_back(flash); + } + } // end opflash loop + if (found_opflash0 == false && found_opflash1 == false){ + std::cout << "no opflashes matched to this slice" << std::endl; continue; } - if (fm_v.size() > 1) std::cout << "WARNING: more than one SimpleFlashMatch for one pfp?" << std::endl; - for (size_t n_fm=0; n_fm < fm_v.size(); n_fm++){ - auto fm = fm_v.at(n_fm); - fm_score = fm->score.total; - if (nu_score >= _nuscore_cut && fm_score < _fmscore_cut && fm_score > 0){ - found_fm = true; - match_fm_v.push_back(fm); - if (_verbose) std::cout << "Nuscore: " << nu_score << ", FmScore: " << fm_score << std::endl; - } - } // end flashmatch loop - if (found_fm ==true){ + else if (found_opflash0 || found_opflash1){ match_slices_v.push_back(slice); - match_pfpid_v.push_back(pfp->Self()); - } - } // end pfp loop - } // end slice loop - if (match_slices_v.empty() && !slice_v.empty()){ - std::cout << "no slices passed the cuts" << std::endl; - _match_type = -1; _pfpid = -1; - _tree->Fill(); - e.put(std::move(lightcalo_v)); - e.put(std::move(slice_lightcalo_assn_v)); - return; - } + art::Ptr nullOpFlash; + if (found_opflash0==false) { + match_op0.push_back(nullOpFlash); + } + else if (found_opflash1==false){ + match_op1.push_back(nullOpFlash); + } - if (match_slices_v.size() != match_fm_v.size()){ - std::cout << "slice and flashmatch vector length mismatch!" << std::endl; - e.put(std::move(lightcalo_v)); - e.put(std::move(slice_lightcalo_assn_v)); - return; + } + } // end opt0finder loop } - - //* OBTAINING VALID SLICES END *// - - //------------------------------// - - //* OBTAINING OPFLASH INFORMATION BEGIN*// - // tpc0 - std::vector> flash0_v; - art::fill_ptr_vector(flash0_v, flash0_h); - std::vector> match_op0_v; - bool found_opflash0 = MatchOpFlash(match_fm_v,flash0_v, match_op0_v); - + // else {} std::vector> flash0_ara_v; - // if using arapucas - if (_use_arapucas){ - ::art::Handle> flash0_ara_h; - e.getByLabel(_opflash_ara_producer_v[0],flash0_ara_h); - if (_verbose) std::cout << "Using PMT OpFlash + X-ARAPUCA OpFlash..." << std::endl; - if (!flash0_ara_h.isValid() || flash0_ara_h->empty()) { - std::cout << "don't have good X-ARAPUCA flashes from producer " << _opflash_ara_producer_v[0] << std::endl; - } - else - art::fill_ptr_vector(flash0_ara_v, flash0_ara_h); - } - // tpc1 - std::vector> flash1_v; - art::fill_ptr_vector(flash1_v, flash1_h); - std::vector> match_op1_v; - bool found_opflash1 = MatchOpFlash(match_fm_v,flash1_v, match_op1_v); - std::vector> flash1_ara_v; if (_use_arapucas){ + ::art::Handle> flash0_ara_h; ::art::Handle> flash1_ara_h; - e.getByLabel(_opflash_ara_producer_v[1],flash1_ara_h); - if (_verbose) std::cout << "Using PMT OpFlash + X-ARAPUCA OpFlash..." << std::endl; - if (!flash1_ara_h.isValid() || flash1_ara_h->empty()) { - std::cout << "don't have good X-ARAPUCA flashes from producer " << _opflash_ara_producer_v[1] << std::endl; - } - else - art::fill_ptr_vector(flash1_ara_v, flash1_ara_h); - } - // if no opflashes found in either TPC - if (found_opflash0 == false && found_opflash1 == false){ - std::cout << "No OpFlashes matched to SimpleFlashes (for the entire event)" << std::endl; - for (size_t n_slice=0; n_slice < match_pfpid_v.size(); n_slice++){ - _match_type = -2; - _pfpid = match_pfpid_v.at(n_slice); - _tree->Fill(); + + for (size_t i=0; i<2; i++){ + ::art::Handle> flash_ara_h; + e.getByLabel(_opflash_ara_producer_v[i], flash_ara_h); + if (!flash_ara_h.isValid() || flash_ara_h->empty()) { + std::cout << "don't have good X-ARAPUCA flashes from producer " << _opflash_ara_producer_v[i] << std::endl; + } + else art::fill_ptr_vector((i==0)? flash0_ara_v : flash1_ara_v, flash_ara_h); } - e.put(std::move(lightcalo_v)); - e.put(std::move(slice_lightcalo_assn_v)); - return; } - //* OBTAINING OPFLASH INFORMATION END *// + int nsuccessful_matches=0; for (size_t n_slice=0; n_slice < match_slices_v.size(); n_slice++){ - // initialize tree variables - _pfpid = match_pfpid_v.at(n_slice); - - std::vector> sp_xyz(3); // position info of each spacepoint per plane - std::vector> sp_charge(3); // vector of charge info for charge-weighting for each plane + // initialize tree2 variables + _nmatch++; + _pfpid = -1; - if (_verbose) - std::cout << "Reconstructing slice " << n_slice << std::endl; + _slice_Q = 0; // total amount of charge + _slice_L = 0; // total amount of light + _slice_E = 0; + std::vector sp_xyz; + std::vector sp_charge; // vector of charge info for charge-weighting + double flash_time = -999; - auto opflash0 = (match_op0_v.at(n_slice)); - auto opflash1 = (match_op1_v.at(n_slice)); + auto opflash0 = (match_op0.at(n_slice)); + auto opflash1 = (match_op1.at(n_slice)); bool flash_in_0 = false; bool flash_in_1 = false; - if (!opflash0.isNull()){ - if (opflash0->TotalPE() > _noise_thresh) + // set threshold above noise PE levels for the flash + float noise_thresh = (!_use_arapucas)? _noise_thresh[0] : _noise_thresh[1]; + + if (!opflash0.isNull() && opflash1.isNull()){ + flash_time = opflash0->Time(); + if (opflash0->TotalPE() > noise_thresh) flash_in_0 = true; else if (_verbose) - std::cout << "Flash Total PE in TPC 0 (" << opflash0->TotalPE() << ") below noise threshold ..." << std::endl; + std::cout << "Flash Total PE in TPC 0 (" << opflash0->TotalPE() << ") below noise threshold ... Skipping" << std::endl; } - if (!opflash1.isNull()){ - if (opflash1->TotalPE() > _noise_thresh) + else if ( opflash0.isNull() && !opflash1.isNull()){ + flash_time = opflash1->Time(); + if (opflash1->TotalPE() > noise_thresh) flash_in_1 = true; else if (_verbose) std::cout << "Flash Total PE in TPC 1 (" << opflash1->TotalPE() << ") below noise threshold ... Skipping" << std::endl; - } - if (!flash_in_0 && !flash_in_1){ - if (opflash0.isNull() || opflash1.isNull()){ - std::cout << "No OpFlashes matched with SimpleFlash objects (for this slice)" << std::endl; - _match_type = -3; - } - else if (opflash0->TotalPE() < _noise_thresh|| opflash1->TotalPE() < _noise_thresh){ - std::cout << "All OpFlashes are below noise threshold..." << std::endl; - _match_type = -4; - } - _opflash_time=-9999; - _dep_pe.clear(); _rec_gamma.clear(); - _true_gamma = -9999; _true_charge = -9999; _true_energy = -9999; - _charge.assign(3,0); _light_med.assign(3,0); _light_avg.assign(3,0); _energy.assign(3,0); - _slice_L = -1; _slice_Q = -1; _slice_E = -1; - _frac_L = -9999; _frac_Q = -9999; _frac_E = -9999; + } + else if (!opflash0.isNull() && !opflash1.isNull()){ + flash_time = opflash0->Time(); + if (opflash0->TotalPE() > noise_thresh) + flash_in_0 = true; + else if (_verbose) + std::cout << "Flash Total PE in TPC 0 (" << opflash0->TotalPE() << ") below noise threshold ... Skipping" << std::endl; + if (opflash1->TotalPE() > noise_thresh) + flash_in_1 = true; + else if (_verbose) + std::cout << "Flash Total PE in TPC 1 (" << opflash1->TotalPE() << ") below noise threshold ... Skipping" << std::endl; + } + else if (opflash0.isNull() && opflash1.isNull()){ + std::cout << "No usable opflashes (none above threshold)." << std::endl; + _match_type = -3; _tree->Fill(); - continue; + return; } - - if (flash_in_0) flash_time = opflash0->Time(); - else if (flash_in_1) flash_time = opflash1->Time(); - - _slice_Q = 0; // total amount of charge - _slice_L = 0; // total amount of light - _slice_E = 0; auto slice = match_slices_v[n_slice]; - // sum charge information (without position info) for Q, higher completeness + // sum charge information (without position info) for Q // find which plane has the most integrated charge for this slice std::vector> slice_hits_v = slice_to_hit.at(slice.key()); std::vector plane_charge{0.,0.,0.}; std::vector plane_hits{0,0,0}; for (size_t i=0; i < slice_hits_v.size(); i++){ auto hit = slice_hits_v[i]; - // TODO: fix hardcoded beam readout time - auto drift_time = (hit->PeakTime() - 500)*0.5; // assuming TPC beam readout starts at 500 ticks, conversion = 0.5 us/tick + auto drift_time = hit->PeakTime()*0.5 - clock_data.TriggerOffsetTPC(); double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) auto hit_plane = hit->View(); plane_charge.at(hit_plane) += hit->Integral()*atten_correction*(1/_cal_area_const.at(hit_plane)); plane_hits.at(hit_plane)++; } - int bestPlane = std::max_element(plane_hits.begin(), plane_hits.end()) - plane_hits.begin(); - _slice_Q = plane_charge.at(bestPlane); - _charge = plane_charge; + + uint bestPlane = std::max_element(plane_charge.begin(), plane_charge.end()) - plane_charge.begin(); + uint bestHits = std::max_element(plane_hits.begin(), plane_hits.end()) - plane_hits.begin(); + + _mean_charge = (plane_charge[0] + plane_charge[1] + plane_charge[2])/3; + _max_charge = plane_charge.at(bestPlane); + _comp_charge = plane_charge.at(bestHits); + + _slice_Q = _comp_charge; + // get charge information to create the weighted map std::vector> pfp_v = slice_to_pfp.at(slice.key()); for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ auto pfp = pfp_v[n_pfp]; if (pfp->IsPrimary()) _pfpid = pfp->Self(); + std::vector> sp_v = pfp_to_spacepoint.at(pfp.key()); for (size_t n_sp=0; n_sp < sp_v.size(); n_sp++){ auto sp = sp_v[n_sp]; std::vector> hit_v = spacepoint_to_hit.at(sp.key()); for (size_t n_hit=0; n_hit < hit_v.size(); n_hit++){ auto hit = hit_v[n_hit]; - auto hit_plane = hit->View(); - // if not the best plane and we're only using the best plane - if ( hit_plane != bestPlane && !_use_all_planes) - continue; - else{ - // get position - const auto &position(sp->XYZ()); - geo::Point_t xyz(position[0],position[1],position[2]); - // correct for e- attenuation - geo::TPCGeo const& tpcGeo = geom->TPC({0, 0}); - double drift_time = (2.0*tpcGeo.HalfWidth() - abs(position[0]))/(det_prop.DriftVelocity()); // cm / (cm/us) - double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) - double charge = (1/_cal_area_const.at(hit_plane))*atten_correction*hit->Integral(); - - sp_xyz.at(hit_plane).push_back(xyz); - sp_charge.at(hit_plane).push_back(charge); - } + // + if (hit->View() !=bestHits) continue; + const auto &position(sp->XYZ()); + geo::Point_t xyz(position[0],position[1],position[2]); + // correct for e- attenuation + auto drift_time = hit->PeakTime()*0.5 - clock_data.TriggerOffsetTPC(); + double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) + double charge = (1/_cal_area_const.at(bestPlane))*atten_correction*hit->Integral(); + sp_xyz.push_back(xyz); + sp_charge.push_back(charge); } } // end spacepoint loop } // end pfp loop - std::vector total_pe(_nchan,0.); // contains PE info from both TPCs: PMTs and ARA (if applicable) + + // get total L count + std::vector> visibility_maps = CalcVisibility(sp_xyz,sp_charge); + auto dir_visibility_map = visibility_maps[0]; + auto ref_visibility_map = visibility_maps[1]; + + std::vector total_pe(_nchan,0.); + std::vector total_gamma(_nchan, 0.); // combining flash PE information from separate TPCs into a single vector for (int tpc=0; tpc<2; tpc++){ bool found_flash = (tpc==0)? flash_in_0 : flash_in_1; if (found_flash){ - auto opflash_pe = (tpc==0)? opflash0->PEs() : opflash1->PEs(); - for (size_t ich=0; ich < opflash_pe.size(); ich++) total_pe[ich] += opflash_pe[ich]; + auto flash_pe_v = (tpc==0)? opflash0->PEs() : opflash1->PEs(); // if using arapucas, need to combine PMT and arapuca PE information into a single vector if (_use_arapucas){ auto flash_ara_v = (tpc==0)? flash0_ara_v : flash1_ara_v; - if (flash_ara_v.empty()) // if there are no valid arapuca flashes - std::cout << "Using PMT information Only..." << std::endl; - else{ - for (size_t nara=0; nara < flash_ara_v.size(); nara++){ - auto const &flash_ara = *flash_ara_v[nara]; - if (abs(flash_time-flash_ara.Time()) < _pmt_ara_offset){ - if (_verbose) - std::cout << "Combining PMT+XARA Flashes with PMT time: " << flash_time << ", ARA time: " << flash_ara.Time() << std::endl; - for (size_t ich=0; ich < (flash_ara.PEs()).size(); ich++) - total_pe.at(ich) += (flash_ara.PEs()).at(ich); - break; - } // end if arapuca and pmt flash time match - } // end of arapuca flash loop + // for PMT flashes, the PE vector is shortened and don't include the last 6 entries for ARAPUCAs + if (flash_pe_v.size()!= _nchan) flash_pe_v.insert(flash_pe_v.end(), {0,0,0,0,0,0}); + for (size_t nara=0; nara < flash_ara_v.size(); nara++){ + auto const &flash_ara = *flash_ara_v[nara]; + if (abs(flash_time-flash_ara.Time()) < _pmt_ara_offset){ + if (_verbose) + std::cout << "Combining PMT+XARA Flashes with PMT time: " << flash_time << ", ARA time: " << flash_ara.Time() << std::endl; + for (size_t ich=0; ich < (flash_ara.PEs()).size(); ich++) + flash_pe_v.at(ich) += (flash_ara.PEs()).at(ich); + break; + } } } // end of arapuca if - } // end of found flash if - } // end of TPC loop + for (size_t ich=0; ich lightcalo_charge; - std::vector lightcalo_light; - std::vector lightcalo_energy; - std::vector lightcalo_plane; - - std::vector> total_gamma(3, std::vector(_nchan,0.)); - for (int nplane = 0; nplane<3; nplane++){ - // get total L count - if (!sp_xyz.at(nplane).empty()){ - std::vector dir_vis_v(_nchan, 0.); // direct visibility - std::vector ref_vis_v(_nchan, 0.); // reflected visibility - CalcVisibility(sp_xyz.at(nplane),sp_charge.at(nplane), dir_vis_v, ref_vis_v); - // calculate the photon estimates for every entry in total_pe - CalcLight(total_pe, dir_vis_v, ref_vis_v, total_gamma.at(nplane)); - _light_med.at(nplane) = CalcMedian(total_gamma.at(nplane)); - _light_avg.at(nplane) = CalcMedian(total_gamma.at(nplane)); - _energy.at(nplane) = (_charge.at(nplane) + _light_med.at(nplane))*1e-6*g4param->Wph(); - double gamma_avg = _light_avg.at(nplane); - double gamma_med = _light_med.at(nplane); - if (nplane==bestPlane){ - _rec_gamma = total_gamma.at(nplane); - if (gamma_med!=0 && !std::isnan(gamma_med)) _slice_L = gamma_med; - else _slice_L = gamma_avg; - // if the plane is the bestPlane, insert it at the front - lightcalo_charge.insert(lightcalo_charge.begin(),_charge.at(nplane)); - lightcalo_light.insert(lightcalo_light.begin(),gamma_med); - lightcalo_energy.insert(lightcalo_energy.begin(),_energy.at(nplane)); - lightcalo_plane.insert(lightcalo_plane.begin(),nplane); - } - else{ - lightcalo_charge.push_back(_charge.at(nplane)); - lightcalo_light.push_back(gamma_med); - lightcalo_energy.push_back(_energy.at(nplane)); - lightcalo_plane.push_back(nplane); - } - } - else{ - _light_med.at(nplane) = -1.; _light_avg.at(nplane) = -1.; _energy.at(nplane) = -1.; - lightcalo_charge.push_back(-1.); lightcalo_light.push_back(-1.); lightcalo_energy.push_back(-1.); - lightcalo_plane.push_back(-1); - } - } - _slice_E = _energy.at(bestPlane); - - // sbn::LightCalo lightcalo(lightcalo_charge, lightcalo_light,lightcalo_energy, - // lightcalo_plane,flash_time); + // calculate final light estimate + // ! TODO: final light estimate should be weighted average + // ! where the weights are 1/poisson_err + _median_gamma = CalcMedian(total_gamma); + _mean_gamma = CalcMean(total_gamma); + + if (_median_gamma!=0 && !std::isnan(_median_gamma)) + _slice_L = _median_gamma; + else + _slice_L = _mean_gamma; + + _slice_E = (_slice_L + _slice_Q)*1e-6*g4param->Wph(); // MeV, Wph = 19.5 eV - // lightcalo_v->push_back(lightcalo); - // util::CreateAssn(*this, e, *lightcalo_v, slice, *slice_lightcalo_assn_v); + _true_gamma = 0; + _true_charge = 0; + _true_energy = 0; - ::art::Handle> energyDeps_h; - e.getByLabel(_simenergy_producer, energyDeps_h); - std::vector> energyDeps; - - if (_truth_validation) TruthValidation(e, piserv, flash_time); - else{ - _true_gamma = -9999; _true_charge = -9999; _true_energy = -9999; - _frac_L = -9999; _frac_Q = -9999; _frac_E = -9999; + if (_truth_validation){ + ::art::Handle> energyDeps_h; + e.getByLabel(_simenergy_producer, energyDeps_h); + std::vector> energyDeps; + + if (!energyDeps_h.isValid() || energyDeps_h->empty()) + std::cout << "Don't have good SimEnergyDeposits!" << std::endl; + else + art::fill_ptr_vector(energyDeps, energyDeps_h); + + for (size_t n_dep=0; n_dep < energyDeps.size(); n_dep++){ + auto energyDep = energyDeps[n_dep]; + const auto trackID = energyDep->TrackID(); + const double time = energyDep->Time() * 1e-3; // us + + art::Ptr mctruth = piserv->TrackIdToMCTruth_P(trackID); + + if ((_truth_neutrino && mctruth->Origin()==simb::kBeamNeutrino ) || + (!_truth_neutrino && abs(time-flash_time) < 1)){ + // note: we divide by the prescale because NumPhotons() stored in simulation has the scint prescale applied + _true_gamma += energyDep->NumPhotons()/_scint_prescale; + _true_charge += energyDep->NumElectrons(); + _true_energy += energyDep->Energy(); + } + } } - _match_type = 1; - _tree->Fill(); + else{ + _true_gamma = -9999; + _true_charge = -9999; + _true_energy = -9999; + } + nsuccessful_matches++; } // end slice loop - e.put(std::move(lightcalo_v)); - e.put(std::move(slice_lightcalo_assn_v)); -} - -void sbnd::LightCaloProducer::beginJob() -{ - art::ServiceHandle fs; - _tree = fs->make("slice_tree",""); - - _tree->Branch("run", &_run, "run/I"); - _tree->Branch("subrun", &_subrun, "subrun/I"); - _tree->Branch("event", &_event, "event/I"); - _tree->Branch("match_type", &_match_type, "match_type/I"); - _tree->Branch("pfpid", &_pfpid, "pfpid/I"); - _tree->Branch("opflash_time", &_opflash_time, "opflash_time/D"); - - _tree->Branch("rec_gamma", "std::vector", &_rec_gamma); - _tree->Branch("dep_pe", "std::vector", &_dep_pe); - - _tree->Branch("true_gamma", &_true_gamma, "true_gamma/D"); - _tree->Branch("true_charge", &_true_charge, "true_charge/D"); - _tree->Branch("true_energy", &_true_energy, "true_energy/D"); - - _tree->Branch("charge_plane0", &_charge[0], "charge_plane0/D"); - _tree->Branch("charge_plane1", &_charge[1], "charge_plane1/D"); - _tree->Branch("charge_plane2", &_charge[2], "charge_plane2/D"); - - _tree->Branch("light_med_plane0", &_light_med[0] ,"light_med_plane0/D"); - _tree->Branch("light_med_plane1", &_light_med[1] ,"light_med_plane1/D"); - _tree->Branch("light_med_plane2", &_light_med[2] ,"light_med_plane2/D"); - - _tree->Branch("light_avg_plane0", &_light_avg[0] ,"light_avg_plane0/D"); - _tree->Branch("light_avg_plane1", &_light_avg[1] ,"light_avg_plane1/D"); - _tree->Branch("light_avg_plane2", &_light_avg[2] ,"light_avg_plane2/D"); - - _tree->Branch("energy_plane0", &_energy[0], "energy_plane0/D"); - _tree->Branch("energy_plane1", &_energy[1], "energy_plane1/D"); - _tree->Branch("energy_plane2", &_energy[2], "energy_plane2/D"); - - _tree->Branch("slice_L", &_slice_L, "slice_L/D"); - _tree->Branch("slice_Q", &_slice_Q, "slice_Q/D"); - _tree->Branch("slice_E", &_slice_E, "slice_E/D"); - _tree->Branch("frac_L", &_frac_L, "frac_L/D"); - _tree->Branch("frac_Q", &_frac_Q, "frac_Q/D"); - _tree->Branch("frac_E", &_frac_E, "frac_E/D"); -} + _match_type=nsuccessful_matches; + _tree->Fill(); +} // end analyze -void sbnd::LightCaloProducer::endJob() -{ - // Implementation of optional member function here. -} // define functions -bool sbnd::LightCaloProducer::MatchOpFlash(std::vector> fm_v, - std::vector> flash_v, - std::vector> &match_v){ - bool any_match = false; - for (size_t ifm=0; ifm nullOpFlash; - bool found_match = false; - auto match_time = fm->time; - for (size_t iop=0; iopTime() - match_time) < _simple_op_offset){ - found_match = true; - any_match = true; - match_v.push_back(opflash); - break; - } - } - if (found_match == false) match_v.push_back(nullOpFlash); - } - if (match_v.size() != fm_v.size()) std::cout << "mismatched opflash and simpleflash vector sizes!" << std::endl; - return any_match; -} - - -void sbnd::LightCaloProducer::CalcVisibility(std::vector xyz_v, - std::vector charge_v, - std::vector &dir_vis_v, - std::vector &ref_vis_v){ - // returns of a vector (len is # of opdet) for the visibility for every opdet +std::vector> sbnd::LightCaloProducer::CalcVisibility(std::vector xyz_v, + std::vector charge_v){ + // returns of two vectors (len is # of opdet) for the visibility for every opdet if (xyz_v.size() != charge_v.size()) std::cout << "spacepoint coord and charge vector size mismatch" << std::endl; + + std::vector dir_visibility_map(_nchan, 0); + std::vector ref_visibility_map(_nchan, 0); double sum_charge0 = 0; double sum_charge1 = 0; for (size_t i=0; i xyz_v, std::vector reflect_visibility; _semi_model->detectedDirectVisibilities(direct_visibility, xyz); _semi_model->detectedReflectedVisibilities(reflect_visibility, xyz); - if (dir_vis_v.size() != direct_visibility.size() || ref_vis_v.size() != direct_visibility.size() ) - std::cout << "mismatch of visibility vector size" << std::endl; + // if (dir_visibility_map.size() != direct_visibility.size()) std::cout << "mismatch of visibility vector size" << std::endl; // weight by charge for (size_t ch=0; ch flash_pe_v, std::vector dir_visibility, @@ -764,21 +643,14 @@ void sbnd::LightCaloProducer::CalcLight(std::vector flash_pe_v, std::vector &total_gamma_v){ for (size_t ch = 0; ch < flash_pe_v.size(); ch++){ auto pe = flash_pe_v[ch]; - double efficiency = 0.03; - if((pe == 0) || std::isinf(abs(1/(dir_visibility[ch]+ref_visibility[ch])))) + auto vuv_eff = _opdet_vuv_eff.at(ch); + auto vis_eff = _opdet_vis_eff.at(ch); + auto tot_visibility = vuv_eff*dir_visibility[ch] + vis_eff*ref_visibility[ch]; + _visibility.at(ch) = tot_visibility; + if((pe == 0) || std::isinf(1/tot_visibility)) continue; - if ( pe < _pmt_pe_range.at(0) || pe > _pmt_pe_range.at(1)) - continue; - if (_opdetmap.isPDType(ch, "pmt_uncoated")) - efficiency = _opdet_dir_eff[0]; - else if (_opdetmap.isPDType(ch, "pmt_coated")) - efficiency = _opdet_dir_eff[1]; - else if (_opdetmap.isPDType(ch, "xarapuca_vis")) - efficiency = _opdet_dir_eff[2]; - else if (_opdetmap.isPDType(ch, "xarapuca_vuv")) - efficiency = _opdet_dir_eff[3]; - // deposited light is inverse of efficiency * inverse of visibility * PE count - total_gamma_v[ch] += (1/efficiency)*(1/(dir_visibility[ch]+ref_visibility[ch]))*pe; + // deposited light is inverse of visibility * PE count + total_gamma_v[ch] += (1/tot_visibility)*pe; } } @@ -810,7 +682,7 @@ double sbnd::LightCaloProducer::CalcMedian(std::vector total_gamma){ med_idx = idx.at(int((gamma_v.size()-zero_counter))/2 + zero_counter); median = gamma_v.at(med_idx); } - median_gamma+=median; // sum the two tpc median light + median_gamma+=median; } return median_gamma; } @@ -835,54 +707,9 @@ double sbnd::LightCaloProducer::CalcMean(std::vector total_gamma){ sum+=gamma; } } - if (counter!=0) mean_gamma+= sum/counter; + if (sum!=0) mean_gamma+= sum/counter; } return mean_gamma; } -void sbnd::LightCaloProducer::TruthValidation(art::Event& e, art::ServiceHandle piserv, double flash_time){ - _true_gamma = 0; - _true_charge = 0; - _true_energy = 0; - - ::art::Handle> energyDeps_h; - e.getByLabel(_simenergy_producer, energyDeps_h); - std::vector> energyDeps; - - if (!energyDeps_h.isValid() || energyDeps_h->empty()){ - std::cout << "Don't have good SimEnergyDeposits!" << std::endl; - _true_gamma = -9999; _true_charge = -9999; _true_energy = -9999; - _frac_L = -9999; _frac_Q = -9999; _frac_E = -9999; - return; - } - else art::fill_ptr_vector(energyDeps, energyDeps_h); - - for (size_t n_dep=0; n_dep < energyDeps.size(); n_dep++){ - auto energyDep = energyDeps[n_dep]; - const auto trackID = energyDep->TrackID(); - const double time = energyDep->Time() * 1e-3; // us - - art::Ptr mctruth = piserv->TrackIdToMCTruth_P(trackID); - - // if validating a neutrino event, check that the origin of the deposit is from a beam neutrino - // if validating a non-neutrino event (e.g. cosmics), match the deposit time with the flash time (may not be complete) - if ((_truth_neutrino && mctruth->Origin()==simb::kBeamNeutrino ) || - (!_truth_neutrino && abs(time-flash_time) < 1)){ - // note: we divide by the prescale because NumPhotons() stored in simulation has the scint prescale applied - _true_gamma += energyDep->NumPhotons()/_scint_prescale; - _true_charge += energyDep->NumElectrons(); - _true_energy += energyDep->Energy(); - } - } - _frac_L = _true_gamma > 0? (_true_gamma - _slice_L)/_true_gamma : -9999; - _frac_Q = _true_charge > 0? (_true_charge - _slice_Q)/_true_charge : -9999; - _frac_E = _true_energy > 0? (_true_energy - _slice_E)/_true_energy : -9999; - - if (_verbose){ - std::cout << "ratio of gamma (median/true): " << _slice_L/_true_gamma << std::endl; - std::cout << "ratio of electron (comp/true): " << _slice_Q/_true_charge << std::endl; - std::cout << "ratio of energy (calc/true): " << _slice_E/_true_energy << std::endl; - } -} - DEFINE_ART_MODULE(sbnd::LightCaloProducer) diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index 6f0a235d9..72ee7506f 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -12,25 +12,33 @@ lightcalo: OpFlashAraProducers: ["opflashtpc0xarapuca", "opflashtpc1xarapuca"] SliceProducer: "pandora" FlashMatchProducer: "fmatch" + OpT0FinderProducer: "opt0finder" UseArapucas: false + UseOpT0Finder: true nuScoreCut: 0.4 # default: accept nusScore > 0.4, to analyze all slices, set nuScoreCut = -1 fmScoreCut: 7 # default: accept 0 < fm score < fmScoreCut, to analyze all slices, set fmScoreCut = 1e3 - UseAllPlanes: false # if true: Q, L, E will be calculated separately for each plane (increases computational time) - # if false: Q, L, E will be calculated for best plane only (highest # of hits) + opt0ScoreCut: 200 # default: accept opt0 match > opt0ScoreCut + Verbose: false - # flash parameters SimpleOpFlashOffset: 0.2 # the offset between the t0 from SimpleFlash and OpFlashes + + OpT0FlashMin: 0.0 # simulation [0.0], light-triggered data [-0.8] + OpT0FlashMax: 2.0 # simulation [2.0], light-triggered data [2.0] + OpT0FractionalCut: 0.5 + + # flash parameters PMTARAFlashOffset: 0.05 # the offset between the t0 of PMT OpFlashes and X-ARA OpFlashes - FlashNoiseThreshold: 600. # for PMTS, flash total PE threshold to ignore a flash (below thresh = noise), equivalent to 10 PE per PMT - PMTPERange: [200,3000] # the lower and upper PE thresholds to evaluate a flash. Below lower -> noise, above upper -> non-linearity + FlashNoiseThreshold: [ 600., 1500. ] # {PMT, xARAPUCA}, flash total PE threshold to ignore a flash # calibration constants & simulation parameters ## shouldn't have to change this unless you change simulation parameters - CalAreaConstants: [ 0.0200906, 0.0200016, 0.0201293 ] # calibration constants for wire planes - OpDetDirectEff: [ 0.152, 0.096, 0.01264, 0.01752 ] # direct (VUV) efficiencies ... uncoated PMT, coated PMT, vis ara, vuv ara - OpDetReflectEff: [ 0.152, 0.104, 0.01264, 0.00271 ] # reflected (VIS) efficiencies - ScintPreScale: 0.152 # Scintillation Pre-Scale factor in simulation (set in ionandscint, should be equal to the maximum efficiency above) + CalAreaConstants: [ 0.0200906, 0.0200016, 0.0201293 ] # calibration constants for wire planes + OpDetVUVEfficiencies: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021] + OpDetVISEfficiencies: [0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + OpDetMask : [39, 66, 67, 71, 85, 86, 87, 92, 115, 138, 141, 170, 197, 217, 218, 221, 222, 223, 226, 245, 248, 249, 302] + + ScintPreScale: 0.039 # Scintillation Pre-Scale factor in simulation (set in ionandscint) # parameters for truth validation TruthValidation: false # can only set to true if the reco2 files have SimEnergyDeposits From f4a7206c84fd8a753643a9129aa9d6b881c037c7 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 13 Nov 2025 13:00:04 -0600 Subject: [PATCH 41/52] add more features to mccalo, now assumes only ONE neutrino interaction per event --- sbndcode/Calorimetry/MCCaloAna_module.cc | 171 +++++++++++++++++------ sbndcode/Calorimetry/run_mcana.fcl | 2 +- 2 files changed, 126 insertions(+), 47 deletions(-) diff --git a/sbndcode/Calorimetry/MCCaloAna_module.cc b/sbndcode/Calorimetry/MCCaloAna_module.cc index 6b70b2ddf..a73ab8bda 100644 --- a/sbndcode/Calorimetry/MCCaloAna_module.cc +++ b/sbndcode/Calorimetry/MCCaloAna_module.cc @@ -60,11 +60,18 @@ class sbnd::MCCaloAna : public art::EDAnalyzer { int _subrun; int _event; - std::vector _nu_E; - std::vector _nu_CCNC; - std::vector _true_gamma; - std::vector _true_charge; - std::vector _true_energy; + double _nu_E; + double _nu_P; + int _nu_CCNC; + double _nu_X; + double _nu_Y; + double _nu_Z; + + double _min_x, _max_x, _min_y, _max_y, _min_z, _max_z; + + double _true_gamma; + double _true_charge; + double _true_energy; std::vector _true_gamma_tpc; std::vector _true_measphotons; @@ -72,9 +79,11 @@ class sbnd::MCCaloAna : public art::EDAnalyzer { std::vector _chargecorr_gamma; std::vector _chargecorr_visibility; + std::vector _chargecorr_visibility_witheff; std::vector _lightcorr_gamma; std::vector _lightcorr_gamma_resim; std::vector _lightcorr_visibility; + std::vector _lightcorr_visibility_witheff; std::vector _opdet_vuv_eff; std::vector _opdet_vis_eff; @@ -110,22 +119,34 @@ sbnd::MCCaloAna::MCCaloAna(fhicl::ParameterSet const& p) art::ServiceHandle fs; _tree = fs->make("mccalo_tree",""); - _tree->Branch("run", &_run, "run/I"); - _tree->Branch("subrun", &_subrun, "subrun/I"); - _tree->Branch("event", &_event, "event/I"); - _tree->Branch("nu_E", "std::vector", &_nu_E); - _tree->Branch("nu_CCNC", "std::vector", &_nu_CCNC); - _tree->Branch("true_gamma", "std::vector", &_true_gamma); - _tree->Branch("true_charge", "std::vector", &_true_charge); - _tree->Branch("true_energy", "std::vector", &_true_energy); + _tree->Branch("run", &_run, "run/I"); + _tree->Branch("subrun", &_subrun, "subrun/I"); + _tree->Branch("event", &_event, "event/I"); + _tree->Branch("nu_E", &_nu_E, "nu_E/D"); + _tree->Branch("nu_P", &_nu_P, "nu_P/D"); + _tree->Branch("nu_CCNC", &_nu_CCNC, "nu_CCNC/I"); + _tree->Branch("nu_X", &_nu_X, "nu_X/D"); + _tree->Branch("nu_Y", &_nu_Y, "nu_Y/D"); + _tree->Branch("nu_Z", &_nu_Z, "nu_Z/D"); + _tree->Branch("max_x", &_max_x, "max_x/D"); + _tree->Branch("max_y", &_max_y, "max_y/D"); + _tree->Branch("max_z", &_max_z, "max_z/D"); + _tree->Branch("min_x", &_min_x, "min_x/D"); + _tree->Branch("min_y", &_min_y, "min_y/D"); + _tree->Branch("min_z", &_min_z, "min_z/D"); + _tree->Branch("true_gamma", &_true_gamma, "true_gamma/D"); + _tree->Branch("true_charge", &_true_charge, "true_charge/D"); + _tree->Branch("true_energy", &_true_energy, "true_energy/D"); _tree->Branch("true_gamma_tpc", "std::vector", &_true_gamma_tpc); _tree->Branch("true_measphotons","std::vector", &_true_measphotons); _tree->Branch("true_resimphotons","std::vector", &_true_resimphotons); _tree->Branch("chargecorr_gamma", "std::vector", &_chargecorr_gamma); _tree->Branch("chargecorr_visibility","std::vector", &_chargecorr_visibility); + _tree->Branch("chargecorr_visibility_witheff","std::vector", &_chargecorr_visibility_witheff); _tree->Branch("lightcorr_gamma", "std::vector", &_lightcorr_gamma); _tree->Branch("lightcorr_gamma_resim","std::vector",&_lightcorr_gamma_resim); _tree->Branch("lightcorr_visibility","std::vector", &_lightcorr_visibility); + _tree->Branch("lightcorr_visibility_witheff","std::vector", &_lightcorr_visibility_witheff); } void sbnd::MCCaloAna::analyze(art::Event const& e) @@ -134,11 +155,18 @@ void sbnd::MCCaloAna::analyze(art::Event const& e) _subrun = e.id().subRun(); _event = e.id().event(); - _nu_E.clear(); - _nu_CCNC.clear(); - _true_gamma.clear(); - _true_charge.clear(); - _true_energy.clear(); + _nu_E = 0; + _nu_P = 0; + _nu_CCNC = -1; + _nu_X = -999; + _nu_Y = -999; + _nu_Z = -999; + _true_gamma = 0; + _true_charge = 0; + _true_energy = 0; + + _min_x = _min_y = _min_z = 1e9; + _max_x = _max_y = _max_z = -1e9; _true_gamma_tpc.clear(); _true_measphotons.clear(); @@ -146,9 +174,11 @@ void sbnd::MCCaloAna::analyze(art::Event const& e) _chargecorr_gamma.clear(); _chargecorr_visibility.clear(); + _chargecorr_visibility_witheff.clear(); _lightcorr_gamma.clear(); _lightcorr_gamma_resim.clear(); _lightcorr_visibility.clear(); + _lightcorr_visibility_witheff.clear(); art::ServiceHandle piserv; @@ -172,17 +202,12 @@ void sbnd::MCCaloAna::analyze(art::Event const& e) fLitePhotonHandle_list = e.getMany>(); auto opdet_simphotons = FillSimPhotonsLite(fLitePhotonHandle_list); - std::vector> edep_photons; - std::vector> edep_electrons; - std::vector> edep_energy; - std::vector> edep_points; + std::vector edep_photons; + std::vector edep_electrons; + std::vector edep_energy; + std::vector edep_points; // std::vector> edep_x, edep_y, edep_z; - _nu_E.resize(mctruths.size(), 0); - _nu_CCNC.resize(mctruths.size(), 0); - _true_gamma.resize(mctruths.size(), 0); - _true_charge.resize(mctruths.size(), 0); - _true_energy.resize(mctruths.size(), 0); _true_measphotons.resize(_nchan,0); _true_resimphotons.resize(_nchan,0); @@ -198,34 +223,65 @@ void sbnd::MCCaloAna::analyze(art::Event const& e) const auto trackID = energyDep->TrackID(); art::Ptr mctruth = piserv->TrackIdToMCTruth_P(trackID); - if (mctruth->Origin() != simb::kBeamNeutrino) continue; - auto it = std::find(mctruths.begin(), mctruths.end(), mctruth); - if (it == mctruths.end()) { - std::cout << "No matching MCTruth found for trackID: " << trackID << std::endl; - continue; + auto nparticles = mctruth->NParticles(); + std::cout << "nparticles: " << nparticles << std::endl; + if (mctruth->Origin() == simb::kBeamNeutrino) + _nu_CCNC = mctruth->GetNeutrino().CCNC(); + for (int p=0; p < nparticles; p++){ + simb::MCParticle const& par = mctruth->GetParticle(p); + std::cout << "pdg: " << par.PdgCode() << std::endl; + if (par.StatusCode()==0 && mctruth->Origin()==simb::kBeamNeutrino){ + _nu_E = par.E(); + _nu_P = par.P(); + _nu_X = par.Vx(); + _nu_Y = par.Vy(); + _nu_Z = par.Vz(); + break; + } + else if (par.StatusCode()==1 && mctruth->Origin()==4){ + _nu_E = par.E(); + _nu_P = par.P(); + _nu_X = par.Vx(); + _nu_Y = par.Vy(); + _nu_Z = par.Vz(); + break; + } } - // get the index of the mctruth in the set - auto mctruth_index = std::distance(mctruths.begin(), it); + // auto it = std::find(mctruths.begin(), mctruths.end(), mctruth); + // if (it == mctruths.end()) { + // std::cout << "No matching MCTruth found for trackID: " << trackID << std::endl; + // continue; + // } - _true_gamma[mctruth_index] += energyDep->NumPhotons(); - _true_charge[mctruth_index] += energyDep->NumElectrons(); - _true_energy[mctruth_index] += energyDep->Energy(); + // // get the index of the mctruth in the set + // auto mctruth_index = std::distance(mctruths.begin(), it); - edep_photons.at(mctruth_index).push_back(energyDep->NumPhotons()); - edep_electrons.at(mctruth_index).push_back(energyDep->NumElectrons()); - edep_energy.at(mctruth_index).push_back(energyDep->Energy()); - edep_points.at(mctruth_index).push_back(energyDep->Start()); + _true_gamma += energyDep->NumPhotons(); + _true_charge += energyDep->NumElectrons(); + _true_energy += energyDep->Energy(); + + edep_photons.push_back(energyDep->NumPhotons()); + edep_electrons.push_back(energyDep->NumElectrons()); + edep_energy.push_back(energyDep->Energy()); + edep_points.push_back(energyDep->Start()); if (energyDep->Start().X() < 0) _true_gamma_tpc.at(0) += energyDep->NumPhotons(); else _true_gamma_tpc.at(1) += energyDep->NumPhotons(); + + if (energyDep->Start().X() > _max_x) _max_x = energyDep->Start().X(); + if (energyDep->Start().Y() > _max_y) _max_y = energyDep->Start().Y(); + if (energyDep->Start().Z() > _max_z) _max_z = energyDep->Start().Z(); + if (energyDep->Start().X() < _min_x) _min_x = energyDep->Start().X(); + if (energyDep->Start().Y() < _min_y) _min_y = energyDep->Start().Y(); + if (energyDep->Start().Z() < _min_z) _min_z = energyDep->Start().Z(); } - auto resim_pe = CalcPE(edep_points.at(0),edep_photons.at(0)); + auto resim_pe = CalcPE(edep_points,edep_photons); for (size_t ich=0; ich < opdet_simphotons.at(0).size(); ich++){ std::string pd_type = _opdetmap.pdType(ich); @@ -237,17 +293,27 @@ void sbnd::MCCaloAna::analyze(art::Event const& e) } for (size_t nnu; nnu < mctruths.size(); nnu++){ - auto true_vis_charge = CalcVisibility(edep_points.at(nnu),edep_electrons.at(nnu)); - auto true_vis_light = CalcVisibility(edep_points.at(nnu),edep_photons.at(nnu)); + auto true_vis_charge = CalcVisibility(edep_points,edep_electrons); + auto true_vis_light = CalcVisibility(edep_points,edep_photons); _chargecorr_gamma.resize(_nchan,0); _chargecorr_visibility.resize(_nchan,0); + _chargecorr_visibility_witheff.resize(_nchan,0); _lightcorr_gamma.resize(_nchan,0); _lightcorr_gamma_resim.resize(_nchan,0); _lightcorr_visibility.resize(_nchan,0); + _lightcorr_visibility_witheff.resize(_nchan,0); + CalcLight(_true_measphotons, true_vis_charge.at(0), true_vis_charge.at(1),_chargecorr_gamma,_chargecorr_visibility); CalcLight(_true_measphotons, true_vis_light.at(0), true_vis_light.at(1),_lightcorr_gamma,_lightcorr_visibility); CalcLight(_true_resimphotons, true_vis_light.at(0), true_vis_light.at(1),_lightcorr_gamma_resim,_lightcorr_visibility); + + for (uint ch = 0; ch < _nchan; ch++){ + auto vuv_eff = _opdet_vuv_eff.at(ch); + auto vis_eff = _opdet_vis_eff.at(ch); + _chargecorr_visibility_witheff[ch] = vuv_eff*true_vis_charge.at(0)[ch] + vis_eff*true_vis_charge.at(1)[ch]; + _lightcorr_visibility_witheff[ch] = vuv_eff*true_vis_light.at(0)[ch] + vis_eff*true_vis_light.at(1)[ch]; + } } _tree->Fill(); @@ -263,9 +329,12 @@ std::vector> sbnd::MCCaloAna::CalcVisibility(std::vector> sbnd::MCCaloAna::CalcVisibility(std::vector reflect_visibility; _semi_model->detectedDirectVisibilities(direct_visibility, xyz); _semi_model->detectedReflectedVisibilities(reflect_visibility, xyz); - // if (dir_visibility_map.size() != direct_visibility.size()) std::cout << "mismatch of visibility vector size" << std::endl; - + if (dir_visibility_map.size() != direct_visibility.size()) std::cout << "mismatch of visibility vector size" << std::endl; + // if (i < 10){ + // std::cout << "xyz: " << xyz << std::endl; + // std::cout << "charge: " << charge << std::endl; + // std::cout << "dir_visibility : " << direct_visibility[7] << std::endl; + // std::cout << "ref_visibility : " << reflect_visibility[7] << std::endl; + // std::cout << "dir_visibility_map: " << dir_visibility_map[7] << std::endl; + // std::cout << "ref_visibility_map: " << ref_visibility_map[7] << std::endl; + // } // weight by charge for (size_t ch=0; ch> sbnd::MCCaloAna::CalcPE(std::vector direct_visibility; std::vector reflect_visibility; diff --git a/sbndcode/Calorimetry/run_mcana.fcl b/sbndcode/Calorimetry/run_mcana.fcl index 55de8b041..169f78a91 100644 --- a/sbndcode/Calorimetry/run_mcana.fcl +++ b/sbndcode/Calorimetry/run_mcana.fcl @@ -41,7 +41,7 @@ physics: } # define the output stream, there could be more than one if using filters - stream1: [mccaloana] + stream1: [out1, mccaloana] # trigger_paths is a keyword and contains the paths that modify the art::event, # ie filters and producers From 103c567b9dc0a07b544e3809c6c649effb892236 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 13 Nov 2025 14:06:51 -0600 Subject: [PATCH 42/52] updates to calls for semi analytical model, now using optical path tool --- sbndcode/Calorimetry/CMakeLists.txt | 2 +- sbndcode/Calorimetry/LightCaloAna_module.cc | 6 +++++- sbndcode/Calorimetry/LightCaloProducer_module.cc | 7 +++++-- sbndcode/Calorimetry/MCCaloAna_config.fcl | 1 + sbndcode/Calorimetry/MCCaloAna_module.cc | 7 ++++++- sbndcode/Calorimetry/lightcalo.fcl | 1 + sbndcode/Calorimetry/lightcalo_ana.fcl | 1 + 7 files changed, 20 insertions(+), 5 deletions(-) diff --git a/sbndcode/Calorimetry/CMakeLists.txt b/sbndcode/Calorimetry/CMakeLists.txt index b4c264484..5f33e235e 100644 --- a/sbndcode/Calorimetry/CMakeLists.txt +++ b/sbndcode/Calorimetry/CMakeLists.txt @@ -2,6 +2,7 @@ set (MODULE_LIBRARIES larsim::Utils larsim::PhotonPropagation larsim::PhotonPropagation_PhotonVisibilityService_service + larsim::OpticalPath larsim::LegacyLArG4 larcorealg::GeoAlgo larcorealg::Geometry @@ -26,7 +27,6 @@ set (MODULE_LIBRARIES art::Utilities canvas::canvas messagefacility::MF_MessageLogger sbnobj::Common_Reco - fhiclcpp::fhiclcpp ROOT::Geom ROOT::XMLIO diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc index 42343ed60..a68baec20 100644 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ b/sbndcode/Calorimetry/LightCaloAna_module.cc @@ -16,6 +16,7 @@ #include "art/Framework/Principal/Handle.h" #include "art/Framework/Principal/Run.h" #include "art/Framework/Principal/SubRun.h" +#include "art/Utilities/make_tool.h" #include "canvas/Utilities/InputTag.h" #include "fhiclcpp/ParameterSet.h" #include "messagefacility/MessageLogger/MessageLogger.h" @@ -50,6 +51,7 @@ #include "larcore/Geometry/Geometry.h" #include "larcorealg/Geometry/GeometryCore.h" #include "larsim/PhotonPropagation/SemiAnalyticalModel.h" +#include "larsim/PhotonPropagation/OpticalPathTools/OpticalPath.h" #include "larsim/Simulation/LArG4Parameters.h" #include "larsim/MCCheater/ParticleInventoryService.h" #include "lardata/DetectorInfoServices/DetectorClocksService.h" @@ -147,6 +149,7 @@ class sbnd::LightCaloAna : public art::EDAnalyzer { std::unique_ptr _semi_model; fhicl::ParameterSet _vuv_params; fhicl::ParameterSet _vis_params; + std::shared_ptr _optical_path_tool; opdet::sbndPDMapAlg _opdetmap; //map for photon detector types unsigned int _nchan = _opdetmap.size(); @@ -198,7 +201,8 @@ sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) { _vuv_params = p.get("VUVHits"); _vis_params = p.get("VIVHits"); - _semi_model = std::make_unique(_vuv_params, _vis_params, true, false); + _optical_path_tool = std::shared_ptr(art::make_tool(p.get("OpticalPathTool"))); + _semi_model = std::make_unique(_vuv_params, _vis_params, _optical_path_tool, true, false); _opflash_producer_v = p.get>("OpFlashProducers"); _opflash_ara_producer_v = p.get>("OpFlashAraProducers"); diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 4591450df..b745b892e 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -13,6 +13,7 @@ #include "art/Framework/Principal/Handle.h" #include "art/Framework/Principal/Run.h" #include "art/Framework/Principal/SubRun.h" +#include "art/Utilities/make_tool.h" #include "canvas/Utilities/InputTag.h" #include "fhiclcpp/ParameterSet.h" #include "messagefacility/MessageLogger/MessageLogger.h" @@ -36,7 +37,6 @@ #include "lardataobj/RecoBase/Wire.h" #include "lardataobj/RecoBase/OpFlash.h" #include "lardataobj/AnalysisBase/T0.h" - #include "lardataobj/Simulation/SimPhotons.h" #include "lardataobj/Simulation/SimEnergyDeposit.h" #include "nusimdata/SimulationBase/GTruth.h" @@ -48,6 +48,7 @@ #include "larcore/Geometry/Geometry.h" #include "larcorealg/Geometry/GeometryCore.h" #include "larsim/PhotonPropagation/SemiAnalyticalModel.h" +#include "larsim/PhotonPropagation/OpticalPathTools/OpticalPath.h" #include "larsim/Simulation/LArG4Parameters.h" #include "larsim/MCCheater/ParticleInventoryService.h" #include "lardata/DetectorInfoServices/DetectorClocksService.h" @@ -148,6 +149,7 @@ class sbnd::LightCaloProducer : public art::EDProducer { std::unique_ptr _semi_model; fhicl::ParameterSet _vuv_params; fhicl::ParameterSet _vis_params; + std::shared_ptr _optical_path_tool; opdet::sbndPDMapAlg _opdetmap; //map for photon detector types unsigned int _nchan = _opdetmap.size(); @@ -195,7 +197,8 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) { _vuv_params = p.get("VUVHits"); _vis_params = p.get("VIVHits"); - _semi_model = std::make_unique(_vuv_params, _vis_params, true, false); + _optical_path_tool = std::shared_ptr(art::make_tool(p.get("OpticalPathTool"))); + _semi_model = std::make_unique(_vuv_params, _vis_params, _optical_path_tool, true, false); _opflash_producer_v = p.get>("OpFlashProducers"); _opflash_ara_producer_v = p.get>("OpFlashAraProducers"); diff --git a/sbndcode/Calorimetry/MCCaloAna_config.fcl b/sbndcode/Calorimetry/MCCaloAna_config.fcl index a53a9b26b..2f988ea28 100644 --- a/sbndcode/Calorimetry/MCCaloAna_config.fcl +++ b/sbndcode/Calorimetry/MCCaloAna_config.fcl @@ -1,4 +1,5 @@ #include "opticalsimparameterisations_sbnd.fcl" +#include "sbndopticalpath_tool.fcl" BEGIN_PROLOG mccaloana: diff --git a/sbndcode/Calorimetry/MCCaloAna_module.cc b/sbndcode/Calorimetry/MCCaloAna_module.cc index 6b70b2ddf..0c713eb07 100644 --- a/sbndcode/Calorimetry/MCCaloAna_module.cc +++ b/sbndcode/Calorimetry/MCCaloAna_module.cc @@ -13,6 +13,7 @@ #include "art/Framework/Principal/Handle.h" #include "art/Framework/Principal/Run.h" #include "art/Framework/Principal/SubRun.h" +#include "art/Utilities/make_tool.h" #include "canvas/Utilities/InputTag.h" #include "fhiclcpp/ParameterSet.h" #include "messagefacility/MessageLogger/MessageLogger.h" @@ -23,6 +24,7 @@ #include "nusimdata/SimulationBase/MCTruth.h" #include "larsim/PhotonPropagation/SemiAnalyticalModel.h" +#include "larsim/PhotonPropagation/OpticalPathTools/OpticalPath.h" #include "larcore/Geometry/Geometry.h" #include "larcorealg/Geometry/GeometryCore.h" #include "sbndcode/OpDetSim/sbndPDMapAlg.hh" @@ -82,6 +84,8 @@ class sbnd::MCCaloAna : public art::EDAnalyzer { std::unique_ptr _semi_model; fhicl::ParameterSet _vuv_params; fhicl::ParameterSet _vis_params; + std::shared_ptr _optical_path_tool; + opdet::sbndPDMapAlg _opdetmap; //map for photon detector types unsigned int _nchan = _opdetmap.size(); @@ -104,7 +108,8 @@ sbnd::MCCaloAna::MCCaloAna(fhicl::ParameterSet const& p) { _vuv_params = p.get("VUVHits"); _vis_params = p.get("VIVHits"); - _semi_model = std::make_unique(_vuv_params, _vis_params, true, false); + _optical_path_tool = std::shared_ptr(art::make_tool(p.get("OpticalPathTool"))); + _semi_model = std::make_unique(_vuv_params, _vis_params, _optical_path_tool, true, false); _opdet_vuv_eff = p.get>("OpDetVUVEfficiencies"); _opdet_vis_eff = p.get>("OpDetVISEfficiencies"); diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index 6f0a235d9..d842a2d56 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -1,4 +1,5 @@ #include "opticalsimparameterisations_sbnd.fcl" +#include "sbndopticalpath_tool.fcl" BEGIN_PROLOG lightcalo: diff --git a/sbndcode/Calorimetry/lightcalo_ana.fcl b/sbndcode/Calorimetry/lightcalo_ana.fcl index 4924945be..8b557567f 100644 --- a/sbndcode/Calorimetry/lightcalo_ana.fcl +++ b/sbndcode/Calorimetry/lightcalo_ana.fcl @@ -1,4 +1,5 @@ #include "opticalsimparameterisations_sbnd.fcl" +#include "sbndopticalpath_tool.fcl" BEGIN_PROLOG lightcaloana: From 81b6742c44c385418935d1a9e6146254401f20af Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 13 Nov 2025 16:35:54 -0600 Subject: [PATCH 43/52] remove simpleflash, add barycenter fm, add template class for collecting matches, add weighted avg - update median calculation to use `nth_element` - compiles but have not yet tested output --- .../Calorimetry/LightCaloProducer_module.cc | 315 ++++++++++-------- sbndcode/Calorimetry/lightcalo.fcl | 12 +- 2 files changed, 186 insertions(+), 141 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 4ecfeeca5..8c3a11a61 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -58,6 +58,7 @@ #include "sbndcode/OpDetSim/sbndPDMapAlg.hh" #include "sbnobj/Common/Reco/LightCaloInfo.h" #include "sbnobj/Common/Reco/OpT0FinderResult.h" +#include "sbnobj/Common/Reco/TPCPMTBarycenterMatch.h" // ROOT includes #include "TFile.h" @@ -67,6 +68,9 @@ #include #include #include // sort +#include +#include +#include namespace sbnd { class LightCaloProducer; @@ -90,6 +94,16 @@ class sbnd::LightCaloProducer : public art::EDProducer { private: + template + void collect_matches(const art::Handle> &handle, + const std::vector> &fm_v, + const std::string &label, + art::Event &e, + std::vector> &match_slices_v, + std::vector> &match_op0, + std::vector> &match_op1, + CheckFunc check); + // Returns visibility vector for all opdets given charge/position information std::vector> CalcVisibility(std::vector xyz_v, std::vector charge_v); @@ -105,6 +119,7 @@ class sbnd::LightCaloProducer : public art::EDProducer { // Returns the mean of the light vector double CalcMean(std::vector total_light); + double CalcMean(std::vector total_light, std::vector total_err); // Performs truth validation, saves info to TTree void TruthValidation(art::Event& e, art::ServiceHandle piserv, double flash_time); @@ -114,14 +129,17 @@ class sbnd::LightCaloProducer : public art::EDProducer { std::vector _opflash_ara_producer_v; std::string _slice_producer; std::string _opt0_producer; + std::string _bcfm_producer; + bool _use_arapucas; bool _use_opt0; + bool _use_bcfm; float _nuscore_cut; float _fopt0score_cut; bool _verbose; - float _fopt0_flash_min; - float _fopt0_flash_max; + float _fopflash_min; + float _fopflash_max; float _fopt0_frac_diff_cut; float _pmt_ara_offset; @@ -202,14 +220,16 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) _opflash_ara_producer_v = p.get>("OpFlashAraProducers"); _slice_producer = p.get("SliceProducer"); _opt0_producer = p.get("OpT0FinderProducer"); + _bcfm_producer = p.get("BCFMProducer"); _use_arapucas = p.get("UseArapucas"); _use_opt0 = p.get("UseOpT0Finder"); + _use_bcfm = p.get("UseBCFM"); _nuscore_cut = p.get("nuScoreCut"); _fopt0score_cut = p.get("opt0ScoreCut"); _verbose = p.get("Verbose"); - _fopt0_flash_min = p.get("OpT0FlashMin"); - _fopt0_flash_max = p.get("OpT0FlashMax"); + _fopflash_min = p.get("OpFlashMin"); + _fopflash_max = p.get("OpFlashMax"); _fopt0_frac_diff_cut = p.get("OpT0FractionalCut"); _pmt_ara_offset = p.get("PMTARAFlashOffset"); @@ -282,98 +302,54 @@ void sbnd::LightCaloProducer::produce(art::Event& e) art::FindManyP slice_to_pfp (slice_h, e, _slice_producer); art::FindManyP slice_to_hit (slice_h, e, _slice_producer); art::FindManyP pfp_to_spacepoint(pfp_h, e, _slice_producer); - art::FindManyP spacepoint_to_hit(spacepoint_h, e, _slice_producer); + art::FindManyP spacepoint_to_hit(spacepoint_h, e, _slice_producer); std::vector> match_slices_v; std::vector> match_op0; std::vector> match_op1; - if (_use_opt0){ - ::art::Handle> opt0_h; - e.getByLabel(_opt0_producer, opt0_h); - if(!opt0_h.isValid() || opt0_h->empty()) { - std::cout << "don't have good OpT0Finder matches!" << std::endl; - return; - } - std::vector> opt0_v; - art::fill_ptr_vector(opt0_v, opt0_h); - - std::map, std::vector>> match_slice_opflash_map; - art::FindManyP opt0_to_slice(opt0_h, e, _opt0_producer); - art::FindManyP opt0_to_flash(opt0_h, e, _opt0_producer); - - for (size_t n_opt0=0; n_opt0 < opt0_v.size(); n_opt0++){ - auto opt0 = opt0_v[n_opt0]; - std::vector> slice_v = opt0_to_slice.at(opt0.key()); - std::vector> flash_v = opt0_to_flash.at(opt0.key()); - - assert(slice_v.size() == 1); - assert(flash_v.size() == 1); - - auto slice = slice_v.front(); - auto flash = flash_v.front(); - - auto opt0_score = opt0->score; - auto opt0_time = opt0->time; - auto opt0_measPE = opt0->measPE; - auto opt0_hypoPE = opt0->hypoPE; - auto opt0_frac_diff = std::abs((opt0_hypoPE - opt0_measPE)/opt0_measPE); - - if (opt0_time < _fopt0_flash_min || opt0_time > _fopt0_flash_max) continue; - if (opt0_score < _fopt0score_cut) continue; - if (opt0_frac_diff > _fopt0_frac_diff_cut) continue; - - // check that slice is not already in the map - auto it = match_slice_opflash_map.find(slice); - if (it == match_slice_opflash_map.end()){ - std::vector> flash_v; - flash_v.push_back(flash); - match_slice_opflash_map.insert(std::pair, std::vector>>(slice, flash_v)); - } - else{ - it->second.push_back(flash); - } - } + std::map, std::vector>> match_slice_opflash_map; - for (auto it = match_slice_opflash_map.begin(); it != match_slice_opflash_map.end(); ++it){ - auto slice = it->first; - auto flash_v = it->second; - if (flash_v.size() > 2){ - std::cout << "more than one opflash matched to this slice!" << std::endl; - continue; - } - bool found_opflash0 = false; - bool found_opflash1 = false; - - for (size_t n_flash=0; n_flash < flash_v.size(); n_flash++){ - auto flash = flash_v[n_flash]; - if (flash->XCenter() > 0){ - found_opflash1 = true; - match_op1.push_back(flash); - } - else if (flash->XCenter() < 0){ - found_opflash0 = true; - match_op0.push_back(flash); - } - } // end opflash loop - if (found_opflash0 == false && found_opflash1 == false){ - std::cout << "no opflashes matched to this slice" << std::endl; - continue; - } - else if (found_opflash0 || found_opflash1){ - match_slices_v.push_back(slice); - art::Ptr nullOpFlash; - if (found_opflash0==false) { - match_op0.push_back(nullOpFlash); - } - else if (found_opflash1==false){ - match_op1.push_back(nullOpFlash); - } + // * get flash matched objects + ::art::Handle> bcfm_h; + e.getByLabel(_bcfm_producer, bcfm_h); + if(!bcfm_h.isValid() || bcfm_h->empty()) { + std::cout << "don't have good barycenter matches!" << std::endl; + return; + } + std::vector> bcfm_v; + art::fill_ptr_vector(bcfm_v, bcfm_h); - } - } // end opt0finder loop + ::art::Handle> opt0_h; + e.getByLabel(_opt0_producer, opt0_h); + if(!opt0_h.isValid() || opt0_h->empty()) { + std::cout << "don't have good OpT0Finder matches!" << std::endl; + return; + } + std::vector> opt0_v; + art::fill_ptr_vector(opt0_v, opt0_h); + + // use templated member helper to fill match vectors + if (_use_bcfm) { + collect_matches(bcfm_h, bcfm_v, _bcfm_producer, e, match_slices_v, match_op0, match_op1, + [this](art::Ptr bcfm) { + if (bcfm->flashTime > _fopflash_max || bcfm->flashTime < _fopflash_min) return false; + if (bcfm->score < 0.02) return false; + return true; + }); + } + else { + collect_matches(opt0_h, opt0_v, _opt0_producer, e, match_slices_v, match_op0, match_op1, + [this](art::Ptr opt0){ + auto opt0_measPE = opt0->measPE; + auto opt0_hypoPE = opt0->hypoPE; + auto opt0_frac_diff = std::abs((opt0_hypoPE - opt0_measPE)/opt0_measPE); + if (opt0->time < _fopflash_min || opt0->time > _fopflash_max) return false; + if (opt0->score < _fopt0score_cut) return false; + if (opt0_frac_diff > _fopt0_frac_diff_cut) return false; + return true; + }); } - // else {} std::vector> flash0_ara_v; std::vector> flash1_ara_v; if (_use_arapucas){ @@ -499,6 +475,7 @@ void sbnd::LightCaloProducer::produce(art::Event& e) auto ref_visibility_map = visibility_maps[1]; std::vector total_pe(_nchan,0.); + std::vector total_err(_nchan,0.); std::vector total_gamma(_nchan, 0.); // combining flash PE information from separate TPCs into a single vector @@ -531,6 +508,11 @@ void sbnd::LightCaloProducer::produce(art::Event& e) total_pe.at(_opdet_mask.at(imask)) = 0; } + // error is proportional to the amount of light + // that actually reached the optical detector + for (size_t ich=0; ichWph(); // MeV, Wph = 19.5 eV @@ -596,6 +571,82 @@ void sbnd::LightCaloProducer::produce(art::Event& e) // define functions +template +void sbnd::LightCaloProducer::collect_matches(const art::Handle> &handle, + const std::vector> &fm_v, + const std::string &label, + art::Event &e, + std::vector> &match_slices_v, + std::vector> &match_op0, + std::vector> &match_op1, + CheckFunc check) +{ + std::map, std::vector>> match_slice_opflash_map; + art::FindManyP fm_to_slice(handle, e, label); + art::FindManyP fm_to_flash(handle, e, label); + + for (size_t n_fm = 0; n_fm < fm_v.size(); ++n_fm) { + auto fm = fm_v[n_fm]; + if (!check(fm)) continue; + + std::vector> slice_v = fm_to_slice.at(fm.key()); + std::vector> flash_v = fm_to_flash.at(fm.key()); + + assert(slice_v.size() == 1); + assert(flash_v.size() == 1); + + auto slice = slice_v.front(); + auto flash = flash_v.front(); + + auto it = match_slice_opflash_map.find(slice); + if (it == match_slice_opflash_map.end()){ + std::vector> fv; + fv.push_back(flash); + match_slice_opflash_map.insert(std::pair, std::vector>>(slice, fv)); + } + else{ + it->second.push_back(flash); + } + } + + for (auto it = match_slice_opflash_map.begin(); it != match_slice_opflash_map.end(); ++it){ + auto slice = it->first; + auto flash_v = it->second; + if (flash_v.size() > 2){ + std::cout << "more than two opflash matched to this slice!" << std::endl; + continue; + } + bool found_opflash0 = false; + bool found_opflash1 = false; + + for (size_t n_flash=0; n_flash < flash_v.size(); n_flash++){ + auto flash = flash_v[n_flash]; + if (flash->XCenter() > 0){ + found_opflash1 = true; + match_op1.push_back(flash); + } + else if (flash->XCenter() < 0){ + found_opflash0 = true; + match_op0.push_back(flash); + } + } // end opflash loop + if (found_opflash0 == false && found_opflash1 == false){ + std::cout << "no opflashes matched to this slice" << std::endl; + continue; + } + else if (found_opflash0 || found_opflash1){ + match_slices_v.push_back(slice); + art::Ptr nullOpFlash; + if (found_opflash0==false) { + match_op0.push_back(nullOpFlash); + } + else if (found_opflash1==false){ + match_op1.push_back(nullOpFlash); + } + } + } +} + std::vector> sbnd::LightCaloProducer::CalcVisibility(std::vector xyz_v, std::vector charge_v){ @@ -666,53 +717,49 @@ double sbnd::LightCaloProducer::CalcMedian(std::vector total_gamma){ if (i%2==1) tpc1_gamma.push_back(total_gamma[i]); } double median_gamma=0; + for (int tpc=0; tpc < 2; tpc++){ - double median = 0; - auto gamma_v = (tpc==0)? tpc0_gamma:tpc1_gamma; - std::vector idx(gamma_v.size()); - std::iota(idx.begin(), idx.end(), 0); - std::sort(idx.begin(), idx.end(), - [&](int A, int B) -> bool { - return gamma_v[A] < gamma_v[B]; - }); - // count number of zero entries - int zero_counter = 0; - for (size_t i=0; i < gamma_v.size(); i++){ - if (gamma_v.at(i) <= 0) zero_counter++; - } - int med_idx=0; - if (zero_counter != int(gamma_v.size())){ - med_idx = idx.at(int((gamma_v.size()-zero_counter))/2 + zero_counter); - median = gamma_v.at(med_idx); - } + // make a copy to avoid changing in-place + std::vector gamma_v = ((tpc==0)? std::vector(tpc0_gamma) : std::vector(tpc1_gamma)); + const auto median_it = gamma_v.begin() + gamma_v.size() / 2; + std::nth_element(gamma_v.begin(), median_it , gamma_v.end()); + auto median = *median_it; median_gamma+=median; } return median_gamma; } -double sbnd::LightCaloProducer::CalcMean(std::vector total_gamma){ - std::vector tpc0_gamma; - std::vector tpc1_gamma; - for (size_t i=0; i total_gamma, std::vector total_err){ + // calculates a weighted average, loops over per tpc and then per channel + double total_mean=0; + for (size_t i=0; i<2; i++){ + double wgt_num = 0; + double wgt_denom = 0; + for (size_t ich=0; i0) ){ + wgt_num += total_gamma[i]*(1./total_err[i]); + wgt_denom += (1./total_err[i]); + } + } + total_mean += wgt_num/wgt_denom; } - double mean_gamma=0; - for (int tpc=0; tpc < 2; tpc++){ - auto gamma_v = (tpc==0)? tpc0_gamma:tpc1_gamma; - - double counter=0; - double sum=0; - for (size_t i=0; i< gamma_v.size(); i++){ - auto gamma = gamma_v[i]; - if (gamma>0){ - counter+=1.0; - sum+=gamma; + return total_mean; +} + +double sbnd::LightCaloProducer::CalcMean(std::vector total_gamma){ + double total_mean=0; + for (size_t i=0; i<2; i++){ + double wgt_num = 0; + double wgt_denom = 0; + for (size_t ich=0; i0) ){ + wgt_num += total_gamma[i]; + wgt_denom += 1; } } - if (sum!=0) mean_gamma+= sum/counter; + total_mean += wgt_num/wgt_denom; } - return mean_gamma; + return total_mean; } DEFINE_ART_MODULE(sbnd::LightCaloProducer) diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index 507425411..36e78bdf2 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -12,20 +12,18 @@ lightcalo: OpFlashProducers: ["opflashtpc0", "opflashtpc1"] OpFlashAraProducers: ["opflashtpc0xarapuca", "opflashtpc1xarapuca"] SliceProducer: "pandora" - FlashMatchProducer: "fmatch" OpT0FinderProducer: "opt0finder" + BCFMProducer: "tpcpmtbarycentermatching" UseArapucas: false - UseOpT0Finder: true + UseBCFM: true + UseOpT0Finder: false nuScoreCut: 0.4 # default: accept nusScore > 0.4, to analyze all slices, set nuScoreCut = -1 - fmScoreCut: 7 # default: accept 0 < fm score < fmScoreCut, to analyze all slices, set fmScoreCut = 1e3 opt0ScoreCut: 200 # default: accept opt0 match > opt0ScoreCut Verbose: false - SimpleOpFlashOffset: 0.2 # the offset between the t0 from SimpleFlash and OpFlashes - - OpT0FlashMin: 0.0 # simulation [0.0], light-triggered data [-0.8] - OpT0FlashMax: 2.0 # simulation [2.0], light-triggered data [2.0] + OpFlashMin: 0.0 # simulation [0.0], light-triggered data [-0.8] + OpFlashMax: 2.0 # simulation [2.0], light-triggered data [2.0] OpT0FractionalCut: 0.5 # flash parameters From ad848b4e2b9c74467145662dd86f4c488469d9fa Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 13 Nov 2025 17:13:19 -0600 Subject: [PATCH 44/52] missing import of optical path fcl config --- sbndcode/Calorimetry/MCCaloAna_config.fcl | 2 ++ sbndcode/Calorimetry/lightcalo.fcl | 5 +++-- sbndcode/Calorimetry/lightcalo_ana.fcl | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/sbndcode/Calorimetry/MCCaloAna_config.fcl b/sbndcode/Calorimetry/MCCaloAna_config.fcl index 2f988ea28..7f0d6c46d 100644 --- a/sbndcode/Calorimetry/MCCaloAna_config.fcl +++ b/sbndcode/Calorimetry/MCCaloAna_config.fcl @@ -8,6 +8,8 @@ mccaloana: VUVHits: @local::sbnd_vuv_RS100cm_hits_parameterization VIVHits: @local::sbnd_vis_RS100cm_hits_parameterization + OpticalPathTool: @local::SBNDOpticalPath + OpDetVUVEfficiencies: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021] OpDetVISEfficiencies: [0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index 36e78bdf2..3db7fa00c 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -8,6 +8,7 @@ lightcalo: VUVHits: @local::sbnd_vuv_RS100cm_hits_parameterization VIVHits: @local::sbnd_vis_RS100cm_hits_parameterization + OpticalPathTool: @local::SBNDOpticalPath OpFlashProducers: ["opflashtpc0", "opflashtpc1"] OpFlashAraProducers: ["opflashtpc0xarapuca", "opflashtpc1xarapuca"] @@ -40,8 +41,8 @@ lightcalo: ScintPreScale: 0.039 # Scintillation Pre-Scale factor in simulation (set in ionandscint) # parameters for truth validation - TruthValidation: false # can only set to true if the reco2 files have SimEnergyDeposits - SimEnergyProducer: "ionandscint" # only looking at energy deposits in the AV + TruthValidation: true # can only set to true if the reco2 files have SimEnergyDeposits + SimEnergyProducer: "ionandscint:priorSCE" # only looking at energy deposits in the AV TruthNeutrino: true # if validating anything other than simb::kBeamNeutrino, set to false } END_PROLOG diff --git a/sbndcode/Calorimetry/lightcalo_ana.fcl b/sbndcode/Calorimetry/lightcalo_ana.fcl index e29ef7287..d3b4e2af6 100644 --- a/sbndcode/Calorimetry/lightcalo_ana.fcl +++ b/sbndcode/Calorimetry/lightcalo_ana.fcl @@ -8,6 +8,7 @@ lightcaloana: VUVHits: @local::sbnd_vuv_RS100cm_hits_parameterization VIVHits: @local::sbnd_vis_RS100cm_hits_parameterization + OpticalPathTool: @local::SBNDOpticalPath OpFlashProducers: ["opflashtpc0", "opflashtpc1"] OpFlashAraProducers: ["opflashtpc0xarapuca", "opflashtpc1xarapuca"] From c789803226f7c82969ae5efb6a05b1d2e5f8abe0 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 13 Nov 2025 17:14:01 -0600 Subject: [PATCH 45/52] properly define tree/branches (it runs now!) --- .../Calorimetry/LightCaloProducer_module.cc | 47 ++++++++++++++++--- sbndcode/Calorimetry/run_lightcalo.fcl | 7 ++- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 8c3a11a61..d1a8c350c 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -247,11 +247,44 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) geom = lar::providerFrom(); + art::ServiceHandle fs; + _tree = fs->make("slice_tree",""); + _tree->Branch("run", &_run, "run/I"); + _tree->Branch("subrun", &_subrun, "subrun/I"); + _tree->Branch("event", &_event, "event/I"); + _tree->Branch("match_type", &_match_type, "match_type/I"); + + _tree2 = fs->make("match_tree",""); + _tree2->Branch("run", &_run, "run/I"); + _tree2->Branch("subrun", &_subrun, "subrun/I"); + _tree2->Branch("event", &_event, "event/I"); + _tree2->Branch("nmatch", &_nmatch, "nmatch/I"); + _tree2->Branch("pfpid", &_pfpid, "pfpid/I"); + _tree2->Branch("opflash_time", &_opflash_time, "opflash_time/D"); + + _tree2->Branch("rec_gamma", "std::vector", &_rec_gamma); + _tree2->Branch("dep_pe", "std::vector", &_dep_pe); + + _tree2->Branch("true_gamma", &_true_gamma, "true_gamma/D"); + _tree2->Branch("true_charge", &_true_charge, "true_charge/D"); + _tree2->Branch("true_energy", &_true_energy, "true_energy/D"); + + _tree2->Branch("visibility", "std::vector", &_visibility); + + _tree2->Branch("median_gamma", &_median_gamma, "median_gamma/D"); + _tree2->Branch("mean_gamma", &_mean_gamma, "mean_gamma/D"); + _tree2->Branch("mean_charge", &_mean_charge, "mean_charge/D"); + _tree2->Branch("max_charge", &_max_charge, "max_charge/D"); + _tree2->Branch("comp_charge", &_comp_charge, "comp_charge/D"); + + _tree2->Branch("slice_L", &_slice_L, "slice_L/D"); + _tree2->Branch("slice_Q", &_slice_Q, "slice_Q/D"); + _tree2->Branch("slice_E", &_slice_E, "slice_E/D"); + // Call appropriate produces<>() functions here. - produces>(); - produces>(); + // produces>(); + // produces>(); // Call appropriate consumes<>() for any products to be retrieved by this module. - } void sbnd::LightCaloProducer::produce(art::Event& e) @@ -418,7 +451,6 @@ void sbnd::LightCaloProducer::produce(art::Event& e) _tree->Fill(); return; } - auto slice = match_slices_v[n_slice]; // sum charge information (without position info) for Q // find which plane has the most integrated charge for this slice @@ -521,7 +553,6 @@ void sbnd::LightCaloProducer::produce(art::Event& e) _opflash_time = flash_time; _dep_pe = total_pe; _rec_gamma = total_gamma; - // calculate final light estimate _mean_gamma = CalcMean(total_gamma,total_err); _slice_L = _mean_gamma; @@ -562,12 +593,14 @@ void sbnd::LightCaloProducer::produce(art::Event& e) _true_gamma = -9999; _true_charge = -9999; _true_energy = -9999; - } + } nsuccessful_matches++; + _tree2->Fill(); + } // end slice loop _match_type=nsuccessful_matches; _tree->Fill(); -} // end analyze +} // end produce // define functions diff --git a/sbndcode/Calorimetry/run_lightcalo.fcl b/sbndcode/Calorimetry/run_lightcalo.fcl index 13e256158..68f14b2eb 100644 --- a/sbndcode/Calorimetry/run_lightcalo.fcl +++ b/sbndcode/Calorimetry/run_lightcalo.fcl @@ -32,7 +32,7 @@ outputs: out1: { module_type: RootOutput - # fileName: "lightcalo-art.root" + fileName: "lightcalo-art.root" dataTier: "reconstructed" compressionLevel:1 SelectEvents: ["reco"] @@ -63,4 +63,7 @@ physics: # end_paths is a keyword and contains the paths that do not modify the art::Event, # ie analyzers and output streams. these all run simultaneously end_paths: [stream1] -} \ No newline at end of file +} + +physics.producers.lightcalo.Verbose: true +physics.producers.lightcalo.TruthValidation: true \ No newline at end of file From 882af924c4258ae8698ef4fd3685844c04d9e366 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 13 Nov 2025 17:17:54 -0600 Subject: [PATCH 46/52] clean up some includes --- sbndcode/Calorimetry/LightCaloProducer_module.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index d1a8c350c..e52f17225 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -31,17 +31,13 @@ #include "lardata/Utilities/AssociationUtil.h" #include "lardataobj/RecoBase/Slice.h" #include "lardataobj/RecoBase/PFParticle.h" -#include "lardataobj/RecoBase/PFParticleMetadata.h" #include "lardataobj/RecoBase/SpacePoint.h" #include "lardataobj/RecoBase/Hit.h" -#include "lardataobj/RecoBase/Wire.h" #include "lardataobj/RecoBase/OpFlash.h" -#include "lardataobj/AnalysisBase/T0.h" -#include "lardataobj/Simulation/SimPhotons.h" + +// LArSoft MC includes #include "lardataobj/Simulation/SimEnergyDeposit.h" -#include "nusimdata/SimulationBase/GTruth.h" #include "nusimdata/SimulationBase/MCTruth.h" -#include "lardataobj/Simulation/SimChannel.h" #include "lardataobj/Simulation/sim.h" #include "larcore/CoreUtils/ServiceUtil.h" From f289952badfc433b11c3bbda1c2f4f610a22c15f Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Tue, 18 Nov 2025 11:20:10 -0600 Subject: [PATCH 47/52] move bulk of code into new function to allow easier returns, officially produce data products - also specify pd types explicitly, default is coated pmts only --- .../Calorimetry/LightCaloProducer_module.cc | 91 +++++++++++++------ sbndcode/Calorimetry/lightcalo.fcl | 2 + 2 files changed, 67 insertions(+), 26 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index e52f17225..431702198 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -90,15 +90,20 @@ class sbnd::LightCaloProducer : public art::EDProducer { private: + void CalculateCalorimetry(art::Event& e, + std::unique_ptr< std::vector >& lightcalo_v, + std::unique_ptr< art::Assns >& slice_assn_v, + std::unique_ptr< art::Assns >& flash_assn_v); + template - void collect_matches(const art::Handle> &handle, - const std::vector> &fm_v, - const std::string &label, - art::Event &e, - std::vector> &match_slices_v, - std::vector> &match_op0, - std::vector> &match_op1, - CheckFunc check); + void CollectMatches(const art::Handle> &handle, + const std::vector> &fm_v, + const std::string &label, + art::Event &e, + std::vector> &match_slices_v, + std::vector> &match_op0, + std::vector> &match_op1, + CheckFunc check); // Returns visibility vector for all opdets given charge/position information std::vector> CalcVisibility(std::vector xyz_v, @@ -123,6 +128,7 @@ class sbnd::LightCaloProducer : public art::EDProducer { // fcl parameters std::vector _opflash_producer_v; std::vector _opflash_ara_producer_v; + std::vector _pd_types; std::string _slice_producer; std::string _opt0_producer; std::string _bcfm_producer; @@ -214,10 +220,10 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) _opflash_producer_v = p.get>("OpFlashProducers"); _opflash_ara_producer_v = p.get>("OpFlashAraProducers"); + _pd_types = p.get>("PDTypes"); _slice_producer = p.get("SliceProducer"); _opt0_producer = p.get("OpT0FinderProducer"); _bcfm_producer = p.get("BCFMProducer"); - _use_arapucas = p.get("UseArapucas"); _use_opt0 = p.get("UseOpT0Finder"); _use_bcfm = p.get("UseBCFM"); _nuscore_cut = p.get("nuScoreCut"); @@ -278,12 +284,31 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) _tree2->Branch("slice_E", &_slice_E, "slice_E/D"); // Call appropriate produces<>() functions here. - // produces>(); - // produces>(); + produces>(); + produces>(); + produces>(); + // Call appropriate consumes<>() for any products to be retrieved by this module. } void sbnd::LightCaloProducer::produce(art::Event& e) +{ + + std::unique_ptr> lightcalo_v (new std::vector); + std::unique_ptr< art::Assns> slice_assn_v (new art::Assns); + std::unique_ptr< art::Assns> flash_assn_v (new art::Assns); + + CalculateCalorimetry(e, lightcalo_v, slice_assn_v, flash_assn_v); + + e.put(std::move(lightcalo_v)); + e.put(std::move(slice_assn_v)); + e.put(std::move(flash_assn_v)); +} + +void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, + std::unique_ptr>& lightcalo_v, + std::unique_ptr< art::Assns>& slice_assn_v, + std::unique_ptr< art::Assns>& flash_assn_v) { // services auto const clock_data = art::ServiceHandle()->DataFor(e); @@ -295,7 +320,6 @@ void sbnd::LightCaloProducer::produce(art::Event& e) _run = e.id().run(); _subrun = e.id().subRun(); _event = e.id().event(); - std::cout << "run: " << _run << ", subrun: " << _subrun << ", event: " << _event << std::endl; // get slices ::art::Handle> slice_h; @@ -321,8 +345,6 @@ void sbnd::LightCaloProducer::produce(art::Event& e) auto const & flash0_h = e.getValidHandle>(_opflash_producer_v[0]); auto const & flash1_h = e.getValidHandle>(_opflash_producer_v[1]); - if (!_use_arapucas && _verbose) - std::cout << "Using PMT OpFlash only..." << std::endl; if( (!flash0_h.isValid() || flash0_h->empty()) && (!flash1_h.isValid() || flash1_h->empty())) { std::cout << "don't have good PMT flashes from producer " << _opflash_producer_v[0] << " or " << _opflash_producer_v[1] << std::endl; return; @@ -360,7 +382,7 @@ void sbnd::LightCaloProducer::produce(art::Event& e) // use templated member helper to fill match vectors if (_use_bcfm) { - collect_matches(bcfm_h, bcfm_v, _bcfm_producer, e, match_slices_v, match_op0, match_op1, + CollectMatches(bcfm_h, bcfm_v, _bcfm_producer, e, match_slices_v, match_op0, match_op1, [this](art::Ptr bcfm) { if (bcfm->flashTime > _fopflash_max || bcfm->flashTime < _fopflash_min) return false; if (bcfm->score < 0.02) return false; @@ -368,7 +390,7 @@ void sbnd::LightCaloProducer::produce(art::Event& e) }); } else { - collect_matches(opt0_h, opt0_v, _opt0_producer, e, match_slices_v, match_op0, match_op1, + CollectMatches(opt0_h, opt0_v, _opt0_producer, e, match_slices_v, match_op0, match_op1, [this](art::Ptr opt0){ auto opt0_measPE = opt0->measPE; auto opt0_hypoPE = opt0->hypoPE; @@ -379,6 +401,14 @@ void sbnd::LightCaloProducer::produce(art::Event& e) return true; }); } + + if (std::find(_pd_types.begin(), _pd_types.end(), "xarapuca_vuv") != _pd_types.end() || + std::find(_pd_types.begin(), _pd_types.end(), "xarapuca_vis") != _pd_types.end()){ + _use_arapucas = true; + } + else + _use_arapucas =false; + std::vector> flash0_ara_v; std::vector> flash1_ara_v; if (_use_arapucas){ @@ -527,7 +557,10 @@ void sbnd::LightCaloProducer::produce(art::Event& e) } } } // end of arapuca if - for (size_t ich=0; ichWph(); // MeV, Wph = 19.5 eV + sbn::LightCalo lightcalo(_slice_Q,_slice_L,_slice_E,bestHits,plane_charge); + lightcalo_v->push_back(lightcalo); + util::CreateAssn(*this, e, *lightcalo_v, slice, *slice_assn_v); + util::CreateAssn(*this, e, *lightcalo_v, opflash0, *flash_assn_v); + util::CreateAssn(*this, e, *lightcalo_v, opflash1, *flash_assn_v); + _true_gamma = 0; _true_charge = 0; _true_energy = 0; @@ -601,14 +640,14 @@ void sbnd::LightCaloProducer::produce(art::Event& e) // define functions template -void sbnd::LightCaloProducer::collect_matches(const art::Handle> &handle, - const std::vector> &fm_v, - const std::string &label, - art::Event &e, - std::vector> &match_slices_v, - std::vector> &match_op0, - std::vector> &match_op1, - CheckFunc check) +void sbnd::LightCaloProducer::CollectMatches(const art::Handle> &handle, + const std::vector> &fm_v, + const std::string &label, + art::Event &e, + std::vector> &match_slices_v, + std::vector> &match_op0, + std::vector> &match_op1, + CheckFunc check) { std::map, std::vector>> match_slice_opflash_map; art::FindManyP fm_to_slice(handle, e, label); diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index 3db7fa00c..a806e8a93 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -12,6 +12,8 @@ lightcalo: OpFlashProducers: ["opflashtpc0", "opflashtpc1"] OpFlashAraProducers: ["opflashtpc0xarapuca", "opflashtpc1xarapuca"] + PDTypes: ["pmt_coated"] # "pmt_uncoated", "xarapuca_vuv", "xarapuca_vis" + SliceProducer: "pandora" OpT0FinderProducer: "opt0finder" BCFMProducer: "tpcpmtbarycentermatching" From 536eaacac3b5800136d9c39c576faf9256d9b801 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Tue, 18 Nov 2025 11:27:08 -0600 Subject: [PATCH 48/52] move accessing flash matching handles into their relevant scopes --- .../Calorimetry/LightCaloProducer_module.cc | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 431702198..0e3caeeb2 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -361,27 +361,17 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, std::map, std::vector>> match_slice_opflash_map; - // * get flash matched objects - ::art::Handle> bcfm_h; - e.getByLabel(_bcfm_producer, bcfm_h); - if(!bcfm_h.isValid() || bcfm_h->empty()) { - std::cout << "don't have good barycenter matches!" << std::endl; - return; - } - std::vector> bcfm_v; - art::fill_ptr_vector(bcfm_v, bcfm_h); - - ::art::Handle> opt0_h; - e.getByLabel(_opt0_producer, opt0_h); - if(!opt0_h.isValid() || opt0_h->empty()) { - std::cout << "don't have good OpT0Finder matches!" << std::endl; - return; - } - std::vector> opt0_v; - art::fill_ptr_vector(opt0_v, opt0_h); - // use templated member helper to fill match vectors if (_use_bcfm) { + ::art::Handle> bcfm_h; + e.getByLabel(_bcfm_producer, bcfm_h); + if(!bcfm_h.isValid() || bcfm_h->empty()) { + std::cout << "don't have good barycenter matches!" << std::endl; + return; + } + std::vector> bcfm_v; + art::fill_ptr_vector(bcfm_v, bcfm_h); + CollectMatches(bcfm_h, bcfm_v, _bcfm_producer, e, match_slices_v, match_op0, match_op1, [this](art::Ptr bcfm) { if (bcfm->flashTime > _fopflash_max || bcfm->flashTime < _fopflash_min) return false; @@ -390,6 +380,15 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, }); } else { + ::art::Handle> opt0_h; + e.getByLabel(_opt0_producer, opt0_h); + if(!opt0_h.isValid() || opt0_h->empty()) { + std::cout << "don't have good OpT0Finder matches!" << std::endl; + return; + } + std::vector> opt0_v; + art::fill_ptr_vector(opt0_v, opt0_h); + CollectMatches(opt0_h, opt0_v, _opt0_producer, e, match_slices_v, match_op0, match_op1, [this](art::Ptr opt0){ auto opt0_measPE = opt0->measPE; @@ -407,7 +406,7 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, _use_arapucas = true; } else - _use_arapucas =false; + _use_arapucas = false; std::vector> flash0_ara_v; std::vector> flash1_ara_v; From 4fc4108c36d0ee0078d70d05f3f6fc6ea4814b8b Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Tue, 18 Nov 2025 13:18:24 -0600 Subject: [PATCH 49/52] remove unneeded modules --- sbndcode/Calorimetry/CMakeLists.txt | 3 +- sbndcode/Calorimetry/LightCaloAna_module.cc | 988 ------------------ sbndcode/Calorimetry/MCCaloAna_config.fcl | 17 - sbndcode/Calorimetry/MCCaloAna_module.cc | 482 --------- sbndcode/Calorimetry/lightcalo_ana.fcl | 50 - sbndcode/Calorimetry/run_lightcaloana.fcl | 50 - .../Calorimetry/run_lightcaloana_data.fcl | 53 - sbndcode/Calorimetry/run_mcana.fcl | 53 - 8 files changed, 1 insertion(+), 1695 deletions(-) delete mode 100644 sbndcode/Calorimetry/LightCaloAna_module.cc delete mode 100644 sbndcode/Calorimetry/MCCaloAna_config.fcl delete mode 100644 sbndcode/Calorimetry/MCCaloAna_module.cc delete mode 100644 sbndcode/Calorimetry/lightcalo_ana.fcl delete mode 100644 sbndcode/Calorimetry/run_lightcaloana.fcl delete mode 100644 sbndcode/Calorimetry/run_lightcaloana_data.fcl delete mode 100644 sbndcode/Calorimetry/run_mcana.fcl diff --git a/sbndcode/Calorimetry/CMakeLists.txt b/sbndcode/Calorimetry/CMakeLists.txt index 5f33e235e..62562fa94 100644 --- a/sbndcode/Calorimetry/CMakeLists.txt +++ b/sbndcode/Calorimetry/CMakeLists.txt @@ -35,9 +35,8 @@ set (MODULE_LIBRARIES sbndcode_RecoUtils sbndcode_OpDetSim ) -cet_build_plugin(LightCaloAna art::module SOURCE LightCaloAna_module.cc LIBRARIES ${MODULE_LIBRARIES}) + cet_build_plugin(LightCaloProducer art::module SOURCE LightCaloProducer_module.cc LIBRARIES ${MODULE_LIBRARIES}) -cet_build_plugin(MCCaloAna art::module SOURCE MCCaloAna_module.cc LIBRARIES ${MODULE_LIBRARIES}) install_headers() install_fhicl() diff --git a/sbndcode/Calorimetry/LightCaloAna_module.cc b/sbndcode/Calorimetry/LightCaloAna_module.cc deleted file mode 100644 index 5beb1c629..000000000 --- a/sbndcode/Calorimetry/LightCaloAna_module.cc +++ /dev/null @@ -1,988 +0,0 @@ -//////////////////////////////////////////////////////////////////////// -// Class: LightCaloAna -// Plugin Type: analyzer -// File: LightCaloAna_module.cc -// -// This module reconstructs the total visible energy in an event by -// combining charge (recob::Hit) and light (recob::OpFlash) information. -// Runs on reco2 files, requires flash-matching -// uses the Semi-Analytical Photon Model -// Authors: Lynn Tung -//////////////////////////////////////////////////////////////////////// - -#include "art/Framework/Core/EDAnalyzer.h" -#include "art/Framework/Core/ModuleMacros.h" -#include "art/Framework/Principal/Event.h" -#include "art/Framework/Principal/Handle.h" -#include "art/Framework/Principal/Run.h" -#include "art/Framework/Principal/SubRun.h" -#include "art/Utilities/make_tool.h" -#include "canvas/Utilities/InputTag.h" -#include "fhiclcpp/ParameterSet.h" -#include "messagefacility/MessageLogger/MessageLogger.h" - -// Additional framework includes -#include "art_root_io/TFileService.h" -#include "canvas/Persistency/Common/FindMany.h" -#include "canvas/Persistency/Common/FindManyP.h" -#include "canvas/Persistency/Common/FindOne.h" -#include "canvas/Persistency/Common/FindOneP.h" -#include "canvas/Persistency/Common/Ptr.h" -#include "canvas/Persistency/Common/PtrVector.h" - -// LArSoft includes -#include "lardata/Utilities/AssociationUtil.h" -#include "lardataobj/RecoBase/Slice.h" -#include "lardataobj/RecoBase/PFParticle.h" -#include "lardataobj/RecoBase/PFParticleMetadata.h" -#include "lardataobj/RecoBase/SpacePoint.h" -#include "lardataobj/RecoBase/Hit.h" -#include "lardataobj/RecoBase/Wire.h" -#include "lardataobj/RecoBase/OpFlash.h" -#include "lardataobj/RecoBase/Shower.h" -#include "lardataobj/RecoBase/Track.h" -#include "larpandora/LArPandoraInterface/LArPandoraHelper.h" - -#include "lardataobj/Simulation/SimPhotons.h" -#include "lardataobj/Simulation/SimEnergyDeposit.h" -#include "nusimdata/SimulationBase/GTruth.h" -#include "nusimdata/SimulationBase/MCTruth.h" -#include "lardataobj/Simulation/SimChannel.h" -#include "lardataobj/Simulation/sim.h" - -#include "larcore/CoreUtils/ServiceUtil.h" -#include "larcore/Geometry/Geometry.h" -#include "larcorealg/Geometry/GeometryCore.h" -#include "larsim/PhotonPropagation/SemiAnalyticalModel.h" -#include "larsim/PhotonPropagation/OpticalPathTools/OpticalPath.h" -#include "larsim/Simulation/LArG4Parameters.h" -#include "larsim/MCCheater/ParticleInventoryService.h" -#include "lardata/DetectorInfoServices/DetectorClocksService.h" -#include "lardata/DetectorInfoServices/DetectorPropertiesService.h" - -// SBND includes -#include "sbnobj/Common/Reco/SimpleFlashMatchVars.h" -#include "sbnobj/Common/Reco/OpT0FinderResult.h" -#include "sbndcode/OpDetSim/sbndPDMapAlg.hh" - -// ROOT includes -#include "TFile.h" -#include "TTree.h" - -// C++ includes -#include -#include -#include // sort - -namespace sbnd { - class LightCaloAna; -} - -class sbnd::LightCaloAna : public art::EDAnalyzer { -public: - explicit LightCaloAna(fhicl::ParameterSet const& p); - // The compiler-generated destructor is fine for non-base - // classes without bare pointers or other resource use. - - // Plugins should not be copied or assigned. - LightCaloAna(LightCaloAna const&) = delete; - LightCaloAna(LightCaloAna&&) = delete; - LightCaloAna& operator=(LightCaloAna const&) = delete; - LightCaloAna& operator=(LightCaloAna&&) = delete; - - // Required functions. - void analyze(art::Event const& e) override; - -private: - - // Matches SimpleFlash time to OpFlashes, fills match_v with succesfully matched OpFlashes - // returns true if match was found - bool MatchOpFlash(std::vector> fm_v, - std::vector> flash_v, - std::vector> &match_v); - - // Returns visibility vector for all opdets given charge/position information - std::vector> CalcVisibility(std::vector xyz_v, - std::vector charge_v); - - // Fills reconstructed photon count vector (total_gamma_v) for all opdets given charge/position information - void CalcLight(std::vector flash_pe_v, - std::vector dir_visibility, - std::vector ref_visibility, - std::vector &total_gamma_v); - - // Returns the median of the light vector - double CalcMedian(std::vector total_light); - - // Returns the mean of the light vector - double CalcMean(std::vector total_light); - - // fcl parameters - std::vector _opflash_producer_v; - std::vector _opflash_ara_producer_v; - std::string _slice_producer; - std::string _opt0_producer; - std::string _flashmatch_producer; - bool _use_arapucas; - bool _use_opt0; - float _nuscore_cut; - float _fmscore_cut; - float _fopt0score_cut; - bool _verbose; - - float _simple_op_offset; - - float _fopt0_flash_min; - float _fopt0_flash_max; - float _fopt0_frac_diff_cut; - - float _pmt_ara_offset; - std::vector _noise_thresh; - - std::vector _cal_area_const; - std::vector _opdet_vuv_eff; - std::vector _opdet_vis_eff; - std::vector _opdet_mask; - float _scint_prescale; - - bool _truth_validation; - std::string _simenergy_producer; - bool _truth_neutrino; - - std::unique_ptr _semi_model; - fhicl::ParameterSet _vuv_params; - fhicl::ParameterSet _vis_params; - std::shared_ptr _optical_path_tool; - - opdet::sbndPDMapAlg _opdetmap; //map for photon detector types - unsigned int _nchan = _opdetmap.size(); - - geo::GeometryCore const* geom; - - int _run, _subrun, _event; - - TTree* _tree; - int _match_type; - // match_type key: - /// -1: no slices passed both the nuscore and flash match score cut - /// -2: no opflashes times found in coincidence with simpleflash time - /// -3: opflashes are empty or PE count too low - - TTree* _tree2; - int _nmatch=0; // number of matches in an event - int _pfpid; // ID of the matched slice - double _opflash_time; // time of matched opflash - - std::vector _dep_pe; // vector of measured photo-electron (PE), one entry = one channel - std::vector _rec_gamma; // vector of reconstructed photon count, one entry = one channel - - double _true_gamma; // true photon count from all energy depositions - double _true_charge; // true electron count from all energy depositions - double _true_energy; // true deposited energy - - std::vector _visibility; - - double _sp_max_x; - double _sp_min_x; - double _sp_max_y; - double _sp_min_y; - double _sp_max_z; - double _sp_min_z; - - double _median_gamma; // median of all reconstructed light estimates - double _mean_gamma; // mean of all reconstructed light estimates - - double _mean_charge; // avg charge from all three planes - double _max_charge; // charge from the plane with the highest amount of charge - double _comp_charge; // charge from the plane with the highest number of hits, "highest completeness" - double _coll_charge; // charge from collection plane only - - double _sp_charge; - double _trk_charge; - double _shw_charge; - - double _trk_sp_charge; - double _shw_sp_charge; - - double _slice_L; // reconstructed photon count - double _slice_Q; // reconstructed electron count - double _slice_E; // reconstructed deposited energy - - double _frac_L; // light fractional difference: (L_{true} - L_{reco})/(L_{true}) - double _frac_Q; // charge fractional difference: (Q_{true} - Q_{reco})/(Q_{true}) - double _frac_E; // energy fractional difference: (E_{true} - E_{reco})/(E_{true}) -}; - - -sbnd::LightCaloAna::LightCaloAna(fhicl::ParameterSet const& p) - : EDAnalyzer{p} // , - // More initializers here. -{ - _vuv_params = p.get("VUVHits"); - _vis_params = p.get("VIVHits"); - _optical_path_tool = std::shared_ptr(art::make_tool(p.get("OpticalPathTool"))); - _semi_model = std::make_unique(_vuv_params, _vis_params, _optical_path_tool, true, false); - - _opflash_producer_v = p.get>("OpFlashProducers"); - _opflash_ara_producer_v = p.get>("OpFlashAraProducers"); - _slice_producer = p.get("SliceProducer"); - _opt0_producer = p.get("OpT0FinderProducer"); - _flashmatch_producer = p.get("FlashMatchProducer"); - _use_arapucas = p.get("UseArapucas"); - _use_opt0 = p.get("UseOpT0Finder"); - _nuscore_cut = p.get("nuScoreCut"); - _fmscore_cut = p.get("fmScoreCut"); - _fopt0score_cut = p.get("opt0ScoreCut"); - _verbose = p.get("Verbose"); - - _simple_op_offset= p.get("SimpleOpFlashOffset"); - - _fopt0_flash_min = p.get("OpT0FlashMin"); - _fopt0_flash_max = p.get("OpT0FlashMax"); - _fopt0_frac_diff_cut = p.get("OpT0FractionalCut"); - - _pmt_ara_offset = p.get("PMTARAFlashOffset"); - _noise_thresh = p.get>("FlashNoiseThreshold"); - - _cal_area_const = p.get>("CalAreaConstants"); - _opdet_vuv_eff = p.get>("OpDetVUVEfficiencies"); - _opdet_vis_eff = p.get>("OpDetVISEfficiencies"); - _opdet_mask = p.get>("OpDetMask"); - _scint_prescale = p.get("ScintPreScale"); - - _truth_validation = p.get("TruthValidation"); - _simenergy_producer = p.get("SimEnergyProducer"); - _truth_neutrino = p.get("TruthNeutrino"); - - geom = lar::providerFrom(); - - art::ServiceHandle fs; - _tree = fs->make("slice_tree",""); - _tree->Branch("run", &_run, "run/I"); - _tree->Branch("subrun", &_subrun, "subrun/I"); - _tree->Branch("event", &_event, "event/I"); - _tree->Branch("match_type", &_match_type, "match_type/I"); - - _tree2 = fs->make("match_tree",""); - _tree2->Branch("run", &_run, "run/I"); - _tree2->Branch("subrun", &_subrun, "subrun/I"); - _tree2->Branch("event", &_event, "event/I"); - _tree2->Branch("nmatch", &_nmatch, "nmatch/I"); - _tree2->Branch("pfpid", &_pfpid, "pfpid/I"); - _tree2->Branch("opflash_time", &_opflash_time, "opflash_time/D"); - - _tree2->Branch("rec_gamma", "std::vector", &_rec_gamma); - _tree2->Branch("dep_pe", "std::vector", &_dep_pe); - - _tree2->Branch("true_gamma", &_true_gamma, "true_gamma/D"); - _tree2->Branch("true_charge", &_true_charge, "true_charge/D"); - _tree2->Branch("true_energy", &_true_energy, "true_energy/D"); - - _tree2->Branch("visibility", "std::vector", &_visibility); - _tree2->Branch("sp_max_x", &_sp_max_x, "sp_x_max/D"); - _tree2->Branch("sp_min_x", &_sp_min_x, "sp_x_min/D"); - _tree2->Branch("sp_max_y", &_sp_max_y, "sp_y_max/D"); - _tree2->Branch("sp_min_y", &_sp_min_y, "sp_y_min/D"); - _tree2->Branch("sp_max_z", &_sp_max_z, "sp_z_max/D"); - _tree2->Branch("sp_min_z", &_sp_min_z, "sp_z_min/D"); - - _tree2->Branch("median_gamma", &_median_gamma, "median_gamma/D"); - _tree2->Branch("mean_gamma", &_mean_gamma, "mean_gamma/D"); - _tree2->Branch("mean_charge", &_mean_charge, "mean_charge/D"); - _tree2->Branch("max_charge", &_max_charge, "max_charge/D"); - _tree2->Branch("comp_charge", &_comp_charge, "comp_charge/D"); - _tree2->Branch("coll_charge", &_coll_charge, "coll_charge/D"); - - _tree2->Branch("sp_charge", &_sp_charge, "sp_charge/D"); - _tree2->Branch("trk_charge", &_trk_charge, "trk_charge/D"); - _tree2->Branch("shw_charge", &_shw_charge, "shw_charge/D"); - _tree2->Branch("trk_sp_charge", &_trk_sp_charge,"trk_sp_charge/D"); - _tree2->Branch("shw_sp_charge", &_shw_sp_charge,"shw_sp_charge/D"); - - _tree2->Branch("slice_L", &_slice_L, "slice_L/D"); - _tree2->Branch("slice_Q", &_slice_Q, "slice_Q/D"); - _tree2->Branch("slice_E", &_slice_E, "slice_E/D"); - _tree2->Branch("frac_L", &_frac_L, "frac_L/D"); - _tree2->Branch("frac_Q", &_frac_Q, "frac_Q/D"); - _tree2->Branch("frac_E", &_frac_E, "frac_E/D"); - -} - -void sbnd::LightCaloAna::analyze(art::Event const& e) -{ - // services - auto const clock_data = art::ServiceHandle()->DataFor(e); - auto const det_prop = art::ServiceHandle()->DataFor(e, clock_data); - - art::ServiceHandle g4param; - art::ServiceHandle piserv; - - _run = e.id().run(); - _subrun = e.id().subRun(); - _event = e.id().event(); - std::cout << "run: " << _run << ", subrun: " << _subrun << ", event: " << _event << std::endl; - - // get slices - ::art::Handle> slice_h; - e.getByLabel(_slice_producer, slice_h); - if(!slice_h.isValid() || slice_h->empty()){ - std::cout << "don't have good slices!" << std::endl; - return; - } - - ::art::Handle> pfp_h; - e.getByLabel(_slice_producer, pfp_h); - if(!pfp_h.isValid() || pfp_h->empty()) { - std::cout << "don't have good PFParticle!" << std::endl; - return; - } - - ::art::Handle> spacepoint_h; - e.getByLabel(_slice_producer, spacepoint_h); - if(!spacepoint_h.isValid() || spacepoint_h->empty()) { - std::cout << "don't have good SpacePoints!" << std::endl; - return; - } - - ::art::Handle> shower_h; - e.getByLabel("pandoraShowerSBN", shower_h); - if(!shower_h.isValid() || shower_h->empty()) { - std::cout << "don't have good Showers!" << std::endl; - return; - } - - ::art::Handle> track_h; - e.getByLabel("pandoraTrack", track_h); - if(!track_h.isValid() || track_h->empty()) { - std::cout << "don't have good Tracks!" << std::endl; - return; - } - - auto const & flash0_h = e.getValidHandle>(_opflash_producer_v[0]); - auto const & flash1_h = e.getValidHandle>(_opflash_producer_v[1]); - if (!_use_arapucas && _verbose) - std::cout << "Using PMT OpFlash only..." << std::endl; - if( (!flash0_h.isValid() || flash0_h->empty()) && (!flash1_h.isValid() || flash1_h->empty())) { - std::cout << "don't have good PMT flashes from producer " << _opflash_producer_v[0] << " or " << _opflash_producer_v[1] << std::endl; - return; - } - - art::FindManyP slice_to_pfp (slice_h, e, _slice_producer); - art::FindManyP slice_to_hit (slice_h, e, _slice_producer); - art::FindManyP pfp_to_spacepoint(pfp_h, e, _slice_producer); - art::FindManyP pfp_to_shower (pfp_h, e, "pandoraShowerSBN"); - art::FindManyP pfp_to_track (pfp_h, e, "pandoraTrack"); - art::FindManyP shower_to_hit (shower_h, e, "pandoraShowerSBN"); - art::FindManyP track_to_hit (track_h, e, "pandoraTrack"); - - art::FindManyP spacepoint_to_hit(spacepoint_h, e, _slice_producer); - - std::vector> match_slices_v; - std::vector> match_op0; - std::vector> match_op1; - - if (_use_opt0){ - ::art::Handle> opt0_h; - e.getByLabel(_opt0_producer, opt0_h); - if(!opt0_h.isValid() || opt0_h->empty()) { - std::cout << "don't have good OpT0Finder matches!" << std::endl; - return; - } - std::vector> opt0_v; - art::fill_ptr_vector(opt0_v, opt0_h); - - std::map, std::vector>> match_slice_opflash_map; - art::FindManyP opt0_to_slice(opt0_h, e, _opt0_producer); - art::FindManyP opt0_to_flash(opt0_h, e, _opt0_producer); - - for (size_t n_opt0=0; n_opt0 < opt0_v.size(); n_opt0++){ - auto opt0 = opt0_v[n_opt0]; - std::vector> slice_v = opt0_to_slice.at(opt0.key()); - std::vector> flash_v = opt0_to_flash.at(opt0.key()); - - assert(slice_v.size() == 1); - assert(flash_v.size() == 1); - - auto slice = slice_v.front(); - auto flash = flash_v.front(); - - auto opt0_score = opt0->score; - auto opt0_time = opt0->time; - auto opt0_measPE = opt0->measPE; - auto opt0_hypoPE = opt0->hypoPE; - auto opt0_frac_diff = std::abs((opt0_hypoPE - opt0_measPE)/opt0_measPE); - - if (opt0_time < _fopt0_flash_min || opt0_time > _fopt0_flash_max) continue; - if (opt0_score < _fopt0score_cut) continue; - if (opt0_frac_diff > _fopt0_frac_diff_cut) continue; - - // check that slice is not already in the map - auto it = match_slice_opflash_map.find(slice); - if (it == match_slice_opflash_map.end()){ - std::vector> flash_v; - flash_v.push_back(flash); - match_slice_opflash_map.insert(std::pair, std::vector>>(slice, flash_v)); - } - else{ - it->second.push_back(flash); - } - } - - for (auto it = match_slice_opflash_map.begin(); it != match_slice_opflash_map.end(); ++it){ - auto slice = it->first; - auto flash_v = it->second; - if (flash_v.size() > 2){ - std::cout << "more than one opflash matched to this slice!" << std::endl; - continue; - } - bool found_opflash0 = false; - bool found_opflash1 = false; - - for (size_t n_flash=0; n_flash < flash_v.size(); n_flash++){ - auto flash = flash_v[n_flash]; - if (flash->XCenter() > 0){ - found_opflash1 = true; - match_op1.push_back(flash); - } - else if (flash->XCenter() < 0){ - found_opflash0 = true; - match_op0.push_back(flash); - } - } // end opflash loop - if (found_opflash0 == false && found_opflash1 == false){ - std::cout << "no opflashes matched to this slice" << std::endl; - continue; - } - else if (found_opflash0 || found_opflash1){ - match_slices_v.push_back(slice); - art::Ptr nullOpFlash; - if (found_opflash0==false) { - match_op0.push_back(nullOpFlash); - } - else if (found_opflash1==false){ - match_op1.push_back(nullOpFlash); - } - - } - } // end opt0finder loop - } - else { // using SimpleFlash - std::vector> slice_v; - art::fill_ptr_vector(slice_v, slice_h); - - art::FindManyP pfp_to_meta(pfp_h, e, _slice_producer); - art::FindManyP pfp_to_sfm (pfp_h, e, _flashmatch_producer); - - std::vector> match_fm_v; - std::vector> flash0_v; - art::fill_ptr_vector(flash0_v, flash0_h); - std::vector> flash1_v; - art::fill_ptr_vector(flash1_v, flash1_h); - - for (size_t n_slice=0; n_slice < slice_v.size(); n_slice++){ - float nu_score = -9999; - float fm_score = -9999; - auto slice = slice_v[n_slice]; - bool found_fm = false; - std::vector> pfp_v = slice_to_pfp.at(n_slice); - for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ - auto pfp = pfp_v[n_pfp]; - - // only select the PRIMARY pfp - if(!pfp->IsPrimary()) - continue; - if(_truth_neutrino && !(abs(pfp->PdgCode()) == 12 || abs(pfp->PdgCode()) == 14|| abs(pfp->PdgCode()) == 16)) - continue; - // if primary, get nu-score - const std::vector> pfpmeta_v = pfp_to_meta.at(pfp->Self()); - const art::Ptr pfpmeta = pfpmeta_v.front(); - larpandoraobj::PFParticleMetadata::PropertiesMap propmap = pfpmeta->GetPropertiesMap(); - if (propmap.count("NuScore")) nu_score = propmap.at("NuScore"); - else nu_score = -1; - - // get fm-score - std::vector> fm_v = pfp_to_sfm.at(pfp.key()); - if (fm_v.empty()){ - std::cout << "No SimpleFlashMatch objects associated with this PFP!" << std::endl; - continue; - } - if (fm_v.size() > 1) - std::cout << "more than one match for one pfp?" << std::endl; - for (size_t n_fm=0; n_fm < fm_v.size(); n_fm++){ - auto fm = fm_v.at(n_fm); - fm_score = fm->score.total; - if (nu_score > _nuscore_cut && fm_score < _fmscore_cut && fm_score > 0){ - found_fm = true; - match_fm_v.push_back(fm); - } - } // end flashmatch loop - if (found_fm ==true) match_slices_v.push_back(slice); - } // end pfp loop - } // end slice loop - if (match_slices_v.empty() && !slice_v.empty()){ - std::cout << "no slices passed the cuts" << std::endl; - _match_type = -1; - _tree->Fill(); - return; - } - - if (match_slices_v.size() != match_fm_v.size()){ - std::cout << "slice and flashmatch vector length mismatch!" << std::endl; - return; - } - - // get relevant opflashes - bool found_opflash0 = MatchOpFlash(match_fm_v,flash0_v, match_op0); - bool found_opflash1 = MatchOpFlash(match_fm_v,flash1_v, match_op1); - - if (found_opflash0 == false && found_opflash1 == false){ - std::cout << "no opflashes matched to simpleflashes" << std::endl; - _match_type = -2; - _tree->Fill(); - return; - } - } - - std::vector> flash0_ara_v; - std::vector> flash1_ara_v; - if (_use_arapucas){ - ::art::Handle> flash0_ara_h; - ::art::Handle> flash1_ara_h; - - for (size_t i=0; i<2; i++){ - ::art::Handle> flash_ara_h; - e.getByLabel(_opflash_ara_producer_v[i], flash_ara_h); - if (!flash_ara_h.isValid() || flash_ara_h->empty()) { - std::cout << "don't have good X-ARAPUCA flashes from producer " << _opflash_ara_producer_v[i] << std::endl; - } - else art::fill_ptr_vector((i==0)? flash0_ara_v : flash1_ara_v, flash_ara_h); - } - } - - int nsuccessful_matches=0; - for (size_t n_slice=0; n_slice < match_slices_v.size(); n_slice++){ - // initialize tree2 variables - _nmatch++; - _pfpid = -1; - - _slice_Q = 0; // total amount of charge - _slice_L = 0; // total amount of light - _slice_E = 0; - - std::vector sp_xyz; - std::vector sp_charge; // vector of charge info for charge-weighting - - double flash_time = -999; - auto opflash0 = (match_op0.at(n_slice)); - auto opflash1 = (match_op1.at(n_slice)); - bool flash_in_0 = false; - bool flash_in_1 = false; - // set threshold above noise PE levels for the flash - float noise_thresh = (!_use_arapucas)? _noise_thresh[0] : _noise_thresh[1]; - - if (!opflash0.isNull() && opflash1.isNull()){ - flash_time = opflash0->Time(); - if (opflash0->TotalPE() > noise_thresh) - flash_in_0 = true; - else if (_verbose) - std::cout << "Flash Total PE in TPC 0 (" << opflash0->TotalPE() << ") below noise threshold ... Skipping" << std::endl; - } - else if ( opflash0.isNull() && !opflash1.isNull()){ - flash_time = opflash1->Time(); - if (opflash1->TotalPE() > noise_thresh) - flash_in_1 = true; - else if (_verbose) - std::cout << "Flash Total PE in TPC 1 (" << opflash1->TotalPE() << ") below noise threshold ... Skipping" << std::endl; - } - else if (!opflash0.isNull() && !opflash1.isNull()){ - flash_time = opflash0->Time(); - if (opflash0->TotalPE() > noise_thresh) - flash_in_0 = true; - else if (_verbose) - std::cout << "Flash Total PE in TPC 0 (" << opflash0->TotalPE() << ") below noise threshold ... Skipping" << std::endl; - if (opflash1->TotalPE() > noise_thresh) - flash_in_1 = true; - else if (_verbose) - std::cout << "Flash Total PE in TPC 1 (" << opflash1->TotalPE() << ") below noise threshold ... Skipping" << std::endl; - } - else if (opflash0.isNull() && opflash1.isNull()){ - std::cout << "No opflashes matched with SimpleFlash objects" << std::endl; - _match_type = -3; - _tree->Fill(); - return; - } - - auto slice = match_slices_v[n_slice]; - // sum charge information (without position info) for Q - // find which plane has the most integrated charge for this slice - std::vector> slice_hits_v = slice_to_hit.at(slice.key()); - std::vector plane_charge{0.,0.,0.}; - std::vector plane_hits{0,0,0}; - for (size_t i=0; i < slice_hits_v.size(); i++){ - auto hit = slice_hits_v[i]; - auto drift_time = hit->PeakTime()*0.5 - clock_data.TriggerOffsetTPC(); - double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) - auto hit_plane = hit->View(); - plane_charge.at(hit_plane) += hit->Integral()*atten_correction*(1/_cal_area_const.at(hit_plane)); - plane_hits.at(hit_plane)++; - } - - uint bestPlane = std::max_element(plane_charge.begin(), plane_charge.end()) - plane_charge.begin(); - uint bestHits = std::max_element(plane_hits.begin(), plane_hits.end()) - plane_hits.begin(); - - _mean_charge = (plane_charge[0] + plane_charge[1] + plane_charge[2])/3; - _max_charge = plane_charge.at(bestPlane); - _comp_charge = plane_charge.at(bestHits); - _coll_charge = plane_charge[2]; - - _slice_Q = _comp_charge; - - _sp_charge = 0; - _shw_sp_charge = 0; - _trk_sp_charge = 0; - - _trk_charge = 0; - _shw_charge = 0; - - _sp_max_x = -1e9; _sp_max_y = -1e9; _sp_max_z = -1e9; - _sp_min_x = 1e9; _sp_min_y = 1e9; _sp_min_z = 1e9; - - // get charge information to create the weighted map - std::vector> pfp_v = slice_to_pfp.at(slice.key()); - for (size_t n_pfp=0; n_pfp < pfp_v.size(); n_pfp++){ - auto pfp = pfp_v[n_pfp]; - if (pfp->IsPrimary()) _pfpid = pfp->Self(); - auto pfpistrack = ::lar_pandora::LArPandoraHelper::IsTrack(pfp); - auto pfpisshower = ::lar_pandora::LArPandoraHelper::IsShower(pfp); - - if (pfpistrack){ - std::vector> trk_v = pfp_to_track.at(pfp.key()); - for (size_t n_trk=0; n_trk < trk_v.size(); n_trk++){ - auto trk = trk_v[n_trk]; - std::vector> hit_v = track_to_hit.at(trk.key()); - for (size_t n_hit=0; n_hit < hit_v.size(); n_hit++){ - auto hit = hit_v[n_hit]; - if (hit->View() !=bestHits) continue; - auto drift_time = hit->PeakTime()*0.5 - clock_data.TriggerOffsetTPC(); - double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) - double charge = (1/_cal_area_const.at(bestPlane))*atten_correction*hit->Integral(); - _trk_charge += charge; - } - } - } - if (pfpisshower){ - std::vector> shw_v = pfp_to_shower.at(pfp.key()); - for (size_t n_shw=0; n_shw < shw_v.size(); n_shw++){ - auto shw = shw_v[n_shw]; - std::vector> hit_v = shower_to_hit.at(shw.key()); - for (size_t n_hit=0; n_hit < hit_v.size(); n_hit++){ - auto hit = hit_v[n_hit]; - if (hit->View() !=bestHits) continue; - auto drift_time = hit->PeakTime()*0.5 - clock_data.TriggerOffsetTPC(); - double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) - double charge = (1/_cal_area_const.at(bestPlane))*atten_correction*hit->Integral(); - _shw_charge += charge; - } - } - } - std::vector> sp_v = pfp_to_spacepoint.at(pfp.key()); - for (size_t n_sp=0; n_sp < sp_v.size(); n_sp++){ - auto sp = sp_v[n_sp]; - std::vector> hit_v = spacepoint_to_hit.at(sp.key()); - for (size_t n_hit=0; n_hit < hit_v.size(); n_hit++){ - auto hit = hit_v[n_hit]; - // - if (hit->View() !=bestHits) continue; - const auto &position(sp->XYZ()); - geo::Point_t xyz(position[0],position[1],position[2]); - // correct for e- attenuation - // geo::TPCGeo const& tpcGeo = geom->TPC({0, 0}); - // double drift_time1 = (abs(tpcGeo.MaxX()) - abs(position[0]))/(det_prop.DriftVelocity()); // cm / (cm/us) - auto drift_time = hit->PeakTime()*0.5 - clock_data.TriggerOffsetTPC(); - double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) - double charge = (1/_cal_area_const.at(bestPlane))*atten_correction*hit->Integral(); - sp_xyz.push_back(xyz); - sp_charge.push_back(charge); - - _sp_charge += charge; - if (pfpistrack) _trk_sp_charge +=charge; - if (pfpisshower) _shw_sp_charge +=charge; - - if (xyz.X() > _sp_max_x) _sp_max_x = xyz.X(); - if (xyz.X() < _sp_min_x) _sp_min_x = xyz.X(); - if (xyz.Y() > _sp_max_y) _sp_max_y = xyz.Y(); - if (xyz.Y() < _sp_min_y) _sp_min_y = xyz.Y(); - if (xyz.Z() > _sp_max_z) _sp_max_z = xyz.Z(); - if (xyz.Z() < _sp_min_z) _sp_min_z = xyz.Z(); - - } - } // end spacepoint loop - } // end pfp loop - - // get total L count - std::vector> visibility_maps = CalcVisibility(sp_xyz,sp_charge); - auto dir_visibility_map = visibility_maps[0]; - auto ref_visibility_map = visibility_maps[1]; - - std::vector total_pe(_nchan,0.); - std::vector total_gamma(_nchan, 0.); - - // combining flash PE information from separate TPCs into a single vector - for (int tpc=0; tpc<2; tpc++){ - bool found_flash = (tpc==0)? flash_in_0 : flash_in_1; - if (found_flash){ - auto flash_pe_v = (tpc==0)? opflash0->PEs() : opflash1->PEs(); - // if using arapucas, need to combine PMT and arapuca PE information into a single vector - if (_use_arapucas){ - auto flash_ara_v = (tpc==0)? flash0_ara_v : flash1_ara_v; - // for PMT flashes, the PE vector is shortened and don't include the last 6 entries for ARAPUCAs - if (flash_pe_v.size()!= _nchan) flash_pe_v.insert(flash_pe_v.end(), {0,0,0,0,0,0}); - for (size_t nara=0; nara < flash_ara_v.size(); nara++){ - auto const &flash_ara = *flash_ara_v[nara]; - if (abs(flash_time-flash_ara.Time()) < _pmt_ara_offset){ - if (_verbose) - std::cout << "Combining PMT+XARA Flashes with PMT time: " << flash_time << ", ARA time: " << flash_ara.Time() << std::endl; - for (size_t ich=0; ich < (flash_ara.PEs()).size(); ich++) - flash_pe_v.at(ich) += (flash_ara.PEs()).at(ich); - break; - } - } - } // end of arapuca if - for (size_t ich=0; ichWph(); // MeV, Wph = 19.5 eV - - _true_gamma = 0; - _true_charge = 0; - _true_energy = 0; - - if (_truth_validation){ - ::art::Handle> energyDeps_h; - e.getByLabel(_simenergy_producer, energyDeps_h); - std::vector> energyDeps; - - if (!energyDeps_h.isValid() || energyDeps_h->empty()) - std::cout << "Don't have good SimEnergyDeposits!" << std::endl; - else - art::fill_ptr_vector(energyDeps, energyDeps_h); - - for (size_t n_dep=0; n_dep < energyDeps.size(); n_dep++){ - auto energyDep = energyDeps[n_dep]; - const auto trackID = energyDep->TrackID(); - const double time = energyDep->Time() * 1e-3; // us - - art::Ptr mctruth = piserv->TrackIdToMCTruth_P(trackID); - - if ((_truth_neutrino && mctruth->Origin()==simb::kBeamNeutrino ) || - (!_truth_neutrino && abs(time-flash_time) < 1)){ - // note: we divide by the prescale because NumPhotons() stored in simulation has the scint prescale applied - _true_gamma += energyDep->NumPhotons()/_scint_prescale; - _true_charge += energyDep->NumElectrons(); - _true_energy += energyDep->Energy(); - } - } - _frac_L = (_true_gamma - _slice_L)/_true_gamma; - _frac_Q = (_true_charge - _slice_Q)/_true_charge; - _frac_E = (_true_energy - _slice_E)/_true_energy; - - if (_verbose){ - std::cout << "ratio of gamma (median/true): " << _median_gamma/_true_gamma << std::endl; - std::cout << "ratio of gamma (mean/true): " << _mean_gamma/_true_gamma << std::endl; - - std::cout << "ratio of electron (mean/true): " << _mean_charge/_true_charge << std::endl; - std::cout << "ratio of electron (max/true): " << _max_charge/_true_charge << std::endl; - std::cout << "ratio of electron (comp/true): " << _comp_charge/_true_charge << std::endl; - - std::cout << "ratio of energy (calc/true): " << _slice_E/_true_energy << std::endl; - } - } - else{ - _true_gamma = -9999; - _true_charge = -9999; - _true_energy = -9999; - _frac_L = -9999; - _frac_Q = -9999; - _frac_E = -9999; - } - _tree2->Fill(); - nsuccessful_matches++; - } // end slice loop - _match_type=nsuccessful_matches; - _tree->Fill(); -} // end analyze - - -// define functions - -bool sbnd::LightCaloAna::MatchOpFlash(std::vector> fm_v, - std::vector> flash_v, - std::vector> &match_v){ - bool any_match = false; - for (size_t ifm=0; ifm nullOpFlash; - bool found_match = false; - auto match_time = fm->time; - for (size_t iop=0; iopTime() - match_time) < _simple_op_offset){ - found_match = true; - any_match = true; - match_v.push_back(opflash); - break; - } - } - if (found_match == false) match_v.push_back(nullOpFlash); - } - if (match_v.size() != fm_v.size()) std::cout << "mismatched opflash and simpleflash vector sizes!" << std::endl; - return any_match; -} - - -std::vector> sbnd::LightCaloAna::CalcVisibility(std::vector xyz_v, - std::vector charge_v){ - // returns of two vectors (len is # of opdet) for the visibility for every opdet - if (xyz_v.size() != charge_v.size()) std::cout << "spacepoint coord and charge vector size mismatch" << std::endl; - - std::vector dir_visibility_map(_nchan, 0); - std::vector ref_visibility_map(_nchan, 0); - double sum_charge0 = 0; - double sum_charge1 = 0; - - for (size_t i=0; i direct_visibility; - std::vector reflect_visibility; - _semi_model->detectedDirectVisibilities(direct_visibility, xyz); - _semi_model->detectedReflectedVisibilities(reflect_visibility, xyz); - // if (dir_visibility_map.size() != direct_visibility.size()) std::cout << "mismatch of visibility vector size" << std::endl; - - // weight by charge - for (size_t ch=0; ch flash_pe_v, - std::vector dir_visibility, - std::vector ref_visibility, - std::vector &total_gamma_v){ - for (size_t ch = 0; ch < flash_pe_v.size(); ch++){ - auto pe = flash_pe_v[ch]; - auto vuv_eff = _opdet_vuv_eff.at(ch); - auto vis_eff = _opdet_vis_eff.at(ch); - auto tot_visibility = vuv_eff*dir_visibility[ch] + vis_eff*ref_visibility[ch]; - _visibility.at(ch) = tot_visibility; - if((pe == 0) || std::isinf(1/tot_visibility)) - continue; - // deposited light is inverse of visibility * PE count - total_gamma_v[ch] += (1/tot_visibility)*pe; - } -} - -double sbnd::LightCaloAna::CalcMedian(std::vector total_gamma){ - std::vector tpc0_gamma; - std::vector tpc1_gamma; - // split into two TPCs - for (size_t i=0; i idx(gamma_v.size()); - std::iota(idx.begin(), idx.end(), 0); - std::sort(idx.begin(), idx.end(), - [&](int A, int B) -> bool { - return gamma_v[A] < gamma_v[B]; - }); - // count number of zero entries - int zero_counter = 0; - for (size_t i=0; i < gamma_v.size(); i++){ - if (gamma_v.at(i) <= 0) zero_counter++; - } - int med_idx=0; - if (zero_counter != int(gamma_v.size())){ - med_idx = idx.at(int((gamma_v.size()-zero_counter))/2 + zero_counter); - median = gamma_v.at(med_idx); - } - median_gamma+=median; - } - return median_gamma; -} - -double sbnd::LightCaloAna::CalcMean(std::vector total_gamma){ - std::vector tpc0_gamma; - std::vector tpc1_gamma; - for (size_t i=0; i0){ - counter+=1.0; - sum+=gamma; - } - } - if (sum!=0) mean_gamma+= sum/counter; - } - return mean_gamma; -} - -DEFINE_ART_MODULE(sbnd::LightCaloAna) diff --git a/sbndcode/Calorimetry/MCCaloAna_config.fcl b/sbndcode/Calorimetry/MCCaloAna_config.fcl deleted file mode 100644 index 7f0d6c46d..000000000 --- a/sbndcode/Calorimetry/MCCaloAna_config.fcl +++ /dev/null @@ -1,17 +0,0 @@ -#include "opticalsimparameterisations_sbnd.fcl" -#include "sbndopticalpath_tool.fcl" - -BEGIN_PROLOG -mccaloana: -{ - module_type: "MCCaloAna" - - VUVHits: @local::sbnd_vuv_RS100cm_hits_parameterization - VIVHits: @local::sbnd_vis_RS100cm_hits_parameterization - OpticalPathTool: @local::SBNDOpticalPath - - OpDetVUVEfficiencies: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021] - OpDetVISEfficiencies: [0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - -} -END_PROLOG \ No newline at end of file diff --git a/sbndcode/Calorimetry/MCCaloAna_module.cc b/sbndcode/Calorimetry/MCCaloAna_module.cc deleted file mode 100644 index 8bb4b38e1..000000000 --- a/sbndcode/Calorimetry/MCCaloAna_module.cc +++ /dev/null @@ -1,482 +0,0 @@ -//////////////////////////////////////////////////////////////////////// -// Class: MCCaloAna -// Plugin Type: analyzer (Unknown Unknown) -// File: MCCaloAna_module.cc -// -// Generated at Tue Apr 29 12:33:40 2025 by Lynn Tung using cetskelgen -// from cetlib version 3.18.02. -//////////////////////////////////////////////////////////////////////// - -#include "art/Framework/Core/EDAnalyzer.h" -#include "art/Framework/Core/ModuleMacros.h" -#include "art/Framework/Principal/Event.h" -#include "art/Framework/Principal/Handle.h" -#include "art/Framework/Principal/Run.h" -#include "art/Framework/Principal/SubRun.h" -#include "art/Utilities/make_tool.h" -#include "canvas/Utilities/InputTag.h" -#include "fhiclcpp/ParameterSet.h" -#include "messagefacility/MessageLogger/MessageLogger.h" - -#include "larsim/MCCheater/ParticleInventoryService.h" -#include "lardataobj/Simulation/SimEnergyDeposit.h" -#include "lardataobj/Simulation/SimPhotons.h" -#include "nusimdata/SimulationBase/MCTruth.h" - -#include "larsim/PhotonPropagation/SemiAnalyticalModel.h" -#include "larsim/PhotonPropagation/OpticalPathTools/OpticalPath.h" -#include "larcore/Geometry/Geometry.h" -#include "larcorealg/Geometry/GeometryCore.h" -#include "sbndcode/OpDetSim/sbndPDMapAlg.hh" - -#include "art_root_io/TFileService.h" -#include "TFile.h" -#include "TTree.h" - -#include - -namespace sbnd { - class MCCaloAna; -} - - -class sbnd::MCCaloAna : public art::EDAnalyzer { -public: - explicit MCCaloAna(fhicl::ParameterSet const& p); - // The compiler-generated destructor is fine for non-base - // classes without bare pointers or other resource use. - - // Plugins should not be copied or assigned. - MCCaloAna(MCCaloAna const&) = delete; - MCCaloAna(MCCaloAna&&) = delete; - MCCaloAna& operator=(MCCaloAna const&) = delete; - MCCaloAna& operator=(MCCaloAna&&) = delete; - - // Required functions. - void analyze(art::Event const& e) override; - -private: - TTree* _tree; - - int _run; - int _subrun; - int _event; - - double _nu_E; - double _nu_P; - int _nu_CCNC; - double _nu_X; - double _nu_Y; - double _nu_Z; - - double _min_x, _max_x, _min_y, _max_y, _min_z, _max_z; - - double _true_gamma; - double _true_charge; - double _true_energy; - - std::vector _true_gamma_tpc; - std::vector _true_measphotons; - std::vector _true_resimphotons; - - std::vector _chargecorr_gamma; - std::vector _chargecorr_visibility; - std::vector _chargecorr_visibility_witheff; - std::vector _lightcorr_gamma; - std::vector _lightcorr_gamma_resim; - std::vector _lightcorr_visibility; - std::vector _lightcorr_visibility_witheff; - - std::vector _opdet_vuv_eff; - std::vector _opdet_vis_eff; - - std::unique_ptr _semi_model; - fhicl::ParameterSet _vuv_params; - fhicl::ParameterSet _vis_params; - std::shared_ptr _optical_path_tool; - - opdet::sbndPDMapAlg _opdetmap; //map for photon detector types - unsigned int _nchan = _opdetmap.size(); - - - std::vector> CalcVisibility(std::vector xyz_v, - std::vector charge_v); - std::vector> CalcPE(std::vector xyz_v, - std::vector light_v); - std::vector> FillSimPhotonsLite(std::vector >> photonHandle_list); - void CalcLight(std::vector flash_pe_v, - std::vector dir_visibility, - std::vector ref_visibility, - std::vector &total_gamma_v, - std::vector &total_visibility_v); -}; - -sbnd::MCCaloAna::MCCaloAna(fhicl::ParameterSet const& p) - : EDAnalyzer{p} // , - // More initializers here. -{ - _vuv_params = p.get("VUVHits"); - _vis_params = p.get("VIVHits"); - _optical_path_tool = std::shared_ptr(art::make_tool(p.get("OpticalPathTool"))); - _semi_model = std::make_unique(_vuv_params, _vis_params, _optical_path_tool, true, false); - _opdet_vuv_eff = p.get>("OpDetVUVEfficiencies"); - _opdet_vis_eff = p.get>("OpDetVISEfficiencies"); - - art::ServiceHandle fs; - _tree = fs->make("mccalo_tree",""); - _tree->Branch("run", &_run, "run/I"); - _tree->Branch("subrun", &_subrun, "subrun/I"); - _tree->Branch("event", &_event, "event/I"); - _tree->Branch("nu_E", &_nu_E, "nu_E/D"); - _tree->Branch("nu_P", &_nu_P, "nu_P/D"); - _tree->Branch("nu_CCNC", &_nu_CCNC, "nu_CCNC/I"); - _tree->Branch("nu_X", &_nu_X, "nu_X/D"); - _tree->Branch("nu_Y", &_nu_Y, "nu_Y/D"); - _tree->Branch("nu_Z", &_nu_Z, "nu_Z/D"); - _tree->Branch("max_x", &_max_x, "max_x/D"); - _tree->Branch("max_y", &_max_y, "max_y/D"); - _tree->Branch("max_z", &_max_z, "max_z/D"); - _tree->Branch("min_x", &_min_x, "min_x/D"); - _tree->Branch("min_y", &_min_y, "min_y/D"); - _tree->Branch("min_z", &_min_z, "min_z/D"); - _tree->Branch("true_gamma", &_true_gamma, "true_gamma/D"); - _tree->Branch("true_charge", &_true_charge, "true_charge/D"); - _tree->Branch("true_energy", &_true_energy, "true_energy/D"); - _tree->Branch("true_gamma_tpc", "std::vector", &_true_gamma_tpc); - _tree->Branch("true_measphotons","std::vector", &_true_measphotons); - _tree->Branch("true_resimphotons","std::vector", &_true_resimphotons); - _tree->Branch("chargecorr_gamma", "std::vector", &_chargecorr_gamma); - _tree->Branch("chargecorr_visibility","std::vector", &_chargecorr_visibility); - _tree->Branch("chargecorr_visibility_witheff","std::vector", &_chargecorr_visibility_witheff); - _tree->Branch("lightcorr_gamma", "std::vector", &_lightcorr_gamma); - _tree->Branch("lightcorr_gamma_resim","std::vector",&_lightcorr_gamma_resim); - _tree->Branch("lightcorr_visibility","std::vector", &_lightcorr_visibility); - _tree->Branch("lightcorr_visibility_witheff","std::vector", &_lightcorr_visibility_witheff); -} - -void sbnd::MCCaloAna::analyze(art::Event const& e) -{ - _run = e.id().run(); - _subrun = e.id().subRun(); - _event = e.id().event(); - - _nu_E = 0; - _nu_P = 0; - _nu_CCNC = -1; - _nu_X = -999; - _nu_Y = -999; - _nu_Z = -999; - _true_gamma = 0; - _true_charge = 0; - _true_energy = 0; - - _min_x = _min_y = _min_z = 1e9; - _max_x = _max_y = _max_z = -1e9; - - _true_gamma_tpc.clear(); - _true_measphotons.clear(); - _true_resimphotons.clear(); - - _chargecorr_gamma.clear(); - _chargecorr_visibility.clear(); - _chargecorr_visibility_witheff.clear(); - _lightcorr_gamma.clear(); - _lightcorr_gamma_resim.clear(); - _lightcorr_visibility.clear(); - _lightcorr_visibility_witheff.clear(); - - art::ServiceHandle piserv; - - art::Handle> mctruth_handle; - e.getByLabel("generator", mctruth_handle); - - std::vector> mctruths; - if (mctruth_handle.isValid()) - art::fill_ptr_vector(mctruths, mctruth_handle); - - ::art::Handle> energyDeps_h; - e.getByLabel("ionandscint", energyDeps_h); - std::vector> energyDeps; - - if (!energyDeps_h.isValid() || energyDeps_h->empty()) - std::cout << "Don't have good SimEnergyDeposits!" << std::endl; - else - art::fill_ptr_vector(energyDeps, energyDeps_h); - - std::vector >> fLitePhotonHandle_list; - fLitePhotonHandle_list = e.getMany>(); - auto opdet_simphotons = FillSimPhotonsLite(fLitePhotonHandle_list); - - std::vector edep_photons; - std::vector edep_electrons; - std::vector edep_energy; - std::vector edep_points; - // std::vector> edep_x, edep_y, edep_z; - - _true_measphotons.resize(_nchan,0); - _true_resimphotons.resize(_nchan,0); - - _true_gamma_tpc.resize(2,0); - - edep_photons.resize(mctruths.size()); - edep_electrons.resize(mctruths.size()); - edep_energy.resize(mctruths.size()); - edep_points.resize(mctruths.size()); - - for (size_t n_dep=0; n_dep < energyDeps.size(); n_dep++){ - auto energyDep = energyDeps[n_dep]; - const auto trackID = energyDep->TrackID(); - - art::Ptr mctruth = piserv->TrackIdToMCTruth_P(trackID); - - auto nparticles = mctruth->NParticles(); - std::cout << "nparticles: " << nparticles << std::endl; - if (mctruth->Origin() == simb::kBeamNeutrino) - _nu_CCNC = mctruth->GetNeutrino().CCNC(); - for (int p=0; p < nparticles; p++){ - simb::MCParticle const& par = mctruth->GetParticle(p); - std::cout << "pdg: " << par.PdgCode() << std::endl; - if (par.StatusCode()==0 && mctruth->Origin()==simb::kBeamNeutrino){ - _nu_E = par.E(); - _nu_P = par.P(); - _nu_X = par.Vx(); - _nu_Y = par.Vy(); - _nu_Z = par.Vz(); - break; - } - else if (par.StatusCode()==1 && mctruth->Origin()==4){ - _nu_E = par.E(); - _nu_P = par.P(); - _nu_X = par.Vx(); - _nu_Y = par.Vy(); - _nu_Z = par.Vz(); - break; - } - } - - // auto it = std::find(mctruths.begin(), mctruths.end(), mctruth); - // if (it == mctruths.end()) { - // std::cout << "No matching MCTruth found for trackID: " << trackID << std::endl; - // continue; - // } - - // // get the index of the mctruth in the set - // auto mctruth_index = std::distance(mctruths.begin(), it); - - _true_gamma += energyDep->NumPhotons(); - _true_charge += energyDep->NumElectrons(); - _true_energy += energyDep->Energy(); - - edep_photons.push_back(energyDep->NumPhotons()); - edep_electrons.push_back(energyDep->NumElectrons()); - edep_energy.push_back(energyDep->Energy()); - edep_points.push_back(energyDep->Start()); - - if (energyDep->Start().X() < 0) - _true_gamma_tpc.at(0) += energyDep->NumPhotons(); - else - _true_gamma_tpc.at(1) += energyDep->NumPhotons(); - - if (energyDep->Start().X() > _max_x) _max_x = energyDep->Start().X(); - if (energyDep->Start().Y() > _max_y) _max_y = energyDep->Start().Y(); - if (energyDep->Start().Z() > _max_z) _max_z = energyDep->Start().Z(); - if (energyDep->Start().X() < _min_x) _min_x = energyDep->Start().X(); - if (energyDep->Start().Y() < _min_y) _min_y = energyDep->Start().Y(); - if (energyDep->Start().Z() < _min_z) _min_z = energyDep->Start().Z(); - } - - - auto resim_pe = CalcPE(edep_points,edep_photons); - - for (size_t ich=0; ich < opdet_simphotons.at(0).size(); ich++){ - std::string pd_type = _opdetmap.pdType(ich); - if(pd_type=="xarapuca_vis" || pd_type=="xarapuca_vuv") continue; - _true_measphotons.at(ich) = opdet_simphotons.at(0).at(ich) + opdet_simphotons.at(1).at(ich); - _true_resimphotons.at(ich) = resim_pe.at(0).at(ich) + resim_pe.at(1).at(ich); - // std::cout << "ich " << ich << " (dir sim/resim): " << opdet_simphotons.at(0).at(ich) << ", " << resim_pe.at(0).at(ich) << std::endl; - // std::cout << "ich " << ich << " (ref sim/resim): " << opdet_simphotons.at(1).at(ich) << ", " << resim_pe.at(1).at(ich) << std::endl; - } - - for (size_t nnu; nnu < mctruths.size(); nnu++){ - auto true_vis_charge = CalcVisibility(edep_points,edep_electrons); - auto true_vis_light = CalcVisibility(edep_points,edep_photons); - - _chargecorr_gamma.resize(_nchan,0); - _chargecorr_visibility.resize(_nchan,0); - _chargecorr_visibility_witheff.resize(_nchan,0); - _lightcorr_gamma.resize(_nchan,0); - _lightcorr_gamma_resim.resize(_nchan,0); - _lightcorr_visibility.resize(_nchan,0); - _lightcorr_visibility_witheff.resize(_nchan,0); - - CalcLight(_true_measphotons, true_vis_charge.at(0), true_vis_charge.at(1),_chargecorr_gamma,_chargecorr_visibility); - CalcLight(_true_measphotons, true_vis_light.at(0), true_vis_light.at(1),_lightcorr_gamma,_lightcorr_visibility); - CalcLight(_true_resimphotons, true_vis_light.at(0), true_vis_light.at(1),_lightcorr_gamma_resim,_lightcorr_visibility); - - for (uint ch = 0; ch < _nchan; ch++){ - auto vuv_eff = _opdet_vuv_eff.at(ch); - auto vis_eff = _opdet_vis_eff.at(ch); - _chargecorr_visibility_witheff[ch] = vuv_eff*true_vis_charge.at(0)[ch] + vis_eff*true_vis_charge.at(1)[ch]; - _lightcorr_visibility_witheff[ch] = vuv_eff*true_vis_light.at(0)[ch] + vis_eff*true_vis_light.at(1)[ch]; - } - } - - _tree->Fill(); -} - -std::vector> sbnd::MCCaloAna::CalcVisibility(std::vector xyz_v, - std::vector charge_v){ - // returns of two vectors (len is # of opdet) for the visibility for every opdet - if (xyz_v.size() != charge_v.size()) std::cout << "spacepoint coord and charge vector size mismatch" << std::endl; - - std::vector dir_visibility_map(_nchan, 0); - std::vector ref_visibility_map(_nchan, 0); - double sum_charge0 = 0; - double sum_charge1 = 0; - - // std::cout << "initial dir_visibility_map: " << dir_visibility_map[7] << std::endl; - // std::cout << "initial ref_visibility_map: " << ref_visibility_map[7] << std::endl; - for (size_t i=0; i direct_visibility; - std::vector reflect_visibility; - _semi_model->detectedDirectVisibilities(direct_visibility, xyz); - _semi_model->detectedReflectedVisibilities(reflect_visibility, xyz); - if (dir_visibility_map.size() != direct_visibility.size()) std::cout << "mismatch of visibility vector size" << std::endl; - // if (i < 10){ - // std::cout << "xyz: " << xyz << std::endl; - // std::cout << "charge: " << charge << std::endl; - // std::cout << "dir_visibility : " << direct_visibility[7] << std::endl; - // std::cout << "ref_visibility : " << reflect_visibility[7] << std::endl; - // std::cout << "dir_visibility_map: " << dir_visibility_map[7] << std::endl; - // std::cout << "ref_visibility_map: " << ref_visibility_map[7] << std::endl; - // } - // weight by charge - for (size_t ch=0; ch> sbnd::MCCaloAna::CalcPE(std::vector xyz_v, - std::vector light_v){ - // returns of two vectors (len is # of opdet) for the visibility for every opdet - - std::vector> pe_v(2); - for (size_t i=0; i<2;i++){ - pe_v.at(i).resize(_nchan,0); - } - - for (size_t i=0; i direct_visibility; - std::vector reflect_visibility; - _semi_model->detectedDirectVisibilities(direct_visibility, xyz); - _semi_model->detectedReflectedVisibilities(reflect_visibility, xyz); - - for (size_t ich=0;ich<_nchan;ich++){ - pe_v.at(0).at(ich) += light*direct_visibility.at(ich); - pe_v.at(1).at(ich) += light*reflect_visibility.at(ich); - } - } - return pe_v; -} - -std::vector> sbnd::MCCaloAna::FillSimPhotonsLite(std::vector >> photonHandle_list){ - std::vector fPDTypes{"pmt_coated", "pmt_uncoated"}; - std::vector> opdet_simphotons; - opdet_simphotons.resize(2); - for (size_t i=0; i<2; i++){ - opdet_simphotons.at(i).resize(_nchan,0); - } - - for ( const art::Handle>& litePhotonHandle: (photonHandle_list) ){ - - std::string spLabel = litePhotonHandle.provenance()->moduleLabel(); - std::vector fSimPhotonsModuleLabel{"pdfastsim"}; - if(std::find(fSimPhotonsModuleLabel.begin(), fSimPhotonsModuleLabel.end(), spLabel)==fSimPhotonsModuleLabel.end()) continue; - - // Reflected light - bool reflected = (litePhotonHandle.provenance()->productInstanceName() == "Reflected"); - - // Loop over the SimPhotonsLite - for ( auto const& fLitePhotons : (*litePhotonHandle) ){ - - int opch=fLitePhotons.OpChannel; - - std::string pd_type = _opdetmap.pdType(opch); - // Channels not sensitive to reflected light - if(reflected && pd_type=="xarapuca_vuv") continue; - // Channels not sensitive to direct light - if(!reflected && (pd_type=="xarapuca_vis" || pd_type=="pmt_uncoated")) continue; - - // Only save the PD types specified in the fhicl list - if(std::find(fPDTypes.begin(), fPDTypes.end(), pd_type ) != fPDTypes.end() ){ - - std::map fLitePhotons_map = fLitePhotons.DetectedPhotons; - int nphotons=0; - - for(auto fphoton = fLitePhotons_map.begin(); fphoton!= fLitePhotons_map.end(); fphoton++){ - nphotons+=fphoton->second; - } - - // Fill #photons per OpChannel - if(reflected){ - opdet_simphotons.at(1).at(opch)+=nphotons; - } - else{ - opdet_simphotons.at(0).at(opch)+=nphotons; - } - } - } - } - - return opdet_simphotons; -} - - -void sbnd::MCCaloAna::CalcLight(std::vector flash_pe_v, - std::vector dir_visibility, - std::vector ref_visibility, - std::vector &total_gamma_v, - std::vector &tot_visibility_v){ - for (size_t ch = 0; ch < flash_pe_v.size(); ch++){ - auto pe = flash_pe_v[ch]; - // auto vuv_eff = _opdet_vuv_eff.at(ch); - // auto vis_eff = _opdet_vis_eff.at(ch); - auto vuv_eff = 1.0; - auto vis_eff = 1.0; - auto tot_visibility = vuv_eff*dir_visibility[ch] + vis_eff*ref_visibility[ch]; - tot_visibility_v.at(ch) = tot_visibility; - if((pe == 0) || std::isinf(1/tot_visibility)) - continue; - // deposited light is inverse of visibility * PE count - total_gamma_v[ch] += (1/tot_visibility)*pe; - } -} - -DEFINE_ART_MODULE(sbnd::MCCaloAna) diff --git a/sbndcode/Calorimetry/lightcalo_ana.fcl b/sbndcode/Calorimetry/lightcalo_ana.fcl deleted file mode 100644 index d3b4e2af6..000000000 --- a/sbndcode/Calorimetry/lightcalo_ana.fcl +++ /dev/null @@ -1,50 +0,0 @@ -#include "opticalsimparameterisations_sbnd.fcl" -#include "sbndopticalpath_tool.fcl" - -BEGIN_PROLOG -lightcaloana: -{ - module_type: "LightCaloAna" - - VUVHits: @local::sbnd_vuv_RS100cm_hits_parameterization - VIVHits: @local::sbnd_vis_RS100cm_hits_parameterization - OpticalPathTool: @local::SBNDOpticalPath - - OpFlashProducers: ["opflashtpc0", "opflashtpc1"] - OpFlashAraProducers: ["opflashtpc0xarapuca", "opflashtpc1xarapuca"] - SliceProducer: "pandora" - FlashMatchProducer: "fmatch" - OpT0FinderProducer: "opt0finder" - UseArapucas: false - UseOpT0Finder: true - nuScoreCut: 0.4 # default: accept nusScore > 0.4, to analyze all slices, set nuScoreCut = -1 - fmScoreCut: 7 # default: accept 0 < fm score < fmScoreCut, to analyze all slices, set fmScoreCut = 1e3 - opt0ScoreCut: 200 # default: accept opt0 match > opt0ScoreCut - - Verbose: false - - SimpleOpFlashOffset: 0.2 # the offset between the t0 from SimpleFlash and OpFlashes - - OpT0FlashMin: 0.0 # simulation [0.0], light-triggered data [-0.8] - OpT0FlashMax: 2.0 # simulation [2.0], light-triggered data [2.0] - OpT0FractionalCut: 0.5 - - # flash parameters - PMTARAFlashOffset: 0.05 # the offset between the t0 of PMT OpFlashes and X-ARA OpFlashes - FlashNoiseThreshold: [ 600., 1500. ] # {PMT, xARAPUCA}, flash total PE threshold to ignore a flash - - # calibration constants & simulation parameters - ## shouldn't have to change this unless you change simulation parameters - CalAreaConstants: [ 0.0200906, 0.0200016, 0.0201293 ] # calibration constants for wire planes - OpDetVUVEfficiencies: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021] - OpDetVISEfficiencies: [0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - OpDetMask : [39, 66, 67, 71, 85, 86, 87, 92, 115, 138, 141, 170, 197, 217, 218, 221, 222, 223, 226, 245, 248, 249, 302] - - ScintPreScale: 0.039 # Scintillation Pre-Scale factor in simulation (set in ionandscint) - - # parameters for truth validation - TruthValidation: false # can only set to true if the reco2 files have SimEnergyDeposits - SimEnergyProducer: "ionandscint" # only looking at energy deposits in the AV - TruthNeutrino: true # if validating anything other than simb::kBeamNeutrino, set to false -} -END_PROLOG diff --git a/sbndcode/Calorimetry/run_lightcaloana.fcl b/sbndcode/Calorimetry/run_lightcaloana.fcl deleted file mode 100644 index 23cc9070a..000000000 --- a/sbndcode/Calorimetry/run_lightcaloana.fcl +++ /dev/null @@ -1,50 +0,0 @@ -#include "lightcalo_ana.fcl" -#include "particleinventoryservice.fcl" -#include "services_sbnd.fcl" -#include "simulationservices_sbnd.fcl" -#include "rootoutput_sbnd.fcl" - -process_name: LightCaloAna - -services: { - # TFileService : {fileName: @local::sbnd_tfileoutput.fileName} - TFileService: {fileName: "lightcalo_tree.root"} - ParticleInventoryService: @local::standard_particleinventoryservice - @table::sbnd_services # from services_sbnd.fcl - @table::sbnd_g4_services - -} - -source: -{ - module_type: RootInput - maxEvents: -1 # Number of events to create -} - -outputs: -{ -} - -physics: -{ - - producers:{ - } - - filters:{} - - analyzers:{ - lightcaloana: @local::lightcaloana - } - - # define the output stream, there could be more than one if using filters - stream1: [lightcaloana] - - # trigger_paths is a keyword and contains the paths that modify the art::event, - # ie filters and producers - trigger_paths: [] - - # end_paths is a keyword and contains the paths that do not modify the art::Event, - # ie analyzers and output streams. these all run simultaneously - end_paths: [stream1] -} \ No newline at end of file diff --git a/sbndcode/Calorimetry/run_lightcaloana_data.fcl b/sbndcode/Calorimetry/run_lightcaloana_data.fcl deleted file mode 100644 index 4490e6205..000000000 --- a/sbndcode/Calorimetry/run_lightcaloana_data.fcl +++ /dev/null @@ -1,53 +0,0 @@ -#include "lightcalo_ana.fcl" -#include "particleinventoryservice.fcl" -#include "services_sbnd.fcl" -#include "simulationservices_sbnd.fcl" -#include "rootoutput_sbnd.fcl" - -process_name: LightCaloAna - -services: { - TFileService : {fileName: @local::sbnd_tfileoutput.fileName} - ParticleInventoryService: @local::standard_particleinventoryservice - @table::sbnd_services # from services_sbnd.fcl - @table::sbnd_g4_services -} - -source: -{ - module_type: RootInput - maxEvents: -1 # Number of events to create -} - -outputs: -{ -} - -physics: -{ - - producers:{ - } - - filters:{} - - analyzers:{ - lightcaloana: @local::lightcaloana - } - - # define the output stream, there could be more than one if using filters - stream1: [lightcaloana] - - # trigger_paths is a keyword and contains the paths that modify the art::event, - # ie filters and producers - trigger_paths: [] - - # end_paths is a keyword and contains the paths that do not modify the art::Event, - # ie analyzers and output streams. these all run simultaneously - end_paths: [stream1] -} - -physics.analyzers.lightcaloana.OpT0FlashMin: -1 -physics.analyzers.lightcaloana.OpT0FlashMax: 5 -# physics.analyzers.lightcaloana.Verbose: false -physics.analyzers.lightcaloana.CalAreaConstants: [0.0211 , 0.0209, 0.0204] diff --git a/sbndcode/Calorimetry/run_mcana.fcl b/sbndcode/Calorimetry/run_mcana.fcl deleted file mode 100644 index 169f78a91..000000000 --- a/sbndcode/Calorimetry/run_mcana.fcl +++ /dev/null @@ -1,53 +0,0 @@ -#include "particleinventoryservice.fcl" -#include "services_sbnd.fcl" -#include "simulationservices_sbnd.fcl" -#include "rootoutput_sbnd.fcl" -#include "MCCaloAna_config.fcl" - -process_name: MCCaloAna - -services: { - TFileService : {fileName: "mcanacalo.root"} - ParticleInventoryService: @local::standard_particleinventoryservice - @table::sbnd_services # from services_sbnd.fcl - @table::sbnd_g4_services -} - -source: -{ - module_type: RootInput - maxEvents: -1 # Number of events to create -} - -outputs: -{ - out1: - { - @table::sbnd_rootoutput - dataTier: "simulated" - } -} - -physics: -{ - - producers:{ - } - - filters:{} - - analyzers:{ - mccaloana: @local::mccaloana - } - - # define the output stream, there could be more than one if using filters - stream1: [out1, mccaloana] - - # trigger_paths is a keyword and contains the paths that modify the art::event, - # ie filters and producers - trigger_paths: [] - - # end_paths is a keyword and contains the paths that do not modify the art::Event, - # ie analyzers and output streams. these all run simultaneously - end_paths: [stream1] -} \ No newline at end of file From 26e3199957b085f25df21ea226dfc4aa0e5f33dd Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Tue, 18 Nov 2025 13:21:37 -0600 Subject: [PATCH 50/52] remove unecessary branches, TTrees, and fix mean functions --- .../Calorimetry/LightCaloProducer_module.cc | 172 +++++++----------- 1 file changed, 62 insertions(+), 110 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 0e3caeeb2..860c0afe5 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -169,16 +169,6 @@ class sbnd::LightCaloProducer : public art::EDProducer { TTree* _tree; int _run, _subrun, _event; - int _match_type; - // match_type key: - /// -1: no slices passed both the nuscore and flash match score cut (in the entire event) - /// -2: no opflashes times found in coincidence with simpleflash time (in the entire event) - /// -3: no opflashes in coincidence with simpleflash (for this slice) - /// -4: opflashes are below the noise threshold (for this slice) - /// 1: successful match - - TTree* _tree2; - int _nmatch=0; // number of matches in an event int _pfpid; // ID of the matched slice double _opflash_time; // time of matched opflash @@ -191,21 +181,10 @@ class sbnd::LightCaloProducer : public art::EDProducer { std::vector _visibility; - double _median_gamma; // median of all reconstructed light estimates - double _mean_gamma; // mean of all reconstructed light estimates - - double _mean_charge; // avg charge from all three planes - double _max_charge; // charge from the plane with the highest amount of charge - double _comp_charge; // charge from the plane with the highest number of hits, "highest completeness" - double _slice_L; // reconstructed photon count double _slice_Q; // reconstructed electron count double _slice_E; // reconstructed deposited energy - std::vector _charge = std::vector(3); // reconstructed electron count per plane - std::vector _light_med = std::vector(3); // median reconstructed photon count per plane - std::vector _light_avg = std::vector(3); // average reconstructed photon count per plane - std::vector _energy = std::vector(3); }; @@ -250,38 +229,24 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) geom = lar::providerFrom(); art::ServiceHandle fs; - _tree = fs->make("slice_tree",""); - _tree->Branch("run", &_run, "run/I"); - _tree->Branch("subrun", &_subrun, "subrun/I"); - _tree->Branch("event", &_event, "event/I"); - _tree->Branch("match_type", &_match_type, "match_type/I"); - - _tree2 = fs->make("match_tree",""); - _tree2->Branch("run", &_run, "run/I"); - _tree2->Branch("subrun", &_subrun, "subrun/I"); - _tree2->Branch("event", &_event, "event/I"); - _tree2->Branch("nmatch", &_nmatch, "nmatch/I"); - _tree2->Branch("pfpid", &_pfpid, "pfpid/I"); - _tree2->Branch("opflash_time", &_opflash_time, "opflash_time/D"); - - _tree2->Branch("rec_gamma", "std::vector", &_rec_gamma); - _tree2->Branch("dep_pe", "std::vector", &_dep_pe); - - _tree2->Branch("true_gamma", &_true_gamma, "true_gamma/D"); - _tree2->Branch("true_charge", &_true_charge, "true_charge/D"); - _tree2->Branch("true_energy", &_true_energy, "true_energy/D"); - - _tree2->Branch("visibility", "std::vector", &_visibility); - - _tree2->Branch("median_gamma", &_median_gamma, "median_gamma/D"); - _tree2->Branch("mean_gamma", &_mean_gamma, "mean_gamma/D"); - _tree2->Branch("mean_charge", &_mean_charge, "mean_charge/D"); - _tree2->Branch("max_charge", &_max_charge, "max_charge/D"); - _tree2->Branch("comp_charge", &_comp_charge, "comp_charge/D"); - - _tree2->Branch("slice_L", &_slice_L, "slice_L/D"); - _tree2->Branch("slice_Q", &_slice_Q, "slice_Q/D"); - _tree2->Branch("slice_E", &_slice_E, "slice_E/D"); + _tree = fs->make("lightcalo",""); + _tree->Branch("run", &_run, "run/I"); + _tree->Branch("subrun", &_subrun, "subrun/I"); + _tree->Branch("event", &_event, "event/I"); + _tree->Branch("pfpid", &_pfpid, "pfpid/I"); + _tree->Branch("opflash_time", &_opflash_time, "opflash_time/D"); + + _tree->Branch("rec_gamma", "std::vector", &_rec_gamma); + _tree->Branch("dep_pe", "std::vector", &_dep_pe); + _tree->Branch("visibility", "std::vector", &_visibility); + + _tree->Branch("slice_L", &_slice_L, "slice_L/D"); + _tree->Branch("slice_Q", &_slice_Q, "slice_Q/D"); + _tree->Branch("slice_E", &_slice_E, "slice_E/D"); + + _tree->Branch("true_gamma", &_true_gamma, "true_gamma/D"); + _tree->Branch("true_charge", &_true_charge, "true_charge/D"); + _tree->Branch("true_energy", &_true_energy, "true_energy/D"); // Call appropriate produces<>() functions here. produces>(); @@ -427,7 +392,6 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, int nsuccessful_matches=0; for (size_t n_slice=0; n_slice < match_slices_v.size(); n_slice++){ // initialize tree2 variables - _nmatch++; _pfpid = -1; _slice_Q = 0; // total amount of charge @@ -472,8 +436,6 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, } else if (opflash0.isNull() && opflash1.isNull()){ std::cout << "No usable opflashes (none above threshold)." << std::endl; - _match_type = -3; - _tree->Fill(); return; } auto slice = match_slices_v[n_slice]; @@ -494,11 +456,7 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, uint bestPlane = std::max_element(plane_charge.begin(), plane_charge.end()) - plane_charge.begin(); uint bestHits = std::max_element(plane_hits.begin(), plane_hits.end()) - plane_hits.begin(); - _mean_charge = (plane_charge[0] + plane_charge[1] + plane_charge[2])/3; - _max_charge = plane_charge.at(bestPlane); - _comp_charge = plane_charge.at(bestHits); - - _slice_Q = _comp_charge; + _slice_Q = plane_charge.at(bestHits); // get charge information to create the weighted map std::vector> pfp_v = slice_to_pfp.at(slice.key()); @@ -582,10 +540,15 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, _dep_pe = total_pe; _rec_gamma = total_gamma; - // calculate final light estimate - _mean_gamma = CalcMean(total_gamma,total_err); - _slice_L = _mean_gamma; - _slice_E = (_slice_L + _slice_Q)*1e-6*g4param->Wph(); // MeV, Wph = 19.5 eV + // calculate final light estimate + _slice_L = CalcMean(total_gamma,total_err); + _slice_E = (_slice_L + _slice_Q)*1e-6*g4param->Wph(); // MeV, Wph = 19.5 eV + + if (_verbose){ + std::cout << "charge: " << _slice_Q << std::endl; + std::cout << "light: " << _slice_L << std::endl; + std::cout << "energy: " << _slice_E << std::endl; + } sbn::LightCalo lightcalo(_slice_Q,_slice_L,_slice_E,bestHits,plane_charge); lightcalo_v->push_back(lightcalo); @@ -604,36 +567,28 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, if (!energyDeps_h.isValid() || energyDeps_h->empty()) std::cout << "Don't have good SimEnergyDeposits!" << std::endl; - else + else{ art::fill_ptr_vector(energyDeps, energyDeps_h); - - for (size_t n_dep=0; n_dep < energyDeps.size(); n_dep++){ - auto energyDep = energyDeps[n_dep]; - const auto trackID = energyDep->TrackID(); - const double time = energyDep->Time() * 1e-3; // us - - art::Ptr mctruth = piserv->TrackIdToMCTruth_P(trackID); - - if ((_truth_neutrino && mctruth->Origin()==simb::kBeamNeutrino ) || - (!_truth_neutrino && abs(time-flash_time) < 1)){ - // note: we divide by the prescale because NumPhotons() stored in simulation has the scint prescale applied - _true_gamma += energyDep->NumPhotons()/_scint_prescale; - _true_charge += energyDep->NumElectrons(); - _true_energy += energyDep->Energy(); - } + for (size_t n_dep=0; n_dep < energyDeps.size(); n_dep++){ + auto energyDep = energyDeps[n_dep]; + const auto trackID = energyDep->TrackID(); + const double time = energyDep->Time() * 1e-3; // us + + art::Ptr mctruth = piserv->TrackIdToMCTruth_P(trackID); + + if ((_truth_neutrino && mctruth->Origin()==simb::kBeamNeutrino ) || + (!_truth_neutrino && abs(time-flash_time) < 1)){ + // note: we divide by the prescale because NumPhotons() stored in simulation has the scint prescale applied + _true_gamma += energyDep->NumPhotons()/_scint_prescale; + _true_charge += energyDep->NumElectrons(); + _true_energy += energyDep->Energy(); + } + } } } - else{ - _true_gamma = -9999; - _true_charge = -9999; - _true_energy = -9999; - } nsuccessful_matches++; - _tree2->Fill(); - + _tree->Fill(); } // end slice loop - _match_type=nsuccessful_matches; - _tree->Fill(); } // end produce @@ -780,6 +735,7 @@ double sbnd::LightCaloProducer::CalcMedian(std::vector total_gamma){ std::vector tpc1_gamma; // split into two TPCs for (size_t i=0; i total_gamma){ double sbnd::LightCaloProducer::CalcMean(std::vector total_gamma, std::vector total_err){ // calculates a weighted average, loops over per tpc and then per channel double total_mean=0; - for (size_t i=0; i<2; i++){ - double wgt_num = 0; - double wgt_denom = 0; - for (size_t ich=0; i0) ){ - wgt_num += total_gamma[i]*(1./total_err[i]); - wgt_denom += (1./total_err[i]); - } - } - total_mean += wgt_num/wgt_denom; + double wgt_num = 0; + double wgt_denom = 0; + + for (size_t ich=0; ich total_gamma){ double total_mean=0; - for (size_t i=0; i<2; i++){ - double wgt_num = 0; - double wgt_denom = 0; - for (size_t ich=0; i0) ){ - wgt_num += total_gamma[i]; - wgt_denom += 1; - } - } - total_mean += wgt_num/wgt_denom; + double wgt_num = 0; + double wgt_denom = 0; + + for (size_t ich=0; ich Date: Tue, 18 Nov 2025 15:04:37 -0600 Subject: [PATCH 51/52] fix median function (don't need to separate between tpcs...) --- .../Calorimetry/LightCaloProducer_module.cc | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 860c0afe5..745d6fabd 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -731,24 +731,17 @@ void sbnd::LightCaloProducer::CalcLight(std::vector flash_pe_v, } double sbnd::LightCaloProducer::CalcMedian(std::vector total_gamma){ - std::vector tpc0_gamma; - std::vector tpc1_gamma; - // split into two TPCs + std::vector gamma_nonzero; for (size_t i=0; i gamma_v = ((tpc==0)? std::vector(tpc0_gamma) : std::vector(tpc1_gamma)); - const auto median_it = gamma_v.begin() + gamma_v.size() / 2; - std::nth_element(gamma_v.begin(), median_it , gamma_v.end()); - auto median = *median_it; - median_gamma+=median; - } return median_gamma; } From c3ecceca6d9e5beb5356dbb5b3d027ec077f26fe Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Wed, 19 Nov 2025 12:07:52 -0600 Subject: [PATCH 52/52] remove truth validation, keep fcl prefix consistent in variable names, generic clean up --- .../Calorimetry/LightCaloProducer_module.cc | 340 +++++++----------- sbndcode/Calorimetry/lightcalo.fcl | 17 +- sbndcode/Calorimetry/run_lightcalo.fcl | 1 - 3 files changed, 143 insertions(+), 215 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 745d6fabd..b416e7489 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -36,7 +36,6 @@ #include "lardataobj/RecoBase/OpFlash.h" // LArSoft MC includes -#include "lardataobj/Simulation/SimEnergyDeposit.h" #include "nusimdata/SimulationBase/MCTruth.h" #include "lardataobj/Simulation/sim.h" @@ -46,13 +45,12 @@ #include "larsim/PhotonPropagation/SemiAnalyticalModel.h" #include "larsim/PhotonPropagation/OpticalPathTools/OpticalPath.h" #include "larsim/Simulation/LArG4Parameters.h" -#include "larsim/MCCheater/ParticleInventoryService.h" #include "lardata/DetectorInfoServices/DetectorClocksService.h" #include "lardata/DetectorInfoServices/DetectorPropertiesService.h" // SBND includes #include "sbndcode/OpDetSim/sbndPDMapAlg.hh" -#include "sbnobj/Common/Reco/LightCaloInfo.h" +#include "sbnobj/Common/Reco/LightCalo.h" #include "sbnobj/Common/Reco/OpT0FinderResult.h" #include "sbnobj/Common/Reco/TPCPMTBarycenterMatch.h" @@ -122,48 +120,41 @@ class sbnd::LightCaloProducer : public art::EDProducer { double CalcMean(std::vector total_light); double CalcMean(std::vector total_light, std::vector total_err); - // Performs truth validation, saves info to TTree - void TruthValidation(art::Event& e, art::ServiceHandle piserv, double flash_time); - // fcl parameters - std::vector _opflash_producer_v; - std::vector _opflash_ara_producer_v; - std::vector _pd_types; - std::string _slice_producer; - std::string _opt0_producer; - std::string _bcfm_producer; - - bool _use_arapucas; - bool _use_opt0; - bool _use_bcfm; - float _nuscore_cut; - float _fopt0score_cut; - bool _verbose; - - float _fopflash_min; - float _fopflash_max; - float _fopt0_frac_diff_cut; - - float _pmt_ara_offset; - std::vector _noise_thresh; - - std::vector _cal_area_const; - std::vector _opdet_vuv_eff; - std::vector _opdet_vis_eff; - std::vector _opdet_mask; - float _scint_prescale; - - bool _truth_validation; - std::string _simenergy_producer; - bool _truth_neutrino; - - std::unique_ptr _semi_model; - fhicl::ParameterSet _vuv_params; - fhicl::ParameterSet _vis_params; - std::shared_ptr _optical_path_tool; - - opdet::sbndPDMapAlg _opdetmap; //map for photon detector types - unsigned int _nchan = _opdetmap.size(); + std::vector fopflash_producer_v; + std::vector fopflash_ara_producer_v; + std::vector fpd_types; + std::string fslice_producer; + std::string fopt0_producer; + std::string fbcfm_producer; + + bool fuse_bcfm; + bool fuse_opt0; + bool fverbose; + + float fnuscore_cut; + float fbcfmscore_cut; + float fopt0score_cut; + + float fopflash_min; + float fopflash_max; + float fopt0_frac_diff_cut; + + float fpmt_ara_offset; + std::vector fnoise_thresh; + + std::vector fcal_area_const; + std::vector fopdet_vuv_eff; + std::vector fopdet_vis_eff; + std::vector fopdet_mask; + + std::unique_ptr fsemi_model; + fhicl::ParameterSet fvuv_params; + fhicl::ParameterSet fvis_params; + std::shared_ptr foptical_path_tool; + + opdet::sbndPDMapAlg opdetmap; //map for photon detector types + unsigned int nchan = opdetmap.size(); geo::GeometryCore const* geom; @@ -174,17 +165,11 @@ class sbnd::LightCaloProducer : public art::EDProducer { std::vector _dep_pe; // vector of measured photo-electron (PE), one entry = one channel std::vector _rec_gamma; // vector of reconstructed photon count, one entry = one channel - - double _true_gamma; // true photon count from all energy depositions - double _true_charge; // true electron count from all energy depositions - double _true_energy; // true deposited energy - std::vector _visibility; double _slice_L; // reconstructed photon count double _slice_Q; // reconstructed electron count double _slice_E; // reconstructed deposited energy - }; @@ -192,39 +177,37 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) : EDProducer{p} // , // More initializers here. { - _vuv_params = p.get("VUVHits"); - _vis_params = p.get("VIVHits"); - _optical_path_tool = std::shared_ptr(art::make_tool(p.get("OpticalPathTool"))); - _semi_model = std::make_unique(_vuv_params, _vis_params, _optical_path_tool, true, false); - - _opflash_producer_v = p.get>("OpFlashProducers"); - _opflash_ara_producer_v = p.get>("OpFlashAraProducers"); - _pd_types = p.get>("PDTypes"); - _slice_producer = p.get("SliceProducer"); - _opt0_producer = p.get("OpT0FinderProducer"); - _bcfm_producer = p.get("BCFMProducer"); - _use_opt0 = p.get("UseOpT0Finder"); - _use_bcfm = p.get("UseBCFM"); - _nuscore_cut = p.get("nuScoreCut"); - _fopt0score_cut = p.get("opt0ScoreCut"); - _verbose = p.get("Verbose"); - - _fopflash_min = p.get("OpFlashMin"); - _fopflash_max = p.get("OpFlashMax"); - _fopt0_frac_diff_cut = p.get("OpT0FractionalCut"); - - _pmt_ara_offset = p.get("PMTARAFlashOffset"); - _noise_thresh = p.get>("FlashNoiseThreshold"); - - _cal_area_const = p.get>("CalAreaConstants"); - _opdet_vuv_eff = p.get>("OpDetVUVEfficiencies"); - _opdet_vis_eff = p.get>("OpDetVISEfficiencies"); - _opdet_mask = p.get>("OpDetMask"); - _scint_prescale = p.get("ScintPreScale"); - - _truth_validation = p.get("TruthValidation"); - _simenergy_producer = p.get("SimEnergyProducer"); - _truth_neutrino = p.get("TruthNeutrino"); + fvuv_params = p.get("VUVHits"); + fvis_params = p.get("VIVHits"); + foptical_path_tool = std::shared_ptr(art::make_tool(p.get("OpticalPathTool"))); + fsemi_model = std::make_unique(fvuv_params, fvis_params, foptical_path_tool, true, false); + + fopflash_producer_v = p.get>("OpFlashProducers"); + fopflash_ara_producer_v = p.get>("OpFlashAraProducers"); + fpd_types = p.get>("PDTypes"); + fslice_producer = p.get("SliceProducer"); + fopt0_producer = p.get("OpT0FinderProducer"); + fbcfm_producer = p.get("BCFMProducer"); + fuse_opt0 = p.get("UseOpT0Finder"); + fuse_bcfm = p.get("UseBCFM"); + + fverbose = p.get("Verbose"); + + fnuscore_cut = p.get("nuScoreCut"); + fbcfmscore_cut = p.get("bcfmScoreCut"); + fopt0score_cut = p.get("opt0ScoreCut"); + fopt0_frac_diff_cut = p.get("opt0FractionalCut"); + + fopflash_min = p.get("OpFlashMin"); + fopflash_max = p.get("OpFlashMax"); + + fpmt_ara_offset = p.get("PMTARAFlashOffset"); + fnoise_thresh = p.get>("FlashNoiseThreshold"); + + fcal_area_const = p.get>("CalAreaConstants"); + fopdet_vuv_eff = p.get>("OpDetVUVEfficiencies"); + fopdet_vis_eff = p.get>("OpDetVISEfficiencies"); + fopdet_mask = p.get>("OpDetMask"); geom = lar::providerFrom(); @@ -240,14 +223,10 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) _tree->Branch("dep_pe", "std::vector", &_dep_pe); _tree->Branch("visibility", "std::vector", &_visibility); - _tree->Branch("slice_L", &_slice_L, "slice_L/D"); _tree->Branch("slice_Q", &_slice_Q, "slice_Q/D"); + _tree->Branch("slice_L", &_slice_L, "slice_L/D"); _tree->Branch("slice_E", &_slice_E, "slice_E/D"); - _tree->Branch("true_gamma", &_true_gamma, "true_gamma/D"); - _tree->Branch("true_charge", &_true_charge, "true_charge/D"); - _tree->Branch("true_energy", &_true_energy, "true_energy/D"); - // Call appropriate produces<>() functions here. produces>(); produces>(); @@ -280,7 +259,6 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, auto const det_prop = art::ServiceHandle()->DataFor(e, clock_data); art::ServiceHandle g4param; - art::ServiceHandle piserv; _run = e.id().run(); _subrun = e.id().subRun(); @@ -288,37 +266,37 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, // get slices ::art::Handle> slice_h; - e.getByLabel(_slice_producer, slice_h); + e.getByLabel(fslice_producer, slice_h); if(!slice_h.isValid() || slice_h->empty()){ std::cout << "don't have good slices!" << std::endl; return; } ::art::Handle> pfp_h; - e.getByLabel(_slice_producer, pfp_h); + e.getByLabel(fslice_producer, pfp_h); if(!pfp_h.isValid() || pfp_h->empty()) { std::cout << "don't have good PFParticle!" << std::endl; return; } ::art::Handle> spacepoint_h; - e.getByLabel(_slice_producer, spacepoint_h); + e.getByLabel(fslice_producer, spacepoint_h); if(!spacepoint_h.isValid() || spacepoint_h->empty()) { std::cout << "don't have good SpacePoints!" << std::endl; return; } - auto const & flash0_h = e.getValidHandle>(_opflash_producer_v[0]); - auto const & flash1_h = e.getValidHandle>(_opflash_producer_v[1]); + auto const & flash0_h = e.getValidHandle>(fopflash_producer_v[0]); + auto const & flash1_h = e.getValidHandle>(fopflash_producer_v[1]); if( (!flash0_h.isValid() || flash0_h->empty()) && (!flash1_h.isValid() || flash1_h->empty())) { - std::cout << "don't have good PMT flashes from producer " << _opflash_producer_v[0] << " or " << _opflash_producer_v[1] << std::endl; + std::cout << "don't have good PMT flashes from producer " << fopflash_producer_v[0] << " or " << fopflash_producer_v[1] << std::endl; return; } - art::FindManyP slice_to_pfp (slice_h, e, _slice_producer); - art::FindManyP slice_to_hit (slice_h, e, _slice_producer); - art::FindManyP pfp_to_spacepoint(pfp_h, e, _slice_producer); - art::FindManyP spacepoint_to_hit(spacepoint_h, e, _slice_producer); + art::FindManyP slice_to_pfp (slice_h, e, fslice_producer); + art::FindManyP slice_to_hit (slice_h, e, fslice_producer); + art::FindManyP pfp_to_spacepoint(pfp_h, e, fslice_producer); + art::FindManyP spacepoint_to_hit(spacepoint_h, e, fslice_producer); std::vector> match_slices_v; std::vector> match_op0; @@ -327,9 +305,9 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, std::map, std::vector>> match_slice_opflash_map; // use templated member helper to fill match vectors - if (_use_bcfm) { + if (fuse_bcfm) { ::art::Handle> bcfm_h; - e.getByLabel(_bcfm_producer, bcfm_h); + e.getByLabel(fbcfm_producer, bcfm_h); if(!bcfm_h.isValid() || bcfm_h->empty()) { std::cout << "don't have good barycenter matches!" << std::endl; return; @@ -337,16 +315,16 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, std::vector> bcfm_v; art::fill_ptr_vector(bcfm_v, bcfm_h); - CollectMatches(bcfm_h, bcfm_v, _bcfm_producer, e, match_slices_v, match_op0, match_op1, + CollectMatches(bcfm_h, bcfm_v, fbcfm_producer, e, match_slices_v, match_op0, match_op1, [this](art::Ptr bcfm) { - if (bcfm->flashTime > _fopflash_max || bcfm->flashTime < _fopflash_min) return false; + if (bcfm->flashTime > fopflash_max || bcfm->flashTime < fopflash_min) return false; if (bcfm->score < 0.02) return false; return true; }); } - else { + else if (fuse_opt0){ ::art::Handle> opt0_h; - e.getByLabel(_opt0_producer, opt0_h); + e.getByLabel(fopt0_producer, opt0_h); if(!opt0_h.isValid() || opt0_h->empty()) { std::cout << "don't have good OpT0Finder matches!" << std::endl; return; @@ -354,36 +332,38 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, std::vector> opt0_v; art::fill_ptr_vector(opt0_v, opt0_h); - CollectMatches(opt0_h, opt0_v, _opt0_producer, e, match_slices_v, match_op0, match_op1, + CollectMatches(opt0_h, opt0_v, fopt0_producer, e, match_slices_v, match_op0, match_op1, [this](art::Ptr opt0){ auto opt0_measPE = opt0->measPE; auto opt0_hypoPE = opt0->hypoPE; auto opt0_frac_diff = std::abs((opt0_hypoPE - opt0_measPE)/opt0_measPE); - if (opt0->time < _fopflash_min || opt0->time > _fopflash_max) return false; - if (opt0->score < _fopt0score_cut) return false; - if (opt0_frac_diff > _fopt0_frac_diff_cut) return false; + if (opt0->time < fopflash_min || opt0->time > fopflash_max) return false; + if (opt0->score < fopt0score_cut) return false; + if (opt0_frac_diff > fopt0_frac_diff_cut) return false; return true; }); } - if (std::find(_pd_types.begin(), _pd_types.end(), "xarapuca_vuv") != _pd_types.end() || - std::find(_pd_types.begin(), _pd_types.end(), "xarapuca_vis") != _pd_types.end()){ - _use_arapucas = true; + if (match_slices_v.empty()) return; + + bool use_arapucas; + if (std::find(fpd_types.begin(), fpd_types.end(), "xarapuca_vuv") != fpd_types.end() || + std::find(fpd_types.begin(), fpd_types.end(), "xarapuca_vis") != fpd_types.end()){ + use_arapucas = true; } - else - _use_arapucas = false; + else use_arapucas = false; std::vector> flash0_ara_v; std::vector> flash1_ara_v; - if (_use_arapucas){ + if (use_arapucas){ ::art::Handle> flash0_ara_h; ::art::Handle> flash1_ara_h; for (size_t i=0; i<2; i++){ ::art::Handle> flash_ara_h; - e.getByLabel(_opflash_ara_producer_v[i], flash_ara_h); + e.getByLabel(fopflash_ara_producer_v[i], flash_ara_h); if (!flash_ara_h.isValid() || flash_ara_h->empty()) { - std::cout << "don't have good X-ARAPUCA flashes from producer " << _opflash_ara_producer_v[i] << std::endl; + std::cout << "don't have good X-ARAPUCA flashes from producer " << fopflash_ara_producer_v[i] << std::endl; } else art::fill_ptr_vector((i==0)? flash0_ara_v : flash1_ara_v, flash_ara_h); } @@ -391,11 +371,15 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, int nsuccessful_matches=0; for (size_t n_slice=0; n_slice < match_slices_v.size(); n_slice++){ - // initialize tree2 variables - _pfpid = -1; - - _slice_Q = 0; // total amount of charge - _slice_L = 0; // total amount of light + // initialize tree variables + _pfpid = -1; + _opflash_time=-1e9; + _rec_gamma.clear(); + _dep_pe.clear(); + _visibility.clear(); + + _slice_Q = 0; + _slice_L = 0; _slice_E = 0; std::vector sp_xyz; @@ -407,37 +391,22 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, bool flash_in_0 = false; bool flash_in_1 = false; // set threshold above noise PE levels for the flash - float noise_thresh = (!_use_arapucas)? _noise_thresh[0] : _noise_thresh[1]; + float noise_thresh = (!use_arapucas)? fnoise_thresh[0] : fnoise_thresh[1]; - if (!opflash0.isNull() && opflash1.isNull()){ + if (!opflash0.isNull() && opflash0->TotalPE() > noise_thresh){ + flash_in_0 = true; flash_time = opflash0->Time(); - if (opflash0->TotalPE() > noise_thresh) - flash_in_0 = true; - else if (_verbose) - std::cout << "Flash Total PE in TPC 0 (" << opflash0->TotalPE() << ") below noise threshold ... Skipping" << std::endl; - } - else if ( opflash0.isNull() && !opflash1.isNull()){ - flash_time = opflash1->Time(); - if (opflash1->TotalPE() > noise_thresh) - flash_in_1 = true; - else if (_verbose) - std::cout << "Flash Total PE in TPC 1 (" << opflash1->TotalPE() << ") below noise threshold ... Skipping" << std::endl; } - else if (!opflash0.isNull() && !opflash1.isNull()){ - flash_time = opflash0->Time(); - if (opflash0->TotalPE() > noise_thresh) - flash_in_0 = true; - else if (_verbose) - std::cout << "Flash Total PE in TPC 0 (" << opflash0->TotalPE() << ") below noise threshold ... Skipping" << std::endl; - if (opflash1->TotalPE() > noise_thresh) - flash_in_1 = true; - else if (_verbose) - std::cout << "Flash Total PE in TPC 1 (" << opflash1->TotalPE() << ") below noise threshold ... Skipping" << std::endl; + if (!opflash1.isNull() && opflash1->TotalPE() > noise_thresh){ + flash_in_1 = true; + flash_time = opflash1->Time(); } - else if (opflash0.isNull() && opflash1.isNull()){ + + if (flash_in_0==false && flash_in_1==false && fverbose){ std::cout << "No usable opflashes (none above threshold)." << std::endl; return; } + auto slice = match_slices_v[n_slice]; // sum charge information (without position info) for Q // find which plane has the most integrated charge for this slice @@ -449,7 +418,7 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, auto drift_time = hit->PeakTime()*0.5 - clock_data.TriggerOffsetTPC(); double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) auto hit_plane = hit->View(); - plane_charge.at(hit_plane) += hit->Integral()*atten_correction*(1/_cal_area_const.at(hit_plane)); + plane_charge.at(hit_plane) += hit->Integral()*atten_correction*(1/fcal_area_const.at(hit_plane)); plane_hits.at(hit_plane)++; } @@ -477,7 +446,7 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, // correct for e- attenuation auto drift_time = hit->PeakTime()*0.5 - clock_data.TriggerOffsetTPC(); double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) - double charge = (1/_cal_area_const.at(bestPlane))*atten_correction*hit->Integral(); + double charge = (1/fcal_area_const.at(bestPlane))*atten_correction*hit->Integral(); sp_xyz.push_back(xyz); sp_charge.push_back(charge); } @@ -489,9 +458,9 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, auto dir_visibility_map = visibility_maps[0]; auto ref_visibility_map = visibility_maps[1]; - std::vector total_pe(_nchan,0.); - std::vector total_err(_nchan,0.); - std::vector total_gamma(_nchan, 0.); + std::vector total_pe(nchan,0.); + std::vector total_err(nchan,0.); + std::vector total_gamma(nchan, 0.); // combining flash PE information from separate TPCs into a single vector for (int tpc=0; tpc<2; tpc++){ @@ -499,15 +468,14 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, if (found_flash){ auto flash_pe_v = (tpc==0)? opflash0->PEs() : opflash1->PEs(); // if using arapucas, need to combine PMT and arapuca PE information into a single vector - if (_use_arapucas){ + if (use_arapucas){ auto flash_ara_v = (tpc==0)? flash0_ara_v : flash1_ara_v; // for PMT flashes, the PE vector is shortened and don't include the last 6 entries for ARAPUCAs - if (flash_pe_v.size()!= _nchan) flash_pe_v.insert(flash_pe_v.end(), {0,0,0,0,0,0}); + if (flash_pe_v.size()!= nchan) flash_pe_v.resize(nchan,0); for (size_t nara=0; nara < flash_ara_v.size(); nara++){ auto const &flash_ara = *flash_ara_v[nara]; - if (abs(flash_time-flash_ara.Time()) < _pmt_ara_offset){ - if (_verbose) - std::cout << "Combining PMT+XARA Flashes with PMT time: " << flash_time << ", ARA time: " << flash_ara.Time() << std::endl; + if (abs(flash_time-flash_ara.Time()) < fpmt_ara_offset){ + if (fverbose) std::cout << "Combining PMT+XARA Flashes with PMT time: " << flash_time << ", ARA time: " << flash_ara.Time() << std::endl; for (size_t ich=0; ich < (flash_ara.PEs()).size(); ich++) flash_pe_v.at(ich) += (flash_ara.PEs()).at(ich); break; @@ -515,15 +483,15 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, } } // end of arapuca if for (size_t ich=0; ichWph(); // MeV, Wph = 19.5 eV + _slice_E = (_slice_L + _slice_Q)*1e-9*g4param->Wph(); // GeV, Wph = 19.5 eV - if (_verbose){ + if (fverbose){ std::cout << "charge: " << _slice_Q << std::endl; std::cout << "light: " << _slice_L << std::endl; std::cout << "energy: " << _slice_E << std::endl; } - sbn::LightCalo lightcalo(_slice_Q,_slice_L,_slice_E,bestHits,plane_charge); + sbn::LightCalo lightcalo(_slice_Q,_slice_L,_slice_E,bestHits); lightcalo_v->push_back(lightcalo); util::CreateAssn(*this, e, *lightcalo_v, slice, *slice_assn_v); util::CreateAssn(*this, e, *lightcalo_v, opflash0, *flash_assn_v); util::CreateAssn(*this, e, *lightcalo_v, opflash1, *flash_assn_v); - _true_gamma = 0; - _true_charge = 0; - _true_energy = 0; - - if (_truth_validation){ - ::art::Handle> energyDeps_h; - e.getByLabel(_simenergy_producer, energyDeps_h); - std::vector> energyDeps; - - if (!energyDeps_h.isValid() || energyDeps_h->empty()) - std::cout << "Don't have good SimEnergyDeposits!" << std::endl; - else{ - art::fill_ptr_vector(energyDeps, energyDeps_h); - for (size_t n_dep=0; n_dep < energyDeps.size(); n_dep++){ - auto energyDep = energyDeps[n_dep]; - const auto trackID = energyDep->TrackID(); - const double time = energyDep->Time() * 1e-3; // us - - art::Ptr mctruth = piserv->TrackIdToMCTruth_P(trackID); - - if ((_truth_neutrino && mctruth->Origin()==simb::kBeamNeutrino ) || - (!_truth_neutrino && abs(time-flash_time) < 1)){ - // note: we divide by the prescale because NumPhotons() stored in simulation has the scint prescale applied - _true_gamma += energyDep->NumPhotons()/_scint_prescale; - _true_charge += energyDep->NumElectrons(); - _true_energy += energyDep->Energy(); - } - } - } - } nsuccessful_matches++; _tree->Fill(); } // end slice loop @@ -652,10 +590,8 @@ void sbnd::LightCaloProducer::CollectMatches(const art::Handle nullOpFlash; @@ -675,8 +611,8 @@ std::vector> sbnd::LightCaloProducer::CalcVisibility(std::ve // returns of two vectors (len is # of opdet) for the visibility for every opdet if (xyz_v.size() != charge_v.size()) std::cout << "spacepoint coord and charge vector size mismatch" << std::endl; - std::vector dir_visibility_map(_nchan, 0); - std::vector ref_visibility_map(_nchan, 0); + std::vector dir_visibility_map(nchan, 0); + std::vector ref_visibility_map(nchan, 0); double sum_charge0 = 0; double sum_charge1 = 0; @@ -690,8 +626,8 @@ std::vector> sbnd::LightCaloProducer::CalcVisibility(std::ve std::vector direct_visibility; std::vector reflect_visibility; - _semi_model->detectedDirectVisibilities(direct_visibility, xyz); - _semi_model->detectedReflectedVisibilities(reflect_visibility, xyz); + fsemi_model->detectedDirectVisibilities(direct_visibility, xyz); + fsemi_model->detectedReflectedVisibilities(reflect_visibility, xyz); // if (dir_visibility_map.size() != direct_visibility.size()) std::cout << "mismatch of visibility vector size" << std::endl; // weight by charge @@ -719,8 +655,8 @@ void sbnd::LightCaloProducer::CalcLight(std::vector flash_pe_v, std::vector &total_gamma_v){ for (size_t ch = 0; ch < flash_pe_v.size(); ch++){ auto pe = flash_pe_v[ch]; - auto vuv_eff = _opdet_vuv_eff.at(ch); - auto vis_eff = _opdet_vis_eff.at(ch); + auto vuv_eff = fopdet_vuv_eff.at(ch); + auto vis_eff = fopdet_vis_eff.at(ch); auto tot_visibility = vuv_eff*dir_visibility[ch] + vis_eff*ref_visibility[ch]; _visibility.at(ch) = tot_visibility; if((pe == 0) || std::isinf(1/tot_visibility)) diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index a806e8a93..e92e0eebb 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -17,34 +17,27 @@ lightcalo: SliceProducer: "pandora" OpT0FinderProducer: "opt0finder" BCFMProducer: "tpcpmtbarycentermatching" - UseArapucas: false + UseBCFM: true UseOpT0Finder: false + Verbose: false + nuScoreCut: 0.4 # default: accept nusScore > 0.4, to analyze all slices, set nuScoreCut = -1 + bcfmScoreCut: 0.02 # defualt: accept bcfm match > bcfmScoreCut opt0ScoreCut: 200 # default: accept opt0 match > opt0ScoreCut - - Verbose: false + opt0FractionalCut: 0.5 OpFlashMin: 0.0 # simulation [0.0], light-triggered data [-0.8] OpFlashMax: 2.0 # simulation [2.0], light-triggered data [2.0] - OpT0FractionalCut: 0.5 # flash parameters PMTARAFlashOffset: 0.05 # the offset between the t0 of PMT OpFlashes and X-ARA OpFlashes FlashNoiseThreshold: [ 600., 1500. ] # {PMT, xARAPUCA}, flash total PE threshold to ignore a flash # calibration constants & simulation parameters - ## shouldn't have to change this unless you change simulation parameters CalAreaConstants: [ 0.0200906, 0.0200016, 0.0201293 ] # calibration constants for wire planes OpDetVUVEfficiencies: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.035, 0.03, 0.021, 0.021, 0.021, 0.021, 0.021, 0.021] OpDetVISEfficiencies: [0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0375, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.039, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] OpDetMask : [39, 66, 67, 71, 85, 86, 87, 92, 115, 138, 141, 170, 197, 217, 218, 221, 222, 223, 226, 245, 248, 249, 302] - - ScintPreScale: 0.039 # Scintillation Pre-Scale factor in simulation (set in ionandscint) - - # parameters for truth validation - TruthValidation: true # can only set to true if the reco2 files have SimEnergyDeposits - SimEnergyProducer: "ionandscint:priorSCE" # only looking at energy deposits in the AV - TruthNeutrino: true # if validating anything other than simb::kBeamNeutrino, set to false } END_PROLOG diff --git a/sbndcode/Calorimetry/run_lightcalo.fcl b/sbndcode/Calorimetry/run_lightcalo.fcl index 68f14b2eb..013441531 100644 --- a/sbndcode/Calorimetry/run_lightcalo.fcl +++ b/sbndcode/Calorimetry/run_lightcalo.fcl @@ -17,7 +17,6 @@ services: FileCatalogMetadata: @local::sbnd_file_catalog_mc # from sam_sbnd.fcl @table::sbnd_services # from services_sbnd.fcl @table::sbnd_g4_services - ParticleInventoryService: @local::standard_particleinventoryservice }