From 94c59df6e4d7797c25be05885b2973783e182069 Mon Sep 17 00:00:00 2001 From: lynnt-uchicago Date: Wed, 19 Oct 2022 10:15:26 -0500 Subject: [PATCH 001/155] 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 002/155] 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 003/155] 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 004/155] 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 005/155] 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 006/155] 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 007/155] 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 008/155] 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 009/155] 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 010/155] 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 011/155] 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 012/155] 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 013/155] 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 014/155] 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 015/155] 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 016/155] 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 017/155] 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 018/155] 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 019/155] 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 020/155] 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 021/155] 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 022/155] 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 023/155] 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 024/155] 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 025/155] 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 026/155] 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 027/155] 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 028/155] 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 029/155] 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 030/155] 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 031/155] 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 032/155] 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 033/155] 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 034/155] 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 035/155] 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 036/155] 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 037/155] 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 038/155] 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 151b2c9d4ff89bd9923bbc67477896c1a6a5bc1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 9 Oct 2025 04:05:54 -0500 Subject: [PATCH 039/155] Setup to start extended fragments feature --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 21 ++++++++++--------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 8 +++---- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index ac94c56e1..5be0a9e5d 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -372,15 +372,15 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) } /** -* @brief Searches for the SPEC-TDC ETRIG timestamp closest to the raw timestamp if any SPEC-TDC ETRIG product is found in the event. -* @param[in] e The event to be processed. -* @param[in] corr_raw_timestamp The corrected raw timestamp from the artdaq::RawEventHeader product. -* @param[in,out] timestamp The closest ETRIG timestamp to the raw timestamp (if found). -* @return A boolean indicating if a valid ETRIG timestamp was found close enough to the raw timestamp. -* @details It searches for the SPEC-TDC products in the event and looks for the ETRIG timestamps. If any ETRIG -* timestamp is found, it checks which one is the closest to the raw timestamp and if it is close enough (i.e. -* within fraw_trig_max_diff) it returns it as output. -*/ + * @brief Searches for the SPEC-TDC ETRIG timestamp closest to the raw timestamp if any SPEC-TDC ETRIG product is found in the event. + * @param[in] e The event to be processed. + * @param[in] corr_raw_timestamp The corrected raw timestamp from the artdaq::RawEventHeader product. + * @param[in,out] timestamp The closest ETRIG timestamp to the raw timestamp (if found). + * @return A boolean indicating if a valid ETRIG timestamp was found close enough to the raw timestamp. + * @details It searches for the SPEC-TDC products in the event and looks for the ETRIG timestamps. If any ETRIG + * timestamp is found, it checks which one is the closest to the raw timestamp and if it is close enough (i.e. + * within fraw_trig_max_diff) it returns it as output. + */ bool sbndaq::SBNDXARAPUCADecoder::get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t& timestamp) { bool ett_found = false; @@ -718,7 +718,7 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto } if (fverbose | fdebug_timing) { - std::cout << std::fixed << std::setprecision(3) << std::endl; + std::cout << std::fixed << std::setprecision(3); if (factive_timing_frame == SPEC_TDC_TIMING) { std::cout << " > SBNDXARAPUCADecoder::decode_fragment: SPEC-TDC time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; } else if (factive_timing_frame == PTB_TIMING) { @@ -726,6 +726,7 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto } else { // CAEN_ONLY_TIMING std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; } + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: TTT_end_ticks = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; } // =============== Start decoding the waveforms =============== // diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index 3456450f9..774032157 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -32,16 +32,16 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: 0 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: -1 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. - debug_fragments_handle: false # (De)activates V1740B CAEN fragments art::Handle information printing. - debug_timing: false # (De)activates timing data printing. + debug_fragments_handle: true # (De)activates V1740B CAEN fragments art::Handle information printing. + debug_timing: true # (De)activates timing data printing. debug_buffer: false # (De)activates buffer status printing. debug_waveforms: false # (De)activates waveforms decoding printing. # - Verbose option. - verbose: false # (De)activates verbosity. + verbose: true # (De)activates verbosity. } END_PROLOG \ No newline at end of file From 1e492fdc7c9745bb4264427560fa3a798d2fe9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 9 Oct 2025 05:33:50 -0500 Subject: [PATCH 040/155] Shift timing function --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 214 ++++++++++++------ 1 file changed, 147 insertions(+), 67 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 5be0a9e5d..655c26cfb 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -137,6 +137,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool get_ptb_hlt_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp, uint16_t & hlt_code); bool get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp); + void shift_time(const artdaq::Fragment& fragment, uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); void save_prod_wvfm(size_t board_idx, size_t ch, double ini_wvfm_timestamp, const std::vector > & wvfms, std::vector & prod_wvfms); void save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, double ini_wvfm_timestamp, double end_wvfm_timestamp, const std::vector > & wvfms); @@ -616,6 +617,10 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto if (valid_fragment) { if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::decode_fragment: decoding V1740 CAEN fragment " << fragment_indices[board_idx] << " from the board " << board_idx << " (slot " << fboard_id_list[board_idx] << "):" << std::endl; + //bool is_nominal_length = false; + //bool is_within_nominal_length = false; + //bool is_first = false; + // =============== Accesses Event metadata and Event header for this fragment =============== // CAENV1740Fragment caen_fragment(fragment); @@ -659,76 +664,81 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto // =============== Extracts timing information for this fragment =============== // // Gets the timing information of the CAEN fragment. - int64_t pulse_duration_ns = num_samples_per_wvfm * fns_per_sample; // ns. - uint64_t frag_timestamp = fragment.timestamp(); // ns. - int64_t frag_timestamp_s = frag_timestamp / NANOSEC_IN_SEC; // s. - int64_t frag_timestamp_ns = frag_timestamp % NANOSEC_IN_SEC; // ns. +// int64_t pulse_duration_ns = num_samples_per_wvfm * fns_per_sample; // ns. +// uint64_t frag_timestamp = fragment.timestamp(); // ns. +// int64_t frag_timestamp_s = frag_timestamp / NANOSEC_IN_SEC; // s. +// int64_t frag_timestamp_ns = frag_timestamp % NANOSEC_IN_SEC; // ns. uint32_t TTT_ticks = header.triggerTime(); int64_t TTT_end_ns = TTT_ticks * NANOSEC_PER_TICK; // ns. - // Gets the full TTT timestamp. - uint64_t full_TTT = 0; - // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. - if (frag_timestamp_ns > TTT_end_ns) { - if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred w.r.t. the fragment timestamp (FTS)." << std::endl; - full_TTT = (frag_timestamp_s + 1) * NANOSEC_IN_SEC + TTT_end_ns; - } else { - full_TTT = frag_timestamp_s * NANOSEC_IN_SEC + TTT_end_ns; - } - - int64_t ref_timestamp = 0; - - double ini_wvfm_timestamp = 0; - double end_wvfm_timestamp = 0; - - // If an ETRIG or HLT timestamp was found it restarts the time from it. Otherwise the CAEN time frame is assigned. - if (factive_timing_frame != CAEN_ONLY_TIMING) { - ref_timestamp = signed_difference(full_TTT, timestamp); // ns. - - ini_wvfm_timestamp = (ref_timestamp - pulse_duration_ns) * NANOSEC_TO_MICROSEC; // us. - end_wvfm_timestamp = ref_timestamp * NANOSEC_TO_MICROSEC; // us. - } else { - ref_timestamp = full_TTT; // ns. - - ini_wvfm_timestamp = ((ref_timestamp - pulse_duration_ns) % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // ns. - end_wvfm_timestamp = (ref_timestamp % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // us. - } - if (fdebug_timing) { - std::cout << std::fixed << std::setprecision(0); - std::cout << "\t\t ns/tick = " << NANOSEC_PER_TICK << ", ns/sample = " << fns_per_sample << std::endl; - std::cout << "\t\t TTT header.TriggerTime() [TTT_ticks] = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; std::cout << "\t\t TTT header.extendedTriggerTime() [TTT_ticks] = " << header.extendedTriggerTime() << " ticks. \t TTT_end_ns = " << print_timestamp(header.extendedTriggerTime() * NANOSEC_PER_TICK) << "." << std::endl; std::cout << "\t\t TTT header.triggerTimeRollOver(): " << header.triggerTimeRollOver() << std::endl; - std::cout << "\t\t Full Fragment timestamp: " << print_timestamp(frag_timestamp) << " = " << frag_timestamp_s << " s " << frag_timestamp_ns << " ns." << std::endl; - std::cout << "\t\t Full TTT - fragment timestamp = "<< abs_difference(full_TTT, frag_timestamp) << " ns." << " Post-percent: " << (double(abs_difference(full_TTT, frag_timestamp)) / double(pulse_duration_ns)) * 100 << "%." << std::endl; - if (factive_timing_frame == SPEC_TDC_TIMING) { - std::cout << "\t ETRIG (SPEC-TDC) timestamp of the fragment: " << std::endl; - std::cout << "\t\t Full UTC ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; - std::cout << "\t\t ETRIG SPEC-TDC difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; - } else if (factive_timing_frame == PTB_TIMING) { - std::cout << "\t HLT ETRIG (PTB) timestamp of the fragment: " << std::endl; - std::cout << "\t\t Full UTC HLT ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; - std::cout << "\t\t HLT ETRIG (PTB) difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; - } else if (factive_timing_frame == CAEN_ONLY_TIMING) { - std::cout << "\t CAEN trigger timestamp (TTT) of the fragment: " << std::endl; - std::cout << "\t\t Full UTC TTT timestamp: " << print_timestamp(full_TTT) << " = " << full_TTT / NANOSEC_IN_SEC << " s " << TTT_end_ns << " ns." << std::endl; - } - } - - if (fverbose | fdebug_timing) { - std::cout << std::fixed << std::setprecision(3); - if (factive_timing_frame == SPEC_TDC_TIMING) { - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: SPEC-TDC time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; - } else if (factive_timing_frame == PTB_TIMING) { - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: PTB time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; - } else { // CAEN_ONLY_TIMING - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; - } - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: TTT_end_ticks = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; } - +// +// // Gets the full TTT timestamp. +// uint64_t full_TTT = 0; +// // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. +// if (frag_timestamp_ns > TTT_end_ns) { +// if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred w.r.t. the fragment timestamp (FTS)." << std::endl; +// full_TTT = (frag_timestamp_s + 1) * NANOSEC_IN_SEC + TTT_end_ns; +// } else { +// full_TTT = frag_timestamp_s * NANOSEC_IN_SEC + TTT_end_ns; +// } +// +// int64_t ref_timestamp = 0; +// +// double ini_wvfm_timestamp = 0; +// double end_wvfm_timestamp = 0; +// +// // If an ETRIG or HLT timestamp was found it restarts the time from it. Otherwise the CAEN time frame is assigned. +// if (factive_timing_frame != CAEN_ONLY_TIMING) { +// ref_timestamp = signed_difference(full_TTT, timestamp); // ns. +// +// ini_wvfm_timestamp = (ref_timestamp - pulse_duration_ns) * NANOSEC_TO_MICROSEC; // us. +// end_wvfm_timestamp = ref_timestamp * NANOSEC_TO_MICROSEC; // us. +// } else { +// ref_timestamp = full_TTT; // ns. +// +// ini_wvfm_timestamp = ((ref_timestamp - pulse_duration_ns) % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // ns. +// end_wvfm_timestamp = (ref_timestamp % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // us. +// } +// +// if (fdebug_timing) { +// std::cout << std::fixed << std::setprecision(0); +// std::cout << "\t\t ns/tick = " << NANOSEC_PER_TICK << ", ns/sample = " << fns_per_sample << std::endl; +// std::cout << "\t\t TTT header.TriggerTime() [TTT_ticks] = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; +// std::cout << "\t\t TTT header.extendedTriggerTime() [TTT_ticks] = " << header.extendedTriggerTime() << " ticks. \t TTT_end_ns = " << print_timestamp(header.extendedTriggerTime() * NANOSEC_PER_TICK) << "." << std::endl; +// std::cout << "\t\t TTT header.triggerTimeRollOver(): " << header.triggerTimeRollOver() << std::endl; +// std::cout << "\t\t Full Fragment timestamp: " << print_timestamp(frag_timestamp) << " = " << frag_timestamp_s << " s " << frag_timestamp_ns << " ns." << std::endl; +// std::cout << "\t\t Full TTT - fragment timestamp = "<< abs_difference(full_TTT, frag_timestamp) << " ns." << " Post-percent: " << (double(abs_difference(full_TTT, frag_timestamp)) / double(pulse_duration_ns)) * 100 << "%." << std::endl; +// if (factive_timing_frame == SPEC_TDC_TIMING) { +// std::cout << "\t ETRIG (SPEC-TDC) timestamp of the fragment: " << std::endl; +// std::cout << "\t\t Full UTC ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; +// std::cout << "\t\t ETRIG SPEC-TDC difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; +// } else if (factive_timing_frame == PTB_TIMING) { +// std::cout << "\t HLT ETRIG (PTB) timestamp of the fragment: " << std::endl; +// std::cout << "\t\t Full UTC HLT ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; +// std::cout << "\t\t HLT ETRIG (PTB) difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; +// } else if (factive_timing_frame == CAEN_ONLY_TIMING) { +// std::cout << "\t CAEN trigger timestamp (TTT) of the fragment: " << std::endl; +// std::cout << "\t\t Full UTC TTT timestamp: " << print_timestamp(full_TTT) << " = " << full_TTT / NANOSEC_IN_SEC << " s " << TTT_end_ns << " ns." << std::endl; +// } +// } +// +// if (fverbose | fdebug_timing) { +// std::cout << std::fixed << std::setprecision(3); +// if (factive_timing_frame == SPEC_TDC_TIMING) { +// std::cout << " > SBNDXARAPUCADecoder::decode_fragment: SPEC-TDC time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; +// } else if (factive_timing_frame == PTB_TIMING) { +// std::cout << " > SBNDXARAPUCADecoder::decode_fragment: PTB time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; +// } else { // CAEN_ONLY_TIMING +// std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; +// } +// std::cout << " > SBNDXARAPUCADecoder::decode_fragment: TTT_end_ticks = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; +// } +// // =============== Start decoding the waveforms =============== // if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding of the waveforms starting... " << std::endl; @@ -771,6 +781,11 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto S++; } } + + + double ini_wvfm_timestamp = 0; + double end_wvfm_timestamp = 0; + shift_time(fragment, TTT_ticks, TTT_end_ns, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); // The decoded waveforms are dumped into two products: // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. @@ -878,6 +893,71 @@ void sbndaq::SBNDXARAPUCADecoder::save_debug_wvfm(size_t board_idx, size_t fragm } +void sbndaq::SBNDXARAPUCADecoder::shift_time(const artdaq::Fragment& fragment, uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp) { + + int64_t pulse_duration_ns = num_samples_per_wvfm * fns_per_sample; // ns. + uint64_t frag_timestamp = fragment.timestamp(); // ns. + int64_t frag_timestamp_s = frag_timestamp / NANOSEC_IN_SEC; // s. + int64_t frag_timestamp_ns = frag_timestamp % NANOSEC_IN_SEC; // ns. + + // Gets the full TTT timestamp. + uint64_t full_TTT = 0; + // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. + if (frag_timestamp_ns > TTT_end_ns) { + if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred w.r.t. the fragment timestamp (FTS)." << std::endl; + full_TTT = (frag_timestamp_s + 1) * NANOSEC_IN_SEC + TTT_end_ns; + } else { + full_TTT = frag_timestamp_s * NANOSEC_IN_SEC + TTT_end_ns; + } + + int64_t ref_timestamp = 0; + + // If an ETRIG or HLT timestamp was found it restarts the time from it. Otherwise the CAEN time frame is assigned. + if (factive_timing_frame != CAEN_ONLY_TIMING) { + ref_timestamp = signed_difference(full_TTT, timestamp); // ns. + + ini_wvfm_timestamp = (ref_timestamp - pulse_duration_ns) * NANOSEC_TO_MICROSEC; // us. + end_wvfm_timestamp = ref_timestamp * NANOSEC_TO_MICROSEC; // us. + } else { + ref_timestamp = full_TTT; // ns. + + ini_wvfm_timestamp = ((ref_timestamp - pulse_duration_ns) % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // ns. + end_wvfm_timestamp = (ref_timestamp % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // us. + } + + if (fdebug_timing) { + std::cout << std::fixed << std::setprecision(0); + std::cout << "\t\t ns/tick = " << NANOSEC_PER_TICK << ", ns/sample = " << fns_per_sample << std::endl; + std::cout << "\t\t TTT header.TriggerTime() [TTT_ticks] = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; + std::cout << "\t\t Full Fragment timestamp: " << print_timestamp(frag_timestamp) << " = " << frag_timestamp_s << " s " << frag_timestamp_ns << " ns." << std::endl; + std::cout << "\t\t Full TTT - fragment timestamp = "<< abs_difference(full_TTT, frag_timestamp) << " ns." << " Post-percent: " << (double(abs_difference(full_TTT, frag_timestamp)) / double(pulse_duration_ns)) * 100 << "%." << std::endl; + if (factive_timing_frame == SPEC_TDC_TIMING) { + std::cout << "\t ETRIG (SPEC-TDC) timestamp of the fragment: " << std::endl; + std::cout << "\t\t Full UTC ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; + std::cout << "\t\t ETRIG SPEC-TDC difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; + } else if (factive_timing_frame == PTB_TIMING) { + std::cout << "\t HLT ETRIG (PTB) timestamp of the fragment: " << std::endl; + std::cout << "\t\t Full UTC HLT ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; + std::cout << "\t\t HLT ETRIG (PTB) difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; + } else if (factive_timing_frame == CAEN_ONLY_TIMING) { + std::cout << "\t CAEN trigger timestamp (TTT) of the fragment: " << std::endl; + std::cout << "\t\t Full UTC TTT timestamp: " << print_timestamp(full_TTT) << " = " << full_TTT / NANOSEC_IN_SEC << " s " << TTT_end_ns << " ns." << std::endl; + } + } + + if (fverbose | fdebug_timing) { + std::cout << std::fixed << std::setprecision(3); + if (factive_timing_frame == SPEC_TDC_TIMING) { + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: SPEC-TDC time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; + } else if (factive_timing_frame == PTB_TIMING) { + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: PTB time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; + } else { // CAEN_ONLY_TIMING + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; + } + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: TTT_end_ticks = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; + } +} + /** * @brief Extract a sample from a 64-bit buffer using the specified bit positions. * @@ -975,11 +1055,11 @@ uint64_t sbndaq::SBNDXARAPUCADecoder::abs_difference(uint64_t t1, uint64_t t2) { } /** -* @brief Formats a timestamp in nanoseconds into a easily readable string format. -* @param[in] timestamp The timestamp in nanoseconds to be formatted. -* @return A string representation of the timestamp in the format "(seconds)nanoseconds ns". -* @details The function divides the input timestamp by 1,000,000,000 to obtain the seconds component and uses the modulus operator to get the remaining nanoseconds. -*/ + * @brief Formats a timestamp in nanoseconds into a easily readable string format. + * @param[in] timestamp The timestamp in nanoseconds to be formatted. + * @return A string representation of the timestamp in the format "(seconds)nanoseconds ns". + * @details The function divides the input timestamp by 1,000,000,000 to obtain the seconds component and uses the modulus operator to get the remaining nanoseconds. + */ std::string sbndaq::SBNDXARAPUCADecoder::print_timestamp(uint64_t timestamp) { return "(" + std::to_string(timestamp / NANOSEC_IN_SEC) + ")" + std::to_string(timestamp % NANOSEC_IN_SEC) + " ns"; } From 3f93cebdce39d9be4f21d180cc9fdcf3d5a576dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 9 Oct 2025 06:07:47 -0500 Subject: [PATCH 041/155] Waveforms decoding function --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 195 ++++++++---------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 2 +- 2 files changed, 89 insertions(+), 108 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 655c26cfb..72020207c 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -138,6 +138,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool get_ptb_hlt_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp, uint16_t & hlt_code); bool get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp); void shift_time(const artdaq::Fragment& fragment, uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); + void decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group); void save_prod_wvfm(size_t board_idx, size_t ch, double ini_wvfm_timestamp, const std::vector > & wvfms, std::vector & prod_wvfms); void save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, double ini_wvfm_timestamp, double end_wvfm_timestamp, const std::vector > & wvfms); @@ -634,7 +635,8 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto // Gets the number of words of the header and the waveforms. uint32_t num_words_per_event = header.eventSize; - uint32_t num_words_per_header = sizeof(CAENV1740EventHeader) / sizeof(uint32_t); + size_t header_size = sizeof(CAENV1740EventHeader); + uint32_t num_words_per_header = header_size / sizeof(uint32_t); uint32_t num_words_per_wvfms = (num_words_per_event - num_words_per_header); uint32_t num_bits_per_all_wvfms = num_words_per_wvfms * BITS_PER_WORD; @@ -663,12 +665,6 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto // =============== Extracts timing information for this fragment =============== // - // Gets the timing information of the CAEN fragment. -// int64_t pulse_duration_ns = num_samples_per_wvfm * fns_per_sample; // ns. -// uint64_t frag_timestamp = fragment.timestamp(); // ns. -// int64_t frag_timestamp_s = frag_timestamp / NANOSEC_IN_SEC; // s. -// int64_t frag_timestamp_ns = frag_timestamp % NANOSEC_IN_SEC; // ns. - uint32_t TTT_ticks = header.triggerTime(); int64_t TTT_end_ns = TTT_ticks * NANOSEC_PER_TICK; // ns. @@ -676,113 +672,53 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto std::cout << "\t\t TTT header.extendedTriggerTime() [TTT_ticks] = " << header.extendedTriggerTime() << " ticks. \t TTT_end_ns = " << print_timestamp(header.extendedTriggerTime() * NANOSEC_PER_TICK) << "." << std::endl; std::cout << "\t\t TTT header.triggerTimeRollOver(): " << header.triggerTimeRollOver() << std::endl; } + +// // =============== Start decoding the waveforms =============== // + std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); + decode_waveforms(fragment, wvfms, header_size, num_channels, num_samples_per_wvfm, num_words_per_wvfms, num_samples_per_group); +// if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding of the waveforms starting... " << std::endl; +// +// std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); // -// // Gets the full TTT timestamp. -// uint64_t full_TTT = 0; -// // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. -// if (frag_timestamp_ns > TTT_end_ns) { -// if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred w.r.t. the fragment timestamp (FTS)." << std::endl; -// full_TTT = (frag_timestamp_s + 1) * NANOSEC_IN_SEC + TTT_end_ns; -// } else { -// full_TTT = frag_timestamp_s * NANOSEC_IN_SEC + TTT_end_ns; -// } -// -// int64_t ref_timestamp = 0; -// -// double ini_wvfm_timestamp = 0; -// double end_wvfm_timestamp = 0; -// -// // If an ETRIG or HLT timestamp was found it restarts the time from it. Otherwise the CAEN time frame is assigned. -// if (factive_timing_frame != CAEN_ONLY_TIMING) { -// ref_timestamp = signed_difference(full_TTT, timestamp); // ns. -// -// ini_wvfm_timestamp = (ref_timestamp - pulse_duration_ns) * NANOSEC_TO_MICROSEC; // us. -// end_wvfm_timestamp = ref_timestamp * NANOSEC_TO_MICROSEC; // us. -// } else { -// ref_timestamp = full_TTT; // ns. +// // Absolute sample number [0, TOTAL_NUM_SAMPLES] where TOTAL_NUM_SAMPLES is the total number of samples stored for an event. +// uint32_t S = 0; +// // Buffer variables. +// uint64_t buffer = 0; +// uint32_t bits_in_buffer = 0; // -// ini_wvfm_timestamp = ((ref_timestamp - pulse_duration_ns) % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // ns. -// end_wvfm_timestamp = (ref_timestamp % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // us. -// } +// // Data pointer to the beggining of the waveforms stores in the event. +// const uint32_t* data_ptr = reinterpret_cast(fragment.dataBeginBytes() + sizeof(CAENV1740EventHeader)); +// // Accesses each word, stores it in the buffer and then the samples are extracted from the buffer. +// for (size_t j = 0; j < num_words_per_wvfms; j++) { +// uint64_t word = read_word(data_ptr); // -// if (fdebug_timing) { -// std::cout << std::fixed << std::setprecision(0); -// std::cout << "\t\t ns/tick = " << NANOSEC_PER_TICK << ", ns/sample = " << fns_per_sample << std::endl; -// std::cout << "\t\t TTT header.TriggerTime() [TTT_ticks] = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; -// std::cout << "\t\t TTT header.extendedTriggerTime() [TTT_ticks] = " << header.extendedTriggerTime() << " ticks. \t TTT_end_ns = " << print_timestamp(header.extendedTriggerTime() * NANOSEC_PER_TICK) << "." << std::endl; -// std::cout << "\t\t TTT header.triggerTimeRollOver(): " << header.triggerTimeRollOver() << std::endl; -// std::cout << "\t\t Full Fragment timestamp: " << print_timestamp(frag_timestamp) << " = " << frag_timestamp_s << " s " << frag_timestamp_ns << " ns." << std::endl; -// std::cout << "\t\t Full TTT - fragment timestamp = "<< abs_difference(full_TTT, frag_timestamp) << " ns." << " Post-percent: " << (double(abs_difference(full_TTT, frag_timestamp)) / double(pulse_duration_ns)) * 100 << "%." << std::endl; -// if (factive_timing_frame == SPEC_TDC_TIMING) { -// std::cout << "\t ETRIG (SPEC-TDC) timestamp of the fragment: " << std::endl; -// std::cout << "\t\t Full UTC ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; -// std::cout << "\t\t ETRIG SPEC-TDC difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; -// } else if (factive_timing_frame == PTB_TIMING) { -// std::cout << "\t HLT ETRIG (PTB) timestamp of the fragment: " << std::endl; -// std::cout << "\t\t Full UTC HLT ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; -// std::cout << "\t\t HLT ETRIG (PTB) difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; -// } else if (factive_timing_frame == CAEN_ONLY_TIMING) { -// std::cout << "\t CAEN trigger timestamp (TTT) of the fragment: " << std::endl; -// std::cout << "\t\t Full UTC TTT timestamp: " << print_timestamp(full_TTT) << " = " << full_TTT / NANOSEC_IN_SEC << " s " << TTT_end_ns << " ns." << std::endl; -// } -// } +// // Adds the new word to the buffer and increments the number of bits stored in it. +// if (fdebug_buffer) std::cout << buffer << "[word: " << word << "]" << std::endl; +// buffer |= word << bits_in_buffer; +// bits_in_buffer += BITS_PER_WORD; // bytes * 8 bits/byte +// if (fdebug_buffer) std::cout << " +" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; // -// if (fverbose | fdebug_timing) { -// std::cout << std::fixed << std::setprecision(3); -// if (factive_timing_frame == SPEC_TDC_TIMING) { -// std::cout << " > SBNDXARAPUCADecoder::decode_fragment: SPEC-TDC time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; -// } else if (factive_timing_frame == PTB_TIMING) { -// std::cout << " > SBNDXARAPUCADecoder::decode_fragment: PTB time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; -// } else { // CAEN_ONLY_TIMING -// std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; +// // Obtains 12-bit sequences from the buffer and assigns each sample to the channel and channel sample it belongs to. +// while (bits_in_buffer >= BITS_PER_SAMPLE) { +// // Computes board channel, channel sample and group channel and assigns the sample to those indices. +// uint32_t g = (S / num_samples_per_group); // Group index. +// uint32_t c = ((S / NUM_CONSECUTIVE_SAMPLES) % NUM_CHANNELS_PER_GROUP) + g * NUM_GROUPS; // Channel index. +// uint32_t s = (S % NUM_CONSECUTIVE_SAMPLES) + ((S / NUM_SAMPLES_PER_ROUND) * NUM_CONSECUTIVE_SAMPLES) % num_samples_per_wvfm; // Sample/channel index. +// uint16_t sample = get_sample(buffer, BITS_PER_SAMPLE - 1, 0); +// wvfms[c][s] = sample; +// if (fdebug_waveforms) std::cout << "\tSample: " << sample << "\tg: " << g << "\tch: " << c << "\ts:" << s << "\tS: " << S << std::endl; +// +// // Updates the buffer status removing the read bits and decreasing the number of bits stored in it. +// buffer >>= BITS_PER_SAMPLE; +// bits_in_buffer -= BITS_PER_SAMPLE; +// if (fdebug_buffer) std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; +// +// // Increments the absolute sample step. +// S++; // } -// std::cout << " > SBNDXARAPUCADecoder::decode_fragment: TTT_end_ticks = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; // } -// - // =============== Start decoding the waveforms =============== // - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding of the waveforms starting... " << std::endl; - - std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); - - // Absolute sample number [0, TOTAL_NUM_SAMPLES] where TOTAL_NUM_SAMPLES is the total number of samples stored for an event. - uint32_t S = 0; - // Buffer variables. - uint64_t buffer = 0; - uint32_t bits_in_buffer = 0; - - // Data pointer to the beggining of the waveforms stores in the event. - const uint32_t* data_ptr = reinterpret_cast(fragment.dataBeginBytes() + sizeof(CAENV1740EventHeader)); - // Accesses each word, stores it in the buffer and then the samples are extracted from the buffer. - for (size_t j = 0; j < num_words_per_wvfms; j++) { - uint64_t word = read_word(data_ptr); - - // Adds the new word to the buffer and increments the number of bits stored in it. - if (fdebug_buffer) std::cout << buffer << "[word: " << word << "]" << std::endl; - buffer |= word << bits_in_buffer; - bits_in_buffer += BITS_PER_WORD; // bytes * 8 bits/byte - if (fdebug_buffer) std::cout << " +" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; - - // Obtains 12-bit sequences from the buffer and assigns each sample to the channel and channel sample it belongs to. - while (bits_in_buffer >= BITS_PER_SAMPLE) { - // Computes board channel, channel sample and group channel and assigns the sample to those indices. - uint32_t g = (S / num_samples_per_group); // Group index. - uint32_t c = ((S / NUM_CONSECUTIVE_SAMPLES) % NUM_CHANNELS_PER_GROUP) + g * NUM_GROUPS; // Channel index. - uint32_t s = (S % NUM_CONSECUTIVE_SAMPLES) + ((S / NUM_SAMPLES_PER_ROUND) * NUM_CONSECUTIVE_SAMPLES) % num_samples_per_wvfm; // Sample/channel index. - uint16_t sample = get_sample(buffer, BITS_PER_SAMPLE - 1, 0); - wvfms[c][s] = sample; - if (fdebug_waveforms) std::cout << "\tSample: " << sample << "\tg: " << g << "\tch: " << c << "\ts:" << s << "\tS: " << S << std::endl; - - // Updates the buffer status removing the read bits and decreasing the number of bits stored in it. - buffer >>= BITS_PER_SAMPLE; - bits_in_buffer -= BITS_PER_SAMPLE; - if (fdebug_buffer) std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; - - // Increments the absolute sample step. - S++; - } - } - + // =============== Shifts timing to the selected timing reference frame =============== // double ini_wvfm_timestamp = 0; double end_wvfm_timestamp = 0; shift_time(fragment, TTT_ticks, TTT_end_ns, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); @@ -958,6 +894,51 @@ void sbndaq::SBNDXARAPUCADecoder::shift_time(const artdaq::Fragment& fragment, u } } +void sbndaq::SBNDXARAPUCADecoder::decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group) { + // =============== Start decoding the waveforms =============== // + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding of the waveforms starting... " << std::endl; + + //std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); + + // Absolute sample number [0, TOTAL_NUM_SAMPLES] where TOTAL_NUM_SAMPLES is the total number of samples stored for an event. + uint32_t S = 0; + // Buffer variables. + uint64_t buffer = 0; + uint32_t bits_in_buffer = 0; + + // Data pointer to the beggining of the waveforms stores in the event. + const uint32_t* data_ptr = reinterpret_cast(fragment.dataBeginBytes() + header_size); + // Accesses each word, stores it in the buffer and then the samples are extracted from the buffer. + for (size_t j = 0; j < num_words_per_wvfms; j++) { + uint64_t word = read_word(data_ptr); + + // Adds the new word to the buffer and increments the number of bits stored in it. + if (fdebug_buffer) std::cout << buffer << "[word: " << word << "]" << std::endl; + buffer |= word << bits_in_buffer; + bits_in_buffer += BITS_PER_WORD; // bytes * 8 bits/byte + if (fdebug_buffer) std::cout << " +" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; + + // Obtains 12-bit sequences from the buffer and assigns each sample to the channel and channel sample it belongs to. + while (bits_in_buffer >= BITS_PER_SAMPLE) { + // Computes board channel, channel sample and group channel and assigns the sample to those indices. + uint32_t g = (S / num_samples_per_group); // Group index. + uint32_t c = ((S / NUM_CONSECUTIVE_SAMPLES) % NUM_CHANNELS_PER_GROUP) + g * NUM_GROUPS; // Channel index. + uint32_t s = (S % NUM_CONSECUTIVE_SAMPLES) + ((S / NUM_SAMPLES_PER_ROUND) * NUM_CONSECUTIVE_SAMPLES) % num_samples_per_wvfm; // Sample/channel index. + uint16_t sample = get_sample(buffer, BITS_PER_SAMPLE - 1, 0); + wvfms[c][s] = sample; + if (fdebug_waveforms) std::cout << "\tSample: " << sample << "\tg: " << g << "\tch: " << c << "\ts:" << s << "\tS: " << S << std::endl; + + // Updates the buffer status removing the read bits and decreasing the number of bits stored in it. + buffer >>= BITS_PER_SAMPLE; + bits_in_buffer -= BITS_PER_SAMPLE; + if (fdebug_buffer) std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; + + // Increments the absolute sample step. + S++; + } + } +} + /** * @brief Extract a sample from a 64-bit buffer using the specified bit positions. * diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index 774032157..022a6888c 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -32,7 +32,7 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: -1 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: 33 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. From b416a56d558710b69fd964fa9a1f67a07df790c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 9 Oct 2025 07:20:43 -0500 Subject: [PATCH 042/155] Add dump waveforms function --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 135 ++++++++---------- 1 file changed, 63 insertions(+), 72 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 72020207c..0131a5e49 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -74,7 +74,6 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { void produce(art::Event& e) override; private: - constexpr static uint64_t NANOSEC_IN_SEC = 1'000'000'000; /**< Number of nanoseconds in one second. */ constexpr static uint64_t MICROSEC_IN_NANOSEC = 1'000; /**< Number of nanoseconds in one microsecond. */ constexpr static double NANOSEC_TO_MICROSEC = 1E-3; /**< Conversion factor from nanoseconds to microseconds. */ @@ -91,6 +90,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { constexpr static uint16_t PTB_TIMING = 1; /**< Timing reference frame: HLT (High Level Trigger) timestamp from the PTB (Penn Trigger Board). */ constexpr static uint16_t CAEN_ONLY_TIMING = 2; /**< Timing reference frame: CAEN-only. */ + constexpr static uint16_t TTT_DEFAULT = 0; /**< Default integer value for the nominal TTT. */ constexpr static uint16_t HLT_NOT_FOUND = 999; /**< Random value to indicate no HL trigger found. */ constexpr static uint16_t HLT_TOO_FAR = 1000; /**< Random value to indicate HL trigger found but too far from the raw timestamp. */ @@ -140,6 +140,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { void shift_time(const artdaq::Fragment& fragment, uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); void decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group); + void dump_waveforms(std::vector & prod_wvfms, const std::vector>& wvfms, std::vector & fragment_indices, size_t board_index, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp); void save_prod_wvfm(size_t board_idx, size_t ch, double ini_wvfm_timestamp, const std::vector > & wvfms, std::vector & prod_wvfms); void save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, double ini_wvfm_timestamp, double end_wvfm_timestamp, const std::vector > & wvfms); @@ -621,7 +622,8 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto //bool is_nominal_length = false; //bool is_within_nominal_length = false; //bool is_first = false; - + //int32_t nominal_TTT = TTT_DEFAULT; + // =============== Accesses Event metadata and Event header for this fragment =============== // CAENV1740Fragment caen_fragment(fragment); @@ -663,6 +665,8 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto std::cout << "\t Number of samples per group (this fragment): " << num_samples_per_group << std::endl; } + std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); + // =============== Extracts timing information for this fragment =============== // uint32_t TTT_ticks = header.triggerTime(); @@ -673,81 +677,41 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto std::cout << "\t\t TTT header.triggerTimeRollOver(): " << header.triggerTimeRollOver() << std::endl; } -// // =============== Start decoding the waveforms =============== // - std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); + // =============== Start decoding the waveforms =============== // + //std::vector > fragment_wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); decode_waveforms(fragment, wvfms, header_size, num_channels, num_samples_per_wvfm, num_words_per_wvfms, num_samples_per_group); -// if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding of the waveforms starting... " << std::endl; -// -// std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); -// -// // Absolute sample number [0, TOTAL_NUM_SAMPLES] where TOTAL_NUM_SAMPLES is the total number of samples stored for an event. -// uint32_t S = 0; -// // Buffer variables. -// uint64_t buffer = 0; -// uint32_t bits_in_buffer = 0; -// -// // Data pointer to the beggining of the waveforms stores in the event. -// const uint32_t* data_ptr = reinterpret_cast(fragment.dataBeginBytes() + sizeof(CAENV1740EventHeader)); -// // Accesses each word, stores it in the buffer and then the samples are extracted from the buffer. -// for (size_t j = 0; j < num_words_per_wvfms; j++) { -// uint64_t word = read_word(data_ptr); -// -// // Adds the new word to the buffer and increments the number of bits stored in it. -// if (fdebug_buffer) std::cout << buffer << "[word: " << word << "]" << std::endl; -// buffer |= word << bits_in_buffer; -// bits_in_buffer += BITS_PER_WORD; // bytes * 8 bits/byte -// if (fdebug_buffer) std::cout << " +" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; -// -// // Obtains 12-bit sequences from the buffer and assigns each sample to the channel and channel sample it belongs to. -// while (bits_in_buffer >= BITS_PER_SAMPLE) { -// // Computes board channel, channel sample and group channel and assigns the sample to those indices. -// uint32_t g = (S / num_samples_per_group); // Group index. -// uint32_t c = ((S / NUM_CONSECUTIVE_SAMPLES) % NUM_CHANNELS_PER_GROUP) + g * NUM_GROUPS; // Channel index. -// uint32_t s = (S % NUM_CONSECUTIVE_SAMPLES) + ((S / NUM_SAMPLES_PER_ROUND) * NUM_CONSECUTIVE_SAMPLES) % num_samples_per_wvfm; // Sample/channel index. -// uint16_t sample = get_sample(buffer, BITS_PER_SAMPLE - 1, 0); -// wvfms[c][s] = sample; -// if (fdebug_waveforms) std::cout << "\tSample: " << sample << "\tg: " << g << "\tch: " << c << "\ts:" << s << "\tS: " << S << std::endl; -// -// // Updates the buffer status removing the read bits and decreasing the number of bits stored in it. -// buffer >>= BITS_PER_SAMPLE; -// bits_in_buffer -= BITS_PER_SAMPLE; -// if (fdebug_buffer) std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; -// -// // Increments the absolute sample step. -// S++; -// } -// } // =============== Shifts timing to the selected timing reference frame =============== // double ini_wvfm_timestamp = 0; double end_wvfm_timestamp = 0; shift_time(fragment, TTT_ticks, TTT_end_ns, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - // The decoded waveforms are dumped into two products: - // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. - // - A decoder_hist.root file gathering a waveform histograms. - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding complete, dumping products..." << std::endl; - - uint32_t num_debug_wvfms; - - if (fstore_debug_waveforms == -1) { - num_debug_wvfms = num_channels; - } else { - num_debug_wvfms = std::min(num_channels, fstore_debug_waveforms); - } - - uint32_t ch; - - for (ch = 0; ch < num_debug_wvfms; ch++) { - save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); - save_debug_wvfm(board_idx, fragment_indices[board_idx], ch, ini_wvfm_timestamp, end_wvfm_timestamp, wvfms); - } - - for (;ch < num_channels; ch++) { - save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); - } - - fragment_indices[board_idx]++; + dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + // // The decoded waveforms are dumped into two products: + // // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. + // // - A decoder_hist.root file gathering a waveform histograms. + // if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding complete, dumping products..." << std::endl; + // + // uint32_t num_debug_wvfms; +// + // if (fstore_debug_waveforms == -1) { + // num_debug_wvfms = num_channels; + // } else { + // num_debug_wvfms = std::min(num_channels, fstore_debug_waveforms); + // } +// + // uint32_t ch; +// + // for (ch = 0; ch < num_debug_wvfms; ch++) { + // save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); + // save_debug_wvfm(board_idx, fragment_indices[board_idx], ch, ini_wvfm_timestamp, end_wvfm_timestamp, wvfms); + // } +// + // for (;ch < num_channels; ch++) { + // save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); + // } +// + // fragment_indices[board_idx]++; } } @@ -898,8 +862,6 @@ void sbndaq::SBNDXARAPUCADecoder::decode_waveforms(const artdaq::Fragment& fragm // =============== Start decoding the waveforms =============== // if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding of the waveforms starting... " << std::endl; - //std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); - // Absolute sample number [0, TOTAL_NUM_SAMPLES] where TOTAL_NUM_SAMPLES is the total number of samples stored for an event. uint32_t S = 0; // Buffer variables. @@ -939,6 +901,35 @@ void sbndaq::SBNDXARAPUCADecoder::decode_waveforms(const artdaq::Fragment& fragm } } +void sbndaq::SBNDXARAPUCADecoder::dump_waveforms(std::vector & prod_wvfms, const std::vector>& wvfms, std::vector & fragment_indices, size_t board_idx, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp) { + + // The decoded waveforms are dumped into two products: + // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. + // - A decoder_hist.root file gathering a waveform histograms. + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding complete, dumping products..." << std::endl; + + uint32_t num_debug_wvfms; + + if (fstore_debug_waveforms == -1) { + num_debug_wvfms = num_channels; + } else { + num_debug_wvfms = std::min(num_channels, fstore_debug_waveforms); + } + + uint32_t ch; + + for (ch = 0; ch < num_debug_wvfms; ch++) { + save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); + save_debug_wvfm(board_idx, fragment_indices[board_idx], ch, ini_wvfm_timestamp, end_wvfm_timestamp, wvfms); + } + + for (;ch < num_channels; ch++) { + save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); + } + + fragment_indices[board_idx]++; +} + /** * @brief Extract a sample from a 64-bit buffer using the specified bit positions. * From 0d9f64460644030a1db0559000e96aaaabc1fdf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Fri, 10 Oct 2025 05:44:36 -0500 Subject: [PATCH 043/155] Combine waveforms and correctly differentiates nominal from extended --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 120 +++++++++++------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 2 +- 2 files changed, 72 insertions(+), 50 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 0131a5e49..ff9b9c99f 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -133,17 +133,19 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fverbose; /**< If `true` it increases verbosity of console output for detailed processing steps. */ // Class methods. - void decode_fragment(uint64_t timestamp, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms); + void decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms); bool get_ptb_hlt_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp, uint16_t & hlt_code); bool get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp); - void shift_time(const artdaq::Fragment& fragment, uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); + void shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); void decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group); - void dump_waveforms(std::vector & prod_wvfms, const std::vector>& wvfms, std::vector & fragment_indices, size_t board_index, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp); + void dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, std::vector & fragment_indices, size_t board_index, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp); void save_prod_wvfm(size_t board_idx, size_t ch, double ini_wvfm_timestamp, const std::vector > & wvfms, std::vector & prod_wvfms); void save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, double ini_wvfm_timestamp, double end_wvfm_timestamp, const std::vector > & wvfms); + void combine_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels); + uint16_t get_sample(uint64_t buffer, uint32_t msb, uint32_t lsb); uint32_t read_word(const uint32_t* & data_ptr); unsigned int get_channel_id(unsigned int board, unsigned int board_channel); @@ -304,6 +306,10 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) bool found_caen = false; std::vector fragment_indices(fnum_caen_boards, 0); + std::vector> wvfms; + std::cout << "wvfms_size: " << wvfms.size() << std::endl; + int32_t nominal_TTT = TTT_DEFAULT; + uint64_t nominal_frag_timestamp = TTT_DEFAULT; if (fverbose | fdebug_fragments_handle) std::cout << "\n > SBNDXARAPUCADecoder::produce: searching for V1740 fragments..." << std::endl; @@ -341,7 +347,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) for (size_t f = 0; f < num_caen_fragments; f++) { const artdaq::Fragment fragment = *container_fragment[f].get(); - decode_fragment(timestamp, fragment_indices, fragment, *prod_wvfms); + decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms); } // End CAEN V1740 fragments loop. } } // End Container fragments loop. @@ -353,7 +359,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) // It searches for all CAEN V1740 fragments. for (size_t f = 0; f < frag_handle_size; f++) { const artdaq::Fragment fragment = fragment_handle->at(f); - decode_fragment(timestamp, fragment_indices, fragment, *prod_wvfms); + decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms); } // End CAEN V1740 fragments loop. } } // End extracting CAEN V1740 fragments. @@ -599,7 +605,10 @@ bool sbndaq::SBNDXARAPUCADecoder::get_ptb_hlt_timestamp(art::Event& e, uint64_t * - Populates the output vector (`prod_wvfms`) with decoded waveforms and optionally generates debug waveforms output. * */ -void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms) { + +void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms) { + std::cout << "decode_wvfms_size: " << wvfms.size() << std::endl; + auto fragment_id = fragment.fragmentID() - ffragment_id_offset; auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); size_t board_idx; @@ -619,10 +628,13 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto if (valid_fragment) { if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::decode_fragment: decoding V1740 CAEN fragment " << fragment_indices[board_idx] << " from the board " << board_idx << " (slot " << fboard_id_list[board_idx] << "):" << std::endl; - //bool is_nominal_length = false; + bool is_nominal_length = false; //bool is_within_nominal_length = false; - //bool is_first = false; - //int32_t nominal_TTT = TTT_DEFAULT; + bool is_first = false; + + + double ini_wvfm_timestamp = 0; + double end_wvfm_timestamp = 0; // =============== Accesses Event metadata and Event header for this fragment =============== // @@ -646,14 +658,15 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto uint32_t num_remaining_bits = num_bits_per_all_wvfms % BITS_PER_SAMPLE; uint32_t num_samples_per_wvfm = num_samples_per_all_wvfms / num_channels; uint32_t num_samples_per_group = num_samples_per_wvfm * NUM_CHANNELS_PER_GROUP; + uint32_t num_nominal_samples_per_wvfm = metadata->nSamples; if (fverbose | fdebug_waveforms) { - if (metadata->nSamples == num_samples_per_wvfm) { + if (num_nominal_samples_per_wvfm == num_samples_per_wvfm) { std::cout << " > SBNDXARAPUCADecoder::decode_fragment: [NOMINAL FRAGMENT] " << num_samples_per_wvfm << " samples/waveform." << " (" << num_samples_per_group << " samples per group - 8 channels per group -)." << std::endl; } else { std::cout << " > SBNDXARAPUCADecoder::decode_fragment: [EXTENDED FRAGMENT] " << num_samples_per_wvfm << " samples/waveform." << " (" << num_samples_per_group << " samples per group - 8 channels per group -)." << std::endl; } - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: nominal number of samples per waveform: " << metadata->nSamples << "." << std::endl; + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: nominal number of samples per waveform: " << num_nominal_samples_per_wvfm << "." << std::endl; std::cout << " > SBNDXARAPUCADecoder::decode_fragment: number of words for this fragment: " << num_words_per_event << " (Header: " << num_words_per_header << ", Waveform: " << num_words_per_wvfms << ") words." << std::endl; } @@ -665,10 +678,11 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto std::cout << "\t Number of samples per group (this fragment): " << num_samples_per_group << std::endl; } - std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); + //std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); // =============== Extracts timing information for this fragment =============== // + uint64_t frag_timestamp = fragment.timestamp(); // ns. uint32_t TTT_ticks = header.triggerTime(); int64_t TTT_end_ns = TTT_ticks * NANOSEC_PER_TICK; // ns. @@ -677,41 +691,38 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, std::vecto std::cout << "\t\t TTT header.triggerTimeRollOver(): " << header.triggerTimeRollOver() << std::endl; } - // =============== Start decoding the waveforms =============== // - //std::vector > fragment_wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); - decode_waveforms(fragment, wvfms, header_size, num_channels, num_samples_per_wvfm, num_words_per_wvfms, num_samples_per_group); - - // =============== Shifts timing to the selected timing reference frame =============== // - double ini_wvfm_timestamp = 0; - double end_wvfm_timestamp = 0; - shift_time(fragment, TTT_ticks, TTT_end_ns, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - - dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); - // // The decoded waveforms are dumped into two products: - // // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. - // // - A decoder_hist.root file gathering a waveform histograms. - // if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding complete, dumping products..." << std::endl; - // - // uint32_t num_debug_wvfms; -// - // if (fstore_debug_waveforms == -1) { - // num_debug_wvfms = num_channels; - // } else { - // num_debug_wvfms = std::min(num_channels, fstore_debug_waveforms); - // } -// - // uint32_t ch; + //// =============== Start decoding the waveforms =============== // + std::vector > fragment_wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); + decode_waveforms(fragment, fragment_wvfms, header_size, num_channels, num_samples_per_wvfm, num_words_per_wvfms, num_samples_per_group); // - // for (ch = 0; ch < num_debug_wvfms; ch++) { - // save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); - // save_debug_wvfm(board_idx, fragment_indices[board_idx], ch, ini_wvfm_timestamp, end_wvfm_timestamp, wvfms); - // } + //// =============== Shifts timing to the selected timing reference frame =============== // // - // for (;ch < num_channels; ch++) { - // save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); - // } -// - // fragment_indices[board_idx]++; + //shift_time(fragment, TTT_ticks, TTT_end_ns, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + //dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + //combine_waveforms(wvfms, fragment_wvfms, num_channels); + + is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); + is_first = (fragment_indices[board_idx] == 0); + + if (is_nominal_length) { + if (!is_first) { + std::cout << " NOT FIRST NOMINAL fragment " << std::endl; + std::cout << " nominal_TTT: " << nominal_TTT << " TTT_end_ns: " << TTT_end_ns << std::endl; + std::cout << " nominal_frag_timestamp: " << nominal_frag_timestamp << " frag_timestamp : " << frag_timestamp << std::endl; + shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + } else { + std::cout << " FIRST NOMINAL fragment " << std::endl; + } + combine_waveforms(wvfms, fragment_wvfms, num_channels); + nominal_TTT = TTT_end_ns; + nominal_frag_timestamp = frag_timestamp; + } else { + std::cout << " EXTENDED fragment " << std::endl; + combine_waveforms(wvfms, fragment_wvfms, num_channels); + } + + fragment_indices[board_idx]++; } } @@ -793,10 +804,9 @@ void sbndaq::SBNDXARAPUCADecoder::save_debug_wvfm(size_t board_idx, size_t fragm } -void sbndaq::SBNDXARAPUCADecoder::shift_time(const artdaq::Fragment& fragment, uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp) { +void sbndaq::SBNDXARAPUCADecoder::shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp) { int64_t pulse_duration_ns = num_samples_per_wvfm * fns_per_sample; // ns. - uint64_t frag_timestamp = fragment.timestamp(); // ns. int64_t frag_timestamp_s = frag_timestamp / NANOSEC_IN_SEC; // s. int64_t frag_timestamp_ns = frag_timestamp % NANOSEC_IN_SEC; // ns. @@ -901,7 +911,7 @@ void sbndaq::SBNDXARAPUCADecoder::decode_waveforms(const artdaq::Fragment& fragm } } -void sbndaq::SBNDXARAPUCADecoder::dump_waveforms(std::vector & prod_wvfms, const std::vector>& wvfms, std::vector & fragment_indices, size_t board_idx, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp) { +void sbndaq::SBNDXARAPUCADecoder::dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, std::vector & fragment_indices, size_t board_idx, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp) { // The decoded waveforms are dumped into two products: // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. @@ -927,7 +937,19 @@ void sbndaq::SBNDXARAPUCADecoder::dump_waveforms(std::vector >& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels) { + if (wvfms.empty()) { + std::cout << "Empty waveforms, resizing to " << num_channels << " channels." << std::endl; + wvfms.resize(num_channels); + std::cout << "BEF COMB - wvfms_size = " << wvfms.size() << " x " << wvfms[0].size() << std::endl; + } + for (uint32_t ch = 0; ch < num_channels; ch++) { + wvfms[ch].insert(wvfms[ch].end(), fragment_wvfms[ch].begin(), fragment_wvfms[ch].end()); + } + std::cout << "AFT COMB - wvfms_size = " << wvfms.size() << " x " << wvfms[0].size() << std::endl; } /** diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index 022a6888c..b9ab4ba0a 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -32,7 +32,7 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: 33 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: 2 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. From c1a42c050f51eba1d4f0103edeeaf89b4f1b5b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Tue, 14 Oct 2025 06:59:02 -0500 Subject: [PATCH 044/155] Combine all extended fragments succesfully --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 32 +++++++++---------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index ff9b9c99f..61231e201 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -133,7 +133,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fverbose; /**< If `true` it increases verbosity of console output for detailed processing steps. */ // Class methods. - void decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms); + void decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); bool get_ptb_hlt_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp, uint16_t & hlt_code); bool get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp); @@ -310,6 +310,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) std::cout << "wvfms_size: " << wvfms.size() << std::endl; int32_t nominal_TTT = TTT_DEFAULT; uint64_t nominal_frag_timestamp = TTT_DEFAULT; + bool last_one = false; if (fverbose | fdebug_fragments_handle) std::cout << "\n > SBNDXARAPUCADecoder::produce: searching for V1740 fragments..." << std::endl; @@ -347,7 +348,8 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) for (size_t f = 0; f < num_caen_fragments; f++) { const artdaq::Fragment fragment = *container_fragment[f].get(); - decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms); + last_one = f == (num_caen_fragments - 1); + decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); } // End CAEN V1740 fragments loop. } } // End Container fragments loop. @@ -359,7 +361,8 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) // It searches for all CAEN V1740 fragments. for (size_t f = 0; f < frag_handle_size; f++) { const artdaq::Fragment fragment = fragment_handle->at(f); - decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms); + last_one = f == (frag_handle_size - 1); + decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); } // End CAEN V1740 fragments loop. } } // End extracting CAEN V1740 fragments. @@ -606,9 +609,7 @@ bool sbndaq::SBNDXARAPUCADecoder::get_ptb_hlt_timestamp(art::Event& e, uint64_t * */ -void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms) { - std::cout << "decode_wvfms_size: " << wvfms.size() << std::endl; - +void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { auto fragment_id = fragment.fragmentID() - ffragment_id_offset; auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); size_t board_idx; @@ -678,8 +679,6 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& std::cout << "\t Number of samples per group (this fragment): " << num_samples_per_group << std::endl; } - //std::vector > wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); - // =============== Extracts timing information for this fragment =============== // uint64_t frag_timestamp = fragment.timestamp(); // ns. @@ -694,13 +693,7 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& //// =============== Start decoding the waveforms =============== // std::vector > fragment_wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); decode_waveforms(fragment, fragment_wvfms, header_size, num_channels, num_samples_per_wvfm, num_words_per_wvfms, num_samples_per_group); -// - //// =============== Shifts timing to the selected timing reference frame =============== // -// - //shift_time(fragment, TTT_ticks, TTT_end_ns, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - //dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); - //combine_waveforms(wvfms, fragment_wvfms, num_channels); - + is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); is_first = (fragment_indices[board_idx] == 0); @@ -721,8 +714,15 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& std::cout << " EXTENDED fragment " << std::endl; combine_waveforms(wvfms, fragment_wvfms, num_channels); } - + fragment_indices[board_idx]++; + + if (last_one) { + std::cout << " LAST fragment " << std::endl; + shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + } + } } diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index b9ab4ba0a..774032157 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -32,7 +32,7 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: 2 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: -1 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. From e1656068b0c2a39177683a04ae40e82dec54869e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Wed, 15 Oct 2025 06:06:52 -0500 Subject: [PATCH 045/155] Add new comments for code documenting. New variable for debugging the extended fragments combination --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 806 ++++++++++-------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 7 +- 2 files changed, 464 insertions(+), 349 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 61231e201..7c46afb10 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -130,29 +130,36 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fdebug_timing; /**< If `true` timing data is printed. */ bool fdebug_buffer; /**< If `true` the buffer status is printed. */ bool fdebug_waveforms; /**< If `true` waveforms decoding data is printed. */ + bool fdebug_extended_fragments; /**< If `true` extended fragments information is printed. */ bool fverbose; /**< If `true` it increases verbosity of console output for detailed processing steps. */ - // Class methods. + // Main processing method. void decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); - bool get_ptb_hlt_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp, uint16_t & hlt_code); - bool get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp); + // Timing. void shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); - void decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group); - - void dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, std::vector & fragment_indices, size_t board_index, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp); - void save_prod_wvfm(size_t board_idx, size_t ch, double ini_wvfm_timestamp, const std::vector > & wvfms, std::vector & prod_wvfms); - void save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, double ini_wvfm_timestamp, double end_wvfm_timestamp, const std::vector > & wvfms); + bool get_spec_tdc_etrig_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp); + bool get_ptb_hlt_timestamp(art::Event& e, uint64_t corr_raw_timestamp, uint64_t & timestamp, uint16_t & hlt_code); - void combine_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels); - + // Waveforms decoding. + void decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group); uint16_t get_sample(uint64_t buffer, uint32_t msb, uint32_t lsb); uint32_t read_word(const uint32_t* & data_ptr); unsigned int get_channel_id(unsigned int board, unsigned int board_channel); - std::string print_timestamp(uint64_t timestamp); + // Combines decoded waveforms. + void combine_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels); + + // Dumps and saves waveforms. + void dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, std::vector & fragment_indices, size_t board_index, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp); + void save_prod_wvfm(size_t board_idx, size_t ch, double ini_wvfm_timestamp, const std::vector > & wvfms, std::vector & prod_wvfms); + void save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, double ini_wvfm_timestamp, double end_wvfm_timestamp, const std::vector > & wvfms); + + // Auxiliary methods. int64_t signed_difference(uint64_t t1, uint64_t t2); uint64_t abs_difference(uint64_t t1, uint64_t t2); + std::string print_timestamp(uint64_t timestamp); + }; /** @@ -210,6 +217,7 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) fdebug_fragments_handle = p.get ("debug_fragments_handle", false); fdebug_timing = p.get ("debug_timing", false); fdebug_waveforms = p.get ("debug_waveforms", false); + fdebug_extended_fragments = p.get ("debug_extended_fragments", false); fdebug_buffer = p.get ("debug_buffer", false); fverbose = p.get ("verbose", false); @@ -229,8 +237,7 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) * 3. It searches for CAEN V1740 fragments in the event, decodes them and creates the output products: a vector of raw::OpDetWaveform. * 4. It dumps the products in the event. */ -void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) -{ +void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::produce: entering the produce function." << std::endl; // Advances the event counter. @@ -307,7 +314,10 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) std::vector fragment_indices(fnum_caen_boards, 0); std::vector> wvfms; - std::cout << "wvfms_size: " << wvfms.size() << std::endl; + if (fdebug_extended_fragments) { + std::cout << " Waveforms size: " << wvfms.size() << std::endl; + } + int32_t nominal_TTT = TTT_DEFAULT; uint64_t nominal_frag_timestamp = TTT_DEFAULT; bool last_one = false; @@ -383,6 +393,241 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) } } +// =============== Main fragment processing method =============== // + +/** + * @brief Decodes a CAEN V1740 fragment, extracts the waveforms and combines them into the output product. + * @param[in] timestamp The valid timestamp used as reference for the event. + * @param[in,out] nominal_frag_timestamp The nominal timestamp calculated for the fragment being processed. + * @param[in,out] nominal_TTT The nominal Trigger Time Tag (TTT) calculated for the fragment being processed. + * @param[in,out] fragment_indices A vector containing the indices of the fragments already processed for each board. + * @param[in] fragment The artdaq::Fragment object to be processed. + * @param[in,out] prod_wvfms The vector of raw::OpDetWaveform objects to be filled with the decoded waveforms. + * @param[in,out] wvfms A 2D vector containing the waveforms for all channels and boards decoded so far. + * @param[in] last_one A boolean flag indicating if the fragment being processed is the last one in the event. + + * @details This method decodes a CAEN V1740 fragment, extracts the waveforms for each channel, shifts them in time according to the + * timing reference and combines them into the output product. + * 1. It checks if the fragment ID corresponds to a valid board. + * 2. It accesses the metadata and header of the fragment to get information about the number of channels, samples, words, etc. + * 3. It calculates the number of samples per waveform and checks if it is a nominal or extended fragment. + * 4. It decodes the waveforms for each channel in the fragment. + * 5. It shifts the waveforms in time according to the timing reference. + * 6. It combines the decoded waveforms into the output product. + * 7. It dumps the waveforms if required. + * + * @pre The art::Event object containing the fragment has been processed to get a valid timing reference. + * @post The vector of raw::OpDetWaveform objects is filled with the decoded waveforms from the fragment. + * @see shift_time + * @see decode_waveforms + * @see combine_waveforms + * @see dump_waveforms + */ + +void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { + auto fragment_id = fragment.fragmentID() - ffragment_id_offset; + auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); + size_t board_idx; + bool valid_fragment = false; + + if (it != fboard_id_list.end()) { + board_idx = it - fboard_id_list.begin(); + if (board_idx >= fnum_caen_boards) { + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: fragment ID " << fragment_id << " (" << board_idx << ") is out of range. Skipping this fragment..." << std::endl; + } else { + valid_fragment = true; + } + } else { + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: fragment ID " << fragment_id << " is not valid. Skipping this fragment..." << std::endl; + } + + if (valid_fragment) { + if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::decode_fragment: decoding V1740 CAEN fragment " << fragment_indices[board_idx] << " from the board " << board_idx << " (slot " << fboard_id_list[board_idx] << "):" << std::endl; + + bool is_nominal_length = false; + bool is_first = false; + + double ini_wvfm_timestamp = 0; + double end_wvfm_timestamp = 0; + + // =============== Accesses Event metadata and Event header for this fragment =============== // + + CAENV1740Fragment caen_fragment(fragment); + CAENV1740FragmentMetadata const* metadata = caen_fragment.Metadata(); + uint32_t num_channels = metadata->nChannels; + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: number of channels: " << num_channels << std::endl; + + // Accesses the event and header data of the CAEN fragment. + CAENV1740Event const* event = caen_fragment.Event(); + CAENV1740EventHeader header = event->Header; + + // Gets the number of words of the header and the waveforms. + uint32_t num_words_per_event = header.eventSize; + size_t header_size = sizeof(CAENV1740EventHeader); + uint32_t num_words_per_header = header_size / sizeof(uint32_t); + uint32_t num_words_per_wvfms = (num_words_per_event - num_words_per_header); + + uint32_t num_bits_per_all_wvfms = num_words_per_wvfms * BITS_PER_WORD; + uint32_t num_samples_per_all_wvfms = num_bits_per_all_wvfms / BITS_PER_SAMPLE; + uint32_t num_remaining_bits = num_bits_per_all_wvfms % BITS_PER_SAMPLE; + uint32_t num_samples_per_wvfm = num_samples_per_all_wvfms / num_channels; + uint32_t num_samples_per_group = num_samples_per_wvfm * NUM_CHANNELS_PER_GROUP; + uint32_t num_nominal_samples_per_wvfm = metadata->nSamples; + + if (fverbose | fdebug_waveforms) { + if (num_nominal_samples_per_wvfm == num_samples_per_wvfm) { + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: [NOMINAL FRAGMENT] " << num_samples_per_wvfm << " samples/waveform." << " (" << num_samples_per_group << " samples per group - 8 channels per group -)." << std::endl; + } else { + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: [EXTENDED FRAGMENT] " << num_samples_per_wvfm << " samples/waveform." << " (" << num_samples_per_group << " samples per group - 8 channels per group -)." << std::endl; + } + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: nominal number of samples per waveform: " << num_nominal_samples_per_wvfm << "." << std::endl; + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: number of words for this fragment: " << num_words_per_event << " (Header: " << num_words_per_header << ", Waveform: " << num_words_per_wvfms << ") words." << std::endl; + } + + if (fdebug_waveforms) { + std::cout << "\t Number of bits for all the waveforms of this fragment: " << BITS_PER_WORD << "\t" << num_bits_per_all_wvfms << std::endl; + std::cout << "\t Number of samples for all the waveforms of this fragment: " << num_samples_per_all_wvfms << std::endl; + std::cout << "\t Number of remaining bits for this fragment: " << num_remaining_bits << std::endl; + std::cout << "\t Number of samples per wvfm (this fragment): " << num_samples_per_wvfm << std::endl; + std::cout << "\t Number of samples per group (this fragment): " << num_samples_per_group << std::endl; + } + + // =============== Extracts timing information for this fragment =============== // + + uint64_t frag_timestamp = fragment.timestamp(); // ns. + uint32_t TTT_ticks = header.triggerTime(); + int64_t TTT_end_ns = TTT_ticks * NANOSEC_PER_TICK; // ns. + + if (fdebug_timing) { + std::cout << "\t\t TTT header.extendedTriggerTime() [TTT_ticks] = " << header.extendedTriggerTime() << " ticks. \t TTT_end_ns = " << print_timestamp(header.extendedTriggerTime() * NANOSEC_PER_TICK) << "." << std::endl; + std::cout << "\t\t TTT header.triggerTimeRollOver(): " << header.triggerTimeRollOver() << std::endl; + } + + //// =============== Start decoding the waveforms =============== // + std::vector > fragment_wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); + decode_waveforms(fragment, fragment_wvfms, header_size, num_channels, num_samples_per_wvfm, num_words_per_wvfms, num_samples_per_group); + + is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); + is_first = (fragment_indices[board_idx] == 0); + + if (fverbose) { + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: processing the decoded fragment and combines the extended ones to their nominal ones if needed." << std::endl; + } + if (is_nominal_length) { + if (!is_first) { + if (fdebug_extended_fragments) { + std::cout << "\t\t NOT FIRST NOMINAL fragment " << std::endl; + std::cout << "\t\t nominal_TTT: " << nominal_TTT << " TTT_end_ns: " << TTT_end_ns << std::endl; + std::cout << "\t\t nominal_frag_timestamp: " << nominal_frag_timestamp << " frag_timestamp : " << frag_timestamp << std::endl; + } + shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + } else { + if (fdebug_extended_fragments) std::cout << "\t\t FIRST NOMINAL fragment " << std::endl; + } + combine_waveforms(wvfms, fragment_wvfms, num_channels); + nominal_TTT = TTT_end_ns; + nominal_frag_timestamp = frag_timestamp; + } else { + if (fdebug_extended_fragments) std::cout << "\t\t EXTENDED fragment " << std::endl; + combine_waveforms(wvfms, fragment_wvfms, num_channels); + } + + fragment_indices[board_idx]++; + + if (last_one) { + if (fdebug_extended_fragments) std::cout << "\t\t LAST fragment " << std::endl; + shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + } + } +} + +// =============== Timing functions =============== // + +/** + * @brief This function shifts the initial and end timestamps of a waveform based on the provided timing information. + * + * @param[in] TTT_ticks The trigger time tag in ticks from the CAEN V1740 header. + * @param[in] TTT_end_ns The end time of the Trigger Time Tag (TTT) in nanoseconds. + * @param[in] frag_timestamp The timestamp of the fragment in nanoseconds. + * @param[in] timestamp The reference timestamp (ETRIG from the SPEC-TDC or HLT from the PTB) in nanoseconds. + * @param[in] num_samples_per_wvfm The number of samples per waveform. + * @param[out] ini_wvfm_timestamp The initial timestamp of the waveform in microseconds (output). + * @param[out] end_wvfm_timestamp The end timestamp of the waveform in microseconds (output). + * + * @details + * This function calculates the initial and end timestamps for a waveform based on the provided timing information. It takes into account + * potential rollovers in the trigger time tag and adjusts the timestamps accordingly. The function supports different timing frames, including + * SPEC-TDC, PTB, and CAEN-only timing. The calculated timestamps are returned in microseconds. + * + * @see get_spec_tdc_etrig_timestamp + * @see get_ptb_hlt_timestamp + */ +void sbndaq::SBNDXARAPUCADecoder::shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp) { + + int64_t pulse_duration_ns = num_samples_per_wvfm * fns_per_sample; // ns. + int64_t frag_timestamp_s = frag_timestamp / NANOSEC_IN_SEC; // s. + int64_t frag_timestamp_ns = frag_timestamp % NANOSEC_IN_SEC; // ns. + + // Gets the full TTT timestamp. + uint64_t full_TTT = 0; + // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. + if (frag_timestamp_ns > TTT_end_ns) { + if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred w.r.t. the fragment timestamp (FTS)." << std::endl; + full_TTT = (frag_timestamp_s + 1) * NANOSEC_IN_SEC + TTT_end_ns; + } else { + full_TTT = frag_timestamp_s * NANOSEC_IN_SEC + TTT_end_ns; + } + + int64_t ref_timestamp = 0; + + // If an ETRIG or HLT timestamp was found it restarts the time from it. Otherwise the CAEN time frame is assigned. + if (factive_timing_frame != CAEN_ONLY_TIMING) { + ref_timestamp = signed_difference(full_TTT, timestamp); // ns. + + ini_wvfm_timestamp = (ref_timestamp - pulse_duration_ns) * NANOSEC_TO_MICROSEC; // us. + end_wvfm_timestamp = ref_timestamp * NANOSEC_TO_MICROSEC; // us. + } else { + ref_timestamp = full_TTT; // ns. + + ini_wvfm_timestamp = ((ref_timestamp - pulse_duration_ns) % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // ns. + end_wvfm_timestamp = (ref_timestamp % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // us. + } + + if (fdebug_timing) { + std::cout << std::fixed << std::setprecision(0); + std::cout << "\t\t ns/tick = " << NANOSEC_PER_TICK << ", ns/sample = " << fns_per_sample << std::endl; + std::cout << "\t\t TTT header.TriggerTime() [TTT_ticks] = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; + std::cout << "\t\t Full Fragment timestamp: " << print_timestamp(frag_timestamp) << " = " << frag_timestamp_s << " s " << frag_timestamp_ns << " ns." << std::endl; + std::cout << "\t\t Full TTT - fragment timestamp = "<< abs_difference(full_TTT, frag_timestamp) << " ns." << " Post-percent: " << (double(abs_difference(full_TTT, frag_timestamp)) / double(pulse_duration_ns)) * 100 << "%." << std::endl; + if (factive_timing_frame == SPEC_TDC_TIMING) { + std::cout << "\t ETRIG (SPEC-TDC) timestamp of the fragment: " << std::endl; + std::cout << "\t\t Full UTC ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; + std::cout << "\t\t ETRIG SPEC-TDC difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; + } else if (factive_timing_frame == PTB_TIMING) { + std::cout << "\t HLT ETRIG (PTB) timestamp of the fragment: " << std::endl; + std::cout << "\t\t Full UTC HLT ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; + std::cout << "\t\t HLT ETRIG (PTB) difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; + } else if (factive_timing_frame == CAEN_ONLY_TIMING) { + std::cout << "\t CAEN trigger timestamp (TTT) of the fragment: " << std::endl; + std::cout << "\t\t Full UTC TTT timestamp: " << print_timestamp(full_TTT) << " = " << full_TTT / NANOSEC_IN_SEC << " s " << TTT_end_ns << " ns." << std::endl; + } + } + + if (fverbose | fdebug_timing) { + std::cout << std::fixed << std::setprecision(3); + if (factive_timing_frame == SPEC_TDC_TIMING) { + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: SPEC-TDC time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; + } else if (factive_timing_frame == PTB_TIMING) { + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: PTB time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; + } else { // CAEN_ONLY_TIMING + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; + } + std::cout << " > SBNDXARAPUCADecoder::decode_fragment: TTT_end_ticks = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; + } +} + /** * @brief Searches for the SPEC-TDC ETRIG timestamp closest to the raw timestamp if any SPEC-TDC ETRIG product is found in the event. * @param[in] e The event to be processed. @@ -577,153 +822,226 @@ bool sbndaq::SBNDXARAPUCADecoder::get_ptb_hlt_timestamp(art::Event& e, uint64_t return hlt_found; } +// =============== Decodes the waveforms =============== // + /** - * @brief This function processes a single fragment from a CAEN V1740 and stores the decoded waveforms in the provided product - * container. + * @brief Decodes the waveforms from a CAEN V1740 fragment (binary decoding stage). * - * @param[in,out] fragment_indices A 1D vector tracking the number of fragments processed for each board. * @param[in] fragment The input CAEN V1740 fragment containing raw data to be decoded. - * @param[out] prod_wvfms Vector where the decoded waveforms will be stored as raw::OpDetWaveform objects. - * - * @details - * - Identifies the board index corresponding to the fragment ID. - * - Verifies the fragment ID against known boards and ensures it is within a valid range. - * - - * - Decodes the fragment reading raw 32-bit words from the fragment, storing them in a buffer, - * and extracting 12-bit samples. The decoding includes: - * - Accessing metadata for the number of channels and samples. - * - Getting the initial timestamp with respect to the selected timing frame. - * - Binary decoding of the raw waveform. To assign efficiently each sequential sample extracted. These indices formulas are - * applied: - * - The board channel index: - * \f[ - * c = \left( \frac{S}{3} \mod 8 \right) + g \times 8 - * \f] - * - The channel sample index: - * \f[ - * s = (S \mod 3) + \left( \frac{S}{24} \times 3 \right) \mod s_{w}} - * \f] - * Where the group index is computed as \f$ \frac{S}{s_{g}} \f$. - * - Mapping samples to corresponding channels. - * - Populates the output vector (`prod_wvfms`) with decoded waveforms and optionally generates debug waveforms output. + * @param[out] wvfms A 2D vector where the decoded waveforms will be stored. Each inner vector corresponds to a channel's waveform. + * @param[in] header_size The size of the event header in bytes. + * @param[in] num_channels The number of channels in the fragment. + * @param[in] num_samples_per_wvfm The number of samples per waveform for each channel. + * @param[in] num_words_per_wvfms The total number of 32-bit words containing waveform data in the fragment. + * @param[in] num_samples_per_group The number of samples per group of channels (8 channels per group). * + * @details This function reads raw 32-bit words from the fragment, storing them in a buffer, and extracts 12-bit samples. + * It assigns each sample to the appropriate channel and sample index based on its position in the sequence. The decoding process includes: + * - Initializing a buffer to hold incoming data and tracking the number of bits currently stored. + * - Iterating over each 32-bit word in the waveform data section of the fragment, adding it to the buffer. + * - Extracting 12-bit samples from the buffer as long as there are enough bits available, and assigning them to their respective channels and sample indices using calculated formulas. + * The function ensures that all samples are correctly mapped to their channels, taking into account the grouping of channels and the interleaving of samples. + * @note The function assumes that the input fragment is valid and contains the expected structure for a CAEN V1740 device. + * @see SBN Document 38475-v1 for more details on the binary decoding. */ +void sbndaq::SBNDXARAPUCADecoder::decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group) { + // =============== Start decoding the waveforms =============== // + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding of the waveforms starting... " << std::endl; + + // Absolute sample number [0, TOTAL_NUM_SAMPLES] where TOTAL_NUM_SAMPLES is the total number of samples stored for an event. + uint32_t S = 0; + // Buffer variables. + uint64_t buffer = 0; + uint32_t bits_in_buffer = 0; -void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { - auto fragment_id = fragment.fragmentID() - ffragment_id_offset; - auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); - size_t board_idx; - bool valid_fragment = false; - - if (it != fboard_id_list.end()) { - board_idx = it - fboard_id_list.begin(); - if (board_idx >= fnum_caen_boards) { - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: fragment ID " << fragment_id << " (" << board_idx << ") is out of range. Skipping this fragment..." << std::endl; - } else { - valid_fragment = true; - } - } else { - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: fragment ID " << fragment_id << " is not valid. Skipping this fragment..." << std::endl; - } - - if (valid_fragment) { - if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::decode_fragment: decoding V1740 CAEN fragment " << fragment_indices[board_idx] << " from the board " << board_idx << " (slot " << fboard_id_list[board_idx] << "):" << std::endl; - - bool is_nominal_length = false; - //bool is_within_nominal_length = false; - bool is_first = false; - + // Data pointer to the beggining of the waveforms stores in the event. + const uint32_t* data_ptr = reinterpret_cast(fragment.dataBeginBytes() + header_size); + // Accesses each word, stores it in the buffer and then the samples are extracted from the buffer. + for (size_t j = 0; j < num_words_per_wvfms; j++) { + uint64_t word = read_word(data_ptr); - double ini_wvfm_timestamp = 0; - double end_wvfm_timestamp = 0; - - // =============== Accesses Event metadata and Event header for this fragment =============== // + // Adds the new word to the buffer and increments the number of bits stored in it. + if (fdebug_buffer) std::cout << buffer << "[word: " << word << "]" << std::endl; + buffer |= word << bits_in_buffer; + bits_in_buffer += BITS_PER_WORD; // bytes * 8 bits/byte + if (fdebug_buffer) std::cout << " +" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; - CAENV1740Fragment caen_fragment(fragment); - CAENV1740FragmentMetadata const* metadata = caen_fragment.Metadata(); - uint32_t num_channels = metadata->nChannels; - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: number of channels: " << num_channels << std::endl; - - // Accesses the event and header data of the CAEN fragment. - CAENV1740Event const* event = caen_fragment.Event(); - CAENV1740EventHeader header = event->Header; - - // Gets the number of words of the header and the waveforms. - uint32_t num_words_per_event = header.eventSize; - size_t header_size = sizeof(CAENV1740EventHeader); - uint32_t num_words_per_header = header_size / sizeof(uint32_t); - uint32_t num_words_per_wvfms = (num_words_per_event - num_words_per_header); - - uint32_t num_bits_per_all_wvfms = num_words_per_wvfms * BITS_PER_WORD; - uint32_t num_samples_per_all_wvfms = num_bits_per_all_wvfms / BITS_PER_SAMPLE; - uint32_t num_remaining_bits = num_bits_per_all_wvfms % BITS_PER_SAMPLE; - uint32_t num_samples_per_wvfm = num_samples_per_all_wvfms / num_channels; - uint32_t num_samples_per_group = num_samples_per_wvfm * NUM_CHANNELS_PER_GROUP; - uint32_t num_nominal_samples_per_wvfm = metadata->nSamples; - - if (fverbose | fdebug_waveforms) { - if (num_nominal_samples_per_wvfm == num_samples_per_wvfm) { - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: [NOMINAL FRAGMENT] " << num_samples_per_wvfm << " samples/waveform." << " (" << num_samples_per_group << " samples per group - 8 channels per group -)." << std::endl; - } else { - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: [EXTENDED FRAGMENT] " << num_samples_per_wvfm << " samples/waveform." << " (" << num_samples_per_group << " samples per group - 8 channels per group -)." << std::endl; - } - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: nominal number of samples per waveform: " << num_nominal_samples_per_wvfm << "." << std::endl; - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: number of words for this fragment: " << num_words_per_event << " (Header: " << num_words_per_header << ", Waveform: " << num_words_per_wvfms << ") words." << std::endl; + // Obtains 12-bit sequences from the buffer and assigns each sample to the channel and channel sample it belongs to. + while (bits_in_buffer >= BITS_PER_SAMPLE) { + // Computes board channel, channel sample and group channel and assigns the sample to those indices. + uint32_t g = (S / num_samples_per_group); // Group index. + uint32_t c = ((S / NUM_CONSECUTIVE_SAMPLES) % NUM_CHANNELS_PER_GROUP) + g * NUM_GROUPS; // Channel index. + uint32_t s = (S % NUM_CONSECUTIVE_SAMPLES) + ((S / NUM_SAMPLES_PER_ROUND) * NUM_CONSECUTIVE_SAMPLES) % num_samples_per_wvfm; // Sample/channel index. + uint16_t sample = get_sample(buffer, BITS_PER_SAMPLE - 1, 0); + wvfms[c][s] = sample; + if (fdebug_waveforms) std::cout << "\tSample: " << sample << "\tg: " << g << "\tch: " << c << "\ts:" << s << "\tS: " << S << std::endl; + + // Updates the buffer status removing the read bits and decreasing the number of bits stored in it. + buffer >>= BITS_PER_SAMPLE; + bits_in_buffer -= BITS_PER_SAMPLE; + if (fdebug_buffer) std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; + + // Increments the absolute sample step. + S++; } + } +} - if (fdebug_waveforms) { - std::cout << "\t Number of bits for all the waveforms of this fragment: " << BITS_PER_WORD << "\t" << num_bits_per_all_wvfms << std::endl; - std::cout << "\t Number of samples for all the waveforms of this fragment: " << num_samples_per_all_wvfms << std::endl; - std::cout << "\t Number of remaining bits for this fragment: " << num_remaining_bits << std::endl; - std::cout << "\t Number of samples per wvfm (this fragment): " << num_samples_per_wvfm << std::endl; - std::cout << "\t Number of samples per group (this fragment): " << num_samples_per_group << std::endl; - } +/** + * @brief Extract a sample from a 64-bit buffer using the specified bit positions. + * + * @param[in] buffer An unsigned 64-bit integer which represents a temporal buffer for the read words and where the samples are extracted from. + * @param[in] msb An unsigned 32-bit integer representing the most significative bit (MSB) where the readout from the buffer paramter. + * @param[in] lsb An unsigned 32-bit integer representing the less significative bit (LSB) from we end read + * + * @details The function shifts the buffer to the right by the number of positions specified by `lsb` so that the least significant bit of the + * sample aligns with bit 0. It then applies a mask to isolate the bits between `lsb` and `msb`, inclusive. + * + * @return The extracted sample as a 16-bit unsigned integer. + */ +uint16_t sbndaq::SBNDXARAPUCADecoder::get_sample(uint64_t buffer, uint32_t msb, uint32_t lsb) { + uint64_t mask = (1U << (msb - lsb + 1)) - 1; + uint64_t sample = buffer >> lsb; + return sample & mask; +} - // =============== Extracts timing information for this fragment =============== // +/** + * @brief Read a 32-bit word from the data pointer and advances the pointer. + * + * @param[in, out] data_ptr A reference to a pointer pointing to the current position in the data. + * + * @details This function retrieves a 32-bit word from the memory location pointed to by `data_ptr`. After reading, it advances `data_ptr` to + * the next 32-bit word location. + * + * @return The 32-bit word read from the location pointed to by `data_ptr`. + */ +uint32_t sbndaq::SBNDXARAPUCADecoder::read_word(const uint32_t* & data_ptr) { + uint32_t word = *data_ptr; + data_ptr += 1; + return word; +} - uint64_t frag_timestamp = fragment.timestamp(); // ns. - uint32_t TTT_ticks = header.triggerTime(); - int64_t TTT_end_ns = TTT_ticks * NANOSEC_PER_TICK; // ns. +/** + * @brief Generates a unique global channel identifier using the board slot and the channel number of that board. + * + * @param[in] board Index of the board in `fboard_id_list` from which to derive the board slot. + * @param[in] board_channel The specific channel number on the given board. + * + * @details This function computes a `channel_id` by combining the board slot and the specific + * channel number on that board. + * The unique identifier `channel_id` (\f$ CH_{ID} $\f) is computed as follows: + * \f[ + * CH\_{ID} = B\_{ID} \times 100 + CH\_{B} + * \f] + * + * Where: + * - \f$ B\_{ID} \f$ is the fragment ID retrieved from `fboard_id_list` based on the slot. + * - \f$ CH\_B \f$ is the channel number on that board. + * + * @return A unique identifier for the specified channel as an unsigned integer. + */ +unsigned int sbndaq::SBNDXARAPUCADecoder::get_channel_id(unsigned int board, unsigned int board_channel) { + unsigned int channel_id = fboard_id_list[board] * 100 + board_channel; + return channel_id; +} - if (fdebug_timing) { - std::cout << "\t\t TTT header.extendedTriggerTime() [TTT_ticks] = " << header.extendedTriggerTime() << " ticks. \t TTT_end_ns = " << print_timestamp(header.extendedTriggerTime() * NANOSEC_PER_TICK) << "." << std::endl; - std::cout << "\t\t TTT header.triggerTimeRollOver(): " << header.triggerTimeRollOver() << std::endl; +// =============== Combines the waveforms from extended fragments =============== // + +/** + * @brief Combines the waveforms from the current fragment with the previously stored waveforms. + * @param[in,out] wvfms A 2D vector containing the (combined if it was needed before) waveforms. + * @param[in] fragment_wvfms A 2D vector containing the waveforms from the current fragment to be combined. + * @param[in] num_channels The number of channels per board. + * + * @details + * The function performs the following steps: + * 1. Checks if the `wvfms` vector is empty. If it is, it resizes it to accommodate `num_channels` channels. + * 2. Iterates over each channel from 0 to `num_channels - 1`. + * 3. For each channel, it appends the samples from `fragment_wvfms` to the corresponding channel in `wvfms`. + * + * This approach ensures that waveforms from multiple fragments are concatenated correctly, maintaining the order of samples for each channel. + * + * @pre The `fragment_wvfms` vector should contain waveforms for all channels of the board being processed. + * @pre The `wvfms` vector should be either empty or already contain waveforms for all channels of the board being processed. + */ +void sbndaq::SBNDXARAPUCADecoder::combine_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels) { + if (fdebug_extended_fragments) std::cout << " > SBNDXARAPUCADecoder::combine_waveforms: combining waveforms from extended fragments..." << std::endl; + if (wvfms.empty()) { + if (fdebug_extended_fragments) { + std::cout << "\t\t Empty waveforms, resizing to " << num_channels << " channels." << std::endl; + } + wvfms.resize(num_channels); + if (fverbose | fdebug_extended_fragments) { + std::cout << "\t\t Waveforms size BEFORE combining = " << wvfms.size() << " x " << wvfms[0].size() << std::endl; + } + } + for (uint32_t ch = 0; ch < num_channels; ch++) { + wvfms[ch].insert(wvfms[ch].end(), fragment_wvfms[ch].begin(), fragment_wvfms[ch].end()); + } + if (fverbose | fdebug_extended_fragments) { + std::cout << "\t\t Waveforms size AFTER combining = " << wvfms.size() << " x " << wvfms[0].size() << std::endl; } +} - //// =============== Start decoding the waveforms =============== // - std::vector > fragment_wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); - decode_waveforms(fragment, fragment_wvfms, header_size, num_channels, num_samples_per_wvfm, num_words_per_wvfms, num_samples_per_group); - - is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); - is_first = (fragment_indices[board_idx] == 0); +// =============== Dumps the decoded waveforms =============== // + +/** + * @brief Dump products into a `raw::OpDetWaveform` object and into a debug histogram file. + * @param[in,out] prod_wvfms A reference to the vector where the produced `raw::OpDetWaveform` objects are dumped into products. + * @param[in,out] wvfms A 2D vector containing the (combined if needed) waveforms. + * @param[in,out] fragment_indices A reference to a vector keeping track of the number of fragments decoded per board. + * @param[in] board_idx The board index (position in the list of boards). + * @param[in] num_channels The number of channels per board. + * @param[in] ini_wvfm_timestamp The initial timestamp of the waveform in microseconds. + * @param[in] end_wvfm_timestamp The final timestamp of the waveform in microseconds. + * + * @details + * The function performs the following steps: + * 1. Determines the number of debug waveforms to be stored based on the configuration parameter `fstore_debug_waveforms`. + * - If `fstore_debug_waveforms` is set to -1, all channels are considered for debug storage. + * - Otherwise, it takes the minimum between `num_channels` and `fstore_debug_waveforms`. + * 2. Iterates over each channel up to the determined number of debug waveforms: + * - Calls `save_prod_wvfm` to convert and store the waveform in the products. + * - Calls `save_debug_wvfm` to save the waveform as a histogram for debugging purposes. + * 3. For any remaining channels beyond the debug limit, it only calls `save_prod_wvfm` to store the waveform in the products. + * 4. Clears the `wvfms` vector to free up memory after processing. + * + * @pre ini_wvfm_timestamp and end_wvfm_timestamp is assumed to be given in microseconds when the timing frame is not CAEN_ONLY_TIMING. + * @pre The `wvfms` vector should contain waveforms for all channels of the board specified by `board_idx`. + * @pre The `fragment_indices` vector should have been initialized with a size equal to the number of boards being processed. + * @pre The `prod_wvfms` vector should be ready to accept new `raw::OpDetWaveform` objects. + * + * @see raw::OpDetWaveform + * @see save_prod_wvfm + * @see save_debug_wvfm + */ +void sbndaq::SBNDXARAPUCADecoder::dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, std::vector & fragment_indices, size_t board_idx, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp) { - if (is_nominal_length) { - if (!is_first) { - std::cout << " NOT FIRST NOMINAL fragment " << std::endl; - std::cout << " nominal_TTT: " << nominal_TTT << " TTT_end_ns: " << TTT_end_ns << std::endl; - std::cout << " nominal_frag_timestamp: " << nominal_frag_timestamp << " frag_timestamp : " << frag_timestamp << std::endl; - shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); - } else { - std::cout << " FIRST NOMINAL fragment " << std::endl; - } - combine_waveforms(wvfms, fragment_wvfms, num_channels); - nominal_TTT = TTT_end_ns; - nominal_frag_timestamp = frag_timestamp; - } else { - std::cout << " EXTENDED fragment " << std::endl; - combine_waveforms(wvfms, fragment_wvfms, num_channels); - } + // The decoded waveforms are dumped into two products: + // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. + // - A decoder_hist.root file gathering a waveform histograms. + if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding complete, dumping products..." << std::endl; - fragment_indices[board_idx]++; + uint32_t num_debug_wvfms; - if (last_one) { - std::cout << " LAST fragment " << std::endl; - shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); - } + if (fstore_debug_waveforms == -1) { + num_debug_wvfms = num_channels; + } else { + num_debug_wvfms = std::min(num_channels, fstore_debug_waveforms); + } + + uint32_t ch; + + for (ch = 0; ch < num_debug_wvfms; ch++) { + save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); + save_debug_wvfm(board_idx, fragment_indices[board_idx], ch, ini_wvfm_timestamp, end_wvfm_timestamp, wvfms); + } + for (;ch < num_channels; ch++) { + save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); } + + wvfms.clear(); } /** @@ -804,211 +1122,7 @@ void sbndaq::SBNDXARAPUCADecoder::save_debug_wvfm(size_t board_idx, size_t fragm } -void sbndaq::SBNDXARAPUCADecoder::shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp) { - - int64_t pulse_duration_ns = num_samples_per_wvfm * fns_per_sample; // ns. - int64_t frag_timestamp_s = frag_timestamp / NANOSEC_IN_SEC; // s. - int64_t frag_timestamp_ns = frag_timestamp % NANOSEC_IN_SEC; // ns. - - // Gets the full TTT timestamp. - uint64_t full_TTT = 0; - // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. - if (frag_timestamp_ns > TTT_end_ns) { - if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred w.r.t. the fragment timestamp (FTS)." << std::endl; - full_TTT = (frag_timestamp_s + 1) * NANOSEC_IN_SEC + TTT_end_ns; - } else { - full_TTT = frag_timestamp_s * NANOSEC_IN_SEC + TTT_end_ns; - } - - int64_t ref_timestamp = 0; - - // If an ETRIG or HLT timestamp was found it restarts the time from it. Otherwise the CAEN time frame is assigned. - if (factive_timing_frame != CAEN_ONLY_TIMING) { - ref_timestamp = signed_difference(full_TTT, timestamp); // ns. - - ini_wvfm_timestamp = (ref_timestamp - pulse_duration_ns) * NANOSEC_TO_MICROSEC; // us. - end_wvfm_timestamp = ref_timestamp * NANOSEC_TO_MICROSEC; // us. - } else { - ref_timestamp = full_TTT; // ns. - - ini_wvfm_timestamp = ((ref_timestamp - pulse_duration_ns) % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // ns. - end_wvfm_timestamp = (ref_timestamp % NANOSEC_IN_SEC) * NANOSEC_TO_MICROSEC; // us. - } - - if (fdebug_timing) { - std::cout << std::fixed << std::setprecision(0); - std::cout << "\t\t ns/tick = " << NANOSEC_PER_TICK << ", ns/sample = " << fns_per_sample << std::endl; - std::cout << "\t\t TTT header.TriggerTime() [TTT_ticks] = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; - std::cout << "\t\t Full Fragment timestamp: " << print_timestamp(frag_timestamp) << " = " << frag_timestamp_s << " s " << frag_timestamp_ns << " ns." << std::endl; - std::cout << "\t\t Full TTT - fragment timestamp = "<< abs_difference(full_TTT, frag_timestamp) << " ns." << " Post-percent: " << (double(abs_difference(full_TTT, frag_timestamp)) / double(pulse_duration_ns)) * 100 << "%." << std::endl; - if (factive_timing_frame == SPEC_TDC_TIMING) { - std::cout << "\t ETRIG (SPEC-TDC) timestamp of the fragment: " << std::endl; - std::cout << "\t\t Full UTC ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; - std::cout << "\t\t ETRIG SPEC-TDC difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; - } else if (factive_timing_frame == PTB_TIMING) { - std::cout << "\t HLT ETRIG (PTB) timestamp of the fragment: " << std::endl; - std::cout << "\t\t Full UTC HLT ETRIG timestamp: " << print_timestamp(timestamp) << "." << std::endl; - std::cout << "\t\t HLT ETRIG (PTB) difference applied to the CAEN frame (full timestamps): " << print_timestamp(full_TTT) << " - " << print_timestamp(timestamp) << " = " << ref_timestamp << " ns." << std::endl; - } else if (factive_timing_frame == CAEN_ONLY_TIMING) { - std::cout << "\t CAEN trigger timestamp (TTT) of the fragment: " << std::endl; - std::cout << "\t\t Full UTC TTT timestamp: " << print_timestamp(full_TTT) << " = " << full_TTT / NANOSEC_IN_SEC << " s " << TTT_end_ns << " ns." << std::endl; - } - } - - if (fverbose | fdebug_timing) { - std::cout << std::fixed << std::setprecision(3); - if (factive_timing_frame == SPEC_TDC_TIMING) { - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: SPEC-TDC time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; - } else if (factive_timing_frame == PTB_TIMING) { - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: PTB time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; - } else { // CAEN_ONLY_TIMING - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN time window of " << end_wvfm_timestamp - ini_wvfm_timestamp << " us: [" << ini_wvfm_timestamp << ", " << end_wvfm_timestamp << "] us." << std::endl; - } - std::cout << " > SBNDXARAPUCADecoder::decode_fragment: TTT_end_ticks = " << TTT_ticks << " ticks. \t TTT_end_ns = " << print_timestamp(TTT_end_ns) << "." << std::endl; - } -} - -void sbndaq::SBNDXARAPUCADecoder::decode_waveforms(const artdaq::Fragment& fragment, std::vector>& wvfms, size_t header_size, uint32_t num_channels, uint32_t num_samples_per_wvfm, uint32_t num_words_per_wvfms, uint32_t num_samples_per_group) { - // =============== Start decoding the waveforms =============== // - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding of the waveforms starting... " << std::endl; - - // Absolute sample number [0, TOTAL_NUM_SAMPLES] where TOTAL_NUM_SAMPLES is the total number of samples stored for an event. - uint32_t S = 0; - // Buffer variables. - uint64_t buffer = 0; - uint32_t bits_in_buffer = 0; - - // Data pointer to the beggining of the waveforms stores in the event. - const uint32_t* data_ptr = reinterpret_cast(fragment.dataBeginBytes() + header_size); - // Accesses each word, stores it in the buffer and then the samples are extracted from the buffer. - for (size_t j = 0; j < num_words_per_wvfms; j++) { - uint64_t word = read_word(data_ptr); - - // Adds the new word to the buffer and increments the number of bits stored in it. - if (fdebug_buffer) std::cout << buffer << "[word: " << word << "]" << std::endl; - buffer |= word << bits_in_buffer; - bits_in_buffer += BITS_PER_WORD; // bytes * 8 bits/byte - if (fdebug_buffer) std::cout << " +" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; - - // Obtains 12-bit sequences from the buffer and assigns each sample to the channel and channel sample it belongs to. - while (bits_in_buffer >= BITS_PER_SAMPLE) { - // Computes board channel, channel sample and group channel and assigns the sample to those indices. - uint32_t g = (S / num_samples_per_group); // Group index. - uint32_t c = ((S / NUM_CONSECUTIVE_SAMPLES) % NUM_CHANNELS_PER_GROUP) + g * NUM_GROUPS; // Channel index. - uint32_t s = (S % NUM_CONSECUTIVE_SAMPLES) + ((S / NUM_SAMPLES_PER_ROUND) * NUM_CONSECUTIVE_SAMPLES) % num_samples_per_wvfm; // Sample/channel index. - uint16_t sample = get_sample(buffer, BITS_PER_SAMPLE - 1, 0); - wvfms[c][s] = sample; - if (fdebug_waveforms) std::cout << "\tSample: " << sample << "\tg: " << g << "\tch: " << c << "\ts:" << s << "\tS: " << S << std::endl; - - // Updates the buffer status removing the read bits and decreasing the number of bits stored in it. - buffer >>= BITS_PER_SAMPLE; - bits_in_buffer -= BITS_PER_SAMPLE; - if (fdebug_buffer) std::cout << " -" << buffer << " [bits in buffer: "<< bits_in_buffer << "]" << std::endl; - - // Increments the absolute sample step. - S++; - } - } -} - -void sbndaq::SBNDXARAPUCADecoder::dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, std::vector & fragment_indices, size_t board_idx, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp) { - - // The decoded waveforms are dumped into two products: - // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. - // - A decoder_hist.root file gathering a waveform histograms. - if (fverbose) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: binary decoding complete, dumping products..." << std::endl; - - uint32_t num_debug_wvfms; - - if (fstore_debug_waveforms == -1) { - num_debug_wvfms = num_channels; - } else { - num_debug_wvfms = std::min(num_channels, fstore_debug_waveforms); - } - - uint32_t ch; - - for (ch = 0; ch < num_debug_wvfms; ch++) { - save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); - save_debug_wvfm(board_idx, fragment_indices[board_idx], ch, ini_wvfm_timestamp, end_wvfm_timestamp, wvfms); - } - - for (;ch < num_channels; ch++) { - save_prod_wvfm(board_idx, ch, ini_wvfm_timestamp, wvfms, prod_wvfms); - } - - wvfms.clear(); -} - -void sbndaq::SBNDXARAPUCADecoder::combine_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels) { - if (wvfms.empty()) { - std::cout << "Empty waveforms, resizing to " << num_channels << " channels." << std::endl; - wvfms.resize(num_channels); - std::cout << "BEF COMB - wvfms_size = " << wvfms.size() << " x " << wvfms[0].size() << std::endl; - } - for (uint32_t ch = 0; ch < num_channels; ch++) { - wvfms[ch].insert(wvfms[ch].end(), fragment_wvfms[ch].begin(), fragment_wvfms[ch].end()); - } - std::cout << "AFT COMB - wvfms_size = " << wvfms.size() << " x " << wvfms[0].size() << std::endl; -} - -/** - * @brief Extract a sample from a 64-bit buffer using the specified bit positions. - * - * @param[in] buffer An unsigned 64-bit integer which represents a temporal buffer for the read words and where the samples are extracted from. - * @param[in] msb An unsigned 32-bit integer representing the most significative bit (MSB) where the readout from the buffer paramter. - * @param[in] lsb An unsigned 32-bit integer representing the less significative bit (LSB) from we end read - * - * @details The function shifts the buffer to the right by the number of positions specified by `lsb` so that the least significant bit of the - * sample aligns with bit 0. It then applies a mask to isolate the bits between `lsb` and `msb`, inclusive. - * - * @return The extracted sample as a 16-bit unsigned integer. - */ -uint16_t sbndaq::SBNDXARAPUCADecoder::get_sample(uint64_t buffer, uint32_t msb, uint32_t lsb) { - uint64_t mask = (1U << (msb - lsb + 1)) - 1; - uint64_t sample = buffer >> lsb; - return sample & mask; -} - -/** - * @brief Read a 32-bit word from the data pointer and advances the pointer. - * - * @param[in, out] data_ptr A reference to a pointer pointing to the current position in the data. - * - * @details This function retrieves a 32-bit word from the memory location pointed to by `data_ptr`. After reading, it advances `data_ptr` to - * the next 32-bit word location. - * - * @return The 32-bit word read from the location pointed to by `data_ptr`. - */ -uint32_t sbndaq::SBNDXARAPUCADecoder::read_word(const uint32_t* & data_ptr) { - uint32_t word = *data_ptr; - data_ptr += 1; - return word; -} - -/** - * @brief Generates a unique global channel identifier using the board slot and the channel number of that board. - * - * @param[in] board Index of the board in `fboard_id_list` from which to derive the board slot. - * @param[in] board_channel The specific channel number on the given board. - * - * @details This function computes a `channel_id` by combining the board slot and the specific - * channel number on that board. - * The unique identifier `channel_id` (\f$ CH_{ID} $\f) is computed as follows: - * \f[ - * CH\_{ID} = B\_{ID} \times 100 + CH\_{B} - * \f] - * - * Where: - * - \f$ B\_{ID} \f$ is the fragment ID retrieved from `fboard_id_list` based on the slot. - * - \f$ CH\_B \f$ is the channel number on that board. - * - * @return A unique identifier for the specified channel as an unsigned integer. - */ -unsigned int sbndaq::SBNDXARAPUCADecoder::get_channel_id(unsigned int board, unsigned int board_channel) { - unsigned int channel_id = fboard_id_list[board] * 100 + board_channel; - return channel_id; -} +// ==================== Auxiliary functions ==================== // /** * @brief Returns the signed difference between two timestamps (t1 - t2). diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index 774032157..d1ac9b9d1 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -36,12 +36,13 @@ xarapucadecoder: # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. - debug_fragments_handle: true # (De)activates V1740B CAEN fragments art::Handle information printing. - debug_timing: true # (De)activates timing data printing. + debug_fragments_handle: false # (De)activates V1740B CAEN fragments art::Handle information printing. + debug_timing: false # (De)activates timing data printing. debug_buffer: false # (De)activates buffer status printing. debug_waveforms: false # (De)activates waveforms decoding printing. + debug_extended_fragments: false # (De)activates extended fragments information printing. # - Verbose option. - verbose: true # (De)activates verbosity. + verbose: false # (De)activates verbosity. } END_PROLOG \ No newline at end of file From 60036c5b1117102af1cbc02941a7acd790ae6484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Wed, 15 Oct 2025 06:19:56 -0500 Subject: [PATCH 046/155] Update SBN Document for reference --- sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 7c46afb10..687818fae 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -10,7 +10,7 @@ * @brief Defines and implements the SBNDXARAPUCADecoder class which inherits from an art::EDProducer * as the decoder for V1740B digitizers, intended for the X-ARAPUCAs. * @details The current version of the SBND X-ARAPUCAs decoder implements the updates shown in - * the SBN Document 38475-v1 in the SBN Document Database. + * the SBN Document 43891-v1 in the SBN Document Database. * @note A Python version of the binary decoding is available for testing purposes. You can find * it [here: V1740 binary decoder](https://github.com/aliciavr/V1740_binary_decoder). */ From 2f7ff4598d720d713fc8c6c662407576efb2117a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Wed, 5 Nov 2025 04:13:09 -0600 Subject: [PATCH 047/155] Add version number and update number of debug waveforms to 0 --- sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc | 1 + sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 687818fae..321f8db04 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -13,6 +13,7 @@ * the SBN Document 43891-v1 in the SBN Document Database. * @note A Python version of the binary decoding is available for testing purposes. You can find * it [here: V1740 binary decoder](https://github.com/aliciavr/V1740_binary_decoder). + * @version 4.0 */ #include "art/Framework/Core/EDProducer.h" diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index d1ac9b9d1..eed2269a9 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -32,7 +32,7 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: -1 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: 0 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. From 15f34cdb45ef5ffb6065bd4973962d9fc3811166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Thu, 6 Nov 2025 03:46:39 -0600 Subject: [PATCH 048/155] First version of timing check implemented (some extended fragments do not fulfill the requirements --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 56 ++++++++++++++----- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 2 +- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 321f8db04..7115b0473 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -135,7 +135,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fverbose; /**< If `true` it increases verbosity of console output for detailed processing steps. */ // Main processing method. - void decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); + void decode_fragment(int32_t& prev_TTT, uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); // Timing. void shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); @@ -320,6 +320,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { } int32_t nominal_TTT = TTT_DEFAULT; + int32_t prev_TTT = TTT_DEFAULT; uint64_t nominal_frag_timestamp = TTT_DEFAULT; bool last_one = false; @@ -360,7 +361,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { for (size_t f = 0; f < num_caen_fragments; f++) { const artdaq::Fragment fragment = *container_fragment[f].get(); last_one = f == (num_caen_fragments - 1); - decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); + decode_fragment(prev_TTT, timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); } // End CAEN V1740 fragments loop. } } // End Container fragments loop. @@ -373,7 +374,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { for (size_t f = 0; f < frag_handle_size; f++) { const artdaq::Fragment fragment = fragment_handle->at(f); last_one = f == (frag_handle_size - 1); - decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); + decode_fragment(prev_TTT, timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); } // End CAEN V1740 fragments loop. } } // End extracting CAEN V1740 fragments. @@ -425,7 +426,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { * @see dump_waveforms */ -void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { +void sbndaq::SBNDXARAPUCADecoder::decode_fragment(int32_t& prev_TTT, uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { auto fragment_id = fragment.fragmentID() - ffragment_id_offset; auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); size_t board_idx; @@ -445,12 +446,6 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& if (valid_fragment) { if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::decode_fragment: decoding V1740 CAEN fragment " << fragment_indices[board_idx] << " from the board " << board_idx << " (slot " << fboard_id_list[board_idx] << "):" << std::endl; - bool is_nominal_length = false; - bool is_first = false; - - double ini_wvfm_timestamp = 0; - double end_wvfm_timestamp = 0; - // =============== Accesses Event metadata and Event header for this fragment =============== // CAENV1740Fragment caen_fragment(fragment); @@ -508,13 +503,30 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& std::vector > fragment_wvfms(num_channels, std::vector(num_samples_per_wvfm, 0)); decode_waveforms(fragment, fragment_wvfms, header_size, num_channels, num_samples_per_wvfm, num_words_per_wvfms, num_samples_per_group); - is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); - is_first = (fragment_indices[board_idx] == 0); + double ini_wvfm_timestamp = 0; + double end_wvfm_timestamp = 0; + + bool is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); + bool is_first = (fragment_indices[board_idx] == 0); + + int32_t TTT_dif = 0; + // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. + if (nominal_TTT > TTT_end_ns) { + if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred." << std::endl; + TTT_dif = nominal_TTT - (NANOSEC_IN_SEC - TTT_end_ns); + } else { + TTT_dif = TTT_end_ns - nominal_TTT; + } + bool is_in_time = TTT_dif <= static_cast(num_nominal_samples_per_wvfm * fns_per_sample); if (fverbose) { std::cout << " > SBNDXARAPUCADecoder::decode_fragment: processing the decoded fragment and combines the extended ones to their nominal ones if needed." << std::endl; } if (is_nominal_length) { + ///// + int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); + std::cout << "\t\t NOMINAL fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; + ////// if (!is_first) { if (fdebug_extended_fragments) { std::cout << "\t\t NOT FIRST NOMINAL fragment " << std::endl; @@ -529,9 +541,23 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& combine_waveforms(wvfms, fragment_wvfms, num_channels); nominal_TTT = TTT_end_ns; nominal_frag_timestamp = frag_timestamp; - } else { - if (fdebug_extended_fragments) std::cout << "\t\t EXTENDED fragment " << std::endl; + } else if (is_in_time) { + if (fdebug_extended_fragments) { + std::cout << "\t\t EXTENDED fragment " << std::endl; + std::cout << "\t\t TTT_dif w.r.t. nominal TTT: " << TTT_dif << " ns, is_in_time: " << is_in_time << std::endl; + } + ///// + int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); + std::cout << "\t\t EXTENDED fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; + ////// combine_waveforms(wvfms, fragment_wvfms, num_channels); + } else if (!is_in_time) { + //combine_waveforms(wvfms, fragment_wvfms, num_channels); //TEMP!!!!! + ///// + int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); + std::cout << "\t\t EXTENDED? fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; + ////// + std::cout << "\t\t WARNING: EXTENDED fragment out of time window! TTT_dif: " << TTT_dif << " ns, fragment idx: " << fragment_indices[board_idx] << ", board idx: " << board_idx << " (slot " << fboard_id_list[board_idx] << "), " << num_samples_per_wvfm << " samples. Skipping this fragment..." << std::endl; } fragment_indices[board_idx]++; @@ -541,7 +567,9 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); } + prev_TTT = TTT_end_ns; } + } // =============== Timing functions =============== // diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index eed2269a9..d1ac9b9d1 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -32,7 +32,7 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: 0 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: -1 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. From 3f44697e583b0dda842ab72e767045551dbac086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Fri, 7 Nov 2025 09:43:44 -0600 Subject: [PATCH 049/155] Add jittering debug option and combine fragments option --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 127 ++++++++++-------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 7 +- 2 files changed, 76 insertions(+), 58 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 7115b0473..fce201a35 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -125,6 +125,8 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { art::ServiceHandle tfs; /**< ServiceHandle object to store the histograms in the decoder_hist.root output file. */ int fstore_debug_waveforms; /**< Number of waveforms to store in the ServiceHandle object for debugging purposes (0: none, -1: all, n: first n waveforms each event). */ + bool fcombine_ext_frag; /**< If `true` combines extended fragments into a single raw::OpDetWaveform object. */ + bool fdebug_tdc_handle; /**< If `true` SPEC-TDC information is printed. */ bool fdebug_ptb_handle; /**< If `true` PTB information is printed. */ bool fdebug_fragments_handle; /**< If `true` V1740B CAEN fragments art::Handle information is printed. */ @@ -132,10 +134,11 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fdebug_buffer; /**< If `true` the buffer status is printed. */ bool fdebug_waveforms; /**< If `true` waveforms decoding data is printed. */ bool fdebug_extended_fragments; /**< If `true` extended fragments information is printed. */ + bool fdebug_jittering; /**< If `true` trigger jittering information is printed. */ bool fverbose; /**< If `true` it increases verbosity of console output for detailed processing steps. */ // Main processing method. - void decode_fragment(int32_t& prev_TTT, uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); + void decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, int32_t& prev_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); // Timing. void shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); @@ -212,6 +215,9 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) // Gets the number of waveforms to store in the debug output file. fstore_debug_waveforms = p.get ("store_debug_waveforms", 0); + // Gets the combination of extended fragments option. + fcombine_ext_frag = p.get ("combine_ext_frag", true); + // Gets the debug and verbose options. fdebug_ptb_handle = p.get ("debug_ptb_handle", false); fdebug_tdc_handle = p.get ("debug_tdc_handle", false); @@ -219,6 +225,7 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) fdebug_timing = p.get ("debug_timing", false); fdebug_waveforms = p.get ("debug_waveforms", false); fdebug_extended_fragments = p.get ("debug_extended_fragments", false); + fdebug_jittering = p.get ("debug_jittering", false); fdebug_buffer = p.get ("debug_buffer", false); fverbose = p.get ("verbose", false); @@ -320,7 +327,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { } int32_t nominal_TTT = TTT_DEFAULT; - int32_t prev_TTT = TTT_DEFAULT; + int32_t prev_TTT = 0; uint64_t nominal_frag_timestamp = TTT_DEFAULT; bool last_one = false; @@ -361,7 +368,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { for (size_t f = 0; f < num_caen_fragments; f++) { const artdaq::Fragment fragment = *container_fragment[f].get(); last_one = f == (num_caen_fragments - 1); - decode_fragment(prev_TTT, timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); + decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, prev_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); } // End CAEN V1740 fragments loop. } } // End Container fragments loop. @@ -374,7 +381,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { for (size_t f = 0; f < frag_handle_size; f++) { const artdaq::Fragment fragment = fragment_handle->at(f); last_one = f == (frag_handle_size - 1); - decode_fragment(prev_TTT, timestamp, nominal_frag_timestamp, nominal_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); + decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, prev_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); } // End CAEN V1740 fragments loop. } } // End extracting CAEN V1740 fragments. @@ -426,7 +433,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { * @see dump_waveforms */ -void sbndaq::SBNDXARAPUCADecoder::decode_fragment(int32_t& prev_TTT, uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { +void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, int32_t& prev_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { auto fragment_id = fragment.fragmentID() - ffragment_id_offset; auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); size_t board_idx; @@ -506,68 +513,76 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(int32_t& prev_TTT, uint64_t ti double ini_wvfm_timestamp = 0; double end_wvfm_timestamp = 0; - bool is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); - bool is_first = (fragment_indices[board_idx] == 0); - - int32_t TTT_dif = 0; - // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. - if (nominal_TTT > TTT_end_ns) { - if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred." << std::endl; - TTT_dif = nominal_TTT - (NANOSEC_IN_SEC - TTT_end_ns); - } else { - TTT_dif = TTT_end_ns - nominal_TTT; - } - bool is_in_time = TTT_dif <= static_cast(num_nominal_samples_per_wvfm * fns_per_sample); - if (fverbose) { std::cout << " > SBNDXARAPUCADecoder::decode_fragment: processing the decoded fragment and combines the extended ones to their nominal ones if needed." << std::endl; } - if (is_nominal_length) { - ///// + + if (fcombine_ext_frag) { + bool is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); + bool is_first = (fragment_indices[board_idx] == 0); + + int32_t TTT_dif = 0; + // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. + if (nominal_TTT > TTT_end_ns) { + if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred." << std::endl; + TTT_dif = nominal_TTT - (NANOSEC_IN_SEC - TTT_end_ns); + } else { + TTT_dif = TTT_end_ns - nominal_TTT; + } + bool is_in_time = TTT_dif <= static_cast(num_nominal_samples_per_wvfm * fns_per_sample); + int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); - std::cout << "\t\t NOMINAL fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; - ////// - if (!is_first) { + + if (is_nominal_length) { + if (fdebug_jittering) { + std::cout << "\t\t NOMINAL fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; + } + if (!is_first) { + if (fdebug_extended_fragments) { + std::cout << "\t\t NOT FIRST NOMINAL fragment " << std::endl; + std::cout << "\t\t nominal_TTT: " << nominal_TTT << " TTT_end_ns: " << TTT_end_ns << std::endl; + std::cout << "\t\t nominal_frag_timestamp: " << nominal_frag_timestamp << " frag_timestamp : " << frag_timestamp << std::endl; + } + shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + } else { + if (fdebug_extended_fragments) std::cout << "\t\t FIRST NOMINAL fragment " << std::endl; + } + combine_waveforms(wvfms, fragment_wvfms, num_channels); + nominal_TTT = TTT_end_ns; + nominal_frag_timestamp = frag_timestamp; + } else if (is_in_time) { if (fdebug_extended_fragments) { - std::cout << "\t\t NOT FIRST NOMINAL fragment " << std::endl; - std::cout << "\t\t nominal_TTT: " << nominal_TTT << " TTT_end_ns: " << TTT_end_ns << std::endl; - std::cout << "\t\t nominal_frag_timestamp: " << nominal_frag_timestamp << " frag_timestamp : " << frag_timestamp << std::endl; + std::cout << "\t\t EXTENDED fragment " << std::endl; + std::cout << "\t\t TTT_dif w.r.t. nominal TTT: " << TTT_dif << " ns, is_in_time: " << is_in_time << std::endl; } + if (fdebug_jittering) { + std::cout << "\t\t EXTENDED fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; + } + + combine_waveforms(wvfms, fragment_wvfms, num_channels); + } else if (!is_in_time) { + //combine_waveforms(wvfms, fragment_wvfms, num_channels); //TEMP!!!!! + if (fdebug_jittering) { + std::cout << "\t\t EXTENDED? fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; + } + std::cout << "\t\t WARNING: EXTENDED fragment out of time window! TTT_dif: " << TTT_dif << " ns, fragment idx: " << fragment_indices[board_idx] << ", board idx: " << board_idx << " (slot " << fboard_id_list[board_idx] << "), " << num_samples_per_wvfm << " samples. Skipping this fragment..." << std::endl; + } + + fragment_indices[board_idx]++; + + if (last_one) { + if (fdebug_extended_fragments) std::cout << "\t\t LAST fragment " << std::endl; shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); - } else { - if (fdebug_extended_fragments) std::cout << "\t\t FIRST NOMINAL fragment " << std::endl; } - combine_waveforms(wvfms, fragment_wvfms, num_channels); - nominal_TTT = TTT_end_ns; - nominal_frag_timestamp = frag_timestamp; - } else if (is_in_time) { - if (fdebug_extended_fragments) { - std::cout << "\t\t EXTENDED fragment " << std::endl; - std::cout << "\t\t TTT_dif w.r.t. nominal TTT: " << TTT_dif << " ns, is_in_time: " << is_in_time << std::endl; - } - ///// - int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); - std::cout << "\t\t EXTENDED fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; - ////// - combine_waveforms(wvfms, fragment_wvfms, num_channels); - } else if (!is_in_time) { - //combine_waveforms(wvfms, fragment_wvfms, num_channels); //TEMP!!!!! - ///// - int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); - std::cout << "\t\t EXTENDED? fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; - ////// - std::cout << "\t\t WARNING: EXTENDED fragment out of time window! TTT_dif: " << TTT_dif << " ns, fragment idx: " << fragment_indices[board_idx] << ", board idx: " << board_idx << " (slot " << fboard_id_list[board_idx] << "), " << num_samples_per_wvfm << " samples. Skipping this fragment..." << std::endl; + prev_TTT = TTT_end_ns; + } else { + shift_time(TTT_ticks, TTT_end_ns, frag_timestamp, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + dump_waveforms(prod_wvfms, fragment_wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + fragment_indices[board_idx]++; } - - fragment_indices[board_idx]++; - if (last_one) { - if (fdebug_extended_fragments) std::cout << "\t\t LAST fragment " << std::endl; - shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); - } - prev_TTT = TTT_end_ns; } } diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index d1ac9b9d1..578dba4c8 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -23,7 +23,7 @@ xarapucadecoder: # - SPEC-TDC access configuration spectdc_product_name: "tdcdecoder" # Name for getting SPEC-TDC Decoder products (if any). spectdc_ftrig_ch: 3 # Channel assigned to flash triggers. - spectdc_etrig_ch: 4 # Channel assigned to ETT (Event Trigger Timestamp) triggers. + spectdc_etrig_ch: 2 # Channel assigned to ETT (Event Trigger Timestamp) triggers. # - PTB access configuration ptb_product_name: "ptbdecoder" # Name for getting PTB Decoder products (if any). allowed_hl_triggers: [1, 2, 3, 4, 5, 14, 15] # List of allowed HLT trigger types (1-5, 14, 15). @@ -32,7 +32,9 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: -1 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: 0 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + # Combination of extended fragments. + combine_ext_frag: false # (De)activates the combination of extended fragments into a single raw::OpDetWaveform object. # - Debug options. debug_tdc_handle: false # (De)activates SPEC-TDC art::Handle information printing. debug_ptb_handle: false # (De)activates PTB art::Handle information printing. @@ -41,6 +43,7 @@ xarapucadecoder: debug_buffer: false # (De)activates buffer status printing. debug_waveforms: false # (De)activates waveforms decoding printing. debug_extended_fragments: false # (De)activates extended fragments information printing. + debug_jittering: false # (De)activates trigger jittering information printing. # - Verbose option. verbose: false # (De)activates verbosity. } From b27bf1ab4670f8cac3787432d49343ce37ee5667 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 13 Nov 2025 12:58:22 -0600 Subject: [PATCH 050/155] 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 051/155] 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 052/155] 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 053/155] 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 054/155] 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 055/155] 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 056/155] 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 057/155] 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 058/155] 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 059/155] 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 060/155] 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 061/155] 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 062/155] 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 063/155] 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 } From 43f761406b187f860d3943471de18d5caaf3ab56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Mon, 24 Nov 2025 11:42:56 -0600 Subject: [PATCH 064/155] Update combination condition with timing features integrating the expected jittering of the extended fragments. --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 137 +++++++++--------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 11 +- 2 files changed, 78 insertions(+), 70 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index fce201a35..4922c7da7 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -126,6 +126,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { int fstore_debug_waveforms; /**< Number of waveforms to store in the ServiceHandle object for debugging purposes (0: none, -1: all, n: first n waveforms each event). */ bool fcombine_ext_frag; /**< If `true` combines extended fragments into a single raw::OpDetWaveform object. */ + int32_t fallowed_jittering; /**< Allowed jittering (in ns) between fragments to be combined. */ bool fdebug_tdc_handle; /**< If `true` SPEC-TDC information is printed. */ bool fdebug_ptb_handle; /**< If `true` PTB information is printed. */ @@ -138,7 +139,7 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { bool fverbose; /**< If `true` it increases verbosity of console output for detailed processing steps. */ // Main processing method. - void decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, int32_t& prev_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); + void decode_fragment(uint64_t timestamp, uint64_t& first_frag_timestamp, size_t& first_frag_idx, int32_t& first_TTT, int32_t& prev_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one); // Timing. void shift_time(uint64_t TTT_ticks, int64_t TTT_end_ns, uint64_t frag_timestamp, uint64_t timestamp, uint32_t num_samples_per_wvfm, double& ini_wvfm_timestamp, double& end_wvfm_timestamp); @@ -152,10 +153,10 @@ class sbndaq::SBNDXARAPUCADecoder : public art::EDProducer { unsigned int get_channel_id(unsigned int board, unsigned int board_channel); // Combines decoded waveforms. - void combine_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels); + void append_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels); // Dumps and saves waveforms. - void dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, std::vector & fragment_indices, size_t board_index, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp); + void dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, size_t first_frag_idx, size_t board_index, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp); void save_prod_wvfm(size_t board_idx, size_t ch, double ini_wvfm_timestamp, const std::vector > & wvfms, std::vector & prod_wvfms); void save_debug_wvfm(size_t board_idx, size_t fragment_idx, int ch, double ini_wvfm_timestamp, double end_wvfm_timestamp, const std::vector > & wvfms); @@ -217,6 +218,7 @@ sbndaq::SBNDXARAPUCADecoder::SBNDXARAPUCADecoder(fhicl::ParameterSet const& p) // Gets the combination of extended fragments option. fcombine_ext_frag = p.get ("combine_ext_frag", true); + fallowed_jittering = p.get ("allowed_jittering", 64); // Gets the debug and verbose options. fdebug_ptb_handle = p.get ("debug_ptb_handle", false); @@ -320,15 +322,16 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { // Flag to track if valid CAEN fragments are found. bool found_caen = false; - std::vector fragment_indices(fnum_caen_boards, 0); + std::vector fragment_indices(fnum_caen_boards, -1); std::vector> wvfms; if (fdebug_extended_fragments) { std::cout << " Waveforms size: " << wvfms.size() << std::endl; } - int32_t nominal_TTT = TTT_DEFAULT; + size_t first_frag_idx = 0; + int32_t first_TTT = TTT_DEFAULT; int32_t prev_TTT = 0; - uint64_t nominal_frag_timestamp = TTT_DEFAULT; + uint64_t first_frag_timestamp = TTT_DEFAULT; bool last_one = false; if (fverbose | fdebug_fragments_handle) std::cout << "\n > SBNDXARAPUCADecoder::produce: searching for V1740 fragments..." << std::endl; @@ -368,7 +371,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { for (size_t f = 0; f < num_caen_fragments; f++) { const artdaq::Fragment fragment = *container_fragment[f].get(); last_one = f == (num_caen_fragments - 1); - decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, prev_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); + decode_fragment(timestamp, first_frag_timestamp, first_frag_idx, first_TTT, prev_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); } // End CAEN V1740 fragments loop. } } // End Container fragments loop. @@ -381,7 +384,7 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { for (size_t f = 0; f < frag_handle_size; f++) { const artdaq::Fragment fragment = fragment_handle->at(f); last_one = f == (frag_handle_size - 1); - decode_fragment(timestamp, nominal_frag_timestamp, nominal_TTT, prev_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); + decode_fragment(timestamp, first_frag_timestamp, first_frag_idx, first_TTT, prev_TTT, fragment_indices, fragment, *prod_wvfms, wvfms, last_one); } // End CAEN V1740 fragments loop. } } // End extracting CAEN V1740 fragments. @@ -407,8 +410,9 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { /** * @brief Decodes a CAEN V1740 fragment, extracts the waveforms and combines them into the output product. * @param[in] timestamp The valid timestamp used as reference for the event. - * @param[in,out] nominal_frag_timestamp The nominal timestamp calculated for the fragment being processed. - * @param[in,out] nominal_TTT The nominal Trigger Time Tag (TTT) calculated for the fragment being processed. + * @param[in,out] first_frag_timestamp The nominal timestamp calculated for the fragment being processed. + * @param[in, out] first_frag_idx The first index of the fragments being combined. + * @param[in,out] first_TTT The nominal Trigger Time Tag (TTT) calculated for the fragment being processed. * @param[in,out] fragment_indices A vector containing the indices of the fragments already processed for each board. * @param[in] fragment The artdaq::Fragment object to be processed. * @param[in,out] prod_wvfms The vector of raw::OpDetWaveform objects to be filled with the decoded waveforms. @@ -429,11 +433,11 @@ void sbndaq::SBNDXARAPUCADecoder::produce(art::Event& e) { * @post The vector of raw::OpDetWaveform objects is filled with the decoded waveforms from the fragment. * @see shift_time * @see decode_waveforms - * @see combine_waveforms + * @see append_waveforms * @see dump_waveforms */ -void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& nominal_frag_timestamp, int32_t& nominal_TTT, int32_t& prev_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { +void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& first_frag_timestamp, size_t& first_frag_idx, int32_t& first_TTT, int32_t& prev_TTT, std::vector & fragment_indices, const artdaq::Fragment& fragment, std::vector & prod_wvfms, std::vector>& wvfms, bool last_one) { auto fragment_id = fragment.fragmentID() - ffragment_id_offset; auto it = std::find(fboard_id_list.begin(), fboard_id_list.end(), fragment_id); size_t board_idx; @@ -451,6 +455,7 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& } if (valid_fragment) { + fragment_indices[board_idx]++; if (fverbose) std::cout << "\n > SBNDXARAPUCADecoder::decode_fragment: decoding V1740 CAEN fragment " << fragment_indices[board_idx] << " from the board " << board_idx << " (slot " << fboard_id_list[board_idx] << "):" << std::endl; // =============== Accesses Event metadata and Event header for this fragment =============== // @@ -518,71 +523,72 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& } if (fcombine_ext_frag) { - bool is_nominal_length = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); + + // Combination variables and checks. + + bool is_nominal = (num_nominal_samples_per_wvfm == num_samples_per_wvfm); bool is_first = (fragment_indices[board_idx] == 0); + int32_t frag_length = num_samples_per_wvfm * fns_per_sample; // ns. + + // - Computation of the difference w.r.t. previous TTT difference. int32_t TTT_dif = 0; - // If the fragment timestamp is greater than the TTT end timestamp, it means that rollover occurred. - if (nominal_TTT > TTT_end_ns) { + if (prev_TTT > TTT_end_ns) { if (fverbose | fdebug_timing) std::cout << " > SBNDXARAPUCADecoder::decode_fragment: CAEN TTT rollover occurred." << std::endl; - TTT_dif = nominal_TTT - (NANOSEC_IN_SEC - TTT_end_ns); + TTT_dif = prev_TTT - (NANOSEC_IN_SEC - TTT_end_ns); } else { - TTT_dif = TTT_end_ns - nominal_TTT; + TTT_dif = TTT_end_ns - prev_TTT; } - bool is_in_time = TTT_dif <= static_cast(num_nominal_samples_per_wvfm * fns_per_sample); - - int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); - - if (is_nominal_length) { - if (fdebug_jittering) { - std::cout << "\t\t NOMINAL fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; - } - if (!is_first) { - if (fdebug_extended_fragments) { - std::cout << "\t\t NOT FIRST NOMINAL fragment " << std::endl; - std::cout << "\t\t nominal_TTT: " << nominal_TTT << " TTT_end_ns: " << TTT_end_ns << std::endl; - std::cout << "\t\t nominal_frag_timestamp: " << nominal_frag_timestamp << " frag_timestamp : " << frag_timestamp << std::endl; + + // - Computation of the difference between TTTs difference and the length of the fragment in ns (to detect jittering between fragments). + //int32_t J = TTT_dif - frag_length; + + // - Combination boolean variable. + //bool dump_comb_wvfms = true; + /* if (is_nominal) { // Nominal fragment + if (!is_first && (TTT_dif <= (frag_length - fallowed_jittering))) { + std::cout << "\t\t WARNING: NOMINAL fragment too close to previous one! TTT_dif: " << TTT_dif << " ns, fragment idx: " << fragment_indices[board_idx] << ", board idx: " << board_idx << " (slot " << fboard_id_list[board_idx] << "), " << num_samples_per_wvfm << " samples. Skipping this fragment..." << std::endl; } - shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); - } else { - if (fdebug_extended_fragments) std::cout << "\t\t FIRST NOMINAL fragment " << std::endl; - } - combine_waveforms(wvfms, fragment_wvfms, num_channels); - nominal_TTT = TTT_end_ns; - nominal_frag_timestamp = frag_timestamp; - } else if (is_in_time) { - if (fdebug_extended_fragments) { - std::cout << "\t\t EXTENDED fragment " << std::endl; - std::cout << "\t\t TTT_dif w.r.t. nominal TTT: " << TTT_dif << " ns, is_in_time: " << is_in_time << std::endl; - } - if (fdebug_jittering) { - std::cout << "\t\t EXTENDED fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; - } + } else { // Extended fragment + if (std::abs(J) <= fallowed_jittering) { + dump_comb_wvfms = false; + } else if (TTT_dif <= (frag_length - fallowed_jittering)) { + dump_comb_wvfms = false; + std::cout << "\t\t WARNING: EXTENDED fragment too close to previous one! TTT_dif: " << TTT_dif << " ns, fragment idx: " << fragment_indices[board_idx] << ", board idx: " << board_idx << " (slot " << fboard_id_list[board_idx] << "), " << num_samples_per_wvfm << " samples. Skipping this fragment..." << std::endl; + } + }*/ - combine_waveforms(wvfms, fragment_wvfms, num_channels); - } else if (!is_in_time) { - //combine_waveforms(wvfms, fragment_wvfms, num_channels); //TEMP!!!!! - if (fdebug_jittering) { - std::cout << "\t\t EXTENDED? fragment (" << num_samples_per_wvfm << "), [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_end_ns - prev_TTT << " ns, length: " << num_samples_per_wvfm * fns_per_sample << " ns, diff_with_length: " << (TTT_end_ns - prev_TTT) - (num_samples_per_wvfm * fns_per_sample) << std::endl; - } - std::cout << "\t\t WARNING: EXTENDED fragment out of time window! TTT_dif: " << TTT_dif << " ns, fragment idx: " << fragment_indices[board_idx] << ", board idx: " << board_idx << " (slot " << fboard_id_list[board_idx] << "), " << num_samples_per_wvfm << " samples. Skipping this fragment..." << std::endl; + + bool dump_comb_wvfms = !is_first && (is_nominal || (!is_nominal && (TTT_dif > (frag_length + fallowed_jittering)))); + + if (is_first) { + first_frag_idx = fragment_indices[board_idx]; + first_TTT = TTT_end_ns; + first_frag_timestamp = frag_timestamp; } - - fragment_indices[board_idx]++; + if (dump_comb_wvfms) { + shift_time(TTT_ticks, first_TTT, first_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + dump_waveforms(prod_wvfms, wvfms, first_frag_idx, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + first_frag_idx = fragment_indices[board_idx]; + first_TTT = TTT_end_ns; + first_frag_timestamp = frag_timestamp; + } + append_waveforms(wvfms, fragment_wvfms, num_channels); + if (last_one) { if (fdebug_extended_fragments) std::cout << "\t\t LAST fragment " << std::endl; - shift_time(TTT_ticks, nominal_TTT, nominal_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - dump_waveforms(prod_wvfms, wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); + fragment_indices[board_idx]++; + shift_time(TTT_ticks, first_TTT, first_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); + dump_waveforms(prod_wvfms, wvfms, first_frag_idx, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); } + prev_TTT = TTT_end_ns; - } else { + + } else { // Combination of extended fragments disabled. shift_time(TTT_ticks, TTT_end_ns, frag_timestamp, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); - dump_waveforms(prod_wvfms, fragment_wvfms, fragment_indices, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); - fragment_indices[board_idx]++; + dump_waveforms(prod_wvfms, fragment_wvfms, first_frag_idx, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); } - } } @@ -1008,8 +1014,8 @@ unsigned int sbndaq::SBNDXARAPUCADecoder::get_channel_id(unsigned int board, uns * @pre The `fragment_wvfms` vector should contain waveforms for all channels of the board being processed. * @pre The `wvfms` vector should be either empty or already contain waveforms for all channels of the board being processed. */ -void sbndaq::SBNDXARAPUCADecoder::combine_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels) { - if (fdebug_extended_fragments) std::cout << " > SBNDXARAPUCADecoder::combine_waveforms: combining waveforms from extended fragments..." << std::endl; +void sbndaq::SBNDXARAPUCADecoder::append_waveforms(std::vector>& wvfms, const std::vector>& fragment_wvfms, uint32_t num_channels) { + if (fdebug_extended_fragments) std::cout << " > SBNDXARAPUCADecoder::append_waveforms: combining waveforms from extended fragments..." << std::endl; if (wvfms.empty()) { if (fdebug_extended_fragments) { std::cout << "\t\t Empty waveforms, resizing to " << num_channels << " channels." << std::endl; @@ -1059,7 +1065,7 @@ void sbndaq::SBNDXARAPUCADecoder::combine_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, std::vector & fragment_indices, size_t board_idx, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp) { +void sbndaq::SBNDXARAPUCADecoder::dump_waveforms(std::vector & prod_wvfms, std::vector>& wvfms, size_t first_frag_idx, size_t board_idx, uint32_t num_channels, double ini_wvfm_timestamp, double end_wvfm_timestamp) { // The decoded waveforms are dumped into two products: // - A xarapucadecoder-art.root file with the OpDetWaveforms as the product of this producer for further analysis. @@ -1078,7 +1084,7 @@ void sbndaq::SBNDXARAPUCADecoder::dump_waveforms(std::vector Date: Tue, 25 Nov 2025 05:02:28 -0600 Subject: [PATCH 065/155] Add warning for some unexpected types of fragments and fix fragments indexing. Improve jittering application. --- .../XARAPUCA/SBNDXARAPUCADecoder_module.cc | 44 +++++++++++-------- .../Decoders/XARAPUCA/xarapucadecoder.fcl | 6 +-- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc index 4922c7da7..76d26660a 100644 --- a/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc +++ b/sbndcode/Decoders/XARAPUCA/SBNDXARAPUCADecoder_module.cc @@ -541,23 +541,7 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& } // - Computation of the difference between TTTs difference and the length of the fragment in ns (to detect jittering between fragments). - //int32_t J = TTT_dif - frag_length; - - // - Combination boolean variable. - //bool dump_comb_wvfms = true; - /* if (is_nominal) { // Nominal fragment - if (!is_first && (TTT_dif <= (frag_length - fallowed_jittering))) { - std::cout << "\t\t WARNING: NOMINAL fragment too close to previous one! TTT_dif: " << TTT_dif << " ns, fragment idx: " << fragment_indices[board_idx] << ", board idx: " << board_idx << " (slot " << fboard_id_list[board_idx] << "), " << num_samples_per_wvfm << " samples. Skipping this fragment..." << std::endl; - } - } else { // Extended fragment - if (std::abs(J) <= fallowed_jittering) { - dump_comb_wvfms = false; - } else if (TTT_dif <= (frag_length - fallowed_jittering)) { - dump_comb_wvfms = false; - std::cout << "\t\t WARNING: EXTENDED fragment too close to previous one! TTT_dif: " << TTT_dif << " ns, fragment idx: " << fragment_indices[board_idx] << ", board idx: " << board_idx << " (slot " << fboard_id_list[board_idx] << "), " << num_samples_per_wvfm << " samples. Skipping this fragment..." << std::endl; - } - }*/ - + int32_t J = TTT_dif - frag_length; bool dump_comb_wvfms = !is_first && (is_nominal || (!is_nominal && (TTT_dif > (frag_length + fallowed_jittering)))); @@ -573,19 +557,43 @@ void sbndaq::SBNDXARAPUCADecoder::decode_fragment(uint64_t timestamp, uint64_t& first_frag_idx = fragment_indices[board_idx]; first_TTT = TTT_end_ns; first_frag_timestamp = frag_timestamp; + if (fdebug_jittering) std::cout << "NC - "; + } else { + if (fdebug_jittering) std::cout << "C - "; } append_waveforms(wvfms, fragment_wvfms, num_channels); if (last_one) { if (fdebug_extended_fragments) std::cout << "\t\t LAST fragment " << std::endl; - fragment_indices[board_idx]++; shift_time(TTT_ticks, first_TTT, first_frag_timestamp, timestamp, num_nominal_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); dump_waveforms(prod_wvfms, wvfms, first_frag_idx, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); } + if (fdebug_jittering) { + if (is_first) { + std::cout << "\t\t FIRST "; + } + if (is_nominal) { + int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); + std::cout << "NOMINAL fragment " << fboard_id_list[board_idx] << " - " << fragment_indices[board_idx] << " (" << num_samples_per_wvfm << "): [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_dif << " ns, length: " << frag_length << " ns, diff_with_length (jitt): " << J << std::endl; + } else { + int32_t TTT_ini_ns = TTT_end_ns - static_cast(num_nominal_samples_per_wvfm * fns_per_sample); + std::cout << "EXTENDED fragment " << fboard_id_list[board_idx] << " - " << fragment_indices[board_idx] << " (" << num_samples_per_wvfm << "): [" << TTT_ini_ns << ", " << TTT_end_ns << "] diff with prev: " << TTT_dif << " ns, length: " << frag_length << " ns, diff_with_length (jitt): " << J << std::endl; + } + } + + // WARNINGS + if (TTT_dif < frag_length - fallowed_jittering) { + if (!is_first) { + if (!is_nominal) std::cout << "\t\t WARNING: EXTENDED fragment too close! This fragment is being combined." << std::endl; + if (is_nominal) std::cout << "\t\t WARNING: NOMINAL fragment too close! This fragment is not being combined." << std::endl; + } + } + prev_TTT = TTT_end_ns; } else { // Combination of extended fragments disabled. + first_frag_idx = fragment_indices[board_idx]; shift_time(TTT_ticks, TTT_end_ns, frag_timestamp, timestamp, num_samples_per_wvfm, ini_wvfm_timestamp, end_wvfm_timestamp); dump_waveforms(prod_wvfms, fragment_wvfms, first_frag_idx, board_idx, num_channels, ini_wvfm_timestamp, end_wvfm_timestamp); } diff --git a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl index d880a853e..adeb66bd8 100644 --- a/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl +++ b/sbndcode/Decoders/XARAPUCA/xarapucadecoder.fcl @@ -32,7 +32,7 @@ xarapucadecoder: # - Output data product instance name. waveforms_instance_name: "XARAPUCAChannels" # Name for the instance product containing the raw decoded waveforms. timing_ref_instance_name: "" # Name for the instance product containing the timing reference information. - store_debug_waveforms: -1 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). + store_debug_waveforms: 0 # Number of waveforms to store (0: none, -1: all, n: first n waveforms). # Combination of extended fragments. combine_ext_frag: true # (De)activates the combination of extended fragments into a single raw::OpDetWaveform object. allowed_jittering: 64 # Allowed jittering (in ns) between fragments to be combined. @@ -44,9 +44,9 @@ xarapucadecoder: debug_buffer: false # (De)activates buffer status printing. debug_waveforms: false # (De)activates waveforms decoding printing. debug_extended_fragments: false # (De)activates extended fragments information printing. - debug_jittering: true # (De)activates trigger jittering information printing. + debug_jittering: false # (De)activates trigger jittering information printing. # - Verbose option. - verbose: true # (De)activates verbosity. + verbose: false # (De)activates verbosity. } END_PROLOG \ No newline at end of file From 8ee9ff55fffa5c50df8263e07c85078f5b641199 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Wed, 14 Jan 2026 10:40:05 -0600 Subject: [PATCH 066/155] cleanup --- .../Calorimetry/LightCaloProducer_module.cc | 9 ++------ sbndcode/Calorimetry/run_lightcalo.fcl | 21 +++++-------------- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index b416e7489..f917481bd 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -369,7 +369,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 tree variables _pfpid = -1; @@ -446,7 +445,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/fcal_area_const.at(bestPlane))*atten_correction*hit->Integral(); + double charge = (1/fcal_area_const.at(hit->View()))*atten_correction*hit->Integral(); sp_xyz.push_back(xyz); sp_charge.push_back(charge); } @@ -524,7 +523,6 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, util::CreateAssn(*this, e, *lightcalo_v, opflash0, *flash_assn_v); util::CreateAssn(*this, e, *lightcalo_v, opflash1, *flash_assn_v); - nsuccessful_matches++; _tree->Fill(); } // end slice loop } // end produce @@ -607,10 +605,8 @@ void sbnd::LightCaloProducer::CollectMatches(const art::Handle> sbnd::LightCaloProducer::CalcVisibility(std::vector xyz_v, - std::vector charge_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; @@ -628,7 +624,6 @@ std::vector> sbnd::LightCaloProducer::CalcVisibility(std::ve std::vector reflect_visibility; 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 for (size_t ch=0; ch Date: Wed, 14 Jan 2026 10:45:14 -0600 Subject: [PATCH 067/155] add to workflow and add sce labels by default --- sbndcode/Calorimetry/lightcalo.fcl | 11 ++++++----- .../standard/reco/config/workflow_reco2.fcl | 5 +++++ .../JobConfigurations/standard/reco/reco2_data.fcl | 4 +++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo.fcl index e92e0eebb..ceee6810f 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -2,7 +2,7 @@ #include "sbndopticalpath_tool.fcl" BEGIN_PROLOG -lightcalo: +sbnd_lightcalo: { module_type: "LightCaloProducer" @@ -12,11 +12,12 @@ lightcalo: OpFlashProducers: ["opflashtpc0", "opflashtpc1"] OpFlashAraProducers: ["opflashtpc0xarapuca", "opflashtpc1xarapuca"] - PDTypes: ["pmt_coated"] # "pmt_uncoated", "xarapuca_vuv", "xarapuca_vis" + # only validated for coated PMTs for now + PDTypes: ["pmt_coated"] # "pmt_uncoated", "xarapuca_vuv", "xarapuca_vis" - SliceProducer: "pandora" - OpT0FinderProducer: "opt0finder" - BCFMProducer: "tpcpmtbarycentermatching" + SliceProducer: "pandoraSCE" + OpT0FinderProducer: "opt0finderSCE" + BCFMProducer: "tpcpmtbarycentermatchingSCE" UseBCFM: true UseOpT0Finder: false diff --git a/sbndcode/JobConfigurations/standard/reco/config/workflow_reco2.fcl b/sbndcode/JobConfigurations/standard/reco/config/workflow_reco2.fcl index 275c22d5e..3e7a225ff 100644 --- a/sbndcode/JobConfigurations/standard/reco/config/workflow_reco2.fcl +++ b/sbndcode/JobConfigurations/standard/reco/config/workflow_reco2.fcl @@ -20,6 +20,7 @@ #include "SBNDCVNMapper.fcl" #include "blipreco_configs.fcl" +#include "lightcalo.fcl" BEGIN_PROLOG @@ -90,6 +91,9 @@ sbnd_reco2_producers:{ module_type: "BlipRecoProducer" BlipAlg: @local::sbnd_blipalg } + + ### light calorimtery + lightcaloSCE : @local::sbnd_lightcalo } sbnd_reco2_producer_sequence: [ @@ -129,6 +133,7 @@ sbnd_reco2_producer_sequence: [ , cvn , cvnSCE , blipreco + , lightcalo ] #FIXME override the producer labels. This should really happen in the module's config fcl diff --git a/sbndcode/JobConfigurations/standard/reco/reco2_data.fcl b/sbndcode/JobConfigurations/standard/reco/reco2_data.fcl index f55de336f..ec02b3aef 100644 --- a/sbndcode/JobConfigurations/standard/reco/reco2_data.fcl +++ b/sbndcode/JobConfigurations/standard/reco/reco2_data.fcl @@ -5,6 +5,7 @@ #include "sbnd_lightpropagationcorrection_config.fcl" #include "frameshift_sbnd_data.fcl" #include "standard_reco2_sbnd.fcl" +#include "lightcalo.fcl" services: { @@ -38,6 +39,7 @@ physics.producers: pandoraSCEShower: @local::sbnd_sce_incremental_pandoraModularShowerCreationData pandoraSCEShowerSBN: @local::sbnd_sce_sbn_pandoraModularShowerCreationData + lightcaloSCE: @local::sbnd_lightcalo frameshift: @local::frameshift_data } @@ -45,7 +47,7 @@ physics.reco2: [ pandora, pandoraTrack, pandoraShower, pandoraShowerSBN, pandora cvn, opt0finder, crtveto, crtspacepointmatching, crttrackmatching, tpcpmtbarycentermatching, pandoraSCE, pandoraSCETrack, pandoraSCEShower, pandoraSCEShowerSBN, pandoraSCECaloData, pandoraSCEPidData, pandoraSCELikePidData, cvnSCE, opt0finderSCE, tpcpmtbarycentermatchingSCE, crtspacepointmatchingSCE, crttrackmatchingSCE, - caloskimCalorimetry, blipreco, lightpropagationcorrectionSCE, frameshift] + caloskimCalorimetry, blipreco, lightpropagationcorrectionSCE, lightcaloSCE, frameshift] physics.analyzers.caloskim.G4producer: "" From e8a12f8bc8d8fca2972e5215267f81cf6de1af9d Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Wed, 14 Jan 2026 14:02:12 -0600 Subject: [PATCH 068/155] remove unused variable, match lightcalo constructor to updated obj --- sbndcode/Calorimetry/LightCaloProducer_module.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index f917481bd..6a5006dbd 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -421,8 +421,7 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, 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(); + int bestHits = std::max_element(plane_hits.begin(), plane_hits.end()) - plane_hits.begin(); _slice_Q = plane_charge.at(bestHits); @@ -517,7 +516,7 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, std::cout << "energy: " << _slice_E << std::endl; } - sbn::LightCalo lightcalo(_slice_Q,_slice_L,_slice_E,bestHits); + 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); From 923e0fe489335350fc577f0542c6f3a6c93e8cbb Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 15 Jan 2026 14:02:27 -0600 Subject: [PATCH 069/155] update to latest TPC calibration constants, opdet efficiencies, and mask; add upper limit to avoid nonlinearity effects (rough idea) --- sbndcode/Calorimetry/LightCaloProducer_module.cc | 15 ++++++++------- sbndcode/Calorimetry/lightcalo.fcl | 9 +++++---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 6a5006dbd..799b6b610 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -142,6 +142,7 @@ class sbnd::LightCaloProducer : public art::EDProducer { float fpmt_ara_offset; std::vector fnoise_thresh; + std::vector fupper_thresh; std::vector fcal_area_const; std::vector fopdet_vuv_eff; @@ -203,6 +204,7 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) fpmt_ara_offset = p.get("PMTARAFlashOffset"); fnoise_thresh = p.get>("FlashNoiseThreshold"); + fupper_thresh = p.get>("OpDetMaxPEThreshold"); fcal_area_const = p.get>("CalAreaConstants"); fopdet_vuv_eff = p.get>("OpDetVUVEfficiencies"); @@ -482,21 +484,20 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, } // end of arapuca if for (size_t ich=0; ich fupper_thresh[0]) continue; // skip if above max PE threshold total_pe[ich] += flash_pe_v[ich]; } } } // end of TPC loop - // mask out specific channels in opdet mask - for (size_t imask=0; imask Date: Thu, 15 Jan 2026 15:18:54 -0600 Subject: [PATCH 070/155] mask should contain both off pmts and not reconstructable pmts --- 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 d1e991514..0bc816d68 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo.fcl @@ -40,6 +40,6 @@ sbnd_lightcalo: CalAreaConstants: [ 0.02052, 0.02044, 0.02019 ] # calibration constants for wire planes, found in sbndcode/LArSoftConfigurations/calorimetry_sbnd.fcl OpDetVUVEfficiencies: [0.0,0.0,0.0,0.0,0.0,0.0,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752] OpDetVISEfficiencies: [0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271] - OpDetMask: [39, 64, 71, 85, 86, 87, 115, 138, 141, 217, 221, 222, 223, 245, 302] + OpDetMask: [ 39, 64, 66, 71, 85, 86, 87, 115, 138, 141, 197, 217, 221, 222, 223, 226, 245, 249, 302] } END_PROLOG From 03e277ff7d82e4a9c2ee27c30cc9a86bdbab7af5 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 15 Jan 2026 15:19:10 -0600 Subject: [PATCH 071/155] add sce lightcalo label to cafmakerjob --- sbndcode/JobConfigurations/standard/caf/cafmakerjob_sbnd_sce.fcl | 1 + 1 file changed, 1 insertion(+) diff --git a/sbndcode/JobConfigurations/standard/caf/cafmakerjob_sbnd_sce.fcl b/sbndcode/JobConfigurations/standard/caf/cafmakerjob_sbnd_sce.fcl index fb4a26030..d9833c723 100644 --- a/sbndcode/JobConfigurations/standard/caf/cafmakerjob_sbnd_sce.fcl +++ b/sbndcode/JobConfigurations/standard/caf/cafmakerjob_sbnd_sce.fcl @@ -16,6 +16,7 @@ physics.producers.cafmaker.CRTTrackMatchLabel: "pandoraSCETrackCRTTrack" physics.producers.cafmaker.OpT0Label: "opt0finderSCE" physics.producers.cafmaker.TPCPMTBarycenterMatchLabel: "tpcpmtbarycentermatchingSCE" physics.producers.cafmaker.CVNLabel: "cvnSCE" +physics.producers.cafmaker.LightCaloLabel: "lightcaloSCE" physics.producers.cnnid.ClusterModuleLabel: "pandoraSCE" physics.producers.cnnid.PFParticleModuleLabel: "pandoraSCE" From 132c8df3cd570ae9e5332f86214f1dd77d9c4f25 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 15 Jan 2026 15:20:04 -0600 Subject: [PATCH 072/155] temporarily disable blipreco --- .../standard/reco/config/workflow_reco2.fcl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sbndcode/JobConfigurations/standard/reco/config/workflow_reco2.fcl b/sbndcode/JobConfigurations/standard/reco/config/workflow_reco2.fcl index 3f540f3a9..d0b1210dc 100755 --- a/sbndcode/JobConfigurations/standard/reco/config/workflow_reco2.fcl +++ b/sbndcode/JobConfigurations/standard/reco/config/workflow_reco2.fcl @@ -138,8 +138,8 @@ sbnd_reco2_producer_sequence: [ , tpcpmtbarycentermatchingSCE , cvn , cvnSCE - , blipreco - , lightcalo + # , blipreco + , lightcaloSCE ] #FIXME override the producer labels. This should really happen in the module's config fcl @@ -238,7 +238,7 @@ sbnd_reco2_analyzer_sequence: [ caloskim , pmtskim , crtana - , blipana + # , blipana ] #FIXME override the analyzer labels. This should really happen in the module's config fcl From d10e1aeed9b61d3417fd2f979feaf6b72a6cd4e2 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Wed, 21 Jan 2026 11:16:54 -0600 Subject: [PATCH 073/155] get opflashes explicitly for slices that cross the cathode; light weighted avg fix - BCFM has at most, one bcfm<->one slice <-> one opflash association, even if there are opflashes in both tpcs. Explicitly look for an opflash (within a fcl parameter window) in the opposite TPC if the slice has spacepoints in both TPCs - bug fix for weighted average; need to treat each TPC as independent for calculating the weighted avg --- .../Calorimetry/LightCaloProducer_module.cc | 144 +++++++++++------- sbndcode/Calorimetry/lightcalo.fcl | 2 +- 2 files changed, 91 insertions(+), 55 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 799b6b610..66cf7d4ea 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -103,6 +103,8 @@ class sbnd::LightCaloProducer : public art::EDProducer { std::vector> &match_op1, CheckFunc check); + art::Ptr FindMatchingFlash(const std::vector> &flash_v, + double ref_time); // Returns visibility vector for all opdets given charge/position information std::vector> CalcVisibility(std::vector xyz_v, std::vector charge_v); @@ -140,7 +142,7 @@ class sbnd::LightCaloProducer : public art::EDProducer { float fopflash_max; float fopt0_frac_diff_cut; - float fpmt_ara_offset; + float fflash_offset; std::vector fnoise_thresh; std::vector fupper_thresh; @@ -202,7 +204,7 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) fopflash_min = p.get("OpFlashMin"); fopflash_max = p.get("OpFlashMax"); - fpmt_ara_offset = p.get("PMTARAFlashOffset"); + fflash_offset = p.get("FlashOffset"); fnoise_thresh = p.get>("FlashNoiseThreshold"); fupper_thresh = p.get>("OpDetMaxPEThreshold"); @@ -287,12 +289,17 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, std::cout << "don't have good SpacePoints!" << std::endl; return; } - - 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 " << fopflash_producer_v[0] << " or " << fopflash_producer_v[1] << std::endl; - return; + + std::vector> flash0_v; + std::vector> flash1_v; + + for (size_t i=0; i<2; i++){ + ::art::Handle> flash_h; + e.getByLabel(fopflash_producer_v[i], flash_h); + if (!flash_h.isValid() || flash_h->empty()) { + std::cout << "don't have good PMT flashes from producer " << fopflash_producer_v[i] << std::endl; + } + else art::fill_ptr_vector((i==0)? flash0_v : flash1_v, flash_h); } art::FindManyP slice_to_pfp (slice_h, e, fslice_producer); @@ -385,28 +392,6 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, 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)? fnoise_thresh[0] : fnoise_thresh[1]; - - if (!opflash0.isNull() && opflash0->TotalPE() > noise_thresh){ - flash_in_0 = true; - flash_time = opflash0->Time(); - } - if (!opflash1.isNull() && opflash1->TotalPE() > noise_thresh){ - flash_in_1 = true; - flash_time = opflash1->Time(); - } - - 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 @@ -414,6 +399,9 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, 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}; + bool has_sp0 = false; + bool has_sp1 = false; + 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(); @@ -447,12 +435,42 @@ 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) double charge = (1/fcal_area_const.at(hit->View()))*atten_correction*hit->Integral(); + if (xyz.X() < 0) has_sp0 = true; + else has_sp1 = true; + sp_xyz.push_back(xyz); sp_charge.push_back(charge); } } // end spacepoint loop } // end pfp loop + 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; + // find matching flashes if slice has reco spacepoints in both TPCs + if ((has_sp0 && has_sp1) && (opflash0.isNull() || opflash1.isNull())){ + if (opflash0.isNull() && opflash1.isNull()){ + if (fverbose) std::cout << "No opflashes found for slice with spacepoints in both TPCs." << std::endl; + return; + } + else if (opflash0.isNull()) opflash0 = FindMatchingFlash(flash0_v, opflash1->Time()); + else if (opflash1.isNull()) opflash1 = FindMatchingFlash(flash1_v, opflash0->Time()); + } + + if (!opflash0.isNull() && opflash0->TotalPE() > fnoise_thresh[0]){ + flash_in_0 = true; + flash_time = opflash0->Time(); + } + if (!opflash1.isNull() && opflash1->TotalPE() > fnoise_thresh[0]){ + flash_in_1 = true; + flash_time = opflash1->Time(); + } + + if (flash_in_0==false && flash_in_1==false && fverbose) + return; + // get total L count std::vector> visibility_maps = CalcVisibility(sp_xyz,sp_charge); auto dir_visibility_map = visibility_maps[0]; @@ -472,14 +490,13 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, 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.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()) < 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; - } + // find matching xarapuca flash + auto flash_ara = FindMatchingFlash(flash_ara_v, flash_time); + if (flash_ara.isNull()) continue; + // add arapuca PEs to the main vector + for (size_t ich=0; ich < (flash_ara->PEs()).size(); ich++){ + if ( (flash_ara->PEs()).at(ich) > fupper_thresh[1]) continue; // skip if above max PE threshold + flash_pe_v.at(ich) += (flash_ara->PEs()).at(ich); } } // end of arapuca if for (size_t ich=0; ich sbnd::LightCaloProducer::FindMatchingFlash(const std::vector> &flash_v, + double ref_time) +{ + double best_dt = 1.e9; + art::Ptr best; + for (size_t i = 0; i < flash_v.size(); ++i) { + art::Ptr cand = flash_v[i]; + double dt = std::abs(cand->Time() - ref_time); + if (dt < best_dt && dt < fflash_offset) { best_dt = dt; best = cand; } + } + return best; +} + std::vector> sbnd::LightCaloProducer::CalcVisibility(std::vector xyz_v, std::vector charge_v){ @@ -679,29 +709,35 @@ double sbnd::LightCaloProducer::CalcMedian(std::vector 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; - double wgt_num = 0; - double wgt_denom = 0; - - for (size_t ich=0; ich total_gamma){ double total_mean=0; - double wgt_num = 0; - double wgt_denom = 0; - - for (size_t ich=0; ich Date: Wed, 21 Jan 2026 11:16:54 -0600 Subject: [PATCH 074/155] get opflashes explicitly for slices that cross the cathode; light weighted avg fix - BCFM has at most, one bcfm<->one slice <-> one opflash association, even if there are opflashes in both tpcs. Explicitly look for an opflash (within a fcl parameter window) in the opposite TPC if the slice has spacepoints in both TPCs - bug fix for weighted average; need to treat each TPC as independent for calculating the weighted avg --- .../Calorimetry/LightCaloProducer_module.cc | 144 +++++++++++------- sbndcode/Calorimetry/lightcalo.fcl | 2 +- 2 files changed, 91 insertions(+), 55 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 799b6b610..66cf7d4ea 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -103,6 +103,8 @@ class sbnd::LightCaloProducer : public art::EDProducer { std::vector> &match_op1, CheckFunc check); + art::Ptr FindMatchingFlash(const std::vector> &flash_v, + double ref_time); // Returns visibility vector for all opdets given charge/position information std::vector> CalcVisibility(std::vector xyz_v, std::vector charge_v); @@ -140,7 +142,7 @@ class sbnd::LightCaloProducer : public art::EDProducer { float fopflash_max; float fopt0_frac_diff_cut; - float fpmt_ara_offset; + float fflash_offset; std::vector fnoise_thresh; std::vector fupper_thresh; @@ -202,7 +204,7 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) fopflash_min = p.get("OpFlashMin"); fopflash_max = p.get("OpFlashMax"); - fpmt_ara_offset = p.get("PMTARAFlashOffset"); + fflash_offset = p.get("FlashOffset"); fnoise_thresh = p.get>("FlashNoiseThreshold"); fupper_thresh = p.get>("OpDetMaxPEThreshold"); @@ -287,12 +289,17 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, std::cout << "don't have good SpacePoints!" << std::endl; return; } - - 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 " << fopflash_producer_v[0] << " or " << fopflash_producer_v[1] << std::endl; - return; + + std::vector> flash0_v; + std::vector> flash1_v; + + for (size_t i=0; i<2; i++){ + ::art::Handle> flash_h; + e.getByLabel(fopflash_producer_v[i], flash_h); + if (!flash_h.isValid() || flash_h->empty()) { + std::cout << "don't have good PMT flashes from producer " << fopflash_producer_v[i] << std::endl; + } + else art::fill_ptr_vector((i==0)? flash0_v : flash1_v, flash_h); } art::FindManyP slice_to_pfp (slice_h, e, fslice_producer); @@ -385,28 +392,6 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, 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)? fnoise_thresh[0] : fnoise_thresh[1]; - - if (!opflash0.isNull() && opflash0->TotalPE() > noise_thresh){ - flash_in_0 = true; - flash_time = opflash0->Time(); - } - if (!opflash1.isNull() && opflash1->TotalPE() > noise_thresh){ - flash_in_1 = true; - flash_time = opflash1->Time(); - } - - 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 @@ -414,6 +399,9 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, 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}; + bool has_sp0 = false; + bool has_sp1 = false; + 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(); @@ -447,12 +435,42 @@ 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) double charge = (1/fcal_area_const.at(hit->View()))*atten_correction*hit->Integral(); + if (xyz.X() < 0) has_sp0 = true; + else has_sp1 = true; + sp_xyz.push_back(xyz); sp_charge.push_back(charge); } } // end spacepoint loop } // end pfp loop + 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; + // find matching flashes if slice has reco spacepoints in both TPCs + if ((has_sp0 && has_sp1) && (opflash0.isNull() || opflash1.isNull())){ + if (opflash0.isNull() && opflash1.isNull()){ + if (fverbose) std::cout << "No opflashes found for slice with spacepoints in both TPCs." << std::endl; + return; + } + else if (opflash0.isNull()) opflash0 = FindMatchingFlash(flash0_v, opflash1->Time()); + else if (opflash1.isNull()) opflash1 = FindMatchingFlash(flash1_v, opflash0->Time()); + } + + if (!opflash0.isNull() && opflash0->TotalPE() > fnoise_thresh[0]){ + flash_in_0 = true; + flash_time = opflash0->Time(); + } + if (!opflash1.isNull() && opflash1->TotalPE() > fnoise_thresh[0]){ + flash_in_1 = true; + flash_time = opflash1->Time(); + } + + if (flash_in_0==false && flash_in_1==false && fverbose) + return; + // get total L count std::vector> visibility_maps = CalcVisibility(sp_xyz,sp_charge); auto dir_visibility_map = visibility_maps[0]; @@ -472,14 +490,13 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, 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.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()) < 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; - } + // find matching xarapuca flash + auto flash_ara = FindMatchingFlash(flash_ara_v, flash_time); + if (flash_ara.isNull()) continue; + // add arapuca PEs to the main vector + for (size_t ich=0; ich < (flash_ara->PEs()).size(); ich++){ + if ( (flash_ara->PEs()).at(ich) > fupper_thresh[1]) continue; // skip if above max PE threshold + flash_pe_v.at(ich) += (flash_ara->PEs()).at(ich); } } // end of arapuca if for (size_t ich=0; ich sbnd::LightCaloProducer::FindMatchingFlash(const std::vector> &flash_v, + double ref_time) +{ + double best_dt = 1.e9; + art::Ptr best; + for (size_t i = 0; i < flash_v.size(); ++i) { + art::Ptr cand = flash_v[i]; + double dt = std::abs(cand->Time() - ref_time); + if (dt < best_dt && dt < fflash_offset) { best_dt = dt; best = cand; } + } + return best; +} + std::vector> sbnd::LightCaloProducer::CalcVisibility(std::vector xyz_v, std::vector charge_v){ @@ -679,29 +709,35 @@ double sbnd::LightCaloProducer::CalcMedian(std::vector 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; - double wgt_num = 0; - double wgt_denom = 0; - - for (size_t ich=0; ich total_gamma){ double total_mean=0; - double wgt_num = 0; - double wgt_denom = 0; - - for (size_t ich=0; ich Date: Wed, 21 Jan 2026 17:06:57 -0600 Subject: [PATCH 075/155] lightcalo fcl organization - add to standard mc/data reco2 workflow - add SCE tag to cafmaker sce for data and mc --- .../{lightcalo.fcl => lightcalo_sbnd.fcl} | 15 ++++++++++----- sbndcode/Calorimetry/lightcalo_sbnd_data.fcl | 14 ++++++++++++++ .../standard/caf/cafmakerjob_sbnd_data_sce.fcl | 2 ++ .../standard/reco/config/workflow_reco2.fcl | 4 ++-- .../standard/reco/reco2_data.fcl | 4 ++-- 5 files changed, 30 insertions(+), 9 deletions(-) rename sbndcode/Calorimetry/{lightcalo.fcl => lightcalo_sbnd.fcl} (93%) create mode 100644 sbndcode/Calorimetry/lightcalo_sbnd_data.fcl diff --git a/sbndcode/Calorimetry/lightcalo.fcl b/sbndcode/Calorimetry/lightcalo_sbnd.fcl similarity index 93% rename from sbndcode/Calorimetry/lightcalo.fcl rename to sbndcode/Calorimetry/lightcalo_sbnd.fcl index 3f1a03343..77ba46bfc 100644 --- a/sbndcode/Calorimetry/lightcalo.fcl +++ b/sbndcode/Calorimetry/lightcalo_sbnd.fcl @@ -15,16 +15,15 @@ sbnd_lightcalo: # only validated for coated PMTs for now PDTypes: ["pmt_coated"] # "pmt_uncoated", "xarapuca_vuv", "xarapuca_vis" - SliceProducer: "pandoraSCE" - OpT0FinderProducer: "opt0finderSCE" - BCFMProducer: "tpcpmtbarycentermatchingSCE" + SliceProducer: "pandora" + OpT0FinderProducer: "opt0finder" + BCFMProducer: "tpcpmtbarycentermatching" 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 + bcfmScoreCut: 0.02 # default: accept bcfm match > bcfmScoreCut opt0ScoreCut: 200 # default: accept opt0 match > opt0ScoreCut opt0FractionalCut: 0.5 @@ -42,4 +41,10 @@ sbnd_lightcalo: OpDetVISEfficiencies: [0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271] OpDetMask: [ 39, 64, 66, 71, 85, 86, 87, 115, 138, 141, 197, 217, 221, 222, 223, 226, 245, 249, 302] } + +sbnd_lightcalo_sce: @local::sbnd_lightcalo +sbnd_lightcalo_sce.SliceProducer: "pandoraSCE" +sbnd_lightcalo_sce.OpT0FinderProducer: "opt0finderSCE" +sbnd_lightcalo_sce.BCFMProducer: "tpcpmtbarycentermatchingSCE" + END_PROLOG diff --git a/sbndcode/Calorimetry/lightcalo_sbnd_data.fcl b/sbndcode/Calorimetry/lightcalo_sbnd_data.fcl new file mode 100644 index 000000000..d90a591c9 --- /dev/null +++ b/sbndcode/Calorimetry/lightcalo_sbnd_data.fcl @@ -0,0 +1,14 @@ +#include "lightcalo_sbnd.fcl" + +BEGIN_PROLOG +sbnd_lightcalo_data: @local::sbnd_lightcalo +sbnd_lightcalo_data.CalAreaConstants: [ 0.02172 , 0.02150, 0.02103 ] # calibration constants for wire planes, found in sbndcode/LArSoftConfigurations/calorimetry_sbnd.fcl +sbnd_lightcalo_data.OpFlashMin: -0.8 # assumption is light-triggered data +sbnd_lightcalo_data.OpFlashMax: 2.0 # assumption is light-triggered data + +sbnd_lightcalo_data_sce: @local::sbnd_lightcalo_data +sbnd_lightcalo_data_sce.SliceProducer: "pandoraSCE" +sbnd_lightcalo_data_sce.OpT0FinderProducer: "opt0finderSCE" +sbnd_lightcalo_data_sce.BCFMProducer: "tpcpmtbarycentermatchingSCE" + +END_PROLOG \ No newline at end of file diff --git a/sbndcode/JobConfigurations/standard/caf/cafmakerjob_sbnd_data_sce.fcl b/sbndcode/JobConfigurations/standard/caf/cafmakerjob_sbnd_data_sce.fcl index 6520f36bd..246df11a0 100644 --- a/sbndcode/JobConfigurations/standard/caf/cafmakerjob_sbnd_data_sce.fcl +++ b/sbndcode/JobConfigurations/standard/caf/cafmakerjob_sbnd_data_sce.fcl @@ -15,6 +15,8 @@ physics.producers.cafmaker.OpT0Label: "opt0finderSCE" physics.producers.cafmaker.TPCPMTBarycenterMatchLabel: "tpcpmtbarycentermatchingSCE" physics.producers.cafmaker.CVNLabel: "cvnSCE" physics.producers.cafmaker.CorrectedOpFlashLabel: "lightpropagationcorrectionSCE" +physics.producers.cafmaker.LightCaloLabel: "lightcaloSCE" + physics.producers.cnnid.WireLabel: "sptpc2d:dnnsp" physics.producers.cnnid.ClusterModuleLabel: "pandoraSCE" diff --git a/sbndcode/JobConfigurations/standard/reco/config/workflow_reco2.fcl b/sbndcode/JobConfigurations/standard/reco/config/workflow_reco2.fcl index d0b1210dc..c02392f38 100755 --- a/sbndcode/JobConfigurations/standard/reco/config/workflow_reco2.fcl +++ b/sbndcode/JobConfigurations/standard/reco/config/workflow_reco2.fcl @@ -20,7 +20,7 @@ #include "SBNDCVNMapper.fcl" #include "blipreco_configs.fcl" -#include "lightcalo.fcl" +#include "lightcalo_sbnd.fcl" BEGIN_PROLOG @@ -97,7 +97,7 @@ sbnd_reco2_producers:{ } ### light calorimtery - lightcaloSCE : @local::sbnd_lightcalo + lightcaloSCE : @local::sbnd_lightcalo_sce } sbnd_reco2_producer_sequence: [ diff --git a/sbndcode/JobConfigurations/standard/reco/reco2_data.fcl b/sbndcode/JobConfigurations/standard/reco/reco2_data.fcl index 56ac8b918..a47f11a7c 100755 --- a/sbndcode/JobConfigurations/standard/reco/reco2_data.fcl +++ b/sbndcode/JobConfigurations/standard/reco/reco2_data.fcl @@ -3,7 +3,7 @@ #include "sbnd_lightpropagationcorrection_config.fcl" #include "frameshift_sbnd_data.fcl" #include "standard_reco2_sbnd.fcl" -#include "lightcalo.fcl" +#include "lightcalo_sbnd_data.fcl" services: { @@ -35,7 +35,7 @@ physics.producers: pandoraSCEShower: @local::sbnd_sce_incremental_pandoraModularShowerCreationData pandoraSCEShowerSBN: @local::sbnd_sce_sbn_pandoraModularShowerCreationData - lightcaloSCE: @local::sbnd_lightcalo + lightcaloSCE: @local::sbnd_lightcalo_data_sce frameshift: @local::frameshift_data } From 4c0ebe00a7326c47d9166679ebf9bcb7ff30e9b9 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Wed, 21 Jan 2026 17:07:07 -0600 Subject: [PATCH 076/155] remove nuscore cut since we're not using it anyways --- sbndcode/Calorimetry/LightCaloProducer_module.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 66cf7d4ea..5ca60ac0b 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -134,7 +134,6 @@ class sbnd::LightCaloProducer : public art::EDProducer { bool fuse_opt0; bool fverbose; - float fnuscore_cut; float fbcfmscore_cut; float fopt0score_cut; @@ -196,7 +195,6 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) 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"); From c67c53bb822dee44030e1732448039c321712789 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Wed, 21 Jan 2026 17:10:30 -0600 Subject: [PATCH 077/155] undo blip commenting out --- .../JobConfigurations/standard/reco/config/workflow_reco2.fcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbndcode/JobConfigurations/standard/reco/config/workflow_reco2.fcl b/sbndcode/JobConfigurations/standard/reco/config/workflow_reco2.fcl index c02392f38..fd2083d46 100755 --- a/sbndcode/JobConfigurations/standard/reco/config/workflow_reco2.fcl +++ b/sbndcode/JobConfigurations/standard/reco/config/workflow_reco2.fcl @@ -138,7 +138,7 @@ sbnd_reco2_producer_sequence: [ , tpcpmtbarycentermatchingSCE , cvn , cvnSCE - # , blipreco + , blipreco , lightcaloSCE ] @@ -238,7 +238,7 @@ sbnd_reco2_analyzer_sequence: [ caloskim , pmtskim , crtana - # , blipana + , blipana ] #FIXME override the analyzer labels. This should really happen in the module's config fcl From 297632a3457f5a973025126a92c0a9c8a9ff0f89 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 22 Jan 2026 11:42:13 -0600 Subject: [PATCH 078/155] use pmt calibration database instead of fcl param to identify on/reconstructable PMTs --- sbndcode/Calorimetry/LightCaloProducer_module.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 5ca60ac0b..80b4d8927 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -54,6 +54,10 @@ #include "sbnobj/Common/Reco/OpT0FinderResult.h" #include "sbnobj/Common/Reco/TPCPMTBarycenterMatch.h" +// Calibration database includes +#include "sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabase.h" +#include "sbndcode/Calibration/PDSDatabaseInterface/IPMTCalibrationDatabaseService.h" + // ROOT includes #include "TFile.h" #include "TTree.h" @@ -155,6 +159,8 @@ class sbnd::LightCaloProducer : public art::EDProducer { fhicl::ParameterSet fvis_params; std::shared_ptr foptical_path_tool; + sbndDB::PMTCalibrationDatabase const* fpmt_calib_db; + opdet::sbndPDMapAlg opdetmap; //map for photon detector types unsigned int nchan = opdetmap.size(); @@ -183,6 +189,7 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) 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); + fpmt_calib_db = lar::providerFrom(); fopflash_producer_v = p.get>("OpFlashProducers"); fopflash_ara_producer_v = p.get>("OpFlashAraProducers"); @@ -508,6 +515,11 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, // error is proportional to the amount of light // that actually reached the optical detector for (size_t ich=0; ichgetReconstructChannel(ich) || !fpmt_calib_db->getOnPMT(ich)) + total_pe.at(ich) = 0; + } // # if ich is in fopdet_mask, set to zero if (fopdet_mask.end() != std::find(fopdet_mask.begin(), fopdet_mask.end(), ich)) total_pe.at(ich) = 0; From 64328610a6de0c0d75ac83d6f584cbe8b1349e31 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 22 Jan 2026 11:42:38 -0600 Subject: [PATCH 079/155] update PMT efficiencies to latest, remove hardcoded off/non-reconstructable PMTs (use pmt calib db instead) --- sbndcode/Calorimetry/lightcalo_sbnd.fcl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sbndcode/Calorimetry/lightcalo_sbnd.fcl b/sbndcode/Calorimetry/lightcalo_sbnd.fcl index 77ba46bfc..27d40e10d 100644 --- a/sbndcode/Calorimetry/lightcalo_sbnd.fcl +++ b/sbndcode/Calorimetry/lightcalo_sbnd.fcl @@ -37,9 +37,9 @@ sbnd_lightcalo: # calibration constants & simulation parameters CalAreaConstants: [ 0.02052, 0.02044, 0.02019 ] # calibration constants for wire planes, found in sbndcode/LArSoftConfigurations/calorimetry_sbnd.fcl - OpDetVUVEfficiencies: [0.0,0.0,0.0,0.0,0.0,0.0,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752,0.0,0.0,0.0,0.0,0.0,0.0,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.0315,0.027,0.01752,0.01752,0.01752,0.01752,0.01752,0.01752] - OpDetVISEfficiencies: [0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03382,0.03382,0.03382,0.03382,0.03382,0.03382,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271,0.01264,0.01264,0.01264,0.01264,0.01264,0.01264,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.03493,0.00271,0.00271,0.00271,0.00271,0.00271,0.00271] - OpDetMask: [ 39, 64, 66, 71, 85, 86, 87, 115, 138, 141, 197, 217, 221, 222, 223, 226, 245, 249, 302] + OpDetVUVEfficiencies: [0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752] + OpDetVISEfficiencies: [0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271] + OpDetMask: [] # list of opdet channels to ignore (off/non-reconstructable PMTs are already identified via calibration db) } sbnd_lightcalo_sce: @local::sbnd_lightcalo From 7fe5babcb58dbc5489b4403d5ebb4e1b8ddfc25b Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Wed, 28 Jan 2026 11:35:53 -0600 Subject: [PATCH 080/155] inherit efficiency, tpc constants from their initial fcls; add units to some fcl comments - also remove unused functions --- .../Calorimetry/LightCaloProducer_module.cc | 93 +++++++++++-------- sbndcode/Calorimetry/lightcalo_sbnd.fcl | 29 ++++-- sbndcode/Calorimetry/lightcalo_sbnd_data.fcl | 2 +- sbndcode/Calorimetry/run_lightcalo.fcl | 2 +- 4 files changed, 76 insertions(+), 50 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 80b4d8927..3864fb992 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -119,11 +119,7 @@ class sbnd::LightCaloProducer : public art::EDProducer { 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); + // Returns the weighted mean of the light vector double CalcMean(std::vector total_light, std::vector total_err); // fcl parameters @@ -150,6 +146,19 @@ class sbnd::LightCaloProducer : public art::EDProducer { std::vector fupper_thresh; std::vector fcal_area_const; + + double fpmtcoated_vuveff_tpc0; + double fpmtcoated_viseff_tpc0; + double fpmtuncoated_eff_tpc0; + + double fpmtcoated_vuveff_tpc1; + double fpmtcoated_viseff_tpc1; + double fpmtuncoated_eff_tpc1; + + double fxarapucavuv_vuveff; + double fxarapucavuv_viseff; + double fxarapucavis_eff; + std::vector fopdet_vuv_eff; std::vector fopdet_vis_eff; std::vector fopdet_mask; @@ -214,10 +223,48 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) fupper_thresh = p.get>("OpDetMaxPEThreshold"); fcal_area_const = p.get>("CalAreaConstants"); - fopdet_vuv_eff = p.get>("OpDetVUVEfficiencies"); - fopdet_vis_eff = p.get>("OpDetVISEfficiencies"); fopdet_mask = p.get>("OpDetMask"); + fpmtcoated_viseff_tpc0 = p.get("PMTCoatedVISEff_tpc0"); + fpmtcoated_vuveff_tpc0 = p.get("PMTCoatedVUVEff_tpc0"); + fpmtuncoated_eff_tpc0 = p.get("PMTUncoatedEff_tpc0"); + fpmtcoated_viseff_tpc1 = p.get("PMTCoatedVISEff_tpc1"); + fpmtcoated_vuveff_tpc1 = p.get("PMTCoatedVUVEff_tpc1"); + fpmtuncoated_eff_tpc1 = p.get("PMTUncoatedEff_tpc1"); + + fxarapucavuv_vuveff = p.get("XArapucaVUVVUVEff"); + fxarapucavuv_viseff = p.get("XArapucaVUVVISEff"); + fxarapucavis_eff = p.get("XArapucaVISEff"); + + // fill efficiency vectors + fopdet_vuv_eff.resize(nchan,0.); + fopdet_vis_eff.resize(nchan,0.); + for (unsigned int ch = 0; ch < nchan; ++ch) { + std::string pd_type = opdetmap.pdType(ch); + if (pd_type == "pmt_coated") { + if (ch%2==0){ + fopdet_vuv_eff[ch] = fpmtcoated_vuveff_tpc0; + fopdet_vis_eff[ch] = fpmtcoated_viseff_tpc0; + } + else{ + fopdet_vuv_eff[ch] = fpmtcoated_vuveff_tpc1; + fopdet_vis_eff[ch] = fpmtcoated_viseff_tpc1; + } + } else if (pd_type == "pmt_uncoated") { + if (ch%2==0) + fopdet_vis_eff[ch] = fpmtuncoated_eff_tpc0; + else + fopdet_vis_eff[ch] = fpmtuncoated_eff_tpc1; + } + else if (pd_type == "xarapuca_vuv") { + fopdet_vuv_eff[ch] = fxarapucavuv_vuveff; + fopdet_vis_eff[ch] = fxarapucavuv_viseff; + } + else if (pd_type == "xarapuca_vis") { + fopdet_vis_eff[ch] = fxarapucavis_eff; + } + } + geom = lar::providerFrom(); art::ServiceHandle fs; @@ -701,21 +748,6 @@ void sbnd::LightCaloProducer::CalcLight(std::vector flash_pe_v, } } -double sbnd::LightCaloProducer::CalcMedian(std::vector total_gamma){ - std::vector gamma_nonzero; - 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; @@ -734,21 +766,4 @@ double sbnd::LightCaloProducer::CalcMean(std::vector total_gamma, std::v return total_mean; } -double sbnd::LightCaloProducer::CalcMean(std::vector total_gamma){ - double total_mean=0; - for (int tpc=0; tpc<2; tpc++){ - double wgt_num = 0; - double wgt_denom = 0; - - for (size_t ich=0; ich opt0ScoreCut 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] + OpFlashMin: 0.0 # in us, simulation [0.0], light-triggered data [-0.8] + OpFlashMax: 2.0 # in us, simulation [2.0], light-triggered data [2.0] # flash parameters - FlashOffset: 0.05 # acceptable offset between the t0 between TPCs or between PMTs/X-ARAPUCAs - FlashNoiseThreshold: [ 600., 1500. ] # {PMT, xARAPUCA}, flash total PE threshold to ignore a flash - OpDetMaxPEThreshold: [4000., 1e9] # PE in a single opdet to ignore (due to saturation effects) + FlashOffset: 0.05 # in us, acceptable offset between the t0 between TPCs or between PMTs/X-ARAPUCAs + FlashNoiseThreshold: [ 600., 1500. ] # in PE, {PMT, xARAPUCA}, flash total PE threshold to ignore a flash + OpDetMaxPEThreshold: [4000., 1e9] # in PE, PE in a single opdet to ignore (due to saturation effects) + OpDetMask: [] # list of opdet channels to ignore (off/non-reconstructable PMTs are already identified via calibration db) # calibration constants & simulation parameters - CalAreaConstants: [ 0.02052, 0.02044, 0.02019 ] # calibration constants for wire planes, found in sbndcode/LArSoftConfigurations/calorimetry_sbnd.fcl - OpDetVUVEfficiencies: [0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.03920, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752, 0.01752] - OpDetVISEfficiencies: [0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.03570, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.01264, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.02600, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271, 0.00271] - OpDetMask: [] # list of opdet channels to ignore (off/non-reconstructable PMTs are already identified via calibration db) + CalAreaConstants: @local::sbnd_calorimetryalgmc.CalAreaConstants + PMTCoatedVISEff_tpc0: @local::sbnd_digipmt_alg.PMTCoatedVISEff_tpc0 + PMTCoatedVUVEff_tpc0: @local::sbnd_digipmt_alg.PMTCoatedVUVEff_tpc0 + PMTUncoatedEff_tpc0: @local::sbnd_digipmt_alg.PMTUncoatedEff_tpc0 + PMTCoatedVISEff_tpc1: @local::sbnd_digipmt_alg.PMTCoatedVISEff_tpc1 + PMTCoatedVUVEff_tpc1: @local::sbnd_digipmt_alg.PMTCoatedVUVEff_tpc1 + PMTUncoatedEff_tpc1: @local::sbnd_digipmt_alg.PMTUncoatedEff_tpc1 + + XArapucaVUVVUVEff: @local::sbnd_digiarapuca_alg.XArapucaVUVEffVUV + XArapucaVUVVISEff: @local::sbnd_digiarapuca_alg.XArapucaVUVEffVis + XArapucaVISEff: @local::sbnd_digiarapuca_alg.XArapucaVISEff } sbnd_lightcalo_sce: @local::sbnd_lightcalo diff --git a/sbndcode/Calorimetry/lightcalo_sbnd_data.fcl b/sbndcode/Calorimetry/lightcalo_sbnd_data.fcl index d90a591c9..3f97ced95 100644 --- a/sbndcode/Calorimetry/lightcalo_sbnd_data.fcl +++ b/sbndcode/Calorimetry/lightcalo_sbnd_data.fcl @@ -2,7 +2,7 @@ BEGIN_PROLOG sbnd_lightcalo_data: @local::sbnd_lightcalo -sbnd_lightcalo_data.CalAreaConstants: [ 0.02172 , 0.02150, 0.02103 ] # calibration constants for wire planes, found in sbndcode/LArSoftConfigurations/calorimetry_sbnd.fcl +sbnd_lightcalo_data.CalAreaConstants: @local::sbnd_calorimetryalgdata.CalAreaConstants sbnd_lightcalo_data.OpFlashMin: -0.8 # assumption is light-triggered data sbnd_lightcalo_data.OpFlashMax: 2.0 # assumption is light-triggered data diff --git a/sbndcode/Calorimetry/run_lightcalo.fcl b/sbndcode/Calorimetry/run_lightcalo.fcl index 2ee6ace69..4f38c10e1 100644 --- a/sbndcode/Calorimetry/run_lightcalo.fcl +++ b/sbndcode/Calorimetry/run_lightcalo.fcl @@ -2,7 +2,7 @@ #include "simulationservices_sbnd.fcl" #include "messages_sbnd.fcl" #include "sam_sbnd.fcl" -#include "lightcalo.fcl" +#include "lightcalo_sbnd.fcl" process_name: LightCaloProducer From 8f48fed15f94ba41b08e336f4df31acf33bdb1d3 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Wed, 28 Jan 2026 11:49:04 -0600 Subject: [PATCH 081/155] checks opflash producer size instead of assuming both tpcs --- .../Calorimetry/LightCaloProducer_module.cc | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 3864fb992..2b93b9608 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -69,6 +69,7 @@ #include #include #include +#include namespace sbnd { class LightCaloProducer; @@ -345,13 +346,18 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, std::vector> flash0_v; std::vector> flash1_v; - for (size_t i=0; i<2; i++){ + for (size_t i=0; i> flash_h; e.getByLabel(fopflash_producer_v[i], flash_h); if (!flash_h.isValid() || flash_h->empty()) { std::cout << "don't have good PMT flashes from producer " << fopflash_producer_v[i] << std::endl; } - else art::fill_ptr_vector((i==0)? flash0_v : flash1_v, flash_h); + else{ + if (fopflash_producer_v[i].find("tpc0") != std::string::npos) + art::fill_ptr_vector(flash0_v, flash_h); + else if (fopflash_producer_v[i].find("tpc1") != std::string::npos) + art::fill_ptr_vector(flash1_v, flash_h); + } } art::FindManyP slice_to_pfp (slice_h, e, fslice_producer); @@ -420,13 +426,18 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, ::art::Handle> flash0_ara_h; ::art::Handle> flash1_ara_h; - for (size_t i=0; i<2; i++){ + for (size_t i=0; 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 " << fopflash_ara_producer_v[i] << std::endl; } - else art::fill_ptr_vector((i==0)? flash0_ara_v : flash1_ara_v, flash_ara_h); + else{ + if (fopflash_ara_producer_v[i].find("tpc0") != std::string::npos) + art::fill_ptr_vector(flash0_ara_v, flash_ara_h); + else if (fopflash_ara_producer_v[i].find("tpc1") != std::string::npos) + art::fill_ptr_vector(flash1_ara_v, flash_ara_h); + } } } From 18876a712dc31a30a1be768633792307ca7e1f8c Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Wed, 28 Jan 2026 12:02:09 -0600 Subject: [PATCH 082/155] add fcl param on whether to fill TTree, add more comments, remove unused headers --- .../Calorimetry/LightCaloProducer_module.cc | 11 +++-- sbndcode/Calorimetry/lightcalo_sbnd.fcl | 43 ++++++++++--------- sbndcode/Calorimetry/run_lightcalo.fcl | 4 +- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 2b93b9608..73b56927e 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -63,11 +63,9 @@ #include "TTree.h" // C++ includes -#include #include #include // sort #include -#include #include #include @@ -98,6 +96,9 @@ class sbnd::LightCaloProducer : public art::EDProducer { std::unique_ptr< art::Assns >& slice_assn_v, std::unique_ptr< art::Assns >& flash_assn_v); + // Templated member function to collect matched slices and opflashes + // The CheckFunc is a callable that takes a Ptr and returns bool + // to determine if the match passes selection criteria template void CollectMatches(const art::Handle> &handle, const std::vector> &fm_v, @@ -108,6 +109,7 @@ class sbnd::LightCaloProducer : public art::EDProducer { std::vector> &match_op1, CheckFunc check); + // Finds the opflash in flash_v that is closest in time to ref_time art::Ptr FindMatchingFlash(const std::vector> &flash_v, double ref_time); // Returns visibility vector for all opdets given charge/position information @@ -134,6 +136,7 @@ class sbnd::LightCaloProducer : public art::EDProducer { bool fuse_bcfm; bool fuse_opt0; bool fverbose; + bool ffill_tree; float fbcfmscore_cut; float fopt0score_cut; @@ -211,6 +214,7 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) fuse_bcfm = p.get("UseBCFM"); fverbose = p.get("Verbose"); + ffill_tree = p.get("FillTree"); fbcfmscore_cut = p.get("bcfmScoreCut"); fopt0score_cut = p.get("opt0ScoreCut"); @@ -608,7 +612,8 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, util::CreateAssn(*this, e, *lightcalo_v, opflash0, *flash_assn_v); util::CreateAssn(*this, e, *lightcalo_v, opflash1, *flash_assn_v); - _tree->Fill(); + if (ffill_tree) + _tree->Fill(); } // end slice loop } // end produce diff --git a/sbndcode/Calorimetry/lightcalo_sbnd.fcl b/sbndcode/Calorimetry/lightcalo_sbnd.fcl index 5e4fede09..29b773bc6 100644 --- a/sbndcode/Calorimetry/lightcalo_sbnd.fcl +++ b/sbndcode/Calorimetry/lightcalo_sbnd.fcl @@ -13,31 +13,32 @@ sbnd_lightcalo: VIVHits: @local::sbnd_vis_RS100cm_hits_parameterization OpticalPathTool: @local::SBNDOpticalPath - OpFlashProducers: ["opflashtpc0", "opflashtpc1"] - OpFlashAraProducers: ["opflashtpc0xarapuca", "opflashtpc1xarapuca"] + OpFlashProducers: ["opflashtpc0", "opflashtpc1"] + OpFlashAraProducers: ["opflashtpc0xarapuca", "opflashtpc1xarapuca"] # only validated for coated PMTs for now - PDTypes: ["pmt_coated"] # "pmt_uncoated", "xarapuca_vuv", "xarapuca_vis" + PDTypes: ["pmt_coated"] # "pmt_uncoated", "xarapuca_vuv", "xarapuca_vis" - SliceProducer: "pandora" - OpT0FinderProducer: "opt0finder" - BCFMProducer: "tpcpmtbarycentermatching" + SliceProducer: "pandora" + OpT0FinderProducer: "opt0finder" + BCFMProducer: "tpcpmtbarycentermatching" - UseBCFM: true - UseOpT0Finder: false - Verbose: false + UseBCFM: true + UseOpT0Finder: false + Verbose: false + FillTree: false - bcfmScoreCut: 0.02 # default: accept bcfm match > bcfmScoreCut - opt0ScoreCut: 200 # default: accept opt0 match > opt0ScoreCut - opt0FractionalCut: 0.5 + bcfmScoreCut: 0.02 # default: accept bcfm match > bcfmScoreCut + opt0ScoreCut: 200 # default: accept opt0 match > opt0ScoreCut + opt0FractionalCut: 0.5 - OpFlashMin: 0.0 # in us, simulation [0.0], light-triggered data [-0.8] - OpFlashMax: 2.0 # in us, simulation [2.0], light-triggered data [2.0] + OpFlashMin: 0.0 # in us, simulation [0.0], light-triggered data [-0.8] + OpFlashMax: 2.0 # in us, simulation [2.0], light-triggered data [2.0] # flash parameters - FlashOffset: 0.05 # in us, acceptable offset between the t0 between TPCs or between PMTs/X-ARAPUCAs - FlashNoiseThreshold: [ 600., 1500. ] # in PE, {PMT, xARAPUCA}, flash total PE threshold to ignore a flash - OpDetMaxPEThreshold: [4000., 1e9] # in PE, PE in a single opdet to ignore (due to saturation effects) - OpDetMask: [] # list of opdet channels to ignore (off/non-reconstructable PMTs are already identified via calibration db) + FlashOffset: 0.05 # in us, acceptable offset between the t0 between TPCs or between PMTs/X-ARAPUCAs + FlashNoiseThreshold: [ 600., 1500. ] # in PE, {PMT, xARAPUCA}, flash total PE threshold to ignore a flash + OpDetMaxPEThreshold: [4000., 1e9] # in PE, PE in a single opdet to ignore (due to saturation effects) + OpDetMask: [] # list of opdet channels to ignore (off/non-reconstructable PMTs are already identified via calibration db) # calibration constants & simulation parameters CalAreaConstants: @local::sbnd_calorimetryalgmc.CalAreaConstants @@ -48,9 +49,9 @@ sbnd_lightcalo: PMTCoatedVUVEff_tpc1: @local::sbnd_digipmt_alg.PMTCoatedVUVEff_tpc1 PMTUncoatedEff_tpc1: @local::sbnd_digipmt_alg.PMTUncoatedEff_tpc1 - XArapucaVUVVUVEff: @local::sbnd_digiarapuca_alg.XArapucaVUVEffVUV - XArapucaVUVVISEff: @local::sbnd_digiarapuca_alg.XArapucaVUVEffVis - XArapucaVISEff: @local::sbnd_digiarapuca_alg.XArapucaVISEff + XArapucaVUVVUVEff: @local::sbnd_digiarapuca_alg.XArapucaVUVEffVUV + XArapucaVUVVISEff: @local::sbnd_digiarapuca_alg.XArapucaVUVEffVis + XArapucaVISEff: @local::sbnd_digiarapuca_alg.XArapucaVISEff } sbnd_lightcalo_sce: @local::sbnd_lightcalo diff --git a/sbndcode/Calorimetry/run_lightcalo.fcl b/sbndcode/Calorimetry/run_lightcalo.fcl index 4f38c10e1..15ca5b05b 100644 --- a/sbndcode/Calorimetry/run_lightcalo.fcl +++ b/sbndcode/Calorimetry/run_lightcalo.fcl @@ -54,4 +54,6 @@ 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.FillTree: true \ No newline at end of file From 8dff5ed623d4ea67f7dca510e0c905a40862861b Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Wed, 28 Jan 2026 12:17:49 -0600 Subject: [PATCH 083/155] cleanup unused includes and dependencies --- sbndcode/Calorimetry/CMakeLists.txt | 24 ++++--------------- .../Calorimetry/LightCaloProducer_module.cc | 4 ---- 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/sbndcode/Calorimetry/CMakeLists.txt b/sbndcode/Calorimetry/CMakeLists.txt index 62562fa94..d33d8946d 100644 --- a/sbndcode/Calorimetry/CMakeLists.txt +++ b/sbndcode/Calorimetry/CMakeLists.txt @@ -1,39 +1,23 @@ set (MODULE_LIBRARIES - larsim::Utils larsim::PhotonPropagation - larsim::PhotonPropagation_PhotonVisibilityService_service larsim::OpticalPath larsim::LegacyLArG4 - larcorealg::GeoAlgo 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 + art_root_io::TFileService_service + art_root_io::tfile_support messagefacility::MF_MessageLogger sbnobj::Common_Reco fhiclcpp::fhiclcpp - ROOT::Geom - ROOT::XMLIO - ROOT::Gdml - ${ROOT_BASIC_LIB_LIST} - sbndcode_RecoUtils sbndcode_OpDetSim + ROOT::Core + ROOT::Tree ) cet_build_plugin(LightCaloProducer art::module SOURCE LightCaloProducer_module.cc LIBRARIES ${MODULE_LIBRARIES}) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 73b56927e..c08e0158a 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -35,10 +35,6 @@ #include "lardataobj/RecoBase/Hit.h" #include "lardataobj/RecoBase/OpFlash.h" -// LArSoft MC includes -#include "nusimdata/SimulationBase/MCTruth.h" -#include "lardataobj/Simulation/sim.h" - #include "larcore/CoreUtils/ServiceUtil.h" #include "larcore/Geometry/Geometry.h" #include "larcorealg/Geometry/GeometryCore.h" From 916b8616590f2eee513bc6f101682a2724c19dc1 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 29 Jan 2026 10:33:47 -0600 Subject: [PATCH 084/155] add initial filename/timestamp info on the output art file --- sbndcode/Calorimetry/run_lightcalo.fcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbndcode/Calorimetry/run_lightcalo.fcl b/sbndcode/Calorimetry/run_lightcalo.fcl index 15ca5b05b..ba0791771 100644 --- a/sbndcode/Calorimetry/run_lightcalo.fcl +++ b/sbndcode/Calorimetry/run_lightcalo.fcl @@ -28,7 +28,7 @@ outputs: out1: { module_type: RootOutput - fileName: "lightcalo-art.root" + fileName: "%ifb_lightcalo-art.root" dataTier: "reconstructed" compressionLevel:1 } From 2e219b719810e2733d60e0ffad5751a629f38ed9 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 29 Jan 2026 10:44:54 -0600 Subject: [PATCH 085/155] update LightCaloProducer to conditionally fill TTree and enhance logging messages; avoid hardcoded TPC tick --- .../Calorimetry/LightCaloProducer_module.cc | 65 ++++++++++--------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index c08e0158a..a570c9aba 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -269,21 +269,22 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) geom = lar::providerFrom(); art::ServiceHandle fs; - _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_Q", &_slice_Q, "slice_Q/D"); - _tree->Branch("slice_L", &_slice_L, "slice_L/D"); - _tree->Branch("slice_E", &_slice_E, "slice_E/D"); - + if (ffill_tree){ + _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_Q", &_slice_Q, "slice_Q/D"); + _tree->Branch("slice_L", &_slice_L, "slice_L/D"); + _tree->Branch("slice_E", &_slice_E, "slice_E/D"); + } // Call appropriate produces<>() functions here. produces>(); produces>(); @@ -325,21 +326,21 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, ::art::Handle> slice_h; e.getByLabel(fslice_producer, slice_h); if(!slice_h.isValid() || slice_h->empty()){ - std::cout << "don't have good slices!" << std::endl; + std::cout << "[LightCaloProducer] : " << fslice_producer << " doesn't have good slices!" << std::endl; return; } ::art::Handle> pfp_h; e.getByLabel(fslice_producer, pfp_h); if(!pfp_h.isValid() || pfp_h->empty()) { - std::cout << "don't have good PFParticle!" << std::endl; + std::cout << "[LightCaloProducer] : " << fslice_producer << " doesn't have good PFParticles!" << std::endl; return; } ::art::Handle> spacepoint_h; e.getByLabel(fslice_producer, spacepoint_h); if(!spacepoint_h.isValid() || spacepoint_h->empty()) { - std::cout << "don't have good SpacePoints!" << std::endl; + std::cout << "[LightCaloProducer] : " << fslice_producer << " don't have good SpacePoints!" << std::endl; return; } @@ -350,7 +351,7 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, ::art::Handle> flash_h; e.getByLabel(fopflash_producer_v[i], flash_h); if (!flash_h.isValid() || flash_h->empty()) { - std::cout << "don't have good PMT flashes from producer " << fopflash_producer_v[i] << std::endl; + std::cout << "[LightCaloProducer] : " << "don't have good PMT flashes from producer " << fopflash_producer_v[i] << std::endl; } else{ if (fopflash_producer_v[i].find("tpc0") != std::string::npos) @@ -376,7 +377,7 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, ::art::Handle> 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; + std::cout << "[LightCaloProducer] : " << "don't have good barycenter matches!" << std::endl; return; } std::vector> bcfm_v; @@ -385,7 +386,7 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, 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->score < 0.02) return false; + if (bcfm->score < fbcfmscore_cut) return false; return true; }); } @@ -393,7 +394,7 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, ::art::Handle> 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; + std::cout << "[LightCaloProducer] : " << "don't have good OpT0Finder matches!" << std::endl; return; } std::vector> opt0_v; @@ -430,7 +431,7 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, ::art::Handle> 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 " << fopflash_ara_producer_v[i] << std::endl; + std::cout << "[LightCaloProducer] : " << "don't have good X-ARAPUCA flashes from producer " << fopflash_ara_producer_v[i] << std::endl; } else{ if (fopflash_ara_producer_v[i].find("tpc0") != std::string::npos) @@ -467,7 +468,7 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, 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(); + auto drift_time = clock_data.TPCTick2TrigTime(hit->PeakTime()); 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/fcal_area_const.at(hit_plane)); @@ -495,7 +496,7 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, 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(); + auto drift_time = clock_data.TPCTick2TrigTime(hit->PeakTime()); double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) double charge = (1/fcal_area_const.at(hit->View()))*atten_correction*hit->Integral(); if (xyz.X() < 0) has_sp0 = true; @@ -515,7 +516,7 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, // find matching flashes if slice has reco spacepoints in both TPCs if ((has_sp0 && has_sp1) && (opflash0.isNull() || opflash1.isNull())){ if (opflash0.isNull() && opflash1.isNull()){ - if (fverbose) std::cout << "No opflashes found for slice with spacepoints in both TPCs." << std::endl; + if (fverbose) std::cout << "[LightCaloProducer] : " << "No opflashes found for slice with spacepoints in both TPCs." << std::endl; return; } else if (opflash0.isNull()) opflash0 = FindMatchingFlash(flash0_v, opflash1->Time()); @@ -531,7 +532,7 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, flash_time = opflash1->Time(); } - if (flash_in_0==false && flash_in_1==false && fverbose) + if (flash_in_0==false && flash_in_1==false) return; // get total L count @@ -597,9 +598,9 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, _slice_E = (_slice_L + _slice_Q)*1e-9*g4param->Wph(); // GeV, Wph = 19.5 eV if (fverbose){ - std::cout << "charge: " << _slice_Q << std::endl; - std::cout << "light: " << _slice_L << std::endl; - std::cout << "energy: " << _slice_E << std::endl; + std::cout << "[LightCaloProducer] : " << "charge: " << _slice_Q << std::endl; + std::cout << "[LightCaloProducer] : " << "light: " << _slice_L << std::endl; + std::cout << "[LightCaloProducer] : " << "energy: " << _slice_E << std::endl; } sbn::LightCalo lightcalo{_slice_Q,_slice_L,_slice_E,bestHits}; @@ -657,7 +658,7 @@ void sbnd::LightCaloProducer::CollectMatches(const art::Handlefirst; auto flash_v = it->second; if (flash_v.size() > 2){ - std::cout << "more than two opflash matched to this slice!" << std::endl; + std::cout << "[LightCaloProducer] : " << "more than two opflash matched to this slice!" << std::endl; continue; } bool found_opflash0 = false; @@ -692,7 +693,7 @@ void sbnd::LightCaloProducer::CollectMatches(const art::Handle sbnd::LightCaloProducer::FindMatchingFlash(const std::vector> &flash_v, double ref_time) { - double best_dt = 1.e9; + double best_dt = std::numeric_limits::max(); art::Ptr best; for (size_t i = 0; i < flash_v.size(); ++i) { art::Ptr cand = flash_v[i]; From 2bfc1df3c464216d8cf79e1737c8fb0ec9df98e8 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 29 Jan 2026 10:45:52 -0600 Subject: [PATCH 086/155] Revert "Update to larsoft v10_14_02" This reverts commit 6ff86f194454b4a5e165aca44ee249a6523d5e50. --- CMakeLists.txt | 2 +- ups/product_deps | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 403af95fe..cd192f906 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ cmake_minimum_required(VERSION 3.20 FATAL_ERROR) -set(${PROJECT_NAME}_CMAKE_PROJECT_VERSION_STRING 10.14.02) +set(${PROJECT_NAME}_CMAKE_PROJECT_VERSION_STRING 10.14.00.01) find_package(cetmodules REQUIRED) project(sbndcode LANGUAGES CXX) diff --git a/ups/product_deps b/ups/product_deps index 2938e2336..9a6f2bb98 100644 --- a/ups/product_deps +++ b/ups/product_deps @@ -253,7 +253,7 @@ wpdir product_dir wire-cell-cfg # #################################### product version qual flags -sbncode v10_14_02 - +sbncode v10_14_00 - cetmodules v3_24_01 - only_for_build sbnd_data v01_41_00 - sbndutil v10_06_01 - optional From eb1a3a91f9f433b67c18cf72a8cf70cde137ede6 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 29 Jan 2026 11:08:06 -0600 Subject: [PATCH 087/155] Add electron lifetime database support to LightCaloProducer and update data fcl configuration --- sbndcode/Calorimetry/CMakeLists.txt | 1 + .../Calorimetry/LightCaloProducer_module.cc | 78 ++++++++++++++++++- sbndcode/Calorimetry/lightcalo_sbnd_data.fcl | 5 ++ 3 files changed, 81 insertions(+), 3 deletions(-) diff --git a/sbndcode/Calorimetry/CMakeLists.txt b/sbndcode/Calorimetry/CMakeLists.txt index d33d8946d..953ec0e64 100644 --- a/sbndcode/Calorimetry/CMakeLists.txt +++ b/sbndcode/Calorimetry/CMakeLists.txt @@ -4,6 +4,7 @@ set (MODULE_LIBRARIES larsim::LegacyLArG4 larcorealg::Geometry larcore::Geometry_Geometry_service + larevt::CalibrationDBI lardata::Utilities lardataobj::RecoBase art::Framework_Core diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index a570c9aba..e31562bd7 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -44,6 +44,10 @@ #include "lardata/DetectorInfoServices/DetectorClocksService.h" #include "lardata/DetectorInfoServices/DetectorPropertiesService.h" +// Calibration database includes for electron lifetime +#include "larevt/CalibrationDBI/Providers/DBFolder.h" +#include "wda.h" + // SBND includes #include "sbndcode/OpDetSim/sbndPDMapAlg.hh" #include "sbnobj/Common/Reco/LightCalo.h" @@ -121,6 +125,15 @@ class sbnd::LightCaloProducer : public art::EDProducer { // Returns the weighted mean of the light vector double CalcMean(std::vector total_light, std::vector total_err); + // Struct to hold electron lifetime data from database + struct ELifetimeInfo { + double tau_tpc0; + double tau_tpc1; + }; + + // Helper to get electron lifetime from database + ELifetimeInfo GetELifetimeFromDB(uint64_t run); + // fcl parameters std::vector fopflash_producer_v; std::vector fopflash_ara_producer_v; @@ -159,6 +172,13 @@ class sbnd::LightCaloProducer : public art::EDProducer { double fxarapucavuv_viseff; double fxarapucavis_eff; + // Electron lifetime database parameters + bool fuse_elifetime_db; + std::string felifetime_db_file; + std::string felifetime_db_tag; + std::unique_ptr felifetime_db; + std::map felifetime_cache; + std::vector fopdet_vuv_eff; std::vector fopdet_vis_eff; std::vector fopdet_mask; @@ -237,6 +257,14 @@ sbnd::LightCaloProducer::LightCaloProducer(fhicl::ParameterSet const& p) fxarapucavuv_viseff = p.get("XArapucaVUVVISEff"); fxarapucavis_eff = p.get("XArapucaVISEff"); + // Electron lifetime database configuration + fuse_elifetime_db = p.get("UseELifetimeDB", false); + if (fuse_elifetime_db) { + felifetime_db_file = p.get("ELifetimeDBFile"); + felifetime_db_tag = p.get("ELifetimeDBTag"); + felifetime_db = std::make_unique(felifetime_db_file, "", "", felifetime_db_tag, true, false); + } + // fill efficiency vectors fopdet_vuv_eff.resize(nchan,0.); fopdet_vis_eff.resize(nchan,0.); @@ -466,10 +494,23 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, bool has_sp0 = false; bool has_sp1 = false; + // Get electron lifetime (from database if enabled, otherwise from detector properties) + double elifetime_tpc0, elifetime_tpc1; + if (fuse_elifetime_db) { + ELifetimeInfo elife_info = GetELifetimeFromDB(e.id().run()); + elifetime_tpc0 = elife_info.tau_tpc0; + elifetime_tpc1 = elife_info.tau_tpc1; + } else { + elifetime_tpc0 = det_prop.ElectronLifetime(); + elifetime_tpc1 = det_prop.ElectronLifetime(); + } + for (size_t i=0; i < slice_hits_v.size(); i++){ auto hit = slice_hits_v[i]; auto drift_time = clock_data.TPCTick2TrigTime(hit->PeakTime()); - double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) + // Use TPC-specific electron lifetime + double elifetime = (hit->WireID().TPC == 0) ? elifetime_tpc0 : elifetime_tpc1; + double atten_correction = std::exp(drift_time/elifetime); // exp(us/us) auto hit_plane = hit->View(); plane_charge.at(hit_plane) += hit->Integral()*atten_correction*(1/fcal_area_const.at(hit_plane)); plane_hits.at(hit_plane)++; @@ -495,9 +536,10 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, if (hit->View() !=bestHits) continue; const auto &position(sp->XYZ()); geo::Point_t xyz(position[0],position[1],position[2]); - // correct for e- attenuation + // correct for e- attenuation using TPC-specific lifetime auto drift_time = clock_data.TPCTick2TrigTime(hit->PeakTime()); - double atten_correction = std::exp(drift_time/det_prop.ElectronLifetime()); // exp(us/us) + double elifetime = (hit->WireID().TPC == 0) ? elifetime_tpc0 : elifetime_tpc1; + double atten_correction = std::exp(drift_time/elifetime); // exp(us/us) double charge = (1/fcal_area_const.at(hit->View()))*atten_correction*hit->Integral(); if (xyz.X() < 0) has_sp0 = true; else has_sp1 = true; @@ -779,4 +821,34 @@ double sbnd::LightCaloProducer::CalcMean(std::vector total_gamma, std::v return total_mean; } +sbnd::LightCaloProducer::ELifetimeInfo sbnd::LightCaloProducer::GetELifetimeFromDB(uint64_t run) { + // Check cache first + if (felifetime_cache.count(run)) { + return felifetime_cache.at(run); + } + + // Query database - translate run into fake "timestamp" + // (same convention as NormalizeDriftSQLite) + felifetime_db->UpdateData((run + 1000000000) * 1000000000); + + ELifetimeInfo info; + double tau_E, tau_W; + felifetime_db->GetNamedChannelData(0, "etau_sce_spatial_east", tau_E); + felifetime_db->GetNamedChannelData(0, "etau_sce_spatial_west", tau_W); + + // TPC0 is East, TPC1 is West + info.tau_tpc0 = tau_E; + info.tau_tpc1 = tau_W; + + if (fverbose) { + std::cout << "[LightCaloProducer] : Electron lifetime from DB for run " << run << std::endl; + std::cout << "[LightCaloProducer] : TPC0 (East): " << info.tau_tpc0 << " us" << std::endl; + std::cout << "[LightCaloProducer] : TPC1 (West): " << info.tau_tpc1 << " us" << std::endl; + } + + // Cache the result + felifetime_cache[run] = info; + return info; +} + DEFINE_ART_MODULE(sbnd::LightCaloProducer) diff --git a/sbndcode/Calorimetry/lightcalo_sbnd_data.fcl b/sbndcode/Calorimetry/lightcalo_sbnd_data.fcl index 3f97ced95..ff08aaaab 100644 --- a/sbndcode/Calorimetry/lightcalo_sbnd_data.fcl +++ b/sbndcode/Calorimetry/lightcalo_sbnd_data.fcl @@ -1,4 +1,5 @@ #include "lightcalo_sbnd.fcl" +#include "calibration_database_GlobalTags_sbnd.fcl" BEGIN_PROLOG sbnd_lightcalo_data: @local::sbnd_lightcalo @@ -6,6 +7,10 @@ sbnd_lightcalo_data.CalAreaConstants: @local::sbnd_calorimetryalgdata.CalAreaCon sbnd_lightcalo_data.OpFlashMin: -0.8 # assumption is light-triggered data sbnd_lightcalo_data.OpFlashMax: 2.0 # assumption is light-triggered data +sbnd_lightcalo_data.UseELifetimeDB: true +sbnd_lightcalo_data.ELifetimeDBFile: tpc_elifetime +sbnd_lightcalo_data.ELifetimeDBTag: @local::SBND_Calibration_GlobalTags.tpc_elifetime_data + sbnd_lightcalo_data_sce: @local::sbnd_lightcalo_data sbnd_lightcalo_data_sce.SliceProducer: "pandoraSCE" sbnd_lightcalo_data_sce.OpT0FinderProducer: "opt0finderSCE" From 81a67e8e0a3b74d1e8b9e29468b3a51eb3b1875a Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 29 Jan 2026 14:07:31 -0600 Subject: [PATCH 088/155] order matters for reco workflow includes! --- sbndcode/JobConfigurations/standard/reco/reco2_data.fcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbndcode/JobConfigurations/standard/reco/reco2_data.fcl b/sbndcode/JobConfigurations/standard/reco/reco2_data.fcl index a47f11a7c..a5214dbf4 100755 --- a/sbndcode/JobConfigurations/standard/reco/reco2_data.fcl +++ b/sbndcode/JobConfigurations/standard/reco/reco2_data.fcl @@ -2,8 +2,8 @@ #include "sbnd_tpcpmt3dbarycentermatching_config.fcl" #include "sbnd_lightpropagationcorrection_config.fcl" #include "frameshift_sbnd_data.fcl" -#include "standard_reco2_sbnd.fcl" #include "lightcalo_sbnd_data.fcl" +#include "standard_reco2_sbnd.fcl" services: { From d6b3270e210f23c39b36a8ec3e0972122d2e0b9e Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 29 Jan 2026 14:21:28 -0600 Subject: [PATCH 089/155] update CMake dependences for TPC calibdb --- sbndcode/Calorimetry/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sbndcode/Calorimetry/CMakeLists.txt b/sbndcode/Calorimetry/CMakeLists.txt index 953ec0e64..f674709d4 100644 --- a/sbndcode/Calorimetry/CMakeLists.txt +++ b/sbndcode/Calorimetry/CMakeLists.txt @@ -4,7 +4,8 @@ set (MODULE_LIBRARIES larsim::LegacyLArG4 larcorealg::Geometry larcore::Geometry_Geometry_service - larevt::CalibrationDBI + larevt::CalibrationDBI_Providers + wda::wda lardata::Utilities lardataobj::RecoBase art::Framework_Core From 1a5e851b3c64a50810683bdd83b5446aa9eb1468 Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 29 Jan 2026 14:37:05 -0600 Subject: [PATCH 090/155] fix some elifetime bugs --- sbndcode/Calorimetry/LightCaloProducer_module.cc | 8 ++------ sbndcode/Calorimetry/lightcalo_sbnd_data.fcl | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index e31562bd7..963db2e33 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -172,7 +172,6 @@ class sbnd::LightCaloProducer : public art::EDProducer { double fxarapucavuv_viseff; double fxarapucavis_eff; - // Electron lifetime database parameters bool fuse_elifetime_db; std::string felifetime_db_file; std::string felifetime_db_tag; @@ -508,7 +507,6 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, for (size_t i=0; i < slice_hits_v.size(); i++){ auto hit = slice_hits_v[i]; auto drift_time = clock_data.TPCTick2TrigTime(hit->PeakTime()); - // Use TPC-specific electron lifetime double elifetime = (hit->WireID().TPC == 0) ? elifetime_tpc0 : elifetime_tpc1; double atten_correction = std::exp(drift_time/elifetime); // exp(us/us) auto hit_plane = hit->View(); @@ -536,7 +534,6 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, if (hit->View() !=bestHits) continue; const auto &position(sp->XYZ()); geo::Point_t xyz(position[0],position[1],position[2]); - // correct for e- attenuation using TPC-specific lifetime auto drift_time = clock_data.TPCTick2TrigTime(hit->PeakTime()); double elifetime = (hit->WireID().TPC == 0) ? elifetime_tpc0 : elifetime_tpc1; double atten_correction = std::exp(drift_time/elifetime); // exp(us/us) @@ -836,9 +833,8 @@ sbnd::LightCaloProducer::ELifetimeInfo sbnd::LightCaloProducer::GetELifetimeFrom felifetime_db->GetNamedChannelData(0, "etau_sce_spatial_east", tau_E); felifetime_db->GetNamedChannelData(0, "etau_sce_spatial_west", tau_W); - // TPC0 is East, TPC1 is West - info.tau_tpc0 = tau_E; - info.tau_tpc1 = tau_W; + info.tau_tpc0 = tau_E*1e3; // the db value is in ms, convert to us + info.tau_tpc1 = tau_W*1e3; // the db value is in ms, convert to us if (fverbose) { std::cout << "[LightCaloProducer] : Electron lifetime from DB for run " << run << std::endl; diff --git a/sbndcode/Calorimetry/lightcalo_sbnd_data.fcl b/sbndcode/Calorimetry/lightcalo_sbnd_data.fcl index ff08aaaab..f3bc835e2 100644 --- a/sbndcode/Calorimetry/lightcalo_sbnd_data.fcl +++ b/sbndcode/Calorimetry/lightcalo_sbnd_data.fcl @@ -8,7 +8,7 @@ sbnd_lightcalo_data.OpFlashMin: -0.8 # assumption is light-triggered data sbnd_lightcalo_data.OpFlashMax: 2.0 # assumption is light-triggered data sbnd_lightcalo_data.UseELifetimeDB: true -sbnd_lightcalo_data.ELifetimeDBFile: tpc_elifetime +sbnd_lightcalo_data.ELifetimeDBFile: "tpc_elifetime" sbnd_lightcalo_data.ELifetimeDBTag: @local::SBND_Calibration_GlobalTags.tpc_elifetime_data sbnd_lightcalo_data_sce: @local::sbnd_lightcalo_data From da3ae912507155fe40e17f07d35b03b2b2ad8d4d Mon Sep 17 00:00:00 2001 From: lynnt20 Date: Thu, 29 Jan 2026 15:05:19 -0600 Subject: [PATCH 091/155] move electron lifetime retrieval to avoid duplication during slice loop --- .../Calorimetry/LightCaloProducer_module.cc | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sbndcode/Calorimetry/LightCaloProducer_module.cc b/sbndcode/Calorimetry/LightCaloProducer_module.cc index 963db2e33..a4a1040a4 100644 --- a/sbndcode/Calorimetry/LightCaloProducer_module.cc +++ b/sbndcode/Calorimetry/LightCaloProducer_module.cc @@ -469,6 +469,17 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, } } + // Get electron lifetime (from database if enabled, otherwise from detector properties) + double elifetime_tpc0, elifetime_tpc1; + if (fuse_elifetime_db) { + ELifetimeInfo elife_info = GetELifetimeFromDB(e.id().run()); + elifetime_tpc0 = elife_info.tau_tpc0; + elifetime_tpc1 = elife_info.tau_tpc1; + } else { + elifetime_tpc0 = det_prop.ElectronLifetime(); + elifetime_tpc1 = det_prop.ElectronLifetime(); + } + for (size_t n_slice=0; n_slice < match_slices_v.size(); n_slice++){ // initialize tree variables _pfpid = -1; @@ -493,17 +504,6 @@ void sbnd::LightCaloProducer::CalculateCalorimetry(art::Event& e, bool has_sp0 = false; bool has_sp1 = false; - // Get electron lifetime (from database if enabled, otherwise from detector properties) - double elifetime_tpc0, elifetime_tpc1; - if (fuse_elifetime_db) { - ELifetimeInfo elife_info = GetELifetimeFromDB(e.id().run()); - elifetime_tpc0 = elife_info.tau_tpc0; - elifetime_tpc1 = elife_info.tau_tpc1; - } else { - elifetime_tpc0 = det_prop.ElectronLifetime(); - elifetime_tpc1 = det_prop.ElectronLifetime(); - } - for (size_t i=0; i < slice_hits_v.size(); i++){ auto hit = slice_hits_v[i]; auto drift_time = clock_data.TPCTick2TrigTime(hit->PeakTime()); From 9b056c49c2879a9eff2ff702b88881e60dc5324d Mon Sep 17 00:00:00 2001 From: Lynn Garren Date: Fri, 30 Jan 2026 14:08:34 -0600 Subject: [PATCH 092/155] remove or disable files which reference LegacyLArG4 --- .../LArG4/legacy_largeantmodules_sbnd.fcl | 8 - .../LArG4/legacy_simulationservices_sbnd.fcl | 146 ------------------ 2 files changed, 154 deletions(-) delete mode 100644 sbndcode/LArG4/legacy_largeantmodules_sbnd.fcl delete mode 100644 sbndcode/LArG4/legacy_simulationservices_sbnd.fcl diff --git a/sbndcode/LArG4/legacy_largeantmodules_sbnd.fcl b/sbndcode/LArG4/legacy_largeantmodules_sbnd.fcl deleted file mode 100644 index c6fe393c6..000000000 --- a/sbndcode/LArG4/legacy_largeantmodules_sbnd.fcl +++ /dev/null @@ -1,8 +0,0 @@ -#include "largeantmodules.fcl" - -BEGIN_PROLOG - -sbnd_largeant: @local::standard_largeant -sbnd_largeantana: @local::standard_largeantana - -END_PROLOG diff --git a/sbndcode/LArG4/legacy_simulationservices_sbnd.fcl b/sbndcode/LArG4/legacy_simulationservices_sbnd.fcl deleted file mode 100644 index d359ac6e6..000000000 --- a/sbndcode/LArG4/legacy_simulationservices_sbnd.fcl +++ /dev/null @@ -1,146 +0,0 @@ -# -# File: simulationservices_sbnd.fcl -# Purpose: collection of standard simulation service settings for SBND -# Version: 1.3 -# -# Provides: -# -# - sbnd_g4_services: services needed by LArG4 -# - sbnd_detsim_services: services needed by readout simulation -# - sbnd_simulation_services: bundle of services including Geant4, optical -# and electronics simulation (also includes the core ones) -# -# Use as: -# -# services: { -# @table::sbnd_simulation_services -# # ... -# } -# -# Changes: -# 20160601 (petrillo@fnal.gov) [v1.1] -# content moved from services_sbnd.fcl -# -# 20190807 (dbrailsf@fnal.gov) [v1.2] -# PhotonVisibilityService included in g4 servces table -# OpDetResponseInterface included in detsim services table -# Disabled sbnd_opsimulation_services table -# Enabled 'FastOptical' in the custom physics list (in largeantparameters) -# 20190807 (dbrailsf@fnal.gov) [v1.3] -# Added an optional largeantparameters config which does not run the optical sim -# 20200616 (ascarff@fnal.gov) [v1.4] -# Change diffusion constants to match ProtoDUNE data - - -#include "services_sbnd.fcl" -#include "simulationservices.fcl" -#include "spacecharge_sbnd.fcl" -#include "larfft_sbnd.fcl" -#include "signalservices_sbnd.fcl" -#include "magfield_larsoft.fcl" -#include "particleinventoryservice.fcl" -#include "backtrackerservice.fcl" -#include "spacecharge.fcl" -#include "noiseservices_sbnd.fcl" -#include "photpropservices_sbnd.fcl" - -BEGIN_PROLOG - -sbnd_largeantparameters: @local::standard_largeantparameters # from simulationservices.fcl -sbnd_largeantparameters.ElectronClusterSize: 20.0 -#Brailsford 27/10/09: Enable the custom physics list and disable its neutron killer -sbnd_largeantparameters.UseCustomPhysics: true -sbnd_largeantparameters.EnabledPhysics: [ "Em", "FastOptical", "SynchrotronAndGN", "Ion", "Hadron", "Decay", "HadronElastic", "Stopping" ] #Removed the neutron killer -sbnd_largeantparameters.UseLitePhotons: true -sbnd_largeantparameters.UseModBoxRecomb: false -sbnd_largeantparameters.UseEllipsModBoxRecomb: true - -#Define a largeantparameters which doesn't use the optical simulation -sbnd_largeantparameters_noopticalsim: @local::sbnd_largeantparameters -sbnd_largeantparameters_noopticalsim.EnabledPhysics: [ "Em", "SynchrotronAndGN", "Ion", "Hadron", "Decay", "HadronElastic", "Stopping" ] -sbnd_largeantparameters_noopticalsim.UseModBoxRecomb: false -sbnd_largeantparameters_noopticalsim.UseEllipsModBoxRecomb: true - -# ascarff 16Jun2020: Change the diffusion constants to match ProtoDUNE results -sbnd_largeantparameters.LongitudinalDiffusion: 4.0e-9 #in cm^2/ns (was 6.2e-9) -sbnd_largeantparameters.TransverseDiffusion: 8.8e-9 #in cm^2/ns (was 16.3e-9) -sbnd_largeantparameters_noopticalsim.LongitudinalDiffusion: 4.0e-9 #in cm^2/ns (was 6.2e-9) -sbnd_largeantparameters_noopticalsim.TransverseDiffusion: 8.8e-9 #in cm^2/ns (was 16.3e-9) - -# gputnam 19Aug2024: Add in service configuration without EMB recombination -sbnd_largeantparameters_modbox: @local::sbnd_largeantparameters -sbnd_largeantparameters_modbox.UseModBoxRecomb: true -sbnd_largeantparameters_modbox.UseEllipsModBoxRecomb: false - - -sbnd_larvoxelcalculator: @local::standard_larvoxelcalculator # from simulationservices.fcl - -sbnd_backtrackerservice: @local::standard_backtrackerservice # from backtrackerservice.fcl - -sbnd_backtrackerservice.BackTracker.G4ModuleLabel: "largeant" -sbnd_backtrackerservice.BackTracker.MinimumHitEnergyFraction: 1e-1 -sbnd_backtrackerservice.BackTracker.OverrideRealData: true - -sbnd_particleinventoryservice: @local::standard_particleinventoryservice - -# Define sbnd_g4_services -sbnd_g4_services: -{ - @table::sbnd_services - @table::sbnd_random_services - LArG4Parameters: @local::sbnd_largeantparameters - LArVoxelCalculator: @local::sbnd_larvoxelcalculator - MagneticField: @local::no_mag_larsoft - PhotonVisibilityService: @local::sbnd_Nhits_vuv_vis_prop_timing_photonvisibilityservice -} # sbnd_g4_services - - - -# Define sbnd_detsim_services -sbnd_detsim_services: -{ - @table::sbnd_services - @table::sbnd_random_services - LArFFT: @local::sbnd_larfft - SignalShapingServiceSBND: @local::sbnd_signalshapingservice # from signalservices_sbnd.fcl - NoiseModel: @local::sbnd_uboonedatadrivennoiseservice - OpDetResponseInterface: @local::sbnd_opdetresponse -} # sbnd_detsim_services - - -# Define sbnd_simulation_services -sbnd_simulation_services: -{ - @table::sbnd_services - @table::sbnd_random_services - @table::sbnd_g4_services - @table::sbnd_detsim_services - SignalShapingServiceSBND: @local::sbnd_signalshapingservice # from signalservices_sbnd.fcl - SpaceCharge: @local::sbnd_spacecharge -} - - -#sbnd_opsimulation_services: -#{ -# @table::sbnd_simulation_services -# OpDetResponseInterface: @local::sbnd_opdetresponse -## PhotonVisibilityService: @local::sbnd_photonvisibilityservice -## OpDigiProperties: @local::sbnd_opdigiproperties -#} - - -# Define sbnd_optical_simulation_services -#sbnd_optical_simulation_services.LArPropertiesService.ScintYield: 24000 -#sbnd_optical_simulation_services.LArPropertiesService.EnableCerenkovLight: false -#sbnd_optical_simulation_services.LArG4Parameters.UseCustomPhysics: true -#sbnd_optical_simulation_services.LArG4Parameters.EnabledPhysics: [ "Em", -# "FastOptical", -# "SynchrotronAndGN", -# "Ion", -# "Hadron", -# "Decay", -# "HadronElastic", -# "Stopping", -# "NeutronTrackingCut" ] - -END_PROLOG From 9297360ffcfbabc353a80eac8be354b0e9ea23e3 Mon Sep 17 00:00:00 2001 From: Lynn Garren Date: Fri, 30 Jan 2026 14:08:50 -0600 Subject: [PATCH 093/155] remove or disable files which reference LegacyLArG4 --- sbndcode/JobConfigurations/standard/detsim/CMakeLists.txt | 3 ++- sbndcode/JobConfigurations/standard/g4/CMakeLists.txt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sbndcode/JobConfigurations/standard/detsim/CMakeLists.txt b/sbndcode/JobConfigurations/standard/detsim/CMakeLists.txt index 0b3773a0c..5803f01d3 100644 --- a/sbndcode/JobConfigurations/standard/detsim/CMakeLists.txt +++ b/sbndcode/JobConfigurations/standard/detsim/CMakeLists.txt @@ -4,5 +4,6 @@ FILE(GLOB fcl_files *.fcl) install_source(EXTRAS ${fcl_files} ) add_subdirectory(detector_variations) -add_subdirectory(legacy) +# LegacyLArG4 is not supported when using geant4 4.11 +##add_subdirectory(legacy) diff --git a/sbndcode/JobConfigurations/standard/g4/CMakeLists.txt b/sbndcode/JobConfigurations/standard/g4/CMakeLists.txt index 91660cfa0..a82cc1a6b 100644 --- a/sbndcode/JobConfigurations/standard/g4/CMakeLists.txt +++ b/sbndcode/JobConfigurations/standard/g4/CMakeLists.txt @@ -7,4 +7,5 @@ add_subdirectory(recomb_variations) add_subdirectory(crt_filter) add_subdirectory(optical_sim) -add_subdirectory(legacy) +# LegacyLArG4 is not supported when using geant4 4.11 +##add_subdirectory(legacy) From a531049c055fad69623d5355ad56071d001722d8 Mon Sep 17 00:00:00 2001 From: Lynn Garren Date: Fri, 30 Jan 2026 14:09:03 -0600 Subject: [PATCH 094/155] remove or disable files which reference LegacyLArG4 --- test/fcl/testFHiCLfiles_sbnd.sh | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/test/fcl/testFHiCLfiles_sbnd.sh b/test/fcl/testFHiCLfiles_sbnd.sh index b9eda6ec0..b2f1695a2 100755 --- a/test/fcl/testFHiCLfiles_sbnd.sh +++ b/test/fcl/testFHiCLfiles_sbnd.sh @@ -46,13 +46,14 @@ if [[ -n "$MRB_BUILDDIR" ]]; then fi fi -if [[ -n "$MRB_SOURCE" ]]; then - SourceFHiCLdir="${MRB_SOURCE}/sbndcode/sbndcode/JobConfigurations" - if [[ -d "$SourceFHiCLdir" ]]; then - echo "Will test the job configuration directory in MRB source area ('${SourceFHiCLdir}')" - TestDirs+=( "$SourceFHiCLdir" ) - fi -fi +# DO NOT test files that are not installed +#if [[ -n "$MRB_SOURCE" ]]; then +# SourceFHiCLdir="${MRB_SOURCE}/sbndcode/sbndcode/JobConfigurations" +# if [[ -d "$SourceFHiCLdir" ]]; then +# echo "Will test the job configuration directory in MRB source area ('${SourceFHiCLdir}')" +# TestDirs+=( "$SourceFHiCLdir" ) +# fi +#fi if [[ "${#TestDirs[@]}]" == 0 ]]; then echo "FATAL: no suitable FHiCL directory found to be tested!" >&2 From cc0cd3ac7f7f101f4541a431927622aba24f2fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20V=C3=A1zquez-Ramos?= Date: Tue, 3 Feb 2026 11:21:27 -0600 Subject: [PATCH 095/155] Restore the shower merging algorithm in another place to avoid inconsistent state of PFParticles (-1 track scores). --- .../scripts/PandoraSettings_Neutrino_SBND.xml | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sbndcode/SBNDPandora/scripts/PandoraSettings_Neutrino_SBND.xml b/sbndcode/SBNDPandora/scripts/PandoraSettings_Neutrino_SBND.xml index 0fb9f13d0..1c177a684 100644 --- a/sbndcode/SBNDPandora/scripts/PandoraSettings_Neutrino_SBND.xml +++ b/sbndcode/SBNDPandora/scripts/PandoraSettings_Neutrino_SBND.xml @@ -447,6 +447,39 @@ TrackParticles3D ShowerParticles3D DaughterVertices3D ClustersU ClustersV ClustersW TrackClusters3D ShowerClusters3D + + + TrackParticles3D ShowerParticles3D + TrackParticles3D ShowerParticles3D DaughterVertices3D ClustersU ClustersV ClustersW TrackClusters3D ShowerClusters3D + + + + + TrackParticles3D + ShowerParticles3D + true + PandoraMVAs/PandoraBdt_SBND.xml + PfoCharBDT2 + PandoraMVAs/PandoraBdt_SBND.xml + PfoCharBDTNoChargeInfo2 + 0.51 + true + + + + + + + + + + + + + + + + NeutrinoParticles3D From 888ecbbaa3c530acc23aafa9e53e17e9a7453936 Mon Sep 17 00:00:00 2001 From: AndyChappell Date: Thu, 5 Feb 2026 02:48:32 -0600 Subject: [PATCH 096/155] Add fcl and pandora xml to support cluster validation metrics in ci system --- .../standard/reco/ci_reco2_sbnd.fcl | 4 ++ .../scripts/PandoraSettings_CI_SBND.xml | 52 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 sbndcode/JobConfigurations/standard/reco/ci_reco2_sbnd.fcl create mode 100644 sbndcode/SBNDPandora/scripts/PandoraSettings_CI_SBND.xml diff --git a/sbndcode/JobConfigurations/standard/reco/ci_reco2_sbnd.fcl b/sbndcode/JobConfigurations/standard/reco/ci_reco2_sbnd.fcl new file mode 100644 index 000000000..0ae1c3621 --- /dev/null +++ b/sbndcode/JobConfigurations/standard/reco/ci_reco2_sbnd.fcl @@ -0,0 +1,4 @@ +#include "standard_reco2_sbnd.fcl" + +physics.producers.pandora.ConfigFile: "PandoraSettings_CI_SBND.xml" +physics.producers.pandora.EnableMCParticles: true diff --git a/sbndcode/SBNDPandora/scripts/PandoraSettings_CI_SBND.xml b/sbndcode/SBNDPandora/scripts/PandoraSettings_CI_SBND.xml new file mode 100644 index 000000000..fede0b0e7 --- /dev/null +++ b/sbndcode/SBNDPandora/scripts/PandoraSettings_CI_SBND.xml @@ -0,0 +1,52 @@ + + + true + false + true + + + + CaloHitListU + CaloHitListV + CaloHitListW + CaloHitList2D + CaloHitList2D + + + + PandoraSettings_Cosmic_SBND.xml + PandoraSettings_Neutrino_SBND.xml + PandoraSettings_Slicing_Standard.xml + + true + false + + + + + + + PandoraMVAs/PandoraBdt_SBND.xml + NeutrinoId + 0 + -1 + 999 + true + + + CaloHitList2D + RecreatedPfos + RecreatedClusters + RecreatedVertices + false + + + + ci_pandora_clusters.root + pandora_clusters + RecreatedClusters + CaloHitList2D + 5 + true + + From bcb99eed83a9a0d6bf07bec57747ed0f05119f11 Mon Sep 17 00:00:00 2001 From: AndyChappell Date: Thu, 5 Feb 2026 04:09:42 -0600 Subject: [PATCH 097/155] Add synchronisation comment to Pandora Master xml --- sbndcode/SBNDPandora/scripts/PandoraSettings_Master_SBND.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sbndcode/SBNDPandora/scripts/PandoraSettings_Master_SBND.xml b/sbndcode/SBNDPandora/scripts/PandoraSettings_Master_SBND.xml index 93658e987..aefbce4da 100644 --- a/sbndcode/SBNDPandora/scripts/PandoraSettings_Master_SBND.xml +++ b/sbndcode/SBNDPandora/scripts/PandoraSettings_Master_SBND.xml @@ -1,3 +1,7 @@ + false From 542d2f53748ac2646c619e51a8a342b2c54fe9c5 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Thu, 3 Apr 2025 11:56:51 -0500 Subject: [PATCH 098/155] Add CRTBlob producer --- sbndcode/CRT/CRTReco/CMakeLists.txt | 6 + .../CRT/CRTReco/CRTBlobProducer_module.cc | 219 ++++++++++++++++++ .../CRT/CRTReco/crtrecoproducers_sbnd.fcl | 11 + 3 files changed, 236 insertions(+) create mode 100644 sbndcode/CRT/CRTReco/CRTBlobProducer_module.cc diff --git a/sbndcode/CRT/CRTReco/CMakeLists.txt b/sbndcode/CRT/CRTReco/CMakeLists.txt index 3ea86c28c..f17015c69 100644 --- a/sbndcode/CRT/CRTReco/CMakeLists.txt +++ b/sbndcode/CRT/CRTReco/CMakeLists.txt @@ -37,4 +37,10 @@ simple_plugin( Eigen3::Eigen ) +simple_plugin( + CRTBlobProducer module + sbnobj::SBND_CRT + sbndcode_GeoWrappers +) + install_fhicl() diff --git a/sbndcode/CRT/CRTReco/CRTBlobProducer_module.cc b/sbndcode/CRT/CRTReco/CRTBlobProducer_module.cc new file mode 100644 index 000000000..0ea91e935 --- /dev/null +++ b/sbndcode/CRT/CRTReco/CRTBlobProducer_module.cc @@ -0,0 +1,219 @@ +//////////////////////////////////////////////////////////////////////// +// Class: CRTBlobProducer +// Plugin Type: producer +// File: CRTBlobProducer_module.cc +// +// Author: Henry Lay (h.lay@sheffield.ac.uk) +//////////////////////////////////////////////////////////////////////// + +#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 "canvas/Persistency/Common/FindOneP.h" +#include "fhiclcpp/ParameterSet.h" +#include "messagefacility/MessageLogger/MessageLogger.h" + +#include "lardata/Utilities/AssociationUtil.h" + +#include "sbnobj/SBND/CRT/CRTCluster.hh" +#include "sbnobj/SBND/CRT/CRTSpacePoint.hh" +#include "sbnobj/SBND/CRT/CRTBlob.hh" + +#include + +namespace sbnd::crt { + class CRTBlobProducer; +} + +class sbnd::crt::CRTBlobProducer : public art::EDProducer { +public: + explicit CRTBlobProducer(fhicl::ParameterSet const& p); + + CRTBlobProducer(CRTBlobProducer const&) = delete; + CRTBlobProducer(CRTBlobProducer&&) = delete; + CRTBlobProducer& operator=(CRTBlobProducer const&) = delete; + CRTBlobProducer& operator=(CRTBlobProducer&&) = delete; + + void produce(art::Event& e) override; + + void OrderSpacePoints(std::vector> &spacePointVec, const art::FindOneP &spacePointsToCluster); + + std::vector>> CreateBlobCandidates(const std::vector> &spacePointVec, + const art::FindOneP &spacePointsToCluster); + + void TimeErrorCalculator(const std::vector ×, double &mean, double &err); + + void OrderBlobCandidates(std::vector>> &blobCandidates); + + std::vector>> ChoseBlobs(std::vector>> &blobCandidates); + +private: + + std::string fCRTSpacePointModuleLabel; + double fCoincidenceTimeRequirement; + bool fUseTs0; +}; + + +sbnd::crt::CRTBlobProducer::CRTBlobProducer(fhicl::ParameterSet const& p) + : EDProducer{p} + , fCRTSpacePointModuleLabel(p.get("CRTSpacePointModuleLabel")) + , fCoincidenceTimeRequirement(p.get("CoincidenceTimeRequirement")) + , fUseTs0(p.get("UseTs0")) +{ + produces>(); + produces>(); +} + +void sbnd::crt::CRTBlobProducer::produce(art::Event& e) +{ + auto blobVec = std::make_unique>(); + auto blobSpacePointAssn = std::make_unique>(); + + art::Handle> CRTSpacePointHandle; + e.getByLabel(fCRTSpacePointModuleLabel, CRTSpacePointHandle); + + std::vector> CRTSpacePointVec; + art::fill_ptr_vector(CRTSpacePointVec, CRTSpacePointHandle); + + art::FindOneP spacePointsToCluster(CRTSpacePointHandle, e, fCRTSpacePointModuleLabel); + + OrderSpacePoints(CRTSpacePointVec, spacePointsToCluster); + + std::vector>> blobCandidates = CreateBlobCandidates(CRTSpacePointVec, spacePointsToCluster); + + OrderBlobCandidates(blobCandidates); + + std::vector>> chosenBlobs = ChoseBlobs(blobCandidates); + + for(auto const& [blob, spIDs] : chosenBlobs) + { + blobVec->push_back(blob); + + for(auto const& spID : spIDs) + util::CreateAssn(*this, e, *blobVec, CRTSpacePointVec[spID], *blobSpacePointAssn); + } + + e.put(std::move(blobVec)); + e.put(std::move(blobSpacePointAssn)); +} + +void sbnd::crt::CRTBlobProducer::OrderSpacePoints(std::vector> &spacePointVec, const art::FindOneP &spacePointsToCluster) +{ + std::sort(spacePointVec.begin(), spacePointVec.end(), + [&](const art::Ptr &a, const art::Ptr &b) -> bool { + if(fUseTs0) + return a->Ts0() < b->Ts0(); + else + return a->Ts1() < b->Ts1(); + }); +} + +std::vector>> sbnd::crt::CRTBlobProducer::CreateBlobCandidates(const std::vector> &spacePointVec, + const art::FindOneP &spacePointsToCluster) +{ + std::vector>> candidates; + + for(unsigned i = 0; i < spacePointVec.size(); ++i) + { + const art::Ptr primarySpacePoint = spacePointVec[i]; + const art::Ptr primaryCluster = spacePointsToCluster.at(primarySpacePoint.key()); + + std::set used_spacepoints = { i }; + std::vector t0s = { primarySpacePoint->Ts0() }; + std::vector t1s = { primarySpacePoint->Ts1() }; + std::vector pes = { primarySpacePoint->PE() }; + + std::map taggers; + for(int i = 0; i < 7; ++i) + taggers[(CRTTagger)i] = 0; + ++taggers[primaryCluster->Tagger()]; + + for(unsigned ii = i+1; ii < spacePointVec.size(); ++ii) + { + const art::Ptr secondarySpacePoint = spacePointVec[ii]; + const art::Ptr secondaryCluster = spacePointsToCluster.at(secondarySpacePoint.key()); + + const double tdiff_prim_sec = fUseTs0 ? secondarySpacePoint->Ts0() - primarySpacePoint->Ts0() : secondarySpacePoint->Ts1() - primarySpacePoint->Ts1(); + + if(tdiff_prim_sec > fCoincidenceTimeRequirement) + break; + + used_spacepoints.insert(ii); + t0s.push_back(secondarySpacePoint->Ts0()); + t1s.push_back(secondarySpacePoint->Ts1()); + pes.push_back(secondarySpacePoint->PE()); + ++taggers[secondaryCluster->Tagger()]; + } + + double t0, et0; + TimeErrorCalculator(t0s, t0, et0); + + double t1, et1; + TimeErrorCalculator(t1s, t1, et1); + + const double pe = std::accumulate(pes.begin(), pes.end(), 0.); + + const CRTBlob blob(t0, et0, t1, et1, pe, taggers); + + candidates.emplace_back(blob, used_spacepoints); + } + + return candidates; +} + +void sbnd::crt::CRTBlobProducer::TimeErrorCalculator(const std::vector ×, double &mean, double &err) +{ + double sum = 0.; + for(auto const &time : times) + sum += time; + + mean = sum / times.size(); + + double summed_var = 0.; + for(auto const &time : times) + summed_var += std::pow((time - mean), 2); + + err = std::sqrt(summed_var / (times.size() - 1)); +} + +void sbnd::crt::CRTBlobProducer::OrderBlobCandidates(std::vector>> &blobCandidates) +{ + std::sort(blobCandidates.begin(), blobCandidates.end(), + [&](const std::pair> &a, const std::pair> &b) -> bool { + return fUseTs0 ? a.first.Ts0Err() < b.first.Ts0Err() : a.first.Ts1Err() < b.first.Ts1Err(); + }); +} + +std::vector>> sbnd::crt::CRTBlobProducer::ChoseBlobs(std::vector>> &blobCandidates) +{ + std::vector>> chosenBlobs; + + std::set used; + + for(auto const& [blob, spIDs] : blobCandidates) + { + bool keep = true; + for(auto const& spID : spIDs) + { + if(used.count(spID) != 0) + keep = false; + } + + if(keep) + { + chosenBlobs.emplace_back(blob, spIDs); + + for(auto const& spID : spIDs) + used.insert(spID); + } + } + + return chosenBlobs; +} + +DEFINE_ART_MODULE(sbnd::crt::CRTBlobProducer) diff --git a/sbndcode/CRT/CRTReco/crtrecoproducers_sbnd.fcl b/sbndcode/CRT/CRTReco/crtrecoproducers_sbnd.fcl index 9aa8e2a26..0b4ca1c3c 100644 --- a/sbndcode/CRT/CRTReco/crtrecoproducers_sbnd.fcl +++ b/sbndcode/CRT/CRTReco/crtrecoproducers_sbnd.fcl @@ -78,4 +78,15 @@ crttrackproducer_data_sbnd: @local::crttrackproducer_sbnd crttrackproducer_data_sbnd.UseTs0: true crttrackproducer_data_sbnd.MaskedTaggers: [ ] +crtblobproducer_sbnd: +{ + CRTSpacePointModuleLabel: "crtspacepoints" + CoincidenceTimeRequirement: 100. + UseTs0: false + module_type: "CRTBlobProducer" +} + +crtblobproducer_data_sbnd: @local::crtblobproducer_sbnd +crtblobproducer_data_sbnd.UseTs0: true + END_PROLOG From 5811843ff090310ea0a9187b259d36d9b9077003 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Thu, 3 Apr 2025 11:58:11 -0500 Subject: [PATCH 099/155] Add blobs to CRT only fcls --- sbndcode/CRT/CRTReco/run_crtblobreco.fcl | 38 +++++++++++++++++++++++ sbndcode/CRT/CRTReco/run_crtreco.fcl | 3 +- sbndcode/CRT/CRTReco/run_crtreco_data.fcl | 1 + sbndcode/CRT/CRTReco/run_crtrecoana.fcl | 3 +- 4 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 sbndcode/CRT/CRTReco/run_crtblobreco.fcl diff --git a/sbndcode/CRT/CRTReco/run_crtblobreco.fcl b/sbndcode/CRT/CRTReco/run_crtblobreco.fcl new file mode 100644 index 000000000..7d46331d2 --- /dev/null +++ b/sbndcode/CRT/CRTReco/run_crtblobreco.fcl @@ -0,0 +1,38 @@ +#include "services_sbnd.fcl" +#include "rootoutput_sbnd.fcl" +#include "crtrecoproducers_sbnd.fcl" + +process_name: CRTBlobReco + +services: +{ + @table::sbnd_services +} + +source: +{ + module_type: RootInput +} + +outputs: +{ + out1: + { + @table::sbnd_rootoutput + dataTier: "reconstructed" + } +} + +physics: +{ + producers: + { + crtblobs: @local::crtblobproducer_sbnd + } + + reco: [ crtblobs ] + stream1: [ out1 ] + + trigger_paths: [ reco ] + end_paths: [ stream1 ] +} diff --git a/sbndcode/CRT/CRTReco/run_crtreco.fcl b/sbndcode/CRT/CRTReco/run_crtreco.fcl index 3a625c1b7..585238a0a 100644 --- a/sbndcode/CRT/CRTReco/run_crtreco.fcl +++ b/sbndcode/CRT/CRTReco/run_crtreco.fcl @@ -33,9 +33,10 @@ physics: crtclustering: @local::crtclusterproducer_sbnd crtspacepoints: @local::crtspacepointproducer_sbnd crttracks: @local::crttrackproducer_sbnd + crtblobs: @local::crtblobproducer_sbnd } - reco: [ crtstrips, crtclustering, crtspacepoints, crttracks ] + reco: [ crtstrips, crtclustering, crtspacepoints, crttracks, crtblobs ] stream1: [ out1 ] trigger_paths: [ reco ] diff --git a/sbndcode/CRT/CRTReco/run_crtreco_data.fcl b/sbndcode/CRT/CRTReco/run_crtreco_data.fcl index 2493c9b33..9e179b108 100644 --- a/sbndcode/CRT/CRTReco/run_crtreco_data.fcl +++ b/sbndcode/CRT/CRTReco/run_crtreco_data.fcl @@ -10,6 +10,7 @@ physics.producers.crtstrips: @local::crtstriphitproducer_data_sbnd physics.producers.crtclustering: @local::crtclusterproducer_data_sbnd physics.producers.crtspacepoints: @local::crtspacepointproducer_data_sbnd physics.producers.crttracks: @local::crttrackproducer_data_sbnd +physics.producers.crtblobs: @local::crtblobproducer_data_sbnd outputs.out1.outputCommands: [ "keep *_*_*_*", "drop *_daq_*_*", diff --git a/sbndcode/CRT/CRTReco/run_crtrecoana.fcl b/sbndcode/CRT/CRTReco/run_crtrecoana.fcl index 983502ca8..6e9f6d8c8 100644 --- a/sbndcode/CRT/CRTReco/run_crtrecoana.fcl +++ b/sbndcode/CRT/CRTReco/run_crtrecoana.fcl @@ -37,6 +37,7 @@ physics: crtclustering: @local::crtclusterproducer_sbnd crtspacepoints: @local::crtspacepointproducer_sbnd crttracks: @local::crttrackproducer_sbnd + crtblobs: @local::crtblobproducer_sbnd } analyzers: @@ -44,7 +45,7 @@ physics: crtana: @local::crtana_sbnd } - reco: [ crtstrips, crtclustering, crtspacepoints, crttracks ] + reco: [ crtstrips, crtclustering, crtspacepoints, crttracks, crtblobs ] ana: [ crtana ] stream1: [ out1 ] From 8dba4972baeb079d312346e1634ce81f96b42a35 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Mon, 16 Feb 2026 05:57:59 -0600 Subject: [PATCH 100/155] Modernise CMakeLists --- sbndcode/CRT/CRTReco/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbndcode/CRT/CRTReco/CMakeLists.txt b/sbndcode/CRT/CRTReco/CMakeLists.txt index f17015c69..ad5cfc7cb 100644 --- a/sbndcode/CRT/CRTReco/CMakeLists.txt +++ b/sbndcode/CRT/CRTReco/CMakeLists.txt @@ -39,8 +39,8 @@ simple_plugin( simple_plugin( CRTBlobProducer module + lardata::Utilities sbnobj::SBND_CRT - sbndcode_GeoWrappers ) install_fhicl() From 5cb14c3ed066bdf7e45b1955dd4b48fe97fb2132 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Thu, 20 Feb 2025 08:12:04 -0600 Subject: [PATCH 101/155] Change ADC saturation value to match data --- sbndcode/CRT/CRTSimulation/crtsimmodules_sbnd.fcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbndcode/CRT/CRTSimulation/crtsimmodules_sbnd.fcl b/sbndcode/CRT/CRTSimulation/crtsimmodules_sbnd.fcl index 2d9acb68e..ca546268b 100644 --- a/sbndcode/CRT/CRTSimulation/crtsimmodules_sbnd.fcl +++ b/sbndcode/CRT/CRTSimulation/crtsimmodules_sbnd.fcl @@ -58,7 +58,7 @@ standard_sbnd_crtsimparams: { # Minimum time between energy deposits that SiPMs can resolve [ns] SipmTimeResponse: 2.0 - AdcSaturation: 4095 + AdcSaturation: 4089 DeadTime: 22000 From 6220ac49bff507347a458c0b284887e7eb0cac50 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Thu, 20 Feb 2025 08:13:41 -0600 Subject: [PATCH 102/155] Use saturation to correctly label strip hits --- sbndcode/CRT/CRTReco/CRTStripHitProducer_module.cc | 4 +++- sbndcode/CRT/CRTReco/crtrecoproducers_sbnd.fcl | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sbndcode/CRT/CRTReco/CRTStripHitProducer_module.cc b/sbndcode/CRT/CRTReco/CRTStripHitProducer_module.cc index 1f212abd1..fe536a734 100644 --- a/sbndcode/CRT/CRTReco/CRTStripHitProducer_module.cc +++ b/sbndcode/CRT/CRTReco/CRTStripHitProducer_module.cc @@ -62,6 +62,7 @@ class sbnd::crt::CRTStripHitProducer : public art::EDProducer { std::string fFEBDataModuleLabel; uint16_t fADCThreshold; + uint16_t fADCSaturation; std::vector fErrorCoeff; bool fAllowFlag1; bool fApplyTs0Window; @@ -88,6 +89,7 @@ sbnd::crt::CRTStripHitProducer::CRTStripHitProducer(fhicl::ParameterSet const& p : EDProducer{p} , fFEBDataModuleLabel(p.get("FEBDataModuleLabel")) , fADCThreshold(p.get("ADCThreshold")) + , fADCSaturation(p.get("ADCSaturation")) , fErrorCoeff(p.get>("ErrorCoeff")) , fAllowFlag1(p.get("AllowFlag1")) , fApplyTs0Window(p.get("ApplyTs0Window")) @@ -290,7 +292,7 @@ std::vector sbnd::crt::CRTStripHitProducer::CreateStripH if(pos - err < 0) err = pos; - stripHits.emplace_back(offline_channel_id, t0, t1, ref_time_s, pos, err, adc1, adc2); + stripHits.emplace_back(offline_channel_id, t0, t1, ref_time_s, pos, err, adc1, adc2, fADCSaturation); } } diff --git a/sbndcode/CRT/CRTReco/crtrecoproducers_sbnd.fcl b/sbndcode/CRT/CRTReco/crtrecoproducers_sbnd.fcl index 9aa8e2a26..2de95131c 100644 --- a/sbndcode/CRT/CRTReco/crtrecoproducers_sbnd.fcl +++ b/sbndcode/CRT/CRTReco/crtrecoproducers_sbnd.fcl @@ -6,6 +6,7 @@ crtstriphitproducer_sbnd: { FEBDataModuleLabel: "crtsim" ADCThreshold: 60 + ADCSaturation: @local::sbnd_crtsim.DetSimParams.AdcSaturation ErrorCoeff: [ 0.26, -0.27, 0.025 ] AllowFlag1: false ApplyTs0Window: false From ae474af618dae9a371e030e97641d022ebf64ad9 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Tue, 17 Feb 2026 10:58:08 -0600 Subject: [PATCH 103/155] Add option for blob branches in CRTAnalysis module --- sbndcode/CRT/CRTAna/CRTAnalysis_module.cc | 78 ++++++++++++++++++++++- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc b/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc index 948d3fd4c..29f6614c9 100644 --- a/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc +++ b/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc @@ -33,6 +33,7 @@ #include "sbnobj/SBND/CRT/CRTCluster.hh" #include "sbnobj/SBND/CRT/CRTSpacePoint.hh" #include "sbnobj/SBND/CRT/CRTTrack.hh" +#include "sbnobj/SBND/CRT/CRTBlob.hh" #include "sbnobj/SBND/Timing/DAQTimestamp.hh" #include "sbndcode/Geometry/GeometryWrappers/CRTGeoService.h" @@ -87,6 +88,8 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { void AnalyseCRTTracks(const art::Event &e, const std::vector> &CRTTrackVec, const art::FindManyP &tracksToSpacePoints, const art::FindOneP &spacePointsToClusters, const art::FindManyP &clustersToStripHits); + void AnalyseCRTBlobs(std::vector> &CRTBlobVec); + void AnalyseTPCMatching(const art::Event &e, const art::Handle> &TPCTrackHandle, const art::Handle> &CRTSpacePointHandle, const art::Handle> &CRTClusterHandle, const art::Handle> &PFPHandle, @@ -104,10 +107,10 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { CRTBackTrackerAlg fCRTBackTrackerAlg; std::string fMCParticleModuleLabel, fSimDepositModuleLabel, fFEBDataModuleLabel, fCRTStripHitModuleLabel, - fCRTClusterModuleLabel, fCRTSpacePointModuleLabel, fCRTTrackModuleLabel, fTPCTrackModuleLabel, + fCRTClusterModuleLabel, fCRTSpacePointModuleLabel, fCRTTrackModuleLabel, fCRTBlobModuleLabel, fTPCTrackModuleLabel, fCRTSpacePointMatchingModuleLabel, fCRTTrackMatchingModuleLabel, fPFPModuleLabel, fPTBModuleLabel, fTDCModuleLabel, fTimingReferenceModuleLabel; - bool fDebug, fDataMode, fNoTPC, fHasPTB, fHasTDC, fTruthMatch; + bool fDebug, fDataMode, fNoTPC, fHasPTB, fHasTDC, fHasBlobs, fTruthMatch; //! Adding some of the reco parameters to save corrections double fPEAttenuation, fTimeWalkNorm, fTimeWalkScale, fPropDelay; @@ -296,6 +299,16 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { std::vector _tr_truth_theta; std::vector _tr_truth_phi; + // crt blob information + std::vector _bl_ts0; + std::vector _bl_ets0; + std::vector _bl_ts1; + std::vector _bl_ets1; + std::vector _bl_pe; + std::vector _bl_nsps; + std::vector> _bl_nsps_per_tagger; + + // tpc track information (including crt matching) std::vector _tpc_start_x; std::vector _tpc_start_y; std::vector _tpc_start_z; @@ -341,12 +354,14 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { std::vector _tpc_tr_end_z; std::vector _tpc_tr_score; + // ptb information (trigger board) std::vector _ptb_hlt_trigger; std::vector _ptb_hlt_timestamp; std::vector _ptb_llt_trigger; std::vector _ptb_llt_timestamp; + // spec tdc information (timing board) std::vector _tdc_channel; std::vector _tdc_timestamp; std::vector _tdc_offset; @@ -364,6 +379,7 @@ sbnd::crt::CRTAnalysis::CRTAnalysis(fhicl::ParameterSet const& p) fCRTClusterModuleLabel = p.get("CRTClusterModuleLabel", "crtclustering"); fCRTSpacePointModuleLabel = p.get("CRTSpacePointModuleLabel", "crtspacepoints"); fCRTTrackModuleLabel = p.get("CRTTrackModuleLabel", "crttracks"); + fCRTBlobModuleLabel = p.get("CRTBlobModuleLabel", "crtblobs"); fTPCTrackModuleLabel = p.get("TPCTrackModuleLabel", "pandoraSCETrack"); fCRTSpacePointMatchingModuleLabel = p.get("CRTSpacePointMatchingModuleLabel", "crtspacepointmatchingSCE"); fCRTTrackMatchingModuleLabel = p.get("CRTTrackMatchingModuleLabel", "crttrackmatchingSCE"); @@ -376,8 +392,8 @@ sbnd::crt::CRTAnalysis::CRTAnalysis(fhicl::ParameterSet const& p) fNoTPC = p.get("NoTPC", false); fHasPTB = p.get("HasPTB", false); fHasTDC = p.get("HasTDC", false); + fHasBlobs = p.get("HasBlobs", false); fTruthMatch = p.get("TruthMatch", true); - //! Adding some of the reco parameters to save corrections fPEAttenuation = p.get("PEAttenuation", 1.0); fTimeWalkNorm = p.get("TimeWalkNorm", 0.0); fTimeWalkScale = p.get("TimeWalkScale", 0.0); @@ -578,6 +594,17 @@ sbnd::crt::CRTAnalysis::CRTAnalysis(fhicl::ParameterSet const& p) fTree->Branch("tr_truth_phi", "std::vector", &_tr_truth_phi); } + if(fHasBlobs) + { + fTree->Branch("bl_ts0", "std::vector", &_bl_ts0); + fTree->Branch("bl_ets0", "std::vector", &_bl_ets0); + fTree->Branch("bl_ts1", "std::vector", &_bl_ts1); + fTree->Branch("bl_ets1", "std::vector", &_bl_ets1); + fTree->Branch("bl_pe", "std::vector", &_bl_pe); + fTree->Branch("bl_nsps", "std::vector", &_bl_nsps); + fTree->Branch("bl_nsps_per_tagger", "std::vector>", &_bl_nsps_per_tagger); + } + if(!fNoTPC) { fTree->Branch("tpc_start_x", "std::vector", &_tpc_start_x); @@ -835,6 +862,23 @@ void sbnd::crt::CRTAnalysis::analyze(art::Event const& e) // Fill CRTTrack variables AnalyseCRTTracks(e, CRTTrackVec, tracksToSpacePoints, spacepointsToClusters, clustersToStripHits); + if(fHasBlobs) + { + // Get CRTBlobs + art::Handle> CRTBlobHandle; + e.getByLabel(fCRTBlobModuleLabel, CRTBlobHandle); + if(!CRTBlobHandle.isValid()){ + std::cout << "CRTBlob product " << fCRTBlobModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + + std::vector> CRTBlobVec; + art::fill_ptr_vector(CRTBlobVec, CRTBlobHandle); + + // Fill CRTBlob variables + AnalyseCRTBlobs(CRTBlobVec); + } + if(fNoTPC) { // Fill the Tree @@ -1585,6 +1629,34 @@ void sbnd::crt::CRTAnalysis::AnalyseCRTTracks(const art::Event &e, const std::ve } } +void sbnd::crt::CRTAnalysis::AnalyseCRTBlobs(std::vector> &CRTBlobVec) +{ + const unsigned nBlobs = CRTBlobVec.size(); + + _bl_ts0.resize(nBlobs); + _bl_ets0.resize(nBlobs); + _bl_ts1.resize(nBlobs); + _bl_ets1.resize(nBlobs); + _bl_pe.resize(nBlobs); + _bl_nsps.resize(nBlobs); + _bl_nsps_per_tagger.resize(nBlobs, std::vector(7)); + + for(unsigned i = 0; i < nBlobs; ++i) + { + const auto blob = CRTBlobVec[i]; + + _bl_ts0[i] = blob->Ts0(); + _bl_ets0[i] = blob->Ts0Err(); + _bl_ts1[i] = blob->Ts1(); + _bl_ets1[i] = blob->Ts1Err(); + _bl_pe[i] = blob->PE(); + _bl_nsps[i] = blob->TotalSpacePoints(); + + for(unsigned j = 0; j < 7; ++j) + _bl_nsps_per_tagger[i][j] = blob->SpacePointsInTagger((CRTTagger)j); + } +} + void sbnd::crt::CRTAnalysis::AnalyseTPCMatching(const art::Event &e, const art::Handle> &TPCTrackHandle, const art::Handle> &CRTSpacePointHandle, const art::Handle> &CRTClusterHandle, const art::Handle> &PFPHandle, From 8e22b42767fbac8142564403f919d28c5053cbbd Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Tue, 17 Feb 2026 11:01:51 -0600 Subject: [PATCH 104/155] Clean up fcls --- sbndcode/CRT/CRTReco/run_crtrecoana.fcl | 3 +++ sbndcode/CRT/CRTReco/run_crtrecoana_data.fcl | 3 +++ sbndcode/CRT/CRTReco/run_crtrecoana_notpc.fcl | 3 --- sbndcode/CRT/CRTReco/run_crtrecoana_notpc_no_flat_tracks.fcl | 3 --- 4 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 sbndcode/CRT/CRTReco/run_crtrecoana_notpc.fcl delete mode 100644 sbndcode/CRT/CRTReco/run_crtrecoana_notpc_no_flat_tracks.fcl diff --git a/sbndcode/CRT/CRTReco/run_crtrecoana.fcl b/sbndcode/CRT/CRTReco/run_crtrecoana.fcl index 6e9f6d8c8..15a37b22d 100644 --- a/sbndcode/CRT/CRTReco/run_crtrecoana.fcl +++ b/sbndcode/CRT/CRTReco/run_crtrecoana.fcl @@ -52,3 +52,6 @@ physics: trigger_paths: [ reco ] end_paths: [ ana, stream1 ] } + +physics.analyzers.crtana.HasBlobs: true +physics.analyzers.crtana.NoTPC: true diff --git a/sbndcode/CRT/CRTReco/run_crtrecoana_data.fcl b/sbndcode/CRT/CRTReco/run_crtrecoana_data.fcl index 11bbc53cf..c249a7d99 100644 --- a/sbndcode/CRT/CRTReco/run_crtrecoana_data.fcl +++ b/sbndcode/CRT/CRTReco/run_crtrecoana_data.fcl @@ -10,5 +10,8 @@ physics.producers.crtstrips: @local::crtstriphitproducer_data_sbnd physics.producers.crtclustering: @local::crtclusterproducer_data_sbnd physics.producers.crtspacepoints: @local::crtspacepointproducer_data_sbnd physics.producers.crttracks: @local::crttrackproducer_data_sbnd +physics.producers.crtblobs: @local::crtblobproducer_data_sbnd physics.analyzers.crtana: @local::crtana_data_sbnd +physics.analyzers.crtana.HasBlobs: true +physics.analyzers.crtana.NoTPC: true diff --git a/sbndcode/CRT/CRTReco/run_crtrecoana_notpc.fcl b/sbndcode/CRT/CRTReco/run_crtrecoana_notpc.fcl deleted file mode 100644 index 621b8d45a..000000000 --- a/sbndcode/CRT/CRTReco/run_crtrecoana_notpc.fcl +++ /dev/null @@ -1,3 +0,0 @@ -#include "run_crtrecoana.fcl" - -physics.analyzers.crtana.NoTPC: true diff --git a/sbndcode/CRT/CRTReco/run_crtrecoana_notpc_no_flat_tracks.fcl b/sbndcode/CRT/CRTReco/run_crtrecoana_notpc_no_flat_tracks.fcl deleted file mode 100644 index 74a8504d7..000000000 --- a/sbndcode/CRT/CRTReco/run_crtrecoana_notpc_no_flat_tracks.fcl +++ /dev/null @@ -1,3 +0,0 @@ -#include "run_crtrecoana_notpc.fcl" - -physics.producers.crttracks.MaskedTaggers: [ 0 ] From 2215cc314f4306603724241360c5a5eaebe025e1 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Wed, 18 Feb 2026 08:03:03 -0600 Subject: [PATCH 105/155] Manually check saturation --- sbndcode/CRT/CRTReco/CRTStripHitProducer_module.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sbndcode/CRT/CRTReco/CRTStripHitProducer_module.cc b/sbndcode/CRT/CRTReco/CRTStripHitProducer_module.cc index fe536a734..93eb61bfa 100644 --- a/sbndcode/CRT/CRTReco/CRTStripHitProducer_module.cc +++ b/sbndcode/CRT/CRTReco/CRTStripHitProducer_module.cc @@ -275,6 +275,10 @@ std::vector sbnd::crt::CRTStripHitProducer::CreateStripH const uint16_t adc1 = sipm1.pedestal < sipm_adcs[adc_i] ? sipm_adcs[adc_i] - sipm1.pedestal : 0; const uint16_t adc2 = sipm2.pedestal < sipm_adcs[adc_i+1] ? sipm_adcs[adc_i+1] - sipm2.pedestal : 0; + // Saturated? + const bool sat1 = sipm_adcs[adc_i] == fADCSaturation; + const bool sat2 = sipm_adcs[adc_i+1] == fADCSaturation; + // Keep hit if both SiPMs above threshold if(adc1 > fADCThreshold && adc2 > fADCThreshold) { @@ -292,7 +296,7 @@ std::vector sbnd::crt::CRTStripHitProducer::CreateStripH if(pos - err < 0) err = pos; - stripHits.emplace_back(offline_channel_id, t0, t1, ref_time_s, pos, err, adc1, adc2, fADCSaturation); + stripHits.emplace_back(offline_channel_id, t0, t1, ref_time_s, pos, err, adc1, adc2, sat1, sat2); } } From 65b6003819c194e6f76e64935583ee12517e3001 Mon Sep 17 00:00:00 2001 From: nathanielerowe <70993723+nathanielerowe@users.noreply.github.com> Date: Thu, 19 Feb 2026 08:26:08 -0600 Subject: [PATCH 106/155] Update sbncode version to v10_14_02_03 --- ups/product_deps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ups/product_deps b/ups/product_deps index e21a2f2aa..38979aeb7 100644 --- a/ups/product_deps +++ b/ups/product_deps @@ -253,7 +253,7 @@ wpdir product_dir wire-cell-cfg # #################################### product version qual flags -sbncode v10_14_02_02 - +sbncode v10_14_02_03 - cetmodules v3_24_01 - only_for_build sbnd_data v01_42_00 - sbndutil v10_06_01 - optional From 6419fbf46a77d4a1e735336b2f0912cb2e86a8ae Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Tue, 6 Feb 2024 08:42:41 -0600 Subject: [PATCH 107/155] Add channel mapping version of module and relevant config --- sbndcode/CRT/CRTEventDisplay/CMakeLists.txt | 5 ++ .../CRTChannelMappingEventDisplay_module.cc | 90 +++++++++++++++++++ .../CRTEventDisplay/crteventdisplay_sbnd.fcl | 14 ++- .../crteventdisplayalg_sbnd.fcl | 24 +++++ .../run_crteventdisplay_channel_mapping.fcl | 29 ++++++ 5 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 sbndcode/CRT/CRTEventDisplay/CRTChannelMappingEventDisplay_module.cc create mode 100644 sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping.fcl diff --git a/sbndcode/CRT/CRTEventDisplay/CMakeLists.txt b/sbndcode/CRT/CRTEventDisplay/CMakeLists.txt index 0a8aa82af..c245b2729 100644 --- a/sbndcode/CRT/CRTEventDisplay/CMakeLists.txt +++ b/sbndcode/CRT/CRTEventDisplay/CMakeLists.txt @@ -13,4 +13,9 @@ simple_plugin( sbndcode_CRT_CRTEventDisplay ) +simple_plugin( + CRTChannelMappingEventDisplay module + sbndcode_CRT_CRTEventDisplay +) + install_fhicl() diff --git a/sbndcode/CRT/CRTEventDisplay/CRTChannelMappingEventDisplay_module.cc b/sbndcode/CRT/CRTEventDisplay/CRTChannelMappingEventDisplay_module.cc new file mode 100644 index 000000000..99c4c1f6d --- /dev/null +++ b/sbndcode/CRT/CRTEventDisplay/CRTChannelMappingEventDisplay_module.cc @@ -0,0 +1,90 @@ +//////////////////////////////////////////////////////////////////////// +// Class: CRTChannelMappingEventDisplay +// Plugin Type: analyzer (Unknown Unknown) +// File: CRTChannelMappingEventDisplay_module.cc +// +// Generated at Thu Oct 6 09:32:09 2022 by Henry Lay 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" + +#include "lardata/DetectorInfoServices/DetectorClocksService.h" +#include "sbndcode/CRT/CRTEventDisplay/CRTEventDisplayAlg.h" + +#include "TSystem.h" + +namespace sbnd::crt { + class CRTChannelMappingEventDisplay; +} + +class sbnd::crt::CRTChannelMappingEventDisplay : public art::EDAnalyzer { +public: + + struct Config { + using Name = fhicl::Name; + using Comment = fhicl::Comment; + + fhicl::Table EventDisplayConfig { + Name("EventDisplayConfig"), + }; + + fhicl::Atom SaveDir { + Name("SaveDir"), + }; + }; + + using Parameters = art::EDAnalyzer::Table; + + explicit CRTChannelMappingEventDisplay(Parameters const &config); + + CRTChannelMappingEventDisplay(CRTChannelMappingEventDisplay const&) = delete; + CRTChannelMappingEventDisplay(CRTChannelMappingEventDisplay&&) = delete; + CRTChannelMappingEventDisplay& operator=(CRTChannelMappingEventDisplay const&) = delete; + CRTChannelMappingEventDisplay& operator=(CRTChannelMappingEventDisplay&&) = delete; + + void analyze(art::Event const& e) override; + +private: + + CRTEventDisplayAlg fCRTEventDisplayAlg; + CRTGeoAlg fCRTGeoAlg; + std::string fSaveDir; + std::vector fChosenTaggers; +}; + + +sbnd::crt::CRTChannelMappingEventDisplay::CRTChannelMappingEventDisplay(Parameters const& config) + : EDAnalyzer{config} + , fCRTEventDisplayAlg(config().EventDisplayConfig()) + , fCRTGeoAlg(config().EventDisplayConfig().GeoAlgConfig()) + , fSaveDir(config().SaveDir()) + , fChosenTaggers(config().EventDisplayConfig().ChosenTaggers()) + { + gSystem->Exec(Form("mkdir -p %s", fSaveDir.c_str())); + } + +void sbnd::crt::CRTChannelMappingEventDisplay::analyze(art::Event const& e) +{ + auto const clockData = art::ServiceHandle()->DataFor(e); + + for(auto const& [ name, module ] : fCRTGeoAlg.GetModules()) + { + if(std::find(fChosenTaggers.begin(), fChosenTaggers.end(), CRTCommonUtils::GetTaggerEnum(module.taggerName)) == fChosenTaggers.end()) + continue; + + fCRTEventDisplayAlg.SetHighlightedModules({module.adID}); + + fCRTEventDisplayAlg.Draw(clockData, e, Form("%s/%s", fSaveDir.c_str(), name.c_str())); + } +} + +DEFINE_ART_MODULE(sbnd::crt::CRTChannelMappingEventDisplay) diff --git a/sbndcode/CRT/CRTEventDisplay/crteventdisplay_sbnd.fcl b/sbndcode/CRT/CRTEventDisplay/crteventdisplay_sbnd.fcl index 03f656d3b..a64ede384 100644 --- a/sbndcode/CRT/CRTEventDisplay/crteventdisplay_sbnd.fcl +++ b/sbndcode/CRT/CRTEventDisplay/crteventdisplay_sbnd.fcl @@ -4,14 +4,20 @@ BEGIN_PROLOG crteventdisplay_sbnd: { - EventDisplayConfig: @local::crteventdisplayalg_sbnd - module_type: "CRTEventDisplay" + EventDisplayConfig: @local::crteventdisplayalg_sbnd + module_type: "CRTEventDisplay" } crteventdisplay_sbnd_data: { - EventDisplayConfig: @local::crteventdisplayalg_sbnd_data - module_type: "CRTEventDisplay" + EventDisplayConfig: @local::crteventdisplayalg_sbnd_data + module_type: "CRTEventDisplay" +} + +crteventdisplay_sbnd_channel_mapping: +{ + EventDisplayConfig: @local::crteventdisplayalg_sbnd_channel_mapping + module_type: "CRTChannelMappingEventDisplay" } END_PROLOG diff --git a/sbndcode/CRT/CRTEventDisplay/crteventdisplayalg_sbnd.fcl b/sbndcode/CRT/CRTEventDisplay/crteventdisplayalg_sbnd.fcl index a2bc90e24..1a5f77633 100644 --- a/sbndcode/CRT/CRTEventDisplay/crteventdisplayalg_sbnd.fcl +++ b/sbndcode/CRT/CRTEventDisplay/crteventdisplayalg_sbnd.fcl @@ -97,4 +97,28 @@ crteventdisplayalg_sbnd_data.UseTs0: true crteventdisplayalg_sbnd_data.MinTime: -1.5e6 crteventdisplayalg_sbnd_data.MaxTime: 1.5e6 +crteventdisplayalg_sbnd_channel_mapping: @local::crteventdisplayalg_sbnd + +crteventdisplayalg_sbnd_channel_mapping.DataMode: true +crteventdisplayalg_sbnd_channel_mapping.SaveRoot: false +crteventdisplayalg_sbnd_channel_mapping.SaveViews: true + +crteventdisplayalg_sbnd_channel_mapping.ChoseTaggers: true +crteventdisplayalg_sbnd_channel_mapping.HighlightModules: true + +crteventdisplayalg_sbnd_channel_mapping.DrawTaggers: true +crteventdisplayalg_sbnd_channel_mapping.DrawModules: true +crteventdisplayalg_sbnd_channel_mapping.DrawFEBs: true +crteventdisplayalg_sbnd_channel_mapping.DrawFEBEnds: true +crteventdisplayalg_sbnd_channel_mapping.DrawStrips: false +crteventdisplayalg_sbnd_channel_mapping.DrawTPC: true +crteventdisplayalg_sbnd_channel_mapping.DrawTrueTracks: false +crteventdisplayalg_sbnd_channel_mapping.DrawSimDeposits: false +crteventdisplayalg_sbnd_channel_mapping.DrawStripHits: false +crteventdisplayalg_sbnd_channel_mapping.DrawClusters: false +crteventdisplayalg_sbnd_channel_mapping.DrawSpacePoints: false +crteventdisplayalg_sbnd_channel_mapping.DrawTracks: false + +crteventdisplayalg_sbnd_channel_mapping.Print: false + END_PROLOG diff --git a/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping.fcl b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping.fcl new file mode 100644 index 000000000..03ab48cad --- /dev/null +++ b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping.fcl @@ -0,0 +1,29 @@ +#include "services_sbnd.fcl" +#include "crt_services_sbnd.fcl" +#include "crteventdisplay_sbnd.fcl" + +process_name: CRTEventDisplay + +services: +{ + @table::sbnd_services + @table::crt_services_data_sbnd +} + +source: +{ + module_type: RootInput + maxEvents: -1 +} + +physics: +{ + analyzers: + { + crtevd: @local::crteventdisplay_sbnd_channel_mapping + } + + ana: [ crtevd ] + + end_paths: [ ana ] +} From bb8dc73da55bcc57d140f208fa4a3d7eb906fd31 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Tue, 6 Feb 2024 08:45:26 -0600 Subject: [PATCH 108/155] Add bash script for making pdf --- sbndcode/CRT/CRTEventDisplay/build_tex.sh | 70 +++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 sbndcode/CRT/CRTEventDisplay/build_tex.sh diff --git a/sbndcode/CRT/CRTEventDisplay/build_tex.sh b/sbndcode/CRT/CRTEventDisplay/build_tex.sh new file mode 100644 index 000000000..77ff9a4e9 --- /dev/null +++ b/sbndcode/CRT/CRTEventDisplay/build_tex.sh @@ -0,0 +1,70 @@ +echo "\documentclass{article} +\usepackage[a4paper, margin=3cm]{geometry} +\usepackage{graphicx} +\usepackage{pgffor} +\usepackage[hidelinks]{hyperref} + +\title{SBND CRT Channel Mapping Displays \\\\ \vspace{1em} \small \textit{Produced using} \texttt{sbndcode v09\_82\_02\_01} \textit{\&} \texttt{sbnd\_v02\_00.gdml}} +\author{Henry Lay \\\\ \small h.lay@lancaster.ac.uk}" > crt_channel_mapping_evds.tex + +walls=(bottom south north west east toplow tophigh) +wallnames=(Bottom South North West East "Top Low" "Top High") + +for wall in "${walls[@]}" +do + list=$(ls /exp/sbnd/data/users/hlay/crt_channel_mapping/${wall}_wall/*_front.pdf) + echo -n "\newcommand*{\\"$wall"ids}{" >> crt_channel_mapping_evds.tex + + for item in ${list} + do + name=$(echo $item | cut -d '/' -f 9) + number=$(echo $name | cut -d '_' -f 2) + echo -n $number, >> crt_channel_mapping_evds.tex + done + + sed -i '$ s/.$//' crt_channel_mapping_evds.tex + echo "}" >> crt_channel_mapping_evds.tex +done + +echo "\begin{document} + +\maketitle + +\centering +\vspace{2em} + +\includegraphics[width=.6\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/luphysics_logo.png} + +\vspace{2em} + +\includegraphics[width=.5\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/sbnd_pride_transparent.png} +\flushleft +\newpage +\tableofcontents +\newpage +\section{Explanation} +This document contains a series of illustrations created using the \texttt{CRTEventDisplay} tool originally written by Tom Brooks \& heavily developed by myself. It shows the position of the various CRT modules according to the gdml file used in SBND simulation and reconstruction. The document is split into sections for the different tagger walls. For each module three illustrations are provided: front, top and side views. The axes show detector coordinates (X, Y and Z) and \`\`building coordinates\" (South, West and Up). The relevant module is shown in green. The TPCs are shown in grey in the centre for reference. The black outer is the full tagger wall. The thin grey are other modules in the wall. The red is the FEB position and the blue corresponds to the end of the FEB with channel 0 (the ethernet ports). +" >> crt_channel_mapping_evds.tex + +for i in "${!walls[@]}" +do + echo "\newpage +\section{${wallnames[i]} Wall} +\begingroup +\foreach \x in \\${walls[i]}ids +{ + \newpage + \subsection{volCRTModule\x\_\x} + \begin{center} + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} + \end{center} +} +\endgroup" >> crt_channel_mapping_evds.tex +done + +echo "\end{document}" >> crt_channel_mapping_evds.tex + +pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/tex_work crt_channel_mapping_evds.tex From 50586c9641a0faface2968055adfca6bc4485702 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Tue, 6 Feb 2024 08:53:12 -0600 Subject: [PATCH 109/155] Z points North not South, duh --- sbndcode/CRT/CRTEventDisplay/build_tex.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbndcode/CRT/CRTEventDisplay/build_tex.sh b/sbndcode/CRT/CRTEventDisplay/build_tex.sh index 77ff9a4e9..a82faa13f 100644 --- a/sbndcode/CRT/CRTEventDisplay/build_tex.sh +++ b/sbndcode/CRT/CRTEventDisplay/build_tex.sh @@ -43,7 +43,7 @@ echo "\begin{document} \tableofcontents \newpage \section{Explanation} -This document contains a series of illustrations created using the \texttt{CRTEventDisplay} tool originally written by Tom Brooks \& heavily developed by myself. It shows the position of the various CRT modules according to the gdml file used in SBND simulation and reconstruction. The document is split into sections for the different tagger walls. For each module three illustrations are provided: front, top and side views. The axes show detector coordinates (X, Y and Z) and \`\`building coordinates\" (South, West and Up). The relevant module is shown in green. The TPCs are shown in grey in the centre for reference. The black outer is the full tagger wall. The thin grey are other modules in the wall. The red is the FEB position and the blue corresponds to the end of the FEB with channel 0 (the ethernet ports). +This document contains a series of illustrations created using the \texttt{CRTEventDisplay} tool originally written by Tom Brooks \& heavily developed by myself. It shows the position of the various CRT modules according to the gdml file used in SBND simulation and reconstruction. The document is split into sections for the different tagger walls. For each module three illustrations are provided: front, top and side views. The axes show detector coordinates (X, Y and Z) and \`\`building coordinates\" (North, West and Up). The relevant module is shown in green. The TPCs are shown in grey in the centre for reference. The black outer is the full tagger wall. The thin grey are other modules in the wall. The red is the FEB position and the blue corresponds to the end of the FEB with channel 0 (the ethernet ports). " >> crt_channel_mapping_evds.tex for i in "${!walls[@]}" From 184da01079e3bc8542a4a029f8654667d740e5a4 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Mon, 24 Jun 2024 11:09:03 -0500 Subject: [PATCH 110/155] Update channel map evds to test David's updates --- sbndcode/CRT/CRTEventDisplay/build_tex.sh | 24 ++++----- ...un_crteventdisplay_channel_mapping_all.fcl | 53 +++++++++++++++++++ 2 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl diff --git a/sbndcode/CRT/CRTEventDisplay/build_tex.sh b/sbndcode/CRT/CRTEventDisplay/build_tex.sh index a82faa13f..1c3f2db41 100644 --- a/sbndcode/CRT/CRTEventDisplay/build_tex.sh +++ b/sbndcode/CRT/CRTEventDisplay/build_tex.sh @@ -4,7 +4,7 @@ echo "\documentclass{article} \usepackage{pgffor} \usepackage[hidelinks]{hyperref} -\title{SBND CRT Channel Mapping Displays \\\\ \vspace{1em} \small \textit{Produced using} \texttt{sbndcode v09\_82\_02\_01} \textit{\&} \texttt{sbnd\_v02\_00.gdml}} +\title{SBND CRT Channel Mapping Displays \\\\ \vspace{1em} \small \textit{Produced using} \texttt{sbndcode v09\_90\_00} \textit{\&} \texttt{sbnd\_v02\_01.gdml}} \author{Henry Lay \\\\ \small h.lay@lancaster.ac.uk}" > crt_channel_mapping_evds.tex walls=(bottom south north west east toplow tophigh) @@ -12,14 +12,14 @@ wallnames=(Bottom South North West East "Top Low" "Top High") for wall in "${walls[@]}" do - list=$(ls /exp/sbnd/data/users/hlay/crt_channel_mapping/${wall}_wall/*_front.pdf) + list=$(ls /exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/${wall}_wall/*_front.pdf) echo -n "\newcommand*{\\"$wall"ids}{" >> crt_channel_mapping_evds.tex for item in ${list} do - name=$(echo $item | cut -d '/' -f 9) - number=$(echo $name | cut -d '_' -f 2) - echo -n $number, >> crt_channel_mapping_evds.tex + name=$(echo $item | cut -d '/' -f 10) + number=$(echo $name | cut -d '_' -f 2) + echo -n $number, >> crt_channel_mapping_evds.tex done sed -i '$ s/.$//' crt_channel_mapping_evds.tex @@ -33,11 +33,11 @@ echo "\begin{document} \centering \vspace{2em} -\includegraphics[width=.6\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/luphysics_logo.png} +\includegraphics[width=.6\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/luphysics_logo.png} \vspace{2em} -\includegraphics[width=.5\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/sbnd_pride_transparent.png} +\includegraphics[width=.5\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/sbnd_pride_transparent.png} \flushleft \newpage \tableofcontents @@ -56,9 +56,9 @@ do \newpage \subsection{volCRTModule\x\_\x} \begin{center} - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} \end{center} } \endgroup" >> crt_channel_mapping_evds.tex @@ -66,5 +66,5 @@ done echo "\end{document}" >> crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/tex_work crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/tex_work crt_channel_mapping_evds.tex diff --git a/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl new file mode 100644 index 000000000..ec5d3b264 --- /dev/null +++ b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl @@ -0,0 +1,53 @@ +#include "crt_channel_map_service.fcl" +#include "crt_calib_service.fcl" +#include "run_crteventdisplay_channel_mapping.fcl" + +process_name: CRTEventDisplay + +services: +{ + @table::sbnd_services + ParticleInventoryService: @local::standard_particleinventoryservice + CRTChannelMapService: @local::crt_channel_map_standard + CRTCalibService: @local::crt_calib_service +} + +source: +{ + module_type: RootInput + maxEvents: -1 + +} + +physics: +{ + analyzers: + { + crtevdbot: @local::crteventdisplay_sbnd_channel_mapping + crtevdsou: @local::crteventdisplay_sbnd_channel_mapping + crtevdnor: @local::crteventdisplay_sbnd_channel_mapping + crtevdwes: @local::crteventdisplay_sbnd_channel_mapping + crtevdeas: @local::crteventdisplay_sbnd_channel_mapping + crtevdtpl: @local::crteventdisplay_sbnd_channel_mapping + crtevdtph: @local::crteventdisplay_sbnd_channel_mapping + } + + ana: [ crtevdbot, crtevdsou, crtevdnor, crtevdwes, crtevdeas, crtevdtpl, crtevdtph ] + + end_paths: [ ana ] +} + +physics.analyzers.crtevdbot.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/bottom_wall" +physics.analyzers.crtevdbot.EventDisplayConfig.ChosenTaggers: [ 0 ] +physics.analyzers.crtevdsou.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/south_wall" +physics.analyzers.crtevdsou.EventDisplayConfig.ChosenTaggers: [ 1 ] +physics.analyzers.crtevdnor.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/north_wall" +physics.analyzers.crtevdnor.EventDisplayConfig.ChosenTaggers: [ 2 ] +physics.analyzers.crtevdwes.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/west_wall" +physics.analyzers.crtevdwes.EventDisplayConfig.ChosenTaggers: [ 3 ] +physics.analyzers.crtevdeas.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/east_wall" +physics.analyzers.crtevdeas.EventDisplayConfig.ChosenTaggers: [ 4 ] +physics.analyzers.crtevdtpl.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/toplow_wall" +physics.analyzers.crtevdtpl.EventDisplayConfig.ChosenTaggers: [ 5 ] +physics.analyzers.crtevdtph.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/tophigh_wall" +physics.analyzers.crtevdtph.EventDisplayConfig.ChosenTaggers: [ 6 ] From f97696f3f24dfcdf50c2598aee82d0daf330f46e Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Sun, 25 Aug 2024 18:03:40 -0500 Subject: [PATCH 111/155] New CRT gdml channel mapping evds --- sbndcode/CRT/CRTEventDisplay/build_tex.sh | 18 +++++++++--------- ...run_crteventdisplay_channel_mapping_all.fcl | 14 +++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/sbndcode/CRT/CRTEventDisplay/build_tex.sh b/sbndcode/CRT/CRTEventDisplay/build_tex.sh index 1c3f2db41..fdaef5ded 100644 --- a/sbndcode/CRT/CRTEventDisplay/build_tex.sh +++ b/sbndcode/CRT/CRTEventDisplay/build_tex.sh @@ -4,7 +4,7 @@ echo "\documentclass{article} \usepackage{pgffor} \usepackage[hidelinks]{hyperref} -\title{SBND CRT Channel Mapping Displays \\\\ \vspace{1em} \small \textit{Produced using} \texttt{sbndcode v09\_90\_00} \textit{\&} \texttt{sbnd\_v02\_01.gdml}} +\title{SBND CRT Channel Mapping Displays \\\\ \vspace{1em} \small \textit{Produced using} \texttt{sbndcode v09\_90\_00} \textit{\&} \texttt{sbnd\_v02\_02.gdml}} \author{Henry Lay \\\\ \small h.lay@lancaster.ac.uk}" > crt_channel_mapping_evds.tex walls=(bottom south north west east toplow tophigh) @@ -12,7 +12,7 @@ wallnames=(Bottom South North West East "Top Low" "Top High") for wall in "${walls[@]}" do - list=$(ls /exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/${wall}_wall/*_front.pdf) + list=$(ls /exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/${wall}_wall/*_front.pdf) echo -n "\newcommand*{\\"$wall"ids}{" >> crt_channel_mapping_evds.tex for item in ${list} @@ -33,11 +33,11 @@ echo "\begin{document} \centering \vspace{2em} -\includegraphics[width=.6\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/luphysics_logo.png} +\includegraphics[width=.6\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/luphysics_logo.png} \vspace{2em} -\includegraphics[width=.5\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/sbnd_pride_transparent.png} +\includegraphics[width=.5\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/sbnd_pride_transparent.png} \flushleft \newpage \tableofcontents @@ -56,9 +56,9 @@ do \newpage \subsection{volCRTModule\x\_\x} \begin{center} - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} \end{center} } \endgroup" >> crt_channel_mapping_evds.tex @@ -66,5 +66,5 @@ done echo "\end{document}" >> crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/tex_work crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/tex_work crt_channel_mapping_evds.tex diff --git a/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl index ec5d3b264..719321a2b 100644 --- a/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl +++ b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl @@ -37,17 +37,17 @@ physics: end_paths: [ ana ] } -physics.analyzers.crtevdbot.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/bottom_wall" +physics.analyzers.crtevdbot.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/bottom_wall" physics.analyzers.crtevdbot.EventDisplayConfig.ChosenTaggers: [ 0 ] -physics.analyzers.crtevdsou.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/south_wall" +physics.analyzers.crtevdsou.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/south_wall" physics.analyzers.crtevdsou.EventDisplayConfig.ChosenTaggers: [ 1 ] -physics.analyzers.crtevdnor.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/north_wall" +physics.analyzers.crtevdnor.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/north_wall" physics.analyzers.crtevdnor.EventDisplayConfig.ChosenTaggers: [ 2 ] -physics.analyzers.crtevdwes.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/west_wall" +physics.analyzers.crtevdwes.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/west_wall" physics.analyzers.crtevdwes.EventDisplayConfig.ChosenTaggers: [ 3 ] -physics.analyzers.crtevdeas.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/east_wall" +physics.analyzers.crtevdeas.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/east_wall" physics.analyzers.crtevdeas.EventDisplayConfig.ChosenTaggers: [ 4 ] -physics.analyzers.crtevdtpl.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/toplow_wall" +physics.analyzers.crtevdtpl.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/toplow_wall" physics.analyzers.crtevdtpl.EventDisplayConfig.ChosenTaggers: [ 5 ] -physics.analyzers.crtevdtph.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/june2024/tophigh_wall" +physics.analyzers.crtevdtph.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/tophigh_wall" physics.analyzers.crtevdtph.EventDisplayConfig.ChosenTaggers: [ 6 ] From 27d0e16b801331255df5cdb70543cdc7021897cd Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Sat, 28 Sep 2024 06:36:48 -0500 Subject: [PATCH 112/155] Changes to channel map evd producer --- sbndcode/CRT/CRTEventDisplay/build_tex.sh | 21 +++++++++---------- ...un_crteventdisplay_channel_mapping_all.fcl | 18 +++++++++------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/sbndcode/CRT/CRTEventDisplay/build_tex.sh b/sbndcode/CRT/CRTEventDisplay/build_tex.sh index fdaef5ded..ff75ab234 100644 --- a/sbndcode/CRT/CRTEventDisplay/build_tex.sh +++ b/sbndcode/CRT/CRTEventDisplay/build_tex.sh @@ -4,15 +4,15 @@ echo "\documentclass{article} \usepackage{pgffor} \usepackage[hidelinks]{hyperref} -\title{SBND CRT Channel Mapping Displays \\\\ \vspace{1em} \small \textit{Produced using} \texttt{sbndcode v09\_90\_00} \textit{\&} \texttt{sbnd\_v02\_02.gdml}} -\author{Henry Lay \\\\ \small h.lay@lancaster.ac.uk}" > crt_channel_mapping_evds.tex +\title{SBND CRT Channel Mapping Displays \\\\ \vspace{1em} \small \textit{Produced using} \texttt{sbndcode v09\_91\_02\_02} \textit{\&} \texttt{sbnd\_v02\_03.gdml}} +\author{Henry Lay \\\\ \small h.lay@sheffield.ac.uk}" > crt_channel_mapping_evds.tex walls=(bottom south north west east toplow tophigh) wallnames=(Bottom South North West East "Top Low" "Top High") for wall in "${walls[@]}" do - list=$(ls /exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/${wall}_wall/*_front.pdf) + list=$(ls /exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/${wall}_wall/*_front.pdf) echo -n "\newcommand*{\\"$wall"ids}{" >> crt_channel_mapping_evds.tex for item in ${list} @@ -33,11 +33,10 @@ echo "\begin{document} \centering \vspace{2em} -\includegraphics[width=.6\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/luphysics_logo.png} - +\includegraphics[width=.6\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/UOSLogo_Primary_Violet_RGB.png} \vspace{2em} -\includegraphics[width=.5\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/sbnd_pride_transparent.png} +\includegraphics[width=.5\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/sbnd_pride_transparent.png} \flushleft \newpage \tableofcontents @@ -56,9 +55,9 @@ do \newpage \subsection{volCRTModule\x\_\x} \begin{center} - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} \end{center} } \endgroup" >> crt_channel_mapping_evds.tex @@ -66,5 +65,5 @@ done echo "\end{document}" >> crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/tex_work crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/tex_work crt_channel_mapping_evds.tex diff --git a/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl index 719321a2b..2e8f01d5e 100644 --- a/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl +++ b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl @@ -1,6 +1,8 @@ +#include "services_sbnd.fcl" +#include "particleinventoryservice.fcl" +#include "crteventdisplay_sbnd.fcl" #include "crt_channel_map_service.fcl" #include "crt_calib_service.fcl" -#include "run_crteventdisplay_channel_mapping.fcl" process_name: CRTEventDisplay @@ -37,17 +39,17 @@ physics: end_paths: [ ana ] } -physics.analyzers.crtevdbot.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/bottom_wall" +physics.analyzers.crtevdbot.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/bottom_wall" physics.analyzers.crtevdbot.EventDisplayConfig.ChosenTaggers: [ 0 ] -physics.analyzers.crtevdsou.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/south_wall" +physics.analyzers.crtevdsou.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/south_wall" physics.analyzers.crtevdsou.EventDisplayConfig.ChosenTaggers: [ 1 ] -physics.analyzers.crtevdnor.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/north_wall" +physics.analyzers.crtevdnor.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/north_wall" physics.analyzers.crtevdnor.EventDisplayConfig.ChosenTaggers: [ 2 ] -physics.analyzers.crtevdwes.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/west_wall" +physics.analyzers.crtevdwes.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/west_wall" physics.analyzers.crtevdwes.EventDisplayConfig.ChosenTaggers: [ 3 ] -physics.analyzers.crtevdeas.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/east_wall" +physics.analyzers.crtevdeas.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/east_wall" physics.analyzers.crtevdeas.EventDisplayConfig.ChosenTaggers: [ 4 ] -physics.analyzers.crtevdtpl.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/toplow_wall" +physics.analyzers.crtevdtpl.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/toplow_wall" physics.analyzers.crtevdtpl.EventDisplayConfig.ChosenTaggers: [ 5 ] -physics.analyzers.crtevdtph.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/august2024/tophigh_wall" +physics.analyzers.crtevdtph.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/tophigh_wall" physics.analyzers.crtevdtph.EventDisplayConfig.ChosenTaggers: [ 6 ] From 25bc90306d11828419ae82d37c90a654e2bda540 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Mon, 27 Jan 2025 05:46:58 -0600 Subject: [PATCH 113/155] New round of channel map evds --- sbndcode/CRT/CRTEventDisplay/build_tex.sh | 18 +++++++++--------- ...run_crteventdisplay_channel_mapping_all.fcl | 14 +++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/sbndcode/CRT/CRTEventDisplay/build_tex.sh b/sbndcode/CRT/CRTEventDisplay/build_tex.sh index ff75ab234..727298f54 100644 --- a/sbndcode/CRT/CRTEventDisplay/build_tex.sh +++ b/sbndcode/CRT/CRTEventDisplay/build_tex.sh @@ -4,7 +4,7 @@ echo "\documentclass{article} \usepackage{pgffor} \usepackage[hidelinks]{hyperref} -\title{SBND CRT Channel Mapping Displays \\\\ \vspace{1em} \small \textit{Produced using} \texttt{sbndcode v09\_91\_02\_02} \textit{\&} \texttt{sbnd\_v02\_03.gdml}} +\title{SBND CRT Channel Mapping Displays \\\\ \vspace{1em} \small \textit{Produced using} \texttt{sbndcode v09\_93\_01\_02} \textit{\&} \texttt{sbnd\_v02\_03.gdml}} \author{Henry Lay \\\\ \small h.lay@sheffield.ac.uk}" > crt_channel_mapping_evds.tex walls=(bottom south north west east toplow tophigh) @@ -12,7 +12,7 @@ wallnames=(Bottom South North West East "Top Low" "Top High") for wall in "${walls[@]}" do - list=$(ls /exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/${wall}_wall/*_front.pdf) + list=$(ls /exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/${wall}_wall/*_front.pdf) echo -n "\newcommand*{\\"$wall"ids}{" >> crt_channel_mapping_evds.tex for item in ${list} @@ -33,10 +33,10 @@ echo "\begin{document} \centering \vspace{2em} -\includegraphics[width=.6\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/UOSLogo_Primary_Violet_RGB.png} +\includegraphics[width=.6\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/UOSLogo_Primary_Violet_RGB.png} \vspace{2em} -\includegraphics[width=.5\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/sbnd_pride_transparent.png} +\includegraphics[width=.5\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/sbnd_pride_transparent.png} \flushleft \newpage \tableofcontents @@ -55,9 +55,9 @@ do \newpage \subsection{volCRTModule\x\_\x} \begin{center} - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} \end{center} } \endgroup" >> crt_channel_mapping_evds.tex @@ -65,5 +65,5 @@ done echo "\end{document}" >> crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/tex_work crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/tex_work crt_channel_mapping_evds.tex diff --git a/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl index 2e8f01d5e..674c5ee6b 100644 --- a/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl +++ b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl @@ -39,17 +39,17 @@ physics: end_paths: [ ana ] } -physics.analyzers.crtevdbot.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/bottom_wall" +physics.analyzers.crtevdbot.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/bottom_wall" physics.analyzers.crtevdbot.EventDisplayConfig.ChosenTaggers: [ 0 ] -physics.analyzers.crtevdsou.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/south_wall" +physics.analyzers.crtevdsou.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/south_wall" physics.analyzers.crtevdsou.EventDisplayConfig.ChosenTaggers: [ 1 ] -physics.analyzers.crtevdnor.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/north_wall" +physics.analyzers.crtevdnor.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/north_wall" physics.analyzers.crtevdnor.EventDisplayConfig.ChosenTaggers: [ 2 ] -physics.analyzers.crtevdwes.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/west_wall" +physics.analyzers.crtevdwes.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/west_wall" physics.analyzers.crtevdwes.EventDisplayConfig.ChosenTaggers: [ 3 ] -physics.analyzers.crtevdeas.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/east_wall" +physics.analyzers.crtevdeas.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/east_wall" physics.analyzers.crtevdeas.EventDisplayConfig.ChosenTaggers: [ 4 ] -physics.analyzers.crtevdtpl.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/toplow_wall" +physics.analyzers.crtevdtpl.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/toplow_wall" physics.analyzers.crtevdtpl.EventDisplayConfig.ChosenTaggers: [ 5 ] -physics.analyzers.crtevdtph.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/oct2024/tophigh_wall" +physics.analyzers.crtevdtph.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/tophigh_wall" physics.analyzers.crtevdtph.EventDisplayConfig.ChosenTaggers: [ 6 ] From a30a782c052e408da79119d4ff73133c9c1ffc02 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Thu, 15 May 2025 10:24:42 -0500 Subject: [PATCH 114/155] Updated CRT channel mapping display --- sbndcode/CRT/CRTEventDisplay/build_tex.sh | 18 +++++++++--------- ...run_crteventdisplay_channel_mapping_all.fcl | 14 +++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/sbndcode/CRT/CRTEventDisplay/build_tex.sh b/sbndcode/CRT/CRTEventDisplay/build_tex.sh index 727298f54..2f4053d7f 100644 --- a/sbndcode/CRT/CRTEventDisplay/build_tex.sh +++ b/sbndcode/CRT/CRTEventDisplay/build_tex.sh @@ -4,7 +4,7 @@ echo "\documentclass{article} \usepackage{pgffor} \usepackage[hidelinks]{hyperref} -\title{SBND CRT Channel Mapping Displays \\\\ \vspace{1em} \small \textit{Produced using} \texttt{sbndcode v09\_93\_01\_02} \textit{\&} \texttt{sbnd\_v02\_03.gdml}} +\title{SBND CRT Channel Mapping Displays \\\\ \vspace{1em} \small \textit{Produced using} \texttt{sbndcode v10\_04\_01} \textit{\&} \texttt{sbnd\_v02\_05.gdml}} \author{Henry Lay \\\\ \small h.lay@sheffield.ac.uk}" > crt_channel_mapping_evds.tex walls=(bottom south north west east toplow tophigh) @@ -12,7 +12,7 @@ wallnames=(Bottom South North West East "Top Low" "Top High") for wall in "${walls[@]}" do - list=$(ls /exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/${wall}_wall/*_front.pdf) + list=$(ls /exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/${wall}_wall/*_front.pdf) echo -n "\newcommand*{\\"$wall"ids}{" >> crt_channel_mapping_evds.tex for item in ${list} @@ -33,10 +33,10 @@ echo "\begin{document} \centering \vspace{2em} -\includegraphics[width=.6\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/UOSLogo_Primary_Violet_RGB.png} +\includegraphics[width=.6\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/UOSLogo_Primary_Violet_RGB.png} \vspace{2em} -\includegraphics[width=.5\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/sbnd_pride_transparent.png} +\includegraphics[width=.5\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/sbnd_pride_transparent.png} \flushleft \newpage \tableofcontents @@ -55,9 +55,9 @@ do \newpage \subsection{volCRTModule\x\_\x} \begin{center} - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} \end{center} } \endgroup" >> crt_channel_mapping_evds.tex @@ -65,5 +65,5 @@ done echo "\end{document}" >> crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/tex_work crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/tex_work crt_channel_mapping_evds.tex diff --git a/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl index 674c5ee6b..9b8275177 100644 --- a/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl +++ b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl @@ -39,17 +39,17 @@ physics: end_paths: [ ana ] } -physics.analyzers.crtevdbot.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/bottom_wall" +physics.analyzers.crtevdbot.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/bottom_wall" physics.analyzers.crtevdbot.EventDisplayConfig.ChosenTaggers: [ 0 ] -physics.analyzers.crtevdsou.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/south_wall" +physics.analyzers.crtevdsou.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/south_wall" physics.analyzers.crtevdsou.EventDisplayConfig.ChosenTaggers: [ 1 ] -physics.analyzers.crtevdnor.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/north_wall" +physics.analyzers.crtevdnor.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/north_wall" physics.analyzers.crtevdnor.EventDisplayConfig.ChosenTaggers: [ 2 ] -physics.analyzers.crtevdwes.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/west_wall" +physics.analyzers.crtevdwes.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/west_wall" physics.analyzers.crtevdwes.EventDisplayConfig.ChosenTaggers: [ 3 ] -physics.analyzers.crtevdeas.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/east_wall" +physics.analyzers.crtevdeas.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/east_wall" physics.analyzers.crtevdeas.EventDisplayConfig.ChosenTaggers: [ 4 ] -physics.analyzers.crtevdtpl.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/toplow_wall" +physics.analyzers.crtevdtpl.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/toplow_wall" physics.analyzers.crtevdtpl.EventDisplayConfig.ChosenTaggers: [ 5 ] -physics.analyzers.crtevdtph.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/jan2025/tophigh_wall" +physics.analyzers.crtevdtph.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/tophigh_wall" physics.analyzers.crtevdtph.EventDisplayConfig.ChosenTaggers: [ 6 ] From 380b27fcfb124f16d2d01df7dec8bb1c7fdf0778 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Fri, 20 Feb 2026 10:41:52 -0600 Subject: [PATCH 115/155] Make tex script more configurable --- sbndcode/CRT/CRTEventDisplay/build_tex.sh | 28 +++++++++++++++-------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/sbndcode/CRT/CRTEventDisplay/build_tex.sh b/sbndcode/CRT/CRTEventDisplay/build_tex.sh index 2f4053d7f..decfbc43e 100644 --- a/sbndcode/CRT/CRTEventDisplay/build_tex.sh +++ b/sbndcode/CRT/CRTEventDisplay/build_tex.sh @@ -1,18 +1,26 @@ +version=$1 +gdml=$2 +author=$3 +email=$4 +edition=$5 + +mkdir /exp/sbnd/data/users/hlay/crt_channel_mapping/${edition}/tex_work + echo "\documentclass{article} \usepackage[a4paper, margin=3cm]{geometry} \usepackage{graphicx} \usepackage{pgffor} \usepackage[hidelinks]{hyperref} -\title{SBND CRT Channel Mapping Displays \\\\ \vspace{1em} \small \textit{Produced using} \texttt{sbndcode v10\_04\_01} \textit{\&} \texttt{sbnd\_v02\_05.gdml}} -\author{Henry Lay \\\\ \small h.lay@sheffield.ac.uk}" > crt_channel_mapping_evds.tex +\title{SBND CRT Channel Mapping Displays \\\\ \vspace{1em} \small \textit{Produced using} \texttt{sbndcode ${version}} \textit{\&} \texttt{${gdml}}} +\author{${author} \\\\ \small ${email}}" > crt_channel_mapping_evds.tex walls=(bottom south north west east toplow tophigh) wallnames=(Bottom South North West East "Top Low" "Top High") for wall in "${walls[@]}" do - list=$(ls /exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/${wall}_wall/*_front.pdf) + list=$(ls /exp/sbnd/data/users/hlay/crt_channel_mapping/${edition}/${wall}_wall/*_front.pdf) echo -n "\newcommand*{\\"$wall"ids}{" >> crt_channel_mapping_evds.tex for item in ${list} @@ -33,10 +41,10 @@ echo "\begin{document} \centering \vspace{2em} -\includegraphics[width=.6\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/UOSLogo_Primary_Violet_RGB.png} +\includegraphics[width=.6\textwidth]{/nashome/h/hlay/UOSLogo_Primary_Violet_RGB.png} \vspace{2em} -\includegraphics[width=.5\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/sbnd_pride_transparent.png} +\includegraphics[width=.5\textwidth]{/nashome/h/hlay/sbnd_pride_transparent.png} \flushleft \newpage \tableofcontents @@ -55,9 +63,9 @@ do \newpage \subsection{volCRTModule\x\_\x} \begin{center} - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/${edition}/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/${edition}/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ + \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/${edition}/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} \end{center} } \endgroup" >> crt_channel_mapping_evds.tex @@ -65,5 +73,5 @@ done echo "\end{document}" >> crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/tex_work crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/${edition}/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/${edition}/tex_work crt_channel_mapping_evds.tex From 9a5c2ed58b9b87dcbd9b9e42baa20afcee0de149 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Fri, 20 Feb 2026 10:47:13 -0600 Subject: [PATCH 116/155] Make compatible with current develop --- .../CRTChannelMappingEventDisplay_module.cc | 11 +++++------ .../run_crteventdisplay_channel_mapping_all.fcl | 7 +++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/sbndcode/CRT/CRTEventDisplay/CRTChannelMappingEventDisplay_module.cc b/sbndcode/CRT/CRTEventDisplay/CRTChannelMappingEventDisplay_module.cc index 99c4c1f6d..cfa00cd45 100644 --- a/sbndcode/CRT/CRTEventDisplay/CRTChannelMappingEventDisplay_module.cc +++ b/sbndcode/CRT/CRTEventDisplay/CRTChannelMappingEventDisplay_module.cc @@ -55,17 +55,16 @@ class sbnd::crt::CRTChannelMappingEventDisplay : public art::EDAnalyzer { private: - CRTEventDisplayAlg fCRTEventDisplayAlg; - CRTGeoAlg fCRTGeoAlg; - std::string fSaveDir; - std::vector fChosenTaggers; + CRTEventDisplayAlg fCRTEventDisplayAlg; + art::ServiceHandle fCRTGeoService; + std::string fSaveDir; + std::vector fChosenTaggers; }; sbnd::crt::CRTChannelMappingEventDisplay::CRTChannelMappingEventDisplay(Parameters const& config) : EDAnalyzer{config} , fCRTEventDisplayAlg(config().EventDisplayConfig()) - , fCRTGeoAlg(config().EventDisplayConfig().GeoAlgConfig()) , fSaveDir(config().SaveDir()) , fChosenTaggers(config().EventDisplayConfig().ChosenTaggers()) { @@ -76,7 +75,7 @@ void sbnd::crt::CRTChannelMappingEventDisplay::analyze(art::Event const& e) { auto const clockData = art::ServiceHandle()->DataFor(e); - for(auto const& [ name, module ] : fCRTGeoAlg.GetModules()) + for(auto const& [ name, module ] : fCRTGeoService->GetModules()) { if(std::find(fChosenTaggers.begin(), fChosenTaggers.end(), CRTCommonUtils::GetTaggerEnum(module.taggerName)) == fChosenTaggers.end()) continue; diff --git a/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl index 9b8275177..435e34615 100644 --- a/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl +++ b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl @@ -1,17 +1,16 @@ #include "services_sbnd.fcl" #include "particleinventoryservice.fcl" #include "crteventdisplay_sbnd.fcl" -#include "crt_channel_map_service.fcl" -#include "crt_calib_service.fcl" +#include "crt_services_sbnd.fcl" process_name: CRTEventDisplay services: { @table::sbnd_services + @table::crt_services_sbnd ParticleInventoryService: @local::standard_particleinventoryservice - CRTChannelMapService: @local::crt_channel_map_standard - CRTCalibService: @local::crt_calib_service + CRTChannelMapService: @local::crt_channel_map_no_inversion } source: From a196d7cb330d8b767e5ba68d32bf1ddfe4e1e5b1 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Fri, 20 Feb 2026 11:23:09 -0600 Subject: [PATCH 117/155] Remove unnecessary fcl --- .../run_crteventdisplay_channel_mapping.fcl | 29 ------------------- 1 file changed, 29 deletions(-) delete mode 100644 sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping.fcl diff --git a/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping.fcl b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping.fcl deleted file mode 100644 index 03ab48cad..000000000 --- a/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping.fcl +++ /dev/null @@ -1,29 +0,0 @@ -#include "services_sbnd.fcl" -#include "crt_services_sbnd.fcl" -#include "crteventdisplay_sbnd.fcl" - -process_name: CRTEventDisplay - -services: -{ - @table::sbnd_services - @table::crt_services_data_sbnd -} - -source: -{ - module_type: RootInput - maxEvents: -1 -} - -physics: -{ - analyzers: - { - crtevd: @local::crteventdisplay_sbnd_channel_mapping - } - - ana: [ crtevd ] - - end_paths: [ ana ] -} From b36419cd57b17ef350b19cd16132d56f7d1afc70 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Tue, 9 Jul 2024 06:46:07 -0500 Subject: [PATCH 118/155] Add functionality for turning off inversion - useful for the channel mapping event displays --- .../CRT/SBNDCRTChannelMap_v5_no_inversion.txt | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 sbndcode/ChannelMaps/CRT/SBNDCRTChannelMap_v5_no_inversion.txt diff --git a/sbndcode/ChannelMaps/CRT/SBNDCRTChannelMap_v5_no_inversion.txt b/sbndcode/ChannelMaps/CRT/SBNDCRTChannelMap_v5_no_inversion.txt new file mode 100644 index 000000000..7e0478c14 --- /dev/null +++ b/sbndcode/ChannelMaps/CRT/SBNDCRTChannelMap_v5_no_inversion.txt @@ -0,0 +1,87 @@ +40 173 0 +41 172 0 +42 168 0 +43 170 0 +44 176 0 +45 59 0 +46 171 0 +47 61 0 +48 166 0 +49 169 0 +50 56 0 +51 60 0 +52 34 0 +53 33 0 +54 57 0 +55 24 0 +56 159 0 +57 153 0 +58 156 0 +59 152 0 +60 182 0 +61 158 0 +62 157 0 +63 136 0 +64 150 0 +65 151 0 +66 134 0 +67 135 0 +68 149 0 +69 58 0 +70 238 0 +71 155 0 +72 222 0 +73 220 0 +74 81 0 +75 85 0 +76 79 0 +77 206 0 +78 204 0 +79 200 0 +80 18 0 +81 132 0 +82 133 0 +83 162 0 +84 143 0 +85 131 0 +86 146 0 +87 147 0 +88 44 0 +89 160 0 +90 19 0 +91 202 0 +92 199 0 +93 197 0 +94 207 0 +95 203 0 +96 45 0 +97 198 0 +98 174 0 +99 148 0 +100 163 0 +101 164 0 +102 165 0 +103 80 0 +104 193 0 +105 42 0 +106 138 0 +107 130 0 +108 77 0 +109 78 0 +110 98 0 +111 97 0 +112 87 0 +113 95 0 +114 94 0 +115 93 0 +116 86 0 +117 83 0 +118 84 0 +119 104 0 +120 103 0 +121 102 0 +122 101 0 +123 100 0 +124 99 0 +125 90 0 +126 91 0 From 2134fb766fe611a3e9a1373c8dcd78abd06f7ce6 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Mon, 23 Feb 2026 03:45:21 -0600 Subject: [PATCH 119/155] More configurable --- sbndcode/CRT/CRTEventDisplay/build_tex.sh | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/sbndcode/CRT/CRTEventDisplay/build_tex.sh b/sbndcode/CRT/CRTEventDisplay/build_tex.sh index decfbc43e..ae6473d55 100644 --- a/sbndcode/CRT/CRTEventDisplay/build_tex.sh +++ b/sbndcode/CRT/CRTEventDisplay/build_tex.sh @@ -3,8 +3,16 @@ gdml=$2 author=$3 email=$4 edition=$5 +basedir=$6 -mkdir /exp/sbnd/data/users/hlay/crt_channel_mapping/${edition}/tex_work +echo $version +echo $gdml +echo $author +echo $email +echo $edition +echo $basedir + +mkdir ${basedir}/${edition}/tex_work echo "\documentclass{article} \usepackage[a4paper, margin=3cm]{geometry} @@ -20,7 +28,7 @@ wallnames=(Bottom South North West East "Top Low" "Top High") for wall in "${walls[@]}" do - list=$(ls /exp/sbnd/data/users/hlay/crt_channel_mapping/${edition}/${wall}_wall/*_front.pdf) + list=$(ls ${basedir}/${edition}/${wall}_wall/*_front.pdf) echo -n "\newcommand*{\\"$wall"ids}{" >> crt_channel_mapping_evds.tex for item in ${list} @@ -63,9 +71,9 @@ do \newpage \subsection{volCRTModule\x\_\x} \begin{center} - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/${edition}/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/${edition}/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ - \includegraphics[width=.85\textwidth]{/exp/sbnd/data/users/hlay/crt_channel_mapping/${edition}/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} + \includegraphics[width=.85\textwidth]{${basedir}/${edition}/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ + \includegraphics[width=.85\textwidth]{${basedir}/${edition}/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ + \includegraphics[width=.85\textwidth]{${basedir}/${edition}/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} \end{center} } \endgroup" >> crt_channel_mapping_evds.tex @@ -73,5 +81,5 @@ done echo "\end{document}" >> crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/${edition}/tex_work crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory /exp/sbnd/data/users/hlay/crt_channel_mapping/${edition}/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory ${basedir}/${edition}/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory ${basedir}/${edition}/tex_work crt_channel_mapping_evds.tex From cc83f737e108ed8172fdc1eac2aa6843a470b823 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Mon, 23 Feb 2026 03:45:48 -0600 Subject: [PATCH 120/155] Correctly name parameter --- sbndcode/CRT/CRTEventDisplay/crteventdisplayalg_sbnd.fcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbndcode/CRT/CRTEventDisplay/crteventdisplayalg_sbnd.fcl b/sbndcode/CRT/CRTEventDisplay/crteventdisplayalg_sbnd.fcl index 1a5f77633..0f7a523c8 100644 --- a/sbndcode/CRT/CRTEventDisplay/crteventdisplayalg_sbnd.fcl +++ b/sbndcode/CRT/CRTEventDisplay/crteventdisplayalg_sbnd.fcl @@ -99,7 +99,7 @@ crteventdisplayalg_sbnd_data.MaxTime: 1.5e6 crteventdisplayalg_sbnd_channel_mapping: @local::crteventdisplayalg_sbnd -crteventdisplayalg_sbnd_channel_mapping.DataMode: true +crteventdisplayalg_sbnd_channel_mapping.MC: false crteventdisplayalg_sbnd_channel_mapping.SaveRoot: false crteventdisplayalg_sbnd_channel_mapping.SaveViews: true From e20d6225d0c530c1e3550a15a1e747518bc9274e Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Mon, 23 Feb 2026 03:51:01 -0600 Subject: [PATCH 121/155] Make consistent between fcl and bash script --- sbndcode/CRT/CRTEventDisplay/build_tex.sh | 18 ++++++++---------- ...run_crteventdisplay_channel_mapping_all.fcl | 17 ++++++++--------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/sbndcode/CRT/CRTEventDisplay/build_tex.sh b/sbndcode/CRT/CRTEventDisplay/build_tex.sh index ae6473d55..507aefd80 100644 --- a/sbndcode/CRT/CRTEventDisplay/build_tex.sh +++ b/sbndcode/CRT/CRTEventDisplay/build_tex.sh @@ -2,17 +2,15 @@ version=$1 gdml=$2 author=$3 email=$4 -edition=$5 -basedir=$6 +basedir=$5 echo $version echo $gdml echo $author echo $email -echo $edition echo $basedir -mkdir ${basedir}/${edition}/tex_work +mkdir ${basedir}/tex_work echo "\documentclass{article} \usepackage[a4paper, margin=3cm]{geometry} @@ -28,7 +26,7 @@ wallnames=(Bottom South North West East "Top Low" "Top High") for wall in "${walls[@]}" do - list=$(ls ${basedir}/${edition}/${wall}_wall/*_front.pdf) + list=$(ls ${basedir}/${wall}_wall/*_front.pdf) echo -n "\newcommand*{\\"$wall"ids}{" >> crt_channel_mapping_evds.tex for item in ${list} @@ -71,9 +69,9 @@ do \newpage \subsection{volCRTModule\x\_\x} \begin{center} - \includegraphics[width=.85\textwidth]{${basedir}/${edition}/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ - \includegraphics[width=.85\textwidth]{${basedir}/${edition}/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ - \includegraphics[width=.85\textwidth]{${basedir}/${edition}/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} + \includegraphics[width=.85\textwidth]{${basedir}/${walls[i]}_wall/volCRTModule\x_\x_front.pdf}\\\\ + \includegraphics[width=.85\textwidth]{${basedir}/${walls[i]}_wall/volCRTModule\x_\x_top.pdf}\\\\ + \includegraphics[width=.85\textwidth]{${basedir}/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} \end{center} } \endgroup" >> crt_channel_mapping_evds.tex @@ -81,5 +79,5 @@ done echo "\end{document}" >> crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory ${basedir}/${edition}/tex_work crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory ${basedir}/${edition}/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory ${basedir}/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory ${basedir}/tex_work crt_channel_mapping_evds.tex diff --git a/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl index 435e34615..6da8eadc1 100644 --- a/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl +++ b/sbndcode/CRT/CRTEventDisplay/run_crteventdisplay_channel_mapping_all.fcl @@ -16,8 +16,7 @@ services: source: { module_type: RootInput - maxEvents: -1 - + maxEvents: -1 } physics: @@ -38,17 +37,17 @@ physics: end_paths: [ ana ] } -physics.analyzers.crtevdbot.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/bottom_wall" +physics.analyzers.crtevdbot.SaveDir: "/YOUR/DIRECTORY/NAME/bottom_wall" physics.analyzers.crtevdbot.EventDisplayConfig.ChosenTaggers: [ 0 ] -physics.analyzers.crtevdsou.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/south_wall" +physics.analyzers.crtevdsou.SaveDir: "/YOUR/DIRECTORY/NAME/south_wall" physics.analyzers.crtevdsou.EventDisplayConfig.ChosenTaggers: [ 1 ] -physics.analyzers.crtevdnor.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/north_wall" +physics.analyzers.crtevdnor.SaveDir: "/YOUR/DIRECTORY/NAME/north_wall" physics.analyzers.crtevdnor.EventDisplayConfig.ChosenTaggers: [ 2 ] -physics.analyzers.crtevdwes.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/west_wall" +physics.analyzers.crtevdwes.SaveDir: "/YOUR/DIRECTORY/NAME/west_wall" physics.analyzers.crtevdwes.EventDisplayConfig.ChosenTaggers: [ 3 ] -physics.analyzers.crtevdeas.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/east_wall" +physics.analyzers.crtevdeas.SaveDir: "/YOUR/DIRECTORY/NAME/east_wall" physics.analyzers.crtevdeas.EventDisplayConfig.ChosenTaggers: [ 4 ] -physics.analyzers.crtevdtpl.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/toplow_wall" +physics.analyzers.crtevdtpl.SaveDir: "/YOUR/DIRECTORY/NAME/toplow_wall" physics.analyzers.crtevdtpl.EventDisplayConfig.ChosenTaggers: [ 5 ] -physics.analyzers.crtevdtph.SaveDir: "/exp/sbnd/data/users/hlay/crt_channel_mapping/mar2025/tophigh_wall" +physics.analyzers.crtevdtph.SaveDir: "/YOUR/DIRECTORY/NAME/tophigh_wall" physics.analyzers.crtevdtph.EventDisplayConfig.ChosenTaggers: [ 6 ] From df8562a173b85d7630d5b065c50c92eecceba216 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Mon, 23 Feb 2026 03:51:55 -0600 Subject: [PATCH 122/155] Include table for no inversion channel map --- sbndcode/ChannelMaps/CRT/crt_channel_map_service_sbnd.fcl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sbndcode/ChannelMaps/CRT/crt_channel_map_service_sbnd.fcl b/sbndcode/ChannelMaps/CRT/crt_channel_map_service_sbnd.fcl index a34f136cd..16e96b3bc 100644 --- a/sbndcode/ChannelMaps/CRT/crt_channel_map_service_sbnd.fcl +++ b/sbndcode/ChannelMaps/CRT/crt_channel_map_service_sbnd.fcl @@ -5,4 +5,9 @@ crt_channel_map_sbnd: FileName: "SBNDCRTChannelMap_Commissioning_v5.txt" } +crt_channel_map_no_inversion: +{ + FileName: "SBNDCRTChannelMap_v5_no_inversion.txt" +} + END_PROLOG From 02dc0456bf359ccfac0548d149be8314a305a540 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Mon, 23 Feb 2026 05:37:13 -0600 Subject: [PATCH 123/155] Ensure tex file is saved in correct area --- sbndcode/CRT/CRTEventDisplay/build_tex.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sbndcode/CRT/CRTEventDisplay/build_tex.sh b/sbndcode/CRT/CRTEventDisplay/build_tex.sh index 507aefd80..235039478 100644 --- a/sbndcode/CRT/CRTEventDisplay/build_tex.sh +++ b/sbndcode/CRT/CRTEventDisplay/build_tex.sh @@ -19,7 +19,7 @@ echo "\documentclass{article} \usepackage[hidelinks]{hyperref} \title{SBND CRT Channel Mapping Displays \\\\ \vspace{1em} \small \textit{Produced using} \texttt{sbndcode ${version}} \textit{\&} \texttt{${gdml}}} -\author{${author} \\\\ \small ${email}}" > crt_channel_mapping_evds.tex +\author{${author} \\\\ \small ${email}}" > ${basedir}/tex_work/crt_channel_mapping_evds.tex walls=(bottom south north west east toplow tophigh) wallnames=(Bottom South North West East "Top Low" "Top High") @@ -27,17 +27,17 @@ wallnames=(Bottom South North West East "Top Low" "Top High") for wall in "${walls[@]}" do list=$(ls ${basedir}/${wall}_wall/*_front.pdf) - echo -n "\newcommand*{\\"$wall"ids}{" >> crt_channel_mapping_evds.tex + echo -n "\newcommand*{\\"$wall"ids}{" >> ${basedir}/tex_work/crt_channel_mapping_evds.tex for item in ${list} do name=$(echo $item | cut -d '/' -f 10) number=$(echo $name | cut -d '_' -f 2) - echo -n $number, >> crt_channel_mapping_evds.tex + echo -n $number, >> ${basedir}/tex_work/crt_channel_mapping_evds.tex done - sed -i '$ s/.$//' crt_channel_mapping_evds.tex - echo "}" >> crt_channel_mapping_evds.tex + sed -i '$ s/.$//' ${basedir}/tex_work/crt_channel_mapping_evds.tex + echo "}" >> ${basedir}/tex_work/crt_channel_mapping_evds.tex done echo "\begin{document} @@ -57,7 +57,7 @@ echo "\begin{document} \newpage \section{Explanation} This document contains a series of illustrations created using the \texttt{CRTEventDisplay} tool originally written by Tom Brooks \& heavily developed by myself. It shows the position of the various CRT modules according to the gdml file used in SBND simulation and reconstruction. The document is split into sections for the different tagger walls. For each module three illustrations are provided: front, top and side views. The axes show detector coordinates (X, Y and Z) and \`\`building coordinates\" (North, West and Up). The relevant module is shown in green. The TPCs are shown in grey in the centre for reference. The black outer is the full tagger wall. The thin grey are other modules in the wall. The red is the FEB position and the blue corresponds to the end of the FEB with channel 0 (the ethernet ports). -" >> crt_channel_mapping_evds.tex +" >> ${basedir}/tex_work/crt_channel_mapping_evds.tex for i in "${!walls[@]}" do @@ -74,10 +74,10 @@ do \includegraphics[width=.85\textwidth]{${basedir}/${walls[i]}_wall/volCRTModule\x_\x_side.pdf} \end{center} } -\endgroup" >> crt_channel_mapping_evds.tex +\endgroup" >> ${basedir}/tex_work/crt_channel_mapping_evds.tex done -echo "\end{document}" >> crt_channel_mapping_evds.tex +echo "\end{document}" >> ${basedir}/tex_work/crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory ${basedir}/tex_work crt_channel_mapping_evds.tex -pdflatex --shell-escape -output-directory ${basedir}/tex_work crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory ${basedir}/tex_work ${basedir}/tex_work/crt_channel_mapping_evds.tex +pdflatex --shell-escape -output-directory ${basedir}/tex_work ${basedir}/tex_work/crt_channel_mapping_evds.tex From 3ba37b53cd3e17178d3f7e09adfe0c832bcea61a Mon Sep 17 00:00:00 2001 From: nathanielerowe <70993723+nathanielerowe@users.noreply.github.com> Date: Thu, 19 Feb 2026 08:26:08 -0600 Subject: [PATCH 124/155] Update sbncode version to v10_14_02_03 --- ups/product_deps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ups/product_deps b/ups/product_deps index e21a2f2aa..38979aeb7 100644 --- a/ups/product_deps +++ b/ups/product_deps @@ -253,7 +253,7 @@ wpdir product_dir wire-cell-cfg # #################################### product version qual flags -sbncode v10_14_02_02 - +sbncode v10_14_02_03 - cetmodules v3_24_01 - only_for_build sbnd_data v01_42_00 - sbndutil v10_06_01 - optional From 029de7c21d910f5c27065335096cf609dd0b2c9d Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Mon, 23 Feb 2026 07:35:03 -0600 Subject: [PATCH 125/155] Missing branch from CRTAnalysis --- sbndcode/CRT/CRTAna/CRTAnalysis_module.cc | 5 +++++ sbndcode/CRT/CRTAna/crtana_sbnd.fcl | 1 + 2 files changed, 6 insertions(+) diff --git a/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc b/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc index 29f6614c9..08b1f8202 100644 --- a/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc +++ b/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc @@ -323,6 +323,7 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { std::vector _tpc_end_dir_z; std::vector _tpc_length; std::vector _tpc_track_score; + std::vector _tpc_whichtpc; std::vector _tpc_truth_trackid; std::vector _tpc_truth_pdg; std::vector _tpc_truth_energy; @@ -621,6 +622,7 @@ sbnd::crt::CRTAnalysis::CRTAnalysis(fhicl::ParameterSet const& p) fTree->Branch("tpc_end_dir_z", "std::vector", &_tpc_end_dir_z); fTree->Branch("tpc_length", "std::vector", &_tpc_length); fTree->Branch("tpc_track_score", "std::vector", &_tpc_track_score); + fTree->Branch("tpc_whichtpc", "std::vector", &_tpc_whichtpc); fTree->Branch("tpc_sp_matched", "std::vector", &_tpc_sp_matched); fTree->Branch("tpc_sp_channel_set", "std::vector>", &_tpc_sp_channel_set); fTree->Branch("tpc_sp_xshift", "std::vector", &_tpc_sp_xshift); @@ -1682,6 +1684,7 @@ void sbnd::crt::CRTAnalysis::AnalyseTPCMatching(const art::Event &e, const art:: _tpc_end_dir_z.resize(nTracks); _tpc_length.resize(nTracks); _tpc_track_score.resize(nTracks); + _tpc_whichtpc.resize(nTracks); _tpc_truth_trackid.resize(nTracks); _tpc_truth_pdg.resize(nTracks); _tpc_truth_energy.resize(nTracks); @@ -1771,6 +1774,7 @@ void sbnd::crt::CRTAnalysis::AnalyseTPCMatching(const art::Event &e, const art:: const art::Ptr crttrack = tracksToTrackMatches.at(track.key()); const std::vector> trackHits = tracksToHits.at(track.key()); + _tpc_whichtpc[nActualTracks] = TPCGeoUtil::DetectedInTPC(trackHits); if(spacepoint.isNonnull()) { @@ -1915,6 +1919,7 @@ void sbnd::crt::CRTAnalysis::AnalyseTPCMatching(const art::Event &e, const art:: _tpc_end_dir_z.resize(nActualTracks); _tpc_length.resize(nActualTracks); _tpc_track_score.resize(nActualTracks); + _tpc_whichtpc.resize(nActualTracks); _tpc_truth_trackid.resize(nActualTracks); _tpc_truth_pdg.resize(nActualTracks); _tpc_truth_energy.resize(nActualTracks); diff --git a/sbndcode/CRT/CRTAna/crtana_sbnd.fcl b/sbndcode/CRT/CRTAna/crtana_sbnd.fcl index f0a36b111..1ab588870 100644 --- a/sbndcode/CRT/CRTAna/crtana_sbnd.fcl +++ b/sbndcode/CRT/CRTAna/crtana_sbnd.fcl @@ -17,6 +17,7 @@ crtana_sbnd: crtana_data_sbnd: @local::crtana_sbnd crtana_data_sbnd.FEBDataModuleLabel: "crtdecoder" crtana_data_sbnd.DataMode: true +crtana_data_sbnd.NoTPC: false crtana_data_sbnd.HasPTB: true crtana_data_sbnd.HasTDC: true From b67448063cc0a9c20449afecf4640dbe9a11c8b3 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Mon, 23 Feb 2026 07:53:20 -0600 Subject: [PATCH 126/155] Add ADRIFT - module for CRT calibration --- sbndcode/CRT/CRTAna/ADRIFT_module.cc | 1420 +++++++++++++++++++++++ sbndcode/CRT/CRTAna/CMakeLists.txt | 2 + sbndcode/CRT/CRTAna/adrift_sbnd.fcl | 31 + sbndcode/CRT/CRTAna/run_adrift_data.fcl | 28 + 4 files changed, 1481 insertions(+) create mode 100644 sbndcode/CRT/CRTAna/ADRIFT_module.cc create mode 100644 sbndcode/CRT/CRTAna/adrift_sbnd.fcl create mode 100644 sbndcode/CRT/CRTAna/run_adrift_data.fcl diff --git a/sbndcode/CRT/CRTAna/ADRIFT_module.cc b/sbndcode/CRT/CRTAna/ADRIFT_module.cc new file mode 100644 index 000000000..01727c94a --- /dev/null +++ b/sbndcode/CRT/CRTAna/ADRIFT_module.cc @@ -0,0 +1,1420 @@ +//////////////////////////////////////////////////////////////////////// +// Class: ADRIFT +// Plugin Type: analyzer +// File: ADRIFT_module.cc +// +// Author: Henry Lay (h.lay@sheffield.ac.uk) +// +// ADC +// Dynamic +// Range +// Improvement +// Facilitation +// Trees +//////////////////////////////////////////////////////////////////////// + +#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 "art_root_io/TFileService.h" +#include "canvas/Persistency/Common/FindManyP.h" +#include "canvas/Persistency/Common/FindOneP.h" + +#include "TTree.h" +#include "TH1D.h" +#include "TF1.h" +#include "TFitResultPtr.h" +#include "TFitResult.h" +#include "TCanvas.h" +#include "TSystem.h" +#include "TStyle.h" +#include "TText.h" + +#include "artdaq-core/Data/RawEvent.hh" + +#include "sbnobj/SBND/CRT/FEBData.hh" +#include "sbnobj/SBND/CRT/CRTStripHit.hh" +#include "sbnobj/SBND/CRT/CRTCluster.hh" +#include "sbnobj/SBND/CRT/CRTSpacePoint.hh" +#include "sbnobj/SBND/CRT/CRTTrack.hh" + +#include "sbndcode/Geometry/GeometryWrappers/CRTGeoService.h" +#include "sbndcode/ChannelMaps/CRT/CRTChannelMapService.h" + +namespace sbnd { + namespace crt { + class ADRIFT; + } +} + + +class sbnd::crt::ADRIFT : public art::EDAnalyzer { +public: + explicit ADRIFT(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. + ADRIFT(ADRIFT const&) = delete; + ADRIFT(ADRIFT&&) = delete; + ADRIFT& operator=(ADRIFT const&) = delete; + ADRIFT& operator=(ADRIFT&&) = delete; + + // Required functions. + void analyze(art::Event const& e) override; + + // Selected optional functions. + void beginJob() override; + void endJob() override; + +private: + + void MakeSaveDirectories(art::Event const &e); + void AnalyseFEBDatas(art::Event const &e, const int window); + void AnalyseStripHits(art::Event const &e, const int window); + void AnalyseSpacePoints(art::Event const &e, const int window); + void AnalyseTracks(art::Event const &e, const int window); + void ProcessEntry(const int ch, const int window); + void PedestalFit(TH1D* hADC, double &fit, double &std, double &chi2, bool &converged, + bool badChannel, const int window); + void PedestalPeak(TH1D* hADC, double &peak); + void Rate(TH1D* hADC, double &rate, int window, double &period); + void PeakPeak(TH1D* hADC, const double &ped, double &peak); + void PeakFit(TH1D* hADC, const double &peak, const double &ped, double &fit, + double &chi2, bool &converged, bool badChannel, const int window); + double Saturation(TH1D* hADC); + void ResetVars(); + void SaveHist(TH1D *hADC, std::string &saveDir, std::string saveName, int rebin, bool badChannel); + static double LanGau(double *x, double *par); + + art::ServiceHandle fCRTGeoService; + + // Inputs + std::string fFEBDataModuleLabel, fCRTStripHitModuleLabel, fCRTClusterModuleLabel, + fCRTSpacePointModuleLabel, fCRTTrackModuleLabel, fDAQHeaderModuleLabel, fDAQHeaderInstanceLabel, + fTopSaveDirectory; + + bool fOnly2HitSpacePoints, fSaveAllFits, fSaveBadFits, fSaveSubset, fFEBs, fStripHits, fSpacePoints, + fTracks, fTrackLA, fSaveROOTHists, fAnalysePE; + + double fTrackAngleLimit, fPullWindow, fReconstructionWindow; + + uint32_t fRawTSCorrection; + + std::vector> fUnixWindows; + + // Other Global Parameters + std::vector fNEvents; + + TTree* fChannelTree; + + uint64_t _unix_start, _unix_end; + int _n_events, _channel, _gdml_id, _mac5, _raw_channel, _tagger, _channel_status; + double _area, _y_average, _ped_calib, _gain_calib, _ped_fit, _ped_fit_std, _ped_fit_chi2, _ped_peak, + _ped_reset_fit, _ped_reset_fit_std, _ped_reset_fit_chi2, _ped_reset_peak, _raw_max_chan_rate, _sh_rate, _sp_rate, _tr_rate, + _sh_peak_fit, _sh_peak_fit_chi2, _sh_peak_peak, _sh_pe_peak_fit, _sh_pe_peak_fit_chi2, _sh_pe_peak_peak, + _sh_sat_rate, _sh_sat_ratio_total, _sh_sat_ratio_peak, _sp_peak_fit, _sp_peak_fit_chi2, _sp_peak_peak, + _sp_pe_peak_fit, _sp_pe_peak_fit_chi2, _sp_pe_peak_peak, _sp_sat_rate, _sp_sat_ratio_total, _sp_sat_ratio_peak, + _tr_peak_fit, _tr_peak_fit_chi2, _tr_peak_peak, _tr_pe_peak_fit, _tr_pe_peak_fit_chi2, _tr_pe_peak_peak, + _tr_sat_rate, _tr_sat_ratio_total, _tr_sat_ratio_peak, _tr_lim_angle_peak_fit, _tr_lim_angle_peak_fit_chi2, _tr_lim_angle_peak_peak, + _tr_lim_angle_pe_peak_fit, _tr_lim_angle_pe_peak_fit_chi2, _tr_lim_angle_pe_peak_peak, _tr_lim_angle_sat_rate, + _tr_lim_angle_sat_ratio_total, _tr_lim_angle_sat_ratio_peak, _sh_ped_to_peak_fit, _sh_ped_reset_to_peak_fit, + _tr_by_length_peak_fit, _tr_by_length_peak_fit_chi2, _tr_by_length_peak_peak, + _tr_by_length_pe_peak_fit, _tr_by_length_pe_peak_fit_chi2, _tr_by_length_pe_peak_peak; + bool _horizontal, _ped_fit_converged, _ped_reset_fit_converged, _sh_peak_fit_converged, _sh_pe_peak_fit_converged, + _sp_peak_fit_converged, _sp_pe_peak_fit_converged, _tr_peak_fit_converged, _tr_pe_peak_fit_converged, _tr_lim_angle_peak_fit_converged, + _tr_lim_angle_pe_peak_fit_converged, _tr_by_length_peak_fit_converged, _tr_by_length_pe_peak_fit_converged; + + std::map> hADCPed, hADCPedReset, hADCMaxChan, hADCSH, hPESH, hADCSP, hPESP, hADCTr, hPETr, + hADCTrLA, hPETrLA, hADCTrByLength, hPETrByLength; + + std::map fPedestalSaveDirectory, fPedestalResetSaveDirectory, fPeakSaveDirectory, fBadPedestalSaveDirectory, + fBadPedestalResetSaveDirectory, fBadPeakSaveDirectory, fPedestalSubsetSaveDirectory, fPedestalResetSubsetSaveDirectory, + fStripHitSubsetSaveDirectory, fStripHitPESubsetSaveDirectory, fSpacePointSubsetSaveDirectory, fSpacePointPESubsetSaveDirectory, + fTrackSubsetSaveDirectory, fTrackPESubsetSaveDirectory, fTrackLASubsetSaveDirectory, fTrackLAPESubsetSaveDirectory, + fTrackByLengthSubsetSaveDirectory, fTrackByLengthPESubsetSaveDirectory; +}; + + +sbnd::crt::ADRIFT::ADRIFT(fhicl::ParameterSet const& p) + : EDAnalyzer{p} +{ + fFEBDataModuleLabel = p.get("FEBDataModuleLabel"); + fCRTStripHitModuleLabel = p.get("CRTStripHitModuleLabel"); + fCRTClusterModuleLabel = p.get("CRTClusterModuleLabel"); + fCRTSpacePointModuleLabel = p.get("CRTSpacePointModuleLabel"); + fCRTTrackModuleLabel = p.get("CRTTrackModuleLabel"); + fDAQHeaderModuleLabel = p.get("DAQHeaderModuleLabel"); + fDAQHeaderInstanceLabel = p.get("DAQHeaderInstanceLabel"); + fTopSaveDirectory = p.get("TopSaveDirectory"); + fOnly2HitSpacePoints = p.get("Only2HitSpacePoints"); + fSaveAllFits = p.get("SaveAllFits"); + fSaveBadFits = p.get("SaveBadFits"); + fSaveSubset = p.get("SaveSubset"); + fFEBs = p.get("FEBs"); + fStripHits = p.get("StripHits"); + fSpacePoints = p.get("SpacePoints"); + fTracks = p.get("Tracks"); + fTrackLA = p.get("TrackLA"); + fSaveROOTHists = p.get("SaveROOTHists"); + fAnalysePE = p.get("AnalysePE"); + fTrackAngleLimit = p.get("TrackAngleLimit"); + fPullWindow = p.get("PullWindow"); + fReconstructionWindow = p.get("ReconstructionWindow"); + fRawTSCorrection = p.get("RawTSCorrection"); + fUnixWindows = p.get>>("UnixWindows", { {0, std::numeric_limits::max()} }); + + art::ServiceHandle fs; + + fChannelTree = fs->make("channel_tree", ""); + fChannelTree->Branch("unix_start", &_unix_start); + fChannelTree->Branch("unix_end", &_unix_end); + fChannelTree->Branch("n_events", &_n_events); + fChannelTree->Branch("channel", &_channel); + fChannelTree->Branch("gdml_id", &_gdml_id); + fChannelTree->Branch("mac5", &_mac5); + fChannelTree->Branch("raw_channel", &_raw_channel); + fChannelTree->Branch("tagger", &_tagger); + fChannelTree->Branch("channel_status", &_channel_status); + fChannelTree->Branch("area", &_area); + fChannelTree->Branch("y_average", &_y_average); + fChannelTree->Branch("horizontal", &_horizontal); + fChannelTree->Branch("ped_calib", &_ped_calib); + fChannelTree->Branch("gain_calib", &_gain_calib); + if(fFEBs) + { + fChannelTree->Branch("ped_fit", &_ped_fit); + fChannelTree->Branch("ped_fit_std", &_ped_fit_std); + fChannelTree->Branch("ped_fit_chi2", &_ped_fit_chi2); + fChannelTree->Branch("ped_fit_converged", &_ped_fit_converged); + fChannelTree->Branch("ped_peak", &_ped_peak); + fChannelTree->Branch("ped_reset_fit", &_ped_reset_fit); + fChannelTree->Branch("ped_reset_fit_std", &_ped_reset_fit_std); + fChannelTree->Branch("ped_reset_fit_chi2", &_ped_reset_fit_chi2); + fChannelTree->Branch("ped_reset_fit_converged", &_ped_reset_fit_converged); + fChannelTree->Branch("ped_reset_peak", &_ped_reset_peak); + fChannelTree->Branch("raw_max_chan_rate", &_raw_max_chan_rate); + } + if(fStripHits) + { + fChannelTree->Branch("sh_rate", &_sh_rate); + fChannelTree->Branch("sh_peak_fit", &_sh_peak_fit); + fChannelTree->Branch("sh_peak_fit_chi2", &_sh_peak_fit_chi2); + fChannelTree->Branch("sh_peak_fit_converged", &_sh_peak_fit_converged); + fChannelTree->Branch("sh_peak_peak", &_sh_peak_peak); + fChannelTree->Branch("sh_sat_rate", &_sh_sat_rate); + fChannelTree->Branch("sh_sat_ratio_total", &_sh_sat_ratio_total); + fChannelTree->Branch("sh_sat_ratio_peak", &_sh_sat_ratio_peak); + fChannelTree->Branch("sh_ped_to_peak_fit", &_sh_ped_to_peak_fit); + fChannelTree->Branch("sh_ped_reset_to_peak_fit", &_sh_ped_reset_to_peak_fit); + + if(fAnalysePE) + { + fChannelTree->Branch("sh_pe_peak_fit", &_sh_pe_peak_fit); + fChannelTree->Branch("sh_pe_peak_fit_chi2", &_sh_pe_peak_fit_chi2); + fChannelTree->Branch("sh_pe_peak_fit_converged", &_sh_pe_peak_fit_converged); + fChannelTree->Branch("sh_pe_peak_peak", &_sh_pe_peak_peak); + } + } + if(fSpacePoints) + { + fChannelTree->Branch("sp_rate", &_sp_rate); + fChannelTree->Branch("sp_peak_fit", &_sp_peak_fit); + fChannelTree->Branch("sp_peak_fit_chi2", &_sp_peak_fit_chi2); + fChannelTree->Branch("sp_peak_fit_converged", &_sp_peak_fit_converged); + fChannelTree->Branch("sp_peak_peak", &_sp_peak_peak); + fChannelTree->Branch("sp_sat_rate", &_sp_sat_rate); + fChannelTree->Branch("sp_sat_ratio_total", &_sp_sat_ratio_total); + fChannelTree->Branch("sp_sat_ratio_peak", &_sp_sat_ratio_peak); + + if(fAnalysePE) + { + fChannelTree->Branch("sp_pe_peak_fit", &_sp_pe_peak_fit); + fChannelTree->Branch("sp_pe_peak_fit_chi2", &_sp_pe_peak_fit_chi2); + fChannelTree->Branch("sp_pe_peak_fit_converged", &_sp_pe_peak_fit_converged); + fChannelTree->Branch("sp_pe_peak_peak", &_sp_pe_peak_peak); + } + } + if(fTracks) + { + fChannelTree->Branch("tr_rate", &_tr_rate); + fChannelTree->Branch("tr_peak_fit", &_tr_peak_fit); + fChannelTree->Branch("tr_peak_fit_chi2", &_tr_peak_fit_chi2); + fChannelTree->Branch("tr_peak_fit_converged", &_tr_peak_fit_converged); + fChannelTree->Branch("tr_peak_peak", &_tr_peak_peak); + fChannelTree->Branch("tr_sat_rate", &_tr_sat_rate); + fChannelTree->Branch("tr_sat_ratio_total", &_tr_sat_ratio_total); + fChannelTree->Branch("tr_sat_ratio_peak", &_tr_sat_ratio_peak); + fChannelTree->Branch("tr_by_length_peak_fit", &_tr_by_length_peak_fit); + fChannelTree->Branch("tr_by_length_peak_fit_chi2", &_tr_by_length_peak_fit_chi2); + fChannelTree->Branch("tr_by_length_peak_fit_converged", &_tr_by_length_peak_fit_converged); + fChannelTree->Branch("tr_by_length_peak_peak", &_tr_by_length_peak_peak); + + if(fAnalysePE) + { + fChannelTree->Branch("tr_pe_peak_fit", &_tr_pe_peak_fit); + fChannelTree->Branch("tr_pe_peak_fit_chi2", &_tr_pe_peak_fit_chi2); + fChannelTree->Branch("tr_pe_peak_fit_converged", &_tr_pe_peak_fit_converged); + fChannelTree->Branch("tr_pe_peak_peak", &_tr_pe_peak_peak); + fChannelTree->Branch("tr_by_length_pe_peak_fit", &_tr_by_length_pe_peak_fit); + fChannelTree->Branch("tr_by_length_pe_peak_fit_chi2", &_tr_by_length_pe_peak_fit_chi2); + fChannelTree->Branch("tr_by_length_pe_peak_fit_converged", &_tr_by_length_pe_peak_fit_converged); + fChannelTree->Branch("tr_by_length_pe_peak_peak", &_tr_by_length_pe_peak_peak); + } + } + if(fTrackLA) + { + fChannelTree->Branch("tr_lim_angle_peak_fit", &_tr_lim_angle_peak_fit); + fChannelTree->Branch("tr_lim_angle_peak_fit_chi2", &_tr_lim_angle_peak_fit_chi2); + fChannelTree->Branch("tr_lim_angle_peak_fit_converged", &_tr_lim_angle_peak_fit_converged); + fChannelTree->Branch("tr_lim_angle_peak_peak", &_tr_lim_angle_peak_peak); + fChannelTree->Branch("tr_lim_angle_sat_rate", &_tr_lim_angle_sat_rate); + fChannelTree->Branch("tr_lim_angle_sat_ratio_total", &_tr_lim_angle_sat_ratio_total); + fChannelTree->Branch("tr_lim_angle_sat_ratio_peak", &_tr_lim_angle_sat_ratio_peak); + + if(fAnalysePE) + { + fChannelTree->Branch("tr_lim_angle_pe_peak_fit", &_tr_lim_angle_pe_peak_fit); + fChannelTree->Branch("tr_lim_angle_pe_peak_fit_chi2", &_tr_lim_angle_pe_peak_fit_chi2); + fChannelTree->Branch("tr_lim_angle_pe_peak_fit_converged", &_tr_lim_angle_pe_peak_fit_converged); + fChannelTree->Branch("tr_lim_angle_pe_peak_peak", &_tr_lim_angle_pe_peak_peak); + } + } + + for(uint window = 0; window < fUnixWindows.size(); ++window) + { + if(fSaveROOTHists) + { + for(int ch = 0; ch < 4480; ++ch) + { + if(fFEBs) + { + hADCPed[window][ch] = fs->make(Form("hADCPed_Window%i_Channel%i", window, ch), ";ADC;Readouts", 1000, -.5, 999.5); + hADCPedReset[window][ch] = fs->make(Form("hADCPedReset_Window%i_Channel%i", window, ch), ";ADC;Readouts", 1000, -.5, 999.5); + hADCMaxChan[window][ch] = fs->make(Form("hADCMaxChan_Window%i_Channel%i", window, ch), ";ADC;Readouts - Max Channel", 4300, -.5, 4299.5); + } + + if(fStripHits) + { + hADCSH[window][ch] = fs->make(Form("hADCSH_Window%i_Channel%i", window, ch), ";ADC;Strip Hits", 4300, -.5, 4299.5); + + if(fAnalysePE) + hPESH[window][ch] = fs->make(Form("hPESH_Window%i_Channel%i", window, ch), ";PE;Strip Hits", 4000, 0, 200); + } + + if(fSpacePoints) + { + hADCSP[window][ch] = fs->make(Form("hADCSP_Window%i_Channel%i", window, ch), ";ADC;Space Points", 4300, -.5, 4299.5); + + if(fAnalysePE) + hPESP[window][ch] = fs->make(Form("hPESP_Window%i_Channel%i", window, ch), ";PE;Space Points", 4000, 0, 200); + } + + if(fTracks) + { + hADCTr[window][ch] = fs->make(Form("hADCTr_Window%i_Channel%i", window, ch), ";ADC;Tracks", 4300, -.5, 4299.5); + hADCTrByLength[window][ch] = fs->make(Form("hADCTrByLength_Window%i_Channel%i", window, ch), ";ADC/Path Length;Tracks", 4300, -.5, 4299.5); + + if(fAnalysePE) + { + hPETr[window][ch] = fs->make(Form("hPETr_Window%i_Channel%i", window, ch), ";PE;Tracks", 4000, 0, 200); + hPETrByLength[window][ch] = fs->make(Form("hPETrByLength_Window%i_Channel%i", window, ch), ";PE/Path Length;Tracks", 4000, 0, 200); + } + } + + if(fTrackLA) + { + hADCTrLA[window][ch] = fs->make(Form("hADCTrLA_Window%i_Channel%i", window, ch), ";ADC;Tracks", 4300, -.5, 4299.5); + + if(fAnalysePE) + hPETrLA[window][ch] = fs->make(Form("hPETrLA_Window%i_Channel%i", window, ch), ";PE;Tracks", 4000, 0, 200); + } + } + } + else + { + for(int ch = 0; ch < 4480; ++ch) + { + if(fFEBs) + { + hADCPed[window][ch] = new TH1D(Form("hADCPed_Window%i_Channel%i", window, ch), ";ADC;Readouts", 1000, -.5, 999.5); + hADCPedReset[window][ch] = new TH1D(Form("hADCPedReset_Window%i_Channel%i", window, ch), ";ADC;Readouts", 1000, -.5, 999.5); + hADCMaxChan[window][ch] = new TH1D(Form("hADCMaxChan_Window%i_Channel%i", window, ch), ";ADC;Readouts - Max Channel", 4300, -.5, 4299.5); + } + + if(fStripHits) + { + hADCSH[window][ch] = new TH1D(Form("hADCSH_Window%i_Channel%i", window, ch), ";ADC;Strip Hits", 4300, -.5, 4299.5); + + if(fAnalysePE) + hPESH[window][ch] = new TH1D(Form("hPESH_Window%i_Channel%i", window, ch), ";PE;Strip Hits", 4000, 0, 200); + } + + if(fSpacePoints) + { + hADCSP[window][ch] = new TH1D(Form("hADCSP_Window%i_Channel%i", window, ch), ";ADC;Space Points", 4300, -.5, 4299.5); + + if(fAnalysePE) + hPESP[window][ch] = new TH1D(Form("hPESP_Window%i_Channel%i", window, ch), ";PE;Space Points", 4000, 0, 200); + } + + if(fTracks) + { + hADCTr[window][ch] = new TH1D(Form("hADCTr_Window%i_Channel%i", window, ch), ";ADC;Tracks", 4300, -.5, 4299.5); + hADCTrByLength[window][ch] = new TH1D(Form("hADCTrByLength_Window%i_Channel%i", window, ch), ";ADC/Path Length;Tracks", 4300, -.5, 4299.5); + + if(fAnalysePE) + { + hPETr[window][ch] = new TH1D(Form("hPETr_Window%i_Channel%i", window, ch), ";PE;Tracks", 4000, 0, 200); + hPETrByLength[window][ch] = new TH1D(Form("hPETrByLength_Window%i_Channel%i", window, ch), ";PE/Path Length;Tracks", 4000, 0, 200); + } + } + + if(fTrackLA) + { + hADCTrLA[window][ch] = new TH1D(Form("hADCTrLA_Window%i_Channel%i", window, ch), ";ADC;Tracks", 4300, -.5, 4299.5); + + if(fAnalysePE) + hPETrLA[window][ch] = new TH1D(Form("hPETrLA_Window%i_Channel%i", window, ch), ";PE;Tracks", 4000, 0, 200); + } + } + } + } + + for(uint i = 0; i < fUnixWindows.size(); ++i) + { + for(uint ii = i + 1; ii < fUnixWindows.size(); ++ii) + { + if(fUnixWindows[i].second > fUnixWindows[ii].first) + { + std::cout << "Unix windows overlap!" << std::endl; + throw std::exception(); + } + } + } +} + +void sbnd::crt::ADRIFT::analyze(art::Event const& e) +{ + // Get Raw TS + art::Handle DAQHeaderHandle; + e.getByLabel(fDAQHeaderModuleLabel, fDAQHeaderInstanceLabel, DAQHeaderHandle); + if(!DAQHeaderHandle.isValid()){ + std::cout << "RawEventHeader product " << fDAQHeaderModuleLabel << " - " << fDAQHeaderInstanceLabel << " not found..." << std::endl; + throw std::exception(); + } + artdaq::RawEvent rawHeaderEvent = artdaq::RawEvent(*DAQHeaderHandle); + uint64_t raw_ts = rawHeaderEvent.timestamp() - fRawTSCorrection; + + uint window = 0; + bool found = false; + + for(uint i = 0; i < fUnixWindows.size(); ++i) + { + if(raw_ts > fUnixWindows[i].first && raw_ts < fUnixWindows[i].second) + { + window = i; + found = true; + break; + } + } + + if(!found) + return; + + if(std::accumulate(fNEvents.begin(), fNEvents.end(), 0) == 0) + MakeSaveDirectories(e); + + if(fFEBs) + AnalyseFEBDatas(e, window); + + if(fStripHits) + AnalyseStripHits(e, window); + + if(fSpacePoints) + AnalyseSpacePoints(e, window); + + if(fTracks || fTrackLA) + AnalyseTracks(e, window); + + ++fNEvents[window]; +} + +void sbnd::crt::ADRIFT::MakeSaveDirectories(art::Event const &e) +{ + for(uint window = 0; window < fUnixWindows.size(); ++window) + { + std::string directory_structure = fUnixWindows.size() == 1 ? Form("run%i", e.run()) : Form("run%i/window%i", e.run(), window); + + if((fSaveAllFits || fSaveBadFits)) + { + gSystem->Exec(Form("mkdir -p %s", fTopSaveDirectory.c_str())); + + if(fFEBs) + { + fPedestalSaveDirectory[window] = Form("%s/%s/pedestals", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fPedestalSaveDirectory[window].c_str())); + + fPedestalResetSaveDirectory[window] = Form("%s/%s/pedestals_reset", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fPedestalResetSaveDirectory[window].c_str())); + + fBadPedestalSaveDirectory[window] = Form("%s/%s/pedestals/bad", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fBadPedestalSaveDirectory[window].c_str())); + + fBadPedestalResetSaveDirectory[window] = Form("%s/%s/pedestals_reset/bad", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fBadPedestalResetSaveDirectory[window].c_str())); + } + + if(fStripHits || fSpacePoints || fTracks || fTrackLA) + { + fPeakSaveDirectory[window] = Form("%s/%s/peaks", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fPeakSaveDirectory[window].c_str())); + + fBadPeakSaveDirectory[window] = Form("%s/%s/peaks/bad", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fBadPeakSaveDirectory[window].c_str())); + } + } + + if(fSaveSubset) + { + gSystem->Exec(Form("mkdir -p %s", fTopSaveDirectory.c_str())); + + if(fFEBs) + { + fPedestalSubsetSaveDirectory[window] = Form("%s/%s/subset/pedestals", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fPedestalSubsetSaveDirectory[window].c_str())); + + fPedestalResetSubsetSaveDirectory[window] = Form("%s/%s/subset/pedestals_reset", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fPedestalResetSubsetSaveDirectory[window].c_str())); + } + + if(fStripHits) + { + fStripHitSubsetSaveDirectory[window] = Form("%s/%s/subset/striphits", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fStripHitSubsetSaveDirectory[window].c_str())); + + if(fAnalysePE) + { + fStripHitPESubsetSaveDirectory[window] = Form("%s/%s/subset/striphits_pe", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fStripHitPESubsetSaveDirectory[window].c_str())); + } + } + + if(fSpacePoints) + { + fSpacePointSubsetSaveDirectory[window] = Form("%s/%s/subset/spacepoints", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fSpacePointSubsetSaveDirectory[window].c_str())); + + if(fAnalysePE) + { + fSpacePointPESubsetSaveDirectory[window] = Form("%s/%s/subset/spacepoints_pe", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fSpacePointPESubsetSaveDirectory[window].c_str())); + } + } + + if(fTracks) + { + fTrackSubsetSaveDirectory[window] = Form("%s/%s/subset/tracks", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fTrackSubsetSaveDirectory[window].c_str())); + + fTrackByLengthSubsetSaveDirectory[window] = Form("%s/%s/subset/tracks_by_length", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fTrackByLengthSubsetSaveDirectory[window].c_str())); + + if(fAnalysePE) + { + fTrackPESubsetSaveDirectory[window] = Form("%s/%s/subset/tracks_pe", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fTrackPESubsetSaveDirectory[window].c_str())); + + fTrackByLengthPESubsetSaveDirectory[window] = Form("%s/%s/subset/tracks_by_length_pe", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fTrackByLengthPESubsetSaveDirectory[window].c_str())); + } + } + + if(fTrackLA) + { + fTrackLASubsetSaveDirectory[window] = Form("%s/%s/subset/tracks_limited_angle", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fTrackLASubsetSaveDirectory[window].c_str())); + + if(fAnalysePE) + { + fTrackLAPESubsetSaveDirectory[window] = Form("%s/%s/subset/tracks_limited_angle_pe", fTopSaveDirectory.c_str(), directory_structure.c_str()); + gSystem->Exec(Form("mkdir -p %s", fTrackLAPESubsetSaveDirectory[window].c_str())); + } + } + } + } + + if((fSaveAllFits || fSaveBadFits || fSaveSubset)) + { + gStyle->SetOptStat(0); + gStyle->SetFrameLineWidth(2); + gStyle->SetTextFont(62); + gStyle->SetTextSize(0.07); + gStyle->SetLabelFont(62, "xyz"); + gStyle->SetLabelSize(0.05, "xyz"); + gStyle->SetTitleSize(0.05, "xyz"); + gStyle->SetTitleFont(62, "xyz"); + } +} + +void sbnd::crt::ADRIFT::AnalyseFEBDatas(art::Event const &e, const int window) +{ + // Get FEBDatas + art::Handle> FEBDataHandle; + e.getByLabel(fFEBDataModuleLabel, FEBDataHandle); + if(!FEBDataHandle.isValid()){ + std::cout << "FEBData product " << fFEBDataModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + std::vector> FEBDataVec; + art::fill_ptr_vector(FEBDataVec, FEBDataHandle); + + // Get FEBData to CRTStripHit Assns + art::FindManyP febDatasToStripHits(FEBDataHandle, e, fCRTStripHitModuleLabel); + + for(const art::Ptr &feb_data : FEBDataVec) + { + const std::vector> strip_hits = febDatasToStripHits.at(feb_data.key()); + const uint m5 = feb_data->Mac5(); + const uint flags = feb_data->Flags(); + + std::set mask_channels; + + for(const art::Ptr &strip_hit : strip_hits) + { + mask_channels.insert(strip_hit->Channel()); + mask_channels.insert(strip_hit->Channel() + 1); + + if(strip_hit->Channel() % 2) + std::cout << "ODD Strip Hit Channel Number" << std::endl; + } + + int max_adc = -1, max_chan = -1; + + for(int i = 0; i < 32; ++i) + { + if(feb_data->ADC(i) > max_adc) + { + max_adc = feb_data->ADC(i); + max_chan = i; + } + + const int ch = m5 * 32 + i; + + if(!mask_channels.count(ch)) + hADCPed[window][ch]->Fill(feb_data->ADC(i)); + + if(flags != 1 && flags != 3) + hADCPedReset[window][ch]->Fill(feb_data->ADC(i)); + } + + if((flags == 1 || flags == 3) && max_chan != -1) + hADCMaxChan[window][m5 * 32 + max_chan]->Fill(feb_data->ADC(max_chan)); + } +} + +void sbnd::crt::ADRIFT::AnalyseStripHits(art::Event const &e, const int window) +{ + // Get CRTStripHits + art::Handle> CRTStripHitHandle; + e.getByLabel(fCRTStripHitModuleLabel, CRTStripHitHandle); + if(!CRTStripHitHandle.isValid()){ + std::cout << "CRTStripHit product " << fCRTStripHitModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + std::vector> CRTStripHitVec; + art::fill_ptr_vector(CRTStripHitVec, CRTStripHitHandle); + + for(const art::Ptr &strip_hit : CRTStripHitVec) + { + if(strip_hit->Channel() % 2) + std::cout << "ODD Strip Hit Channel Number" << std::endl; + + CRTSiPMGeo sipm1 = fCRTGeoService->GetSiPM(strip_hit->Channel()); + CRTSiPMGeo sipm2 = fCRTGeoService->GetSiPM(strip_hit->Channel() + 1); + + hADCSH[window][strip_hit->Channel()]->Fill(strip_hit->ADC1() + sipm1.pedestal); + hADCSH[window][strip_hit->Channel() + 1]->Fill(strip_hit->ADC2() + sipm2.pedestal); + + if(fAnalysePE) + { + if((strip_hit->ADC1() + sipm1.pedestal) < 4089) + hPESH[window][strip_hit->Channel()]->Fill(strip_hit->ADC1() * sipm1.gain); + if((strip_hit->ADC2() + sipm2.pedestal) < 4089) + hPESH[window][strip_hit->Channel() + 1]->Fill(strip_hit->ADC2() * sipm2.gain); + } + } +} + +void sbnd::crt::ADRIFT::AnalyseSpacePoints(art::Event const &e, const int window) +{ + // Get CRTSpacePoints + art::Handle> CRTSpacePointHandle; + e.getByLabel(fCRTSpacePointModuleLabel, CRTSpacePointHandle); + if(!CRTSpacePointHandle.isValid()){ + std::cout << "CRTSpacePoint product " << fCRTSpacePointModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + std::vector> CRTSpacePointVec; + art::fill_ptr_vector(CRTSpacePointVec, CRTSpacePointHandle); + + // Get CRTClusters + art::Handle> CRTClusterHandle; + e.getByLabel(fCRTClusterModuleLabel, CRTClusterHandle); + if(!CRTClusterHandle.isValid()){ + std::cout << "CRTCluster product " << fCRTClusterModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + + // Get CRTSpacePoint to CRTCluster Assns + art::FindOneP spacepointsToClusters(CRTSpacePointHandle, e, fCRTSpacePointModuleLabel); + + // Get CRTCluster to CRTStripHit Assns + art::FindManyP clustersToStripHits(CRTClusterHandle, e, fCRTClusterModuleLabel); + + for(const art::Ptr &space_point : CRTSpacePointVec) + { + const art::Ptr cluster = spacepointsToClusters.at(space_point.key()); + + if(fOnly2HitSpacePoints && cluster->NHits() > 2) + continue; + + const std::vector> strip_hits = clustersToStripHits.at(cluster.key()); + + for(const art::Ptr &strip_hit : strip_hits) + { + if(strip_hit->Channel() % 2) + std::cout << "ODD Strip Hit Channel Number" << std::endl; + + CRTSiPMGeo sipm1 = fCRTGeoService->GetSiPM(strip_hit->Channel()); + CRTSiPMGeo sipm2 = fCRTGeoService->GetSiPM(strip_hit->Channel() + 1); + + hADCSP[window][strip_hit->Channel()]->Fill(strip_hit->ADC1() + sipm1.pedestal); + hADCSP[window][strip_hit->Channel() + 1]->Fill(strip_hit->ADC2() + sipm2.pedestal); + + if(fAnalysePE) + { + if((strip_hit->ADC1() + sipm1.pedestal) < 4089) + hPESP[window][strip_hit->Channel()]->Fill(strip_hit->ADC1() * sipm1.gain); + if((strip_hit->ADC2() + sipm2.pedestal) < 4089) + hPESP[window][strip_hit->Channel() + 1]->Fill(strip_hit->ADC2() * sipm2.gain); + } + } + } +} + +void sbnd::crt::ADRIFT::AnalyseTracks(art::Event const &e, const int window) +{ + // Get CRTTracks + art::Handle> CRTTrackHandle; + e.getByLabel(fCRTTrackModuleLabel, CRTTrackHandle); + if(!CRTTrackHandle.isValid()){ + std::cout << "CRTTrack product " << fCRTTrackModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + std::vector> CRTTrackVec; + art::fill_ptr_vector(CRTTrackVec, CRTTrackHandle); + + // Get CRTSpacePoints + art::Handle> CRTSpacePointHandle; + e.getByLabel(fCRTSpacePointModuleLabel, CRTSpacePointHandle); + if(!CRTSpacePointHandle.isValid()){ + std::cout << "CRTSpacePoint product " << fCRTSpacePointModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + + // Get CRTClusters + art::Handle> CRTClusterHandle; + e.getByLabel(fCRTClusterModuleLabel, CRTClusterHandle); + if(!CRTClusterHandle.isValid()){ + std::cout << "CRTCluster product " << fCRTClusterModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + + // Get CRTTrack to CRTSpacePoint Assns + art::FindManyP tracksToSpacePoints(CRTTrackHandle, e, fCRTTrackModuleLabel); + + // Get CRTSpacePoint to CRTCluster Assns + art::FindOneP spacepointsToClusters(CRTSpacePointHandle, e, fCRTSpacePointModuleLabel); + + // Get CRTCluster to CRTStripHit Assns + art::FindManyP clustersToStripHits(CRTClusterHandle, e, fCRTClusterModuleLabel); + + for(const art::Ptr &track : CRTTrackVec) + { + const std::vector> space_points = tracksToSpacePoints.at(track.key()); + + const geo::Vector_t tr_dir_vec = track->Direction(); + const TVector3 tr_dir = TVector3(tr_dir_vec.X(), tr_dir_vec.Y(), tr_dir_vec.Z()); + + for(const art::Ptr &space_point : space_points) + { + const art::Ptr cluster = spacepointsToClusters.at(space_point.key()); + + const std::vector> strip_hits = clustersToStripHits.at(cluster.key()); + const CRTTagger tagger = cluster->Tagger(); + TVector3 normal; + if(tagger == kBottomTagger || tagger == kTopLowTagger || tagger == kTopHighTagger) + normal = TVector3(0, 1, 0); + else if(tagger == kWestTagger || tagger == kEastTagger) + normal = TVector3(1, 0, 0); + else if(tagger == kSouthTagger || tagger == kNorthTagger) + normal = TVector3(0, 0, 1); + + const double angle = TMath::RadToDeg() * normal.Angle(tr_dir); + const double path_length = 1 / TMath::Cos(normal.Angle(tr_dir)); + + for(const art::Ptr &strip_hit : strip_hits) + { + if(strip_hit->Channel() % 2) + std::cout << "ODD Strip Hit Channel Number" << std::endl; + + CRTSiPMGeo sipm1 = fCRTGeoService->GetSiPM(strip_hit->Channel()); + CRTSiPMGeo sipm2 = fCRTGeoService->GetSiPM(strip_hit->Channel() + 1); + + if(fTracks) + { + hADCTr[window][strip_hit->Channel()]->Fill(strip_hit->ADC1() + sipm1.pedestal); + hADCTr[window][strip_hit->Channel() + 1]->Fill(strip_hit->ADC2() + sipm2.pedestal); + + if(fAnalysePE) + { + if((strip_hit->ADC1() + sipm1.pedestal) < 4089) + hPETr[window][strip_hit->Channel()]->Fill(strip_hit->ADC1() * sipm1.gain); + if((strip_hit->ADC2() + sipm2.pedestal) < 4089) + hPETr[window][strip_hit->Channel() + 1]->Fill(strip_hit->ADC2() * sipm2.gain); + } + + if((strip_hit->ADC1() + sipm1.pedestal) < 4089) + { + hADCTrByLength[window][strip_hit->Channel()]->Fill((strip_hit->ADC1() + sipm1.pedestal) / path_length); + + if(fAnalysePE && (strip_hit->ADC1() + sipm1.pedestal) < 4089) + hPETrByLength[window][strip_hit->Channel()]->Fill((strip_hit->ADC1() * sipm1.gain) / path_length); + } + if((strip_hit->ADC2() + sipm2.pedestal) < 4089) + { + hADCTrByLength[window][strip_hit->Channel() + 1]->Fill((strip_hit->ADC2() + sipm2.pedestal) / path_length); + + if(fAnalysePE && (strip_hit->ADC2() + sipm2.pedestal) < 4089) + hPETrByLength[window][strip_hit->Channel() + 1]->Fill((strip_hit->ADC2() * sipm2.gain) / path_length); + } + } + + if(fTrackLA && angle < fTrackAngleLimit) + { + hADCTrLA[window][strip_hit->Channel()]->Fill(strip_hit->ADC1() + sipm1.pedestal); + hADCTrLA[window][strip_hit->Channel() + 1]->Fill(strip_hit->ADC2() + sipm2.pedestal); + + if(fAnalysePE) + { + if((strip_hit->ADC1() + sipm1.pedestal) < 4089) + hPETrLA[window][strip_hit->Channel()]->Fill(strip_hit->ADC1() * sipm1.gain); + if((strip_hit->ADC2() + sipm2.pedestal) < 4089) + hPETrLA[window][strip_hit->Channel() + 1]->Fill(strip_hit->ADC2() * sipm2.gain); + } + } + } + } + } +} + +void sbnd::crt::ADRIFT::beginJob() +{ + fNEvents = std::vector(fUnixWindows.size(), 0); +} + +void sbnd::crt::ADRIFT::endJob() +{ + art::ServiceHandle ChannelMapService; + + for(int gdml_i = 0; gdml_i < 140; ++gdml_i) + { + ResetVars(); + + std::cout << "=== Processing module " << gdml_i << std::endl; + + uint mac5 = ChannelMapService->GetMAC5FromOfflineModuleID(gdml_i); + bool invert = ChannelMapService->GetInversionFromOfflineModuleID(gdml_i); + + for(int ch_i = 0; ch_i < 32; ++ch_i) + { + const int ch = ChannelMapService->ConstructOfflineChannelIDFromOfflineModuleIDAndOfflineLocalChannel(gdml_i, ch_i); + + _channel = ch; + _gdml_id = gdml_i; + _mac5 = mac5; + _raw_channel = invert ? 31 - ch_i : ch_i; + _tagger = fCRTGeoService->ChannelToTaggerEnum(ch); + _channel_status = fCRTGeoService->GetSiPM(ch).status; + _area = fCRTGeoService->StripArea(ch); + _y_average = fCRTGeoService->StripAverageY(ch); + _ped_calib = fCRTGeoService->GetSiPM(ch).pedestal; + _gain_calib = fCRTGeoService->GetSiPM(ch).gain; + _horizontal = _tagger == kBottomTagger || _tagger == kTopLowTagger || _tagger == kTopHighTagger; + + for(uint window = 0; window < fUnixWindows.size(); ++window) + ProcessEntry(ch, window); + } + } +} + +void sbnd::crt::ADRIFT::ProcessEntry(const int ch, const int window) +{ + _unix_start = fUnixWindows[window].first; + _unix_end = fUnixWindows[window].second; + _n_events = fNEvents[window]; + + if(fSaveSubset && (ch > 1471 && ch < 1728)) + { + if(fFEBs) + { + SaveHist(hADCPed[window][ch], fPedestalSubsetSaveDirectory[window], Form("pedestal_channel_%i", ch), 2, _channel_status); + SaveHist(hADCPedReset[window][ch], fPedestalResetSubsetSaveDirectory[window], Form("pedestal_reset_channel_%i", ch), 2, _channel_status); + } + + if(fStripHits) + { + SaveHist(hADCSH[window][ch], fStripHitSubsetSaveDirectory[window], Form("strip_hit_channel_%i", ch), 20, _channel_status); + + if(fAnalysePE) + SaveHist(hPESH[window][ch], fStripHitPESubsetSaveDirectory[window], Form("strip_hit_pe_channel_%i", ch), 20, _channel_status); + } + + if(fSpacePoints) + { + SaveHist(hADCSP[window][ch], fSpacePointSubsetSaveDirectory[window], Form("space_point_channel_%i", ch), 20, _channel_status); + if(fAnalysePE) + SaveHist(hPESP[window][ch], fSpacePointPESubsetSaveDirectory[window], Form("space_point_pe_channel_%i", ch), 20, _channel_status); + } + + if(fTracks) + { + SaveHist(hADCTr[window][ch], fTrackSubsetSaveDirectory[window], Form("track_channel_%i", ch), 20, _channel_status); + SaveHist(hADCTrByLength[window][ch], fTrackByLengthSubsetSaveDirectory[window], Form("track_by_length_channel_%i", ch), 20, _channel_status); + if(fAnalysePE) + { + SaveHist(hPETr[window][ch], fTrackPESubsetSaveDirectory[window], Form("track_pe_channel_%i", ch), 20, _channel_status); + SaveHist(hPETrByLength[window][ch], fTrackByLengthPESubsetSaveDirectory[window], Form("track_by_length_pe_channel_%i", ch), 20, _channel_status); + } + } + + if(fTrackLA) + { + SaveHist(hADCTrLA[window][ch], fTrackLASubsetSaveDirectory[window], Form("track_limited_angle_channel_%i", ch), 20, _channel_status); + if(fAnalysePE) + SaveHist(hPETrLA[window][ch], fTrackLAPESubsetSaveDirectory[window], Form("track_limited_angle_pe_channel_%i", ch), 20, _channel_status); + } + + } + + if(fFEBs) + { + PedestalFit(hADCPed[window][ch], _ped_fit, _ped_fit_std, _ped_fit_chi2, _ped_fit_converged, _channel_status, window); + PedestalPeak(hADCPed[window][ch], _ped_peak); + + PedestalFit(hADCPedReset[window][ch], _ped_reset_fit, _ped_reset_fit_std, _ped_reset_fit_chi2, _ped_reset_fit_converged, _channel_status, window); + PedestalPeak(hADCPedReset[window][ch], _ped_reset_peak); + + Rate(hADCMaxChan[window][ch], _raw_max_chan_rate, window, fPullWindow); + } + + if(fStripHits) + { + Rate(hADCSH[window][ch], _sh_rate, window, fReconstructionWindow); + + PeakPeak(hADCSH[window][ch], _ped_calib, _sh_peak_peak); + PeakFit(hADCSH[window][ch], _sh_peak_peak, _ped_calib, _sh_peak_fit, _sh_peak_fit_chi2, _sh_peak_fit_converged, _channel_status, window); + _sh_ped_to_peak_fit = _sh_peak_fit - _ped_fit; + _sh_ped_reset_to_peak_fit = _sh_peak_fit - _ped_reset_fit; + + if(fAnalysePE) + { + PeakPeak(hPESH[window][ch], _ped_calib, _sh_pe_peak_peak); + PeakFit(hPESH[window][ch], _sh_pe_peak_peak, _ped_calib, _sh_pe_peak_fit, _sh_pe_peak_fit_chi2, _sh_pe_peak_fit_converged, _channel_status, window); + } + + const double sh_sat = Saturation(hADCSH[window][ch]); + _sh_sat_rate = sh_sat / (fNEvents[window] * fReconstructionWindow); + _sh_sat_ratio_total = sh_sat / hADCSH[window][ch]->GetEntries(); + _sh_sat_ratio_peak = sh_sat / hADCSH[window][ch]->GetBinContent(hADCSH[window][ch]->FindBin(_sh_peak_peak)); + } + + if(fSpacePoints) + { + Rate(hADCSP[window][ch], _sp_rate, window, fReconstructionWindow); + + PeakPeak(hADCSP[window][ch], _ped_calib, _sp_peak_peak); + PeakFit(hADCSP[window][ch], _sp_peak_peak, _ped_calib, _sp_peak_fit, _sp_peak_fit_chi2, _sp_peak_fit_converged, _channel_status, window); + + if(fAnalysePE) + { + PeakPeak(hPESP[window][ch], _ped_calib, _sp_pe_peak_peak); + PeakFit(hPESP[window][ch], _sp_pe_peak_peak, _ped_calib, _sp_pe_peak_fit, _sp_pe_peak_fit_chi2, _sp_pe_peak_fit_converged, _channel_status, window); + } + + const double sp_sat = Saturation(hADCSP[window][ch]); + _sp_sat_rate = sp_sat / (fNEvents[window] * fReconstructionWindow); + _sp_sat_ratio_total = sp_sat / hADCSP[window][ch]->GetEntries(); + _sp_sat_ratio_peak = sp_sat / hADCSP[window][ch]->GetBinContent(hADCSP[window][ch]->FindBin(_sp_peak_peak)); + } + + if(fTracks && _tagger != kBottomTagger) + { + Rate(hADCTr[window][ch], _tr_rate, window, fReconstructionWindow); + + PeakPeak(hADCTr[window][ch], _ped_calib, _tr_peak_peak); + PeakFit(hADCTr[window][ch], _tr_peak_peak, _ped_calib, _tr_peak_fit, _tr_peak_fit_chi2, _tr_peak_fit_converged, _channel_status, window); + + PeakPeak(hADCTrByLength[window][ch], _ped_calib, _tr_by_length_peak_peak); + PeakFit(hADCTrByLength[window][ch], _tr_by_length_peak_peak, _ped_calib, _tr_by_length_peak_fit, _tr_by_length_peak_fit_chi2, _tr_by_length_peak_fit_converged, _channel_status, window); + + if(fAnalysePE) + { + PeakPeak(hPETr[window][ch], _ped_calib, _tr_pe_peak_peak); + PeakFit(hPETr[window][ch], _tr_pe_peak_peak, _ped_calib, _tr_pe_peak_fit, _tr_pe_peak_fit_chi2, _tr_pe_peak_fit_converged, _channel_status, window); + + PeakPeak(hPETrByLength[window][ch], _ped_calib, _tr_by_length_pe_peak_peak); + PeakFit(hPETrByLength[window][ch], _tr_by_length_pe_peak_peak, _ped_calib, _tr_by_length_pe_peak_fit, _tr_by_length_pe_peak_fit_chi2, _tr_by_length_pe_peak_fit_converged, _channel_status, window); + } + + const double tr_sat = Saturation(hADCTr[window][ch]); + _tr_sat_rate = tr_sat / (fNEvents[window] * fReconstructionWindow); + _tr_sat_ratio_total = tr_sat / hADCTr[window][ch]->GetEntries(); + _tr_sat_ratio_peak = tr_sat / hADCTr[window][ch]->GetBinContent(hADCTr[window][ch]->FindBin(_tr_peak_peak)); + } + + if(fTrackLA && _tagger != kBottomTagger) + { + PeakPeak(hADCTrLA[window][ch], _ped_calib, _tr_lim_angle_peak_peak); + PeakFit(hADCTrLA[window][ch], _tr_lim_angle_peak_peak, _ped_calib, _tr_lim_angle_peak_fit, _tr_lim_angle_peak_fit_chi2, _tr_lim_angle_peak_fit_converged, _channel_status, window); + + if(fAnalysePE) + { + PeakPeak(hPETrLA[window][ch], _ped_calib, _tr_lim_angle_pe_peak_peak); + PeakFit(hPETrLA[window][ch], _tr_lim_angle_pe_peak_peak, _ped_calib, _tr_lim_angle_pe_peak_fit, _tr_lim_angle_pe_peak_fit_chi2, _tr_lim_angle_pe_peak_fit_converged, _channel_status, window); + } + + const double tr_lim_angle_sat = Saturation(hADCTrLA[window][ch]); + _tr_lim_angle_sat_rate = tr_lim_angle_sat / (fNEvents[window] * fReconstructionWindow); + _tr_lim_angle_sat_ratio_total = tr_lim_angle_sat / hADCTrLA[window][ch]->GetEntries(); + _tr_lim_angle_sat_ratio_peak = tr_lim_angle_sat / hADCTrLA[window][ch]->GetBinContent(hADCTrLA[window][ch]->FindBin(_tr_lim_angle_peak_peak)); + } + + fChannelTree->Fill(); +} + +void sbnd::crt::ADRIFT::PedestalFit(TH1D* hADC, double &fit, double &std, double &chi2, bool &converged, + bool badChannel, const int window) +{ + TF1 *gaus = new TF1("gaus", "gaus", 0, 500); + const TString name = hADC->GetName(); + TString ch_name = name; + TString type = ""; + + const int window_log = window == 0 ? 0 : std::floor(std::log10(window)); + + if(name.Contains("Reset")) + { + ch_name.Remove(0, 27 + window_log + 1); + type = "reset"; + } + else + ch_name.Remove(0,22 + window_log + 1); + + int ch = std::stoi(ch_name.Data()); + + TH1D* hADC2 = (TH1D*) hADC->Clone(name + "_for_fit"); + hADC2->Rebin(5); + + TFitResultPtr fit_result = hADC2->Fit(gaus, "QRS"); + converged = !(bool)(int(fit_result)); + + if(!converged && !badChannel) + std::cout << "Pedestal fit has not converged - " << hADC->GetName() << std::endl; + + fit = gaus->GetParameter("Mean"); + std = gaus->GetParameter("Sigma"); + chi2 = gaus->GetChisquare() / gaus->GetNDF(); + + if(fSaveAllFits || (fSaveBadFits && !converged) || (fSaveSubset && ch > 1471 && ch < 1728)) + { + TCanvas *c = new TCanvas(Form("c%s", name.Data()), Form("c%s", name.Data())); + c->cd(); + + hADC2->SetLineColor(kOrange+2); + hADC2->SetLineWidth(2); + hADC2->Draw("histe"); + gaus->SetLineColor(kSpring-6); + gaus->Draw("same"); + + if(badChannel) + { + TText *t = new TText(.5, .75, "Bad Channel"); + t->SetTextSize(0.1); + t->SetTextColor(kRed); + t->Draw(); + } + + if(converged) + { + if(type.Contains("reset")) + { + c->SaveAs(Form("%s/pedestal_reset_fit_channel_%s.png", fPedestalResetSaveDirectory[window].c_str(), ch_name.Data())); + c->SaveAs(Form("%s/pedestal_reset_fit_channel_%s.pdf", fPedestalResetSaveDirectory[window].c_str(), ch_name.Data())); + } + else + { + c->SaveAs(Form("%s/pedestal_fit_channel_%s.png", fPedestalSaveDirectory[window].c_str(), ch_name.Data())); + c->SaveAs(Form("%s/pedestal_fit_channel_%s.pdf", fPedestalSaveDirectory[window].c_str(), ch_name.Data())); + } + } + else + { + if(type.Contains("reset")) + { + c->SaveAs(Form("%s/pedestal_reset_fit_channel_%s.png", fBadPedestalResetSaveDirectory[window].c_str(), ch_name.Data())); + c->SaveAs(Form("%s/pedestal_reset_fit_channel_%s.pdf", fBadPedestalResetSaveDirectory[window].c_str(), ch_name.Data())); + } + else + { + c->SaveAs(Form("%s/pedestal_fit_channel_%s.png", fBadPedestalSaveDirectory[window].c_str(), ch_name.Data())); + c->SaveAs(Form("%s/pedestal_fit_channel_%s.pdf", fBadPedestalSaveDirectory[window].c_str(), ch_name.Data())); + } + } + } +} + +void sbnd::crt::ADRIFT::PedestalPeak(TH1D* hADC, double &peak) +{ + const int bin = hADC->GetMaximumBin(); + + peak = hADC->GetBinCenter(bin); +} + +void sbnd::crt::ADRIFT::Rate(TH1D* hADC, double &rate, int window, double &period) +{ + rate = hADC->GetEntries() / (fNEvents[window] * period); +} + +void sbnd::crt::ADRIFT::PeakPeak(TH1D* hist, const double &ped, double &peak) +{ + int bin = 0; + double max = std::numeric_limits::lowest(); + + const TString name = hist->GetName(); + + const int start = name.Contains("PE") ? 0 : (int)ped + 20; + + for(int i = start; i < 4000; ++i) + { + if(hist->GetBinContent(i) > max) + { + max = hist->GetBinContent(i); + bin = i; + } + } + + peak = hist->GetBinCenter(bin); +} + +void sbnd::crt::ADRIFT::PeakFit(TH1D* hist, const double &peak, const double &ped, double &fit, + double &chi2, bool &converged, bool badChannel, const int window) +{ + const TString name = hist->GetName(); + const bool pe = name.Contains("PE"); + TString ch_name = name; + TString type = ""; + + const double start = pe ? 0 : ped + 20; + const double end = pe ? 200 : 4000; + const double width = pe ? 0.25 : 10; + const double sigma = pe ? 1 : 50; + + TF1 *langau = new TF1("langau", LanGau, start, end, 4); + double params[4] = { width, peak, hist->GetEntries(), sigma }; + langau->SetParameters(params); + + const int window_log = window == 0 ? 0 : std::floor(std::log10(window)); + + if(name.Contains("SH")) + { + const int end = pe ? 20 + window_log + 1 : 21 + window_log + 1; + ch_name.Remove(0, end); + type = "strip_hit"; + } + else if(name.Contains("SP")) + { + const int end = pe ? 20 + window_log + 1 : 21 + window_log + 1; + ch_name.Remove(0, end); + type = "space_point"; + } + else if(name.Contains("TrLA")) + { + const int end = pe ? 22 + window_log + 1 : 23 + window_log + 1; + ch_name.Remove(0, end); + type = "track_limited_angle"; + } + else if(name.Contains("TrByLength")) + { + const int end = pe ? 28 + window_log + 1 : 29 + window_log + 1; + ch_name.Remove(0, end); + type = "track_by_length"; + } + else if(name.Contains("Tr")) + { + const int end = pe ? 20 + window_log + 1 : 21 + window_log + 1; + ch_name.Remove(0, end); + type = "track"; + } + else + std::cout << "Cannot identify histogram type (" << name << ")" << std::endl; + + int ch = std::stoi(ch_name.Data()); + + TH1D* hist2 = (TH1D*) hist->Clone(name + "_for_fit"); + hist2->Rebin(20); + + TFitResultPtr fit_result = hist2->Fit(langau, "QRS"); + converged = !(bool)(int(fit_result)); + + if(!converged && !badChannel) + std::cout << "Peak fit has not converged - " << hist->GetName() << std::endl; + + fit = langau->GetParameter(1); + chi2 = langau->GetChisquare() / langau->GetNDF(); + + if(fSaveAllFits || (fSaveBadFits && !converged) || (fSaveSubset && ch > 1471 && ch < 1728)) + { + TCanvas *c = new TCanvas(Form("c%s", name.Data()), Form("c%s", name.Data())); + c->cd(); + + hist2->SetLineColor(kOrange+2); + hist2->SetLineWidth(2); + hist2->Draw("histe"); + langau->SetLineColor(kSpring-6); + langau->Draw("same"); + + if(badChannel) + { + TText *t = new TText(.5, .75, "Bad Channel"); + t->SetTextSize(0.1); + t->SetTextColor(kRed); + t->Draw(); + } + + if(pe) + { + if(converged) + { + c->SaveAs(Form("%s/peak_fit_%s_pe_channel_%s.png", fPeakSaveDirectory[window].c_str(), type.Data(), ch_name.Data())); + c->SaveAs(Form("%s/peak_fit_%s_pe_channel_%s.pdf", fPeakSaveDirectory[window].c_str(), type.Data(), ch_name.Data())); + } + else + { + c->SaveAs(Form("%s/peak_fit_%s_pe_channel_%s.png", fBadPeakSaveDirectory[window].c_str(), type.Data(), ch_name.Data())); + c->SaveAs(Form("%s/peak_fit_%s_pe_channel_%s.pdf", fBadPeakSaveDirectory[window].c_str(), type.Data(), ch_name.Data())); + } + } + else + { + if(converged) + { + c->SaveAs(Form("%s/peak_fit_%s_channel_%s.png", fPeakSaveDirectory[window].c_str(), type.Data(), ch_name.Data())); + c->SaveAs(Form("%s/peak_fit_%s_channel_%s.pdf", fPeakSaveDirectory[window].c_str(), type.Data(), ch_name.Data())); + } + else + { + c->SaveAs(Form("%s/peak_fit_%s_channel_%s.png", fBadPeakSaveDirectory[window].c_str(), type.Data(), ch_name.Data())); + c->SaveAs(Form("%s/peak_fit_%s_channel_%s.pdf", fBadPeakSaveDirectory[window].c_str(), type.Data(), ch_name.Data())); + } + } + } +} + +double sbnd::crt::ADRIFT::Saturation(TH1D* hADC) +{ + const double sat = hADC->GetBinContent(4090); + + for(int i = 4080; i < 4101; ++i) + { + if(i == 4090) + continue; + + if(hADC->GetBinContent(i) > sat) + std::cout << "Saturation appears to be in bin " << i << " (" << hADC->GetBinContent(i) + << ") not bin 4090 (" << sat << ")" << std::endl; + } + + return sat; +} + +void sbnd::crt::ADRIFT::ResetVars() +{ + _channel = std::numeric_limits::lowest(); + _gdml_id = std::numeric_limits::lowest(); + _mac5 = std::numeric_limits::lowest(); + _raw_channel = std::numeric_limits::lowest(); + _tagger = std::numeric_limits::lowest(); + _channel_status = std::numeric_limits::lowest(); + + _area = std::numeric_limits::lowest(); + _y_average = std::numeric_limits::lowest(); + _ped_calib = std::numeric_limits::lowest(); + _gain_calib = std::numeric_limits::lowest(); + _ped_fit = std::numeric_limits::lowest(); + _ped_fit_std = std::numeric_limits::lowest(); + _ped_fit_chi2 = std::numeric_limits::lowest(); + _ped_peak = std::numeric_limits::lowest(); + _ped_reset_fit = std::numeric_limits::lowest(); + _ped_reset_fit_std = std::numeric_limits::lowest(); + _ped_reset_fit_chi2 = std::numeric_limits::lowest(); + _ped_reset_peak = std::numeric_limits::lowest(); + _sh_rate = std::numeric_limits::lowest(); + _sp_rate = std::numeric_limits::lowest(); + _tr_rate = std::numeric_limits::lowest(); + _sh_peak_fit = std::numeric_limits::lowest(); + _sh_peak_fit_chi2 = std::numeric_limits::lowest(); + _sh_peak_peak = std::numeric_limits::lowest(); + _sh_sat_rate = std::numeric_limits::lowest(); + _sh_sat_ratio_total = std::numeric_limits::lowest(); + _sh_sat_ratio_peak = std::numeric_limits::lowest(); + _sh_ped_to_peak_fit = std::numeric_limits::lowest(); + _sh_ped_reset_to_peak_fit = std::numeric_limits::lowest(); + _sp_peak_fit = std::numeric_limits::lowest(); + _sp_peak_fit_chi2 = std::numeric_limits::lowest(); + _sp_peak_peak = std::numeric_limits::lowest(); + _sp_sat_rate = std::numeric_limits::lowest(); + _sp_sat_ratio_total = std::numeric_limits::lowest(); + _sp_sat_ratio_peak = std::numeric_limits::lowest(); + _tr_peak_fit = std::numeric_limits::lowest(); + _tr_peak_fit_chi2 = std::numeric_limits::lowest(); + _tr_peak_peak = std::numeric_limits::lowest(); + _tr_sat_rate = std::numeric_limits::lowest(); + _tr_sat_ratio_total = std::numeric_limits::lowest(); + _tr_sat_ratio_peak = std::numeric_limits::lowest(); + _tr_by_length_peak_fit = std::numeric_limits::lowest(); + _tr_by_length_peak_fit_chi2 = std::numeric_limits::lowest(); + _tr_by_length_peak_peak = std::numeric_limits::lowest(); + _tr_lim_angle_peak_fit = std::numeric_limits::lowest(); + _tr_lim_angle_peak_fit_chi2 = std::numeric_limits::lowest(); + _tr_lim_angle_peak_peak = std::numeric_limits::lowest(); + _tr_lim_angle_sat_rate = std::numeric_limits::lowest(); + _tr_lim_angle_sat_ratio_total = std::numeric_limits::lowest(); + _tr_lim_angle_sat_ratio_peak = std::numeric_limits::lowest(); + _sh_pe_peak_fit = std::numeric_limits::lowest(); + _sh_pe_peak_fit_chi2 = std::numeric_limits::lowest(); + _sh_pe_peak_peak = std::numeric_limits::lowest(); + _sp_pe_peak_fit = std::numeric_limits::lowest(); + _sp_pe_peak_fit_chi2 = std::numeric_limits::lowest(); + _sp_pe_peak_peak = std::numeric_limits::lowest(); + _tr_pe_peak_fit = std::numeric_limits::lowest(); + _tr_pe_peak_fit_chi2 = std::numeric_limits::lowest(); + _tr_pe_peak_peak = std::numeric_limits::lowest(); + _tr_by_length_pe_peak_fit = std::numeric_limits::lowest(); + _tr_by_length_pe_peak_fit_chi2 = std::numeric_limits::lowest(); + _tr_by_length_pe_peak_peak = std::numeric_limits::lowest(); + _tr_lim_angle_pe_peak_fit = std::numeric_limits::lowest(); + _tr_lim_angle_pe_peak_fit_chi2 = std::numeric_limits::lowest(); + _tr_lim_angle_pe_peak_peak = std::numeric_limits::lowest(); + + _horizontal = false; + _ped_fit_converged = false; + _ped_reset_fit_converged = false; + _sh_peak_fit_converged = false; + _sp_peak_fit_converged = false; + _tr_peak_fit_converged = false; + _tr_by_length_peak_fit_converged = false; + _tr_lim_angle_peak_fit_converged = false; + _sh_pe_peak_fit_converged = false; + _sp_pe_peak_fit_converged = false; + _tr_pe_peak_fit_converged = false; + _tr_by_length_pe_peak_fit_converged = false; + _tr_lim_angle_pe_peak_fit_converged = false; +} + +void sbnd::crt::ADRIFT::SaveHist(TH1D *hist, std::string &saveDir, std::string saveName, int rebin, bool badChannel) +{ + TCanvas *c = new TCanvas(Form("c%s", saveName.c_str()), Form("c%s", saveName.c_str())); + c->cd(); + + const TString name = hist->GetName(); + TH1D* hist2 = (TH1D*) hist->Clone(name + "_for_save"); + + hist2->SetLineColor(kOrange+2); + hist2->SetLineWidth(2); + hist2->Rebin(rebin); + hist2->Draw("histe"); + + if(badChannel) + { + TText *t = new TText(.5, .75, "Bad Channel"); + t->SetTextSize(0.1); + t->SetTextColor(kRed); + t->Draw(); + } + + c->SaveAs(Form("%s/%s.png", saveDir.c_str(), saveName.c_str())); + c->SaveAs(Form("%s/%s.pdf", saveDir.c_str(), saveName.c_str())); +} + +double sbnd::crt::ADRIFT::LanGau(double *x, double *par) +{ + //Fit parameters: + //par[0]=Width (scale) parameter of Landau density + //par[1]=Most Probable (MP, location) parameter of Landau density + //par[2]=Total area (integral -inf to inf, normalization constant) + //par[3]=Width (sigma) of convoluted Gaussian function + // + //In the Landau distribution (represented by the CERNLIB approximation), + //the maximum is located at x=-0.22278298 with the location parameter=0. + //This shift is corrected within this function, so that the actual + //maximum is identical to the MP parameter. + + // Numeric constants + double invsq2pi = 0.3989422804014; // (2 pi)^(-1/2) + double mpshift = -0.22278298; // Landau maximum location + + // Control constants + double np = 100.0; // number of convolution steps + double sc = 5.0; // convolution extends to +-sc Gaussian sigmas + + // Variables + double xx; + double mpc; + double fland; + double sum = 0.0; + double xlow,xupp; + double step; + double i; + + // MP shift correction + mpc = par[1] - mpshift * par[0]; + + // Range of convolution integral + xlow = x[0] - sc * par[3]; + xupp = x[0] + sc * par[3]; + + step = (xupp-xlow) / np; + + // Convolution integral of Landau and Gaussian by sum + for(i=1.0; i<=np/2; i++) { + xx = xlow + (i-.5) * step; + fland = TMath::Landau(xx,mpc,par[0]) / par[0]; + sum += fland * TMath::Gaus(x[0],xx,par[3]); + + xx = xupp - (i-.5) * step; + fland = TMath::Landau(xx,mpc,par[0]) / par[0]; + sum += fland * TMath::Gaus(x[0],xx,par[3]); + } + + return (par[2] * step * sum * invsq2pi / par[3]); +} + +DEFINE_ART_MODULE(sbnd::crt::ADRIFT) diff --git a/sbndcode/CRT/CRTAna/CMakeLists.txt b/sbndcode/CRT/CRTAna/CMakeLists.txt index 76a0241af..2cbcc6327 100644 --- a/sbndcode/CRT/CRTAna/CMakeLists.txt +++ b/sbndcode/CRT/CRTAna/CMakeLists.txt @@ -1,9 +1,11 @@ art_make( MODULE_LIBRARIES ROOT::Tree + ROOT::Graf3d art_root_io::TFileService_service larsim::Utils lardata::DetectorClocksService + sbndaq_artdaq_core::sbndaq-artdaq-core_Obj_SBND sbnobj::SBND_CRT sbnobj::SBND_Timing sbndcode_CRT_CRTBackTracker diff --git a/sbndcode/CRT/CRTAna/adrift_sbnd.fcl b/sbndcode/CRT/CRTAna/adrift_sbnd.fcl new file mode 100644 index 000000000..0be839450 --- /dev/null +++ b/sbndcode/CRT/CRTAna/adrift_sbnd.fcl @@ -0,0 +1,31 @@ +BEGIN_PROLOG + +adrift_data_sbnd: +{ + module_type: "ADRIFT" + FEBDataModuleLabel: "crtdecoder" + CRTStripHitModuleLabel: "crtstrips" + CRTClusterModuleLabel: "crtclustering" + CRTSpacePointModuleLabel: "crtspacepoints" + CRTTrackModuleLabel: "crttracks" + DAQHeaderModuleLabel: "daq" + DAQHeaderInstanceLabel: "RawEventHeader" + TopSaveDirectory: "/exp/sbnd/data/users/hlay/crt_comm_summer_2024/plots/adrift" + Only2HitSpacePoints: false + SaveAllFits: false + SaveBadFits: false + SaveSubset: false + FEBs: true + StripHits: true + SpacePoints: true + Tracks: true + TrackLA: true + SaveROOTHists: true + AnalysePE: false + TrackAngleLimit: 20 + PullWindow: 0.05 + ReconstructionWindow: 3.22e-3 + RawTSCorrection: 367000 +} + +END_PROLOG diff --git a/sbndcode/CRT/CRTAna/run_adrift_data.fcl b/sbndcode/CRT/CRTAna/run_adrift_data.fcl new file mode 100644 index 000000000..237978055 --- /dev/null +++ b/sbndcode/CRT/CRTAna/run_adrift_data.fcl @@ -0,0 +1,28 @@ +#include "services_sbnd.fcl" +#include "crt_services_sbnd.fcl" +#include "adrift_sbnd.fcl" + +process_name: ADRIFT + +services: +{ + TFileService: { fileName: "adrift_sbnd.root" } + @table::sbnd_basic_services + @table::crt_services_data_sbnd +} + +source: +{ + module_type: RootInput +} + +physics: +{ + analyzers: + { + adrift: @local::adrift_data_sbnd + } + + ana: [ adrift ] + end_paths: [ ana ] +} From 70411b58bddbd04c2d5a2f15a52b6f0f3ecc0129 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Mon, 23 Feb 2026 07:58:38 -0600 Subject: [PATCH 127/155] Add CRTRateAnalysis - module for CRT real time rate analysis --- sbndcode/CRT/CRTAna/CRTRateAnalysis_module.cc | 292 ++++++++++++++++++ sbndcode/CRT/CRTAna/crtrateana_sbnd.fcl | 13 + sbndcode/CRT/CRTAna/run_crtrateana_data.fcl | 28 ++ 3 files changed, 333 insertions(+) create mode 100644 sbndcode/CRT/CRTAna/CRTRateAnalysis_module.cc create mode 100644 sbndcode/CRT/CRTAna/crtrateana_sbnd.fcl create mode 100644 sbndcode/CRT/CRTAna/run_crtrateana_data.fcl diff --git a/sbndcode/CRT/CRTAna/CRTRateAnalysis_module.cc b/sbndcode/CRT/CRTAna/CRTRateAnalysis_module.cc new file mode 100644 index 000000000..418c9c250 --- /dev/null +++ b/sbndcode/CRT/CRTAna/CRTRateAnalysis_module.cc @@ -0,0 +1,292 @@ +//////////////////////////////////////////////////////////////////////// +// Class: CRTRateAnalysis +// Plugin Type: analyzer (Unknown Unknown) +// File: CRTRateAnalysis_module.cc +// +// Generated at Tue Jan 7 05:28:06 2025 by Henry Lay 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 "art_root_io/TFileService.h" + +#include "TTree.h" + +#include "canvas/Persistency/Common/FindOneP.h" +#include "canvas/Persistency/Common/FindManyP.h" + +#include "artdaq-core/Data/RawEvent.hh" + +#include "sbnobj/SBND/CRT/FEBData.hh" +#include "sbnobj/SBND/CRT/CRTSpacePoint.hh" +#include "sbnobj/SBND/CRT/CRTCluster.hh" +#include "sbnobj/SBND/CRT/CRTBlob.hh" + +#include "sbndcode/Geometry/GeometryWrappers/CRTGeoService.h" +#include "sbndcode/ChannelMaps/CRT/CRTChannelMapService.h" + +namespace sbnd { + namespace crt { + class CRTRateAnalysis; + } +} + + +class sbnd::crt::CRTRateAnalysis : public art::EDAnalyzer { +public: + explicit CRTRateAnalysis(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. + CRTRateAnalysis(CRTRateAnalysis const&) = delete; + CRTRateAnalysis(CRTRateAnalysis&&) = delete; + CRTRateAnalysis& operator=(CRTRateAnalysis const&) = delete; + CRTRateAnalysis& operator=(CRTRateAnalysis&&) = delete; + + // Required functions. + void analyze(art::Event const& e) override; + + void ResetEventVars(); + void ResetRawVars(); + void ResetSpacePointVars(); + void ResetBlobVars(); + +private: + + art::ServiceHandle fCRTGeoService; + art::ServiceHandle fCRTChannelMapService; + + std::string fFEBDataModuleLabel, fCRTSpacePointModuleLabel, + fCRTBlobModuleLabel, fDAQHeaderModuleLabel, fDAQHeaderInstanceLabel; + + TTree *fEventTree, *fRawTree, *fSpacePointTree, *fBlobTree; + + int32_t _run, _subrun, _event; + uint32_t _event_header_ts; + + int16_t _tagger, _module; + uint16_t _max_channel; + + int16_t _n_hits; + double _x, _y, _z, _pe; + + int16_t _n_total_sps, _n_bottom_sps, _n_bottom_sps_twohits, _n_south_sps, + _n_north_sps, _n_west_sps, _n_east_sps, _n_toplow_sps, _n_tophigh_sps; +}; + + +sbnd::crt::CRTRateAnalysis::CRTRateAnalysis(fhicl::ParameterSet const& p) + : EDAnalyzer{p} + , fFEBDataModuleLabel(p.get("FEBDataModuleLabel")) + , fCRTSpacePointModuleLabel(p.get("CRTSpacePointModuleLabel")) + , fCRTBlobModuleLabel(p.get("CRTBlobModuleLabel")) + , fDAQHeaderModuleLabel(p.get("DAQHeaderModuleLabel")) + , fDAQHeaderInstanceLabel(p.get("DAQHeaderInstanceLabel")) +{ + art::ServiceHandle fs; + + fEventTree = fs->make("events", ""); + fEventTree->Branch("run", &_run); + fEventTree->Branch("subrun", &_subrun); + fEventTree->Branch("event", &_event); + fEventTree->Branch("event_header_ts", &_event_header_ts); + + fRawTree = fs->make("readouts", ""); + fRawTree->Branch("run", &_run); + fRawTree->Branch("subrun", &_subrun); + fRawTree->Branch("event", &_event); + fRawTree->Branch("event_header_ts", &_event_header_ts); + fRawTree->Branch("tagger", &_tagger); + fRawTree->Branch("module", &_module); + fRawTree->Branch("max_channel", &_max_channel); + + fSpacePointTree = fs->make("spacepoints", ""); + fSpacePointTree->Branch("run", &_run); + fSpacePointTree->Branch("subrun", &_subrun); + fSpacePointTree->Branch("event", &_event); + fSpacePointTree->Branch("event_header_ts", &_event_header_ts); + fSpacePointTree->Branch("tagger", &_tagger); + fSpacePointTree->Branch("n_hits", &_n_hits); + fSpacePointTree->Branch("x", &_x); + fSpacePointTree->Branch("y", &_y); + fSpacePointTree->Branch("z", &_z); + fSpacePointTree->Branch("pe", &_pe); + + fBlobTree = fs->make("blobs", ""); + fBlobTree->Branch("run", &_run); + fBlobTree->Branch("subrun", &_subrun); + fBlobTree->Branch("event", &_event); + fBlobTree->Branch("event_header_ts", &_event_header_ts); + fBlobTree->Branch("n_total_sps", &_n_total_sps); + fBlobTree->Branch("n_bottom_sps", &_n_bottom_sps); + fBlobTree->Branch("n_bottom_sps_twohits", &_n_bottom_sps_twohits); + fBlobTree->Branch("n_south_sps", &_n_south_sps); + fBlobTree->Branch("n_north_sps", &_n_north_sps); + fBlobTree->Branch("n_west_sps", &_n_west_sps); + fBlobTree->Branch("n_east_sps", &_n_east_sps); + fBlobTree->Branch("n_toplow_sps", &_n_toplow_sps); + fBlobTree->Branch("n_tophigh_sps", &_n_tophigh_sps); + fBlobTree->Branch("pe", &_pe); +} + +void sbnd::crt::CRTRateAnalysis::analyze(art::Event const& e) +{ + ResetEventVars(); + + _run = e.id().run(); + _subrun = e.id().subRun(); + _event = e.id().event(); + + art::Handle DAQHeaderHandle; + e.getByLabel(fDAQHeaderModuleLabel, fDAQHeaderInstanceLabel, DAQHeaderHandle); + + if(DAQHeaderHandle.isValid()) + { + artdaq::RawEvent rawHeaderEvent = artdaq::RawEvent(*DAQHeaderHandle); + uint64_t raw_ts = rawHeaderEvent.timestamp(); + _event_header_ts = raw_ts / static_cast(1e9); + } + + fEventTree->Fill(); + + art::Handle> FEBDataHandle; + e.getByLabel(fFEBDataModuleLabel, FEBDataHandle); + + std::vector> FEBDataVec; + art::fill_ptr_vector(FEBDataVec, FEBDataHandle); + + for(auto const& data : FEBDataVec) + { + ResetRawVars(); + _tagger = fCRTGeoService->AuxDetIndexToTaggerEnum(data->Mac5()); + _module = data->Mac5(); + + int max_adc = -1, max_ch = -1; + + for(int ch = 0; ch < 32; ++ch) + { + int adc = data->ADC(ch); + + if(adc > max_adc) + { + max_adc = adc; + max_ch = ch; + } + } + + _max_channel = fCRTChannelMapService->ConstructOfflineChannelIDFromOfflineModuleIDAndOfflineLocalChannel(_module, max_ch); + + fRawTree->Fill(); + } + + art::Handle> CRTSpacePointHandle; + e.getByLabel(fCRTSpacePointModuleLabel, CRTSpacePointHandle); + + std::vector> CRTSpacePointVec; + art::fill_ptr_vector(CRTSpacePointVec, CRTSpacePointHandle); + + art::FindOneP spacePointsToClusters(CRTSpacePointHandle, e, fCRTSpacePointModuleLabel); + + for(auto const& spacePoint : CRTSpacePointVec) + { + ResetSpacePointVars(); + + const art::Ptr cluster = spacePointsToClusters.at(spacePoint.key()); + + _tagger = cluster->Tagger(); + _n_hits = cluster->NHits(); + _x = spacePoint->X(); + _y = spacePoint->Y(); + _z = spacePoint->Z(); + _pe = spacePoint->PE(); + + fSpacePointTree->Fill(); + } + + art::Handle> CRTBlobHandle; + e.getByLabel(fCRTBlobModuleLabel, CRTBlobHandle); + + std::vector> CRTBlobVec; + art::fill_ptr_vector(CRTBlobVec, CRTBlobHandle); + + art::FindManyP blobsToSpacePoints(CRTBlobHandle, e, fCRTBlobModuleLabel); + + for(auto const& blob : CRTBlobVec) + { + ResetBlobVars(); + + _n_total_sps = blob->TotalSpacePoints(); + _n_bottom_sps = blob->SpacePointsInTagger(kBottomTagger); + _n_south_sps = blob->SpacePointsInTagger(kSouthTagger); + _n_north_sps = blob->SpacePointsInTagger(kNorthTagger); + _n_west_sps = blob->SpacePointsInTagger(kWestTagger); + _n_east_sps = blob->SpacePointsInTagger(kEastTagger); + _n_toplow_sps = blob->SpacePointsInTagger(kTopLowTagger); + _n_tophigh_sps = blob->SpacePointsInTagger(kTopHighTagger); + _pe = blob->PE(); + + _n_bottom_sps_twohits = 0; + + const std::vector> spacePoints = blobsToSpacePoints.at(blob.key()); + + for(auto const& spacePoint : spacePoints) + { + const art::Ptr cluster = spacePointsToClusters.at(spacePoint.key()); + + if(cluster->Tagger() == kBottomTagger && cluster->NHits() > 1) + ++_n_bottom_sps_twohits; + } + + fBlobTree->Fill(); + } +} + +void sbnd::crt::CRTRateAnalysis::ResetEventVars() +{ + _run = -1; _subrun = -1; _event = -1; + _event_header_ts = std::numeric_limits::max(); +} + +void sbnd::crt::CRTRateAnalysis::ResetRawVars() +{ + _tagger = -1; _module = -1; + _max_channel = std::numeric_limits::max(); +} + +void sbnd::crt::CRTRateAnalysis::ResetSpacePointVars() +{ + _tagger = -1; + + _n_hits = -1; + + _x = std::numeric_limits::lowest(); + _y = std::numeric_limits::lowest(); + _z = std::numeric_limits::lowest(); + _pe = std::numeric_limits::lowest(); +} + +void sbnd::crt::CRTRateAnalysis::ResetBlobVars() +{ + _n_total_sps = -1; + _n_bottom_sps = -1; + _n_bottom_sps_twohits = -1; + _n_south_sps = -1; + _n_north_sps = -1; + _n_west_sps = -1; + _n_east_sps = -1; + _n_toplow_sps = -1; + _n_tophigh_sps = -1; + + _pe = std::numeric_limits::lowest(); +} + +DEFINE_ART_MODULE(sbnd::crt::CRTRateAnalysis) diff --git a/sbndcode/CRT/CRTAna/crtrateana_sbnd.fcl b/sbndcode/CRT/CRTAna/crtrateana_sbnd.fcl new file mode 100644 index 000000000..b9ffc2186 --- /dev/null +++ b/sbndcode/CRT/CRTAna/crtrateana_sbnd.fcl @@ -0,0 +1,13 @@ +BEGIN_PROLOG + +crtrateana_data_sbnd: +{ + FEBDataModuleLabel: "crtdecoder" + CRTSpacePointModuleLabel: "crtspacepoints" + CRTBlobModuleLabel: "crtblobs" + DAQHeaderModuleLabel: "daq" + DAQHeaderInstanceLabel: "RawEventHeader" + module_type: "CRTRateAnalysis" +} + +END_PROLOG diff --git a/sbndcode/CRT/CRTAna/run_crtrateana_data.fcl b/sbndcode/CRT/CRTAna/run_crtrateana_data.fcl new file mode 100644 index 000000000..b3c6f1c4e --- /dev/null +++ b/sbndcode/CRT/CRTAna/run_crtrateana_data.fcl @@ -0,0 +1,28 @@ +#include "services_sbnd.fcl" +#include "crt_services_sbnd.fcl" +#include "crtrateana_sbnd.fcl" + +process_name: CRTRateAnalysis + +services: +{ + @table::sbnd_basic_services + @table::crt_services_data_sbnd + TFileService: { fileName: "crtrateana_sbnd.root" } +} + +source: +{ + module_type: RootInput +} + +physics: +{ + analyzers: + { + crtrateana: @local::crtrateana_data_sbnd + } + + ana: [ crtrateana ] + end_paths: [ ana ] +} From a446e0ba31d7b8d4c6d2a0a444d83bee8ef55a74 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Mon, 23 Feb 2026 08:10:50 -0600 Subject: [PATCH 128/155] Add CRTTopHatAnalysis - module for CRT beam top hat analysis --- .../CRT/CRTAna/CRTTopHatAnalysis_module.cc | 821 ++++++++++++++++++ sbndcode/CRT/CRTAna/crttophatana_sbnd.fcl | 12 + sbndcode/CRT/CRTAna/run_crttophatana_data.fcl | 28 + 3 files changed, 861 insertions(+) create mode 100644 sbndcode/CRT/CRTAna/CRTTopHatAnalysis_module.cc create mode 100644 sbndcode/CRT/CRTAna/crttophatana_sbnd.fcl create mode 100644 sbndcode/CRT/CRTAna/run_crttophatana_data.fcl diff --git a/sbndcode/CRT/CRTAna/CRTTopHatAnalysis_module.cc b/sbndcode/CRT/CRTAna/CRTTopHatAnalysis_module.cc new file mode 100644 index 000000000..f338ce846 --- /dev/null +++ b/sbndcode/CRT/CRTAna/CRTTopHatAnalysis_module.cc @@ -0,0 +1,821 @@ +//////////////////////////////////////////////////////////////////////// +// Class: CRTTopHatAnalysis +// Plugin Type: analyzer +// File: CRTTopHatAnalysis_module.cc +// Author: Henry Lay (h.lay@sheffield.ac.uk) +//////////////////////////////////////////////////////////////////////// + +#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 "art_root_io/TFileService.h" +#include "canvas/Persistency/Common/FindManyP.h" + +#include "TTree.h" + +#include "lardataobj/AnalysisBase/T0.h" +#include "lardataobj/RecoBase/Track.h" +#include "lardataobj/RecoBase/PFParticle.h" +#include "lardataobj/RecoBase/PFParticleMetadata.h" + +#include "larsim/Utils/TruthMatchUtils.h" +#include "lardata/DetectorInfoServices/DetectorClocksService.h" + +#include "sbndaq-artdaq-core/Obj/SBND/pmtSoftwareTrigger.hh" + +#include "sbnobj/SBND/CRT/FEBData.hh" +#include "sbnobj/SBND/CRT/CRTStripHit.hh" +#include "sbnobj/SBND/CRT/CRTCluster.hh" +#include "sbnobj/SBND/CRT/CRTSpacePoint.hh" +#include "sbnobj/SBND/CRT/CRTTrack.hh" +#include "sbnobj/SBND/Timing/DAQTimestamp.hh" + +#include "sbndcode/Geometry/GeometryWrappers/CRTGeoService.h" +#include "sbndcode/Geometry/GeometryWrappers/TPCGeoAlg.h" +#include "sbndcode/CRT/CRTBackTracker/CRTBackTrackerAlg.h" +#include "sbndcode/CRT/CRTUtils/CRTCommonUtils.h" +#include "sbndcode/Decoders/PTB/sbndptb.h" +#include "sbndcode/Timing/SBNDRawTimingObj.h" + +namespace sbnd::crt { + class CRTTopHatAnalysis; +} + +class sbnd::crt::CRTTopHatAnalysis : public art::EDAnalyzer { +public: + explicit CRTTopHatAnalysis(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. + CRTTopHatAnalysis(CRTTopHatAnalysis const&) = delete; + CRTTopHatAnalysis(CRTTopHatAnalysis&&) = delete; + CRTTopHatAnalysis& operator=(CRTTopHatAnalysis const&) = delete; + CRTTopHatAnalysis& operator=(CRTTopHatAnalysis&&) = delete; + + // Required functions. + void analyze(art::Event const& e) override; + + void AnalysePTBs(std::vector> &PTBVec); + + void AnalyseTDCs(std::vector> &TDCVec); + + void SortReferencing(); + + void AnalyseCRTStripHits(const art::Event &e, const std::vector> &CRTStripHitVec); + + void AnalyseCRTClusters(const art::Event &e, const std::vector> &CRTClusterVec, + const art::FindManyP &clustersToSpacePoints); + + void AnalyseCRTTracks(const art::Event &e, const std::vector> &CRTTrackVec); + + void AnalysePMTSoftwareTriggers(const art::Event &e, const std::vector> &PMTSoftwareTriggerVec); + + +private: + + art::ServiceHandle fCRTGeoService; + TPCGeoAlg fTPCGeoAlg; + + std::string fCRTStripHitModuleLabel, fCRTClusterModuleLabel, fCRTSpacePointModuleLabel, + fCRTTrackModuleLabel, fPTBModuleLabel, fTDCModuleLabel, fTimingReferenceModuleLabel, + fPMTSoftwareTriggerModuleLabel; + bool fDebug, fCutT0, fSavePMTSoftwareTrigger; + double fMinT0, fMaxT0; + std::vector fAllowedPTBHLTs; + + TTree* fTree; + + // Tree variables + + int _run; + int _subrun; + int _event; + int _crt_timing_reference_type; + int _crt_timing_reference_channel; + + //strip hit to select the strip which has ADC above threshold + std::vector _sh_channel; + std::vector _sh_tagger; + std::vector _sh_ts0; + std::vector _sh_ts0_rwm_ref; + std::vector _sh_ts0_ptb_hlt_beam_gate_ref; + std::vector _sh_ts1; + std::vector _sh_ts1_rwm_ref; + std::vector _sh_ts1_ptb_hlt_beam_gate_ref; + std::vector _sh_unixs; + std::vector _sh_pos; + std::vector _sh_err; + std::vector _sh_adc1; + std::vector _sh_adc2; + std::vector _sh_saturated1; + std::vector _sh_saturated2; + std::vector _sh_truth_trackid; + std::vector _sh_truth_completeness; + std::vector _sh_truth_purity; + std::vector _sh_truth_pos; + std::vector _sh_truth_energy; + std::vector _sh_truth_time; + + //cluster from x-y coincidence for CRTSpacePoint + std::vector _cl_ts0; + std::vector _cl_ts0_rwm_ref; + std::vector _cl_ts0_ptb_hlt_beam_gate_ref; + std::vector _cl_ts1; + std::vector _cl_ts1_rwm_ref; + std::vector _cl_ts1_ptb_hlt_beam_gate_ref; + std::vector _cl_unixs; + std::vector _cl_nhits; + std::vector _cl_tagger; + std::vector _cl_composition; + std::vector _cl_has_sp; + std::vector _cl_sp_x; + std::vector _cl_sp_ex; + std::vector _cl_sp_y; + std::vector _cl_sp_ey; + std::vector _cl_sp_z; + std::vector _cl_sp_ez; + std::vector _cl_sp_pe; + std::vector _cl_sp_ts0; + std::vector _cl_sp_ts0_rwm_ref; + std::vector _cl_sp_ts0_ptb_hlt_beam_gate_ref; + std::vector _cl_sp_ets0; + std::vector _cl_sp_ts1; + std::vector _cl_sp_ts1_rwm_ref; + std::vector _cl_sp_ts1_ptb_hlt_beam_gate_ref; + std::vector _cl_sp_ets1; + std::vector _cl_sp_complete; + + //track level information + std::vector _tr_start_x; + std::vector _tr_start_y; + std::vector _tr_start_z; + std::vector _tr_end_x; + std::vector _tr_end_y; + std::vector _tr_end_z; + std::vector _tr_dir_x; + std::vector _tr_dir_y; + std::vector _tr_dir_z; + std::vector _tr_ts0; + std::vector _tr_ts0_rwm_ref; + std::vector _tr_ts0_ptb_hlt_beam_gate_ref; + std::vector _tr_ets0; + std::vector _tr_ts1; + std::vector _tr_ts1_rwm_ref; + std::vector _tr_ts1_ptb_hlt_beam_gate_ref; + std::vector _tr_ets1; + std::vector _tr_pe; + std::vector _tr_length; + std::vector _tr_tof; + std::vector _tr_theta; + std::vector _tr_phi; + std::vector _tr_triple; + std::vector _tr_tagger1; + std::vector _tr_tagger2; + std::vector _tr_tagger3; + + std::vector _ptb_hlt_trigger; + std::vector _ptb_hlt_timestamp; + + std::vector _ptb_llt_trigger; + std::vector _ptb_llt_timestamp; + + std::vector _tdc_channel; + std::vector _tdc_timestamp; + std::vector _tdc_offset; + std::vector _tdc_name; + + bool _etrig_good, _rwm_good, _ptb_hlt_beam_gate_good, _crt_t1_reset_good; + double _rwm_etrig_diff, _ptb_hlt_beam_gate_etrig_diff, _rwm_crt_t1_reset_diff, _ptb_hlt_beam_gate_crt_t1_reset_diff, + _rwm_ptb_hlt_beam_gate_diff; + + bool _pmt_st_found_trigger; + double _pmt_st_corrected_peak_time, _pmt_st_corrected_peak_time_rwm_ref; +}; + +sbnd::crt::CRTTopHatAnalysis::CRTTopHatAnalysis(fhicl::ParameterSet const& p) + : EDAnalyzer{p} +{ + fCRTStripHitModuleLabel = p.get("CRTStripHitModuleLabel", "crtstrips"); + fCRTClusterModuleLabel = p.get("CRTClusterModuleLabel", "crtclustering"); + fCRTSpacePointModuleLabel = p.get("CRTSpacePointModuleLabel", "crtspacepoints"); + fCRTTrackModuleLabel = p.get("CRTTrackModuleLabel", "crttracks"); + fPTBModuleLabel = p.get("PTBModuleLabel", "ptbdecoder"); + fTDCModuleLabel = p.get("TDCModuleLabel", "tdcdecoder"); + fTimingReferenceModuleLabel = p.get("TimingReferenceModuleLabel", "crtstrips"); + fPMTSoftwareTriggerModuleLabel = p.get("PMTSoftwareTriggerModuleLabel", "pmtmetricbnblight"); + fDebug = p.get("Debug", false); + fCutT0 = p.get("CutT0", false); + fSavePMTSoftwareTrigger = p.get("SavePMTSoftwareTrigger", false); + fMinT0 = p.get("MinT0", std::numeric_limits::min()); + fMaxT0 = p.get("MaxT0", std::numeric_limits::max()); + fAllowedPTBHLTs = p.get>("AllowedPTBHLTs", { 26, 27 }); + + art::ServiceHandle fs; + + fTree = fs->make("tree",""); + fTree->Branch("run", &_run); + fTree->Branch("subrun", &_subrun); + fTree->Branch("event", &_event); + fTree->Branch("crt_timing_reference_type", &_crt_timing_reference_type); + fTree->Branch("crt_timing_reference_channel", &_crt_timing_reference_channel); + + fTree->Branch("sh_channel", "std::vector", &_sh_channel); + fTree->Branch("sh_tagger", "std::vector", &_sh_tagger); + fTree->Branch("sh_ts0", "std::vector", &_sh_ts0); + fTree->Branch("sh_ts0_rwm_ref", "std::vector", &_sh_ts0_rwm_ref); + fTree->Branch("sh_ts0_ptb_hlt_beam_gate_ref", "std::vector", &_sh_ts0_ptb_hlt_beam_gate_ref); + fTree->Branch("sh_ts1", "std::vector", &_sh_ts1); + fTree->Branch("sh_ts1_rwm_ref", "std::vector", &_sh_ts1_rwm_ref); + fTree->Branch("sh_ts1_ptb_hlt_beam_gate_ref", "std::vector", &_sh_ts1_ptb_hlt_beam_gate_ref); + fTree->Branch("sh_unixs", "std::vector", &_sh_unixs); + fTree->Branch("sh_pos", "std::vector", &_sh_pos); + fTree->Branch("sh_err", "std::vector", &_sh_err); + fTree->Branch("sh_adc1", "std::vector", &_sh_adc1); + fTree->Branch("sh_adc2", "std::vector", &_sh_adc2); + fTree->Branch("sh_saturated1", "std::vector", &_sh_saturated1); + fTree->Branch("sh_saturated2", "std::vector", &_sh_saturated2); + + fTree->Branch("cl_ts0", "std::vector", &_cl_ts0); + fTree->Branch("cl_ts0_rwm_ref", "std::vector", &_cl_ts0_rwm_ref); + fTree->Branch("cl_ts0_ptb_hlt_beam_gate_ref", "std::vector", &_cl_ts0_ptb_hlt_beam_gate_ref); + fTree->Branch("cl_ts1", "std::vector", &_cl_ts1); + fTree->Branch("cl_ts1_rwm_ref", "std::vector", &_cl_ts1_rwm_ref); + fTree->Branch("cl_ts1_ptb_hlt_beam_gate_ref", "std::vector", &_cl_ts1_ptb_hlt_beam_gate_ref); + fTree->Branch("cl_unixs", "std::vector", &_cl_unixs); + fTree->Branch("cl_nhits", "std::vector", &_cl_nhits); + fTree->Branch("cl_tagger", "std::vector", &_cl_tagger); + fTree->Branch("cl_composition", "std::vector", &_cl_composition); + fTree->Branch("cl_has_sp", "std::vector", &_cl_has_sp); + fTree->Branch("cl_sp_x", "std::vector", &_cl_sp_x); + fTree->Branch("cl_sp_ex", "std::vector", &_cl_sp_ex); + fTree->Branch("cl_sp_y", "std::vector", &_cl_sp_y); + fTree->Branch("cl_sp_ey", "std::vector", &_cl_sp_ey); + fTree->Branch("cl_sp_z", "std::vector", &_cl_sp_z); + fTree->Branch("cl_sp_ez", "std::vector", &_cl_sp_ez); + fTree->Branch("cl_sp_pe", "std::vector", &_cl_sp_pe); + fTree->Branch("cl_sp_ts0", "std::vector", &_cl_sp_ts0); + fTree->Branch("cl_sp_ts0_rwm_ref", "std::vector", &_cl_sp_ts0_rwm_ref); + fTree->Branch("cl_sp_ts0_ptb_hlt_beam_gate_ref", "std::vector", &_cl_sp_ts0_ptb_hlt_beam_gate_ref); + fTree->Branch("cl_sp_ets0", "std::vector", &_cl_sp_ets0); + fTree->Branch("cl_sp_ts1", "std::vector", &_cl_sp_ts1); + fTree->Branch("cl_sp_ts1_rwm_ref", "std::vector", &_cl_sp_ts1_rwm_ref); + fTree->Branch("cl_sp_ts1_ptb_hlt_beam_gate_ref", "std::vector", &_cl_sp_ts1_ptb_hlt_beam_gate_ref); + fTree->Branch("cl_sp_ets1", "std::vector", &_cl_sp_ets1); + fTree->Branch("cl_sp_complete", "std::vector", &_cl_sp_complete); + + fTree->Branch("tr_start_x", "std::vector", &_tr_start_x); + fTree->Branch("tr_start_y", "std::vector", &_tr_start_y); + fTree->Branch("tr_start_z", "std::vector", &_tr_start_z); + fTree->Branch("tr_end_x", "std::vector", &_tr_end_x); + fTree->Branch("tr_end_y", "std::vector", &_tr_end_y); + fTree->Branch("tr_end_z", "std::vector", &_tr_end_z); + fTree->Branch("tr_dir_x", "std::vector", &_tr_dir_x); + fTree->Branch("tr_dir_y", "std::vector", &_tr_dir_y); + fTree->Branch("tr_dir_z", "std::vector", &_tr_dir_z); + fTree->Branch("tr_ts0", "std::vector", &_tr_ts0); + fTree->Branch("tr_ts0_rwm_ref", "std::vector", &_tr_ts0_rwm_ref); + fTree->Branch("tr_ts0_ptb_hlt_beam_gate_ref", "std::vector", &_tr_ts0_ptb_hlt_beam_gate_ref); + fTree->Branch("tr_ets0", "std::vector", &_tr_ets0); + fTree->Branch("tr_ts1", "std::vector", &_tr_ts1); + fTree->Branch("tr_ts1_rwm_ref", "std::vector", &_tr_ts1_rwm_ref); + fTree->Branch("tr_ts1_ptb_hlt_beam_gate_ref", "std::vector", &_tr_ts1_ptb_hlt_beam_gate_ref); + fTree->Branch("tr_ets1", "std::vector", &_tr_ets1); + fTree->Branch("tr_pe", "std::vector", &_tr_pe); + fTree->Branch("tr_length", "std::vector", &_tr_length); + fTree->Branch("tr_tof", "std::vector", &_tr_tof); + fTree->Branch("tr_theta", "std::vector", &_tr_theta); + fTree->Branch("tr_phi", "std::vector", &_tr_phi); + fTree->Branch("tr_triple", "std::vector", &_tr_triple); + fTree->Branch("tr_tagger1", "std::vector", &_tr_tagger1); + fTree->Branch("tr_tagger2", "std::vector", &_tr_tagger2); + fTree->Branch("tr_tagger3", "std::vector", &_tr_tagger3); + + fTree->Branch("ptb_hlt_trigger", "std::vector", &_ptb_hlt_trigger); + fTree->Branch("ptb_hlt_timestamp", "std::vector", &_ptb_hlt_timestamp); + fTree->Branch("ptb_llt_trigger", "std::vector", &_ptb_llt_trigger); + fTree->Branch("ptb_llt_timestamp", "std::vector", &_ptb_llt_timestamp); + + fTree->Branch("tdc_channel", "std::vector", &_tdc_channel); + fTree->Branch("tdc_timestamp", "std::vector", &_tdc_timestamp); + fTree->Branch("tdc_offset", "std::vector", &_tdc_offset); + fTree->Branch("tdc_name", "std::vector", &_tdc_name); + + fTree->Branch("etrig_good", &_etrig_good); + fTree->Branch("rwm_good", &_rwm_good); + fTree->Branch("ptb_hlt_beam_gate_good", &_ptb_hlt_beam_gate_good); + fTree->Branch("crt_t1_reset_good", &_crt_t1_reset_good); + fTree->Branch("rwm_etrig_diff", &_rwm_etrig_diff); + fTree->Branch("ptb_hlt_beam_gate_etrig_diff", &_ptb_hlt_beam_gate_etrig_diff); + fTree->Branch("rwm_crt_t1_reset_diff", &_rwm_crt_t1_reset_diff); + fTree->Branch("ptb_hlt_beam_gate_crt_t1_reset_diff", &_ptb_hlt_beam_gate_crt_t1_reset_diff); + fTree->Branch("rwm_ptb_hlt_beam_gate_diff", &_rwm_ptb_hlt_beam_gate_diff); + + if(fSavePMTSoftwareTrigger) + { + fTree->Branch("pmt_st_found_trigger", &_pmt_st_found_trigger); + fTree->Branch("pmt_st_corrected_peak_time", &_pmt_st_corrected_peak_time); + fTree->Branch("pmt_st_corrected_peak_time", &_pmt_st_corrected_peak_time); + fTree->Branch("pmt_st_corrected_peak_time_rwm_ref", &_pmt_st_corrected_peak_time_rwm_ref); + } +} + +void sbnd::crt::CRTTopHatAnalysis::analyze(art::Event const& e) +{ + _run = e.id().run(); + _subrun = e.id().subRun(); + _event = e.id().event(); + + _crt_timing_reference_type = -1; + _crt_timing_reference_channel = -1; + + art::Handle TimingReferenceHandle; + e.getByLabel(fTimingReferenceModuleLabel, TimingReferenceHandle); + if(TimingReferenceHandle.isValid()) + { + _crt_timing_reference_type = TimingReferenceHandle->timingType; + _crt_timing_reference_channel = TimingReferenceHandle->timingChannel; + } + + // Get PTBs + art::Handle> PTBHandle; + e.getByLabel(fPTBModuleLabel, PTBHandle); + if(!PTBHandle.isValid()){ + std::cout << "PTB product " << fPTBModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + std::vector> PTBVec; + art::fill_ptr_vector(PTBVec, PTBHandle); + + // Fill PTB variables + AnalysePTBs(PTBVec); + + // Get TDCs + art::Handle> TDCHandle; + e.getByLabel(fTDCModuleLabel, TDCHandle); + if(!TDCHandle.isValid()){ + std::cout << "TDC product " << fTDCModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + std::vector> TDCVec; + art::fill_ptr_vector(TDCVec, TDCHandle); + + // Fill TDC variables + AnalyseTDCs(TDCVec); + + SortReferencing(); + + // Get CRTStripHits + art::Handle> CRTStripHitHandle; + e.getByLabel(fCRTStripHitModuleLabel, CRTStripHitHandle); + if(!CRTStripHitHandle.isValid()){ + std::cout << "CRTStripHit product " << fCRTStripHitModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + std::vector> CRTStripHitVec; + art::fill_ptr_vector(CRTStripHitVec, CRTStripHitHandle); + + // Fill CRTStripHit variables + AnalyseCRTStripHits(e, CRTStripHitVec); + + // Get CRTClusters + art::Handle> CRTClusterHandle; + e.getByLabel(fCRTClusterModuleLabel, CRTClusterHandle); + if(!CRTClusterHandle.isValid()){ + std::cout << "CRTCluster product " << fCRTClusterModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + std::vector> CRTClusterVec; + art::fill_ptr_vector(CRTClusterVec, CRTClusterHandle); + + // Get CRTCluster to CRTSpacePoint Assns + art::FindManyP clustersToSpacePoints(CRTClusterHandle, e, fCRTSpacePointModuleLabel); + + // Fill CRTCluster variables + AnalyseCRTClusters(e, CRTClusterVec, clustersToSpacePoints); + + // Get CRTTracks + art::Handle> CRTTrackHandle; + e.getByLabel(fCRTTrackModuleLabel, CRTTrackHandle); + if(!CRTTrackHandle.isValid()){ + std::cout << "CRTTrack product " << fCRTTrackModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + std::vector> CRTTrackVec; + art::fill_ptr_vector(CRTTrackVec, CRTTrackHandle); + + // Fill CRTTrack variables + AnalyseCRTTracks(e, CRTTrackVec); + + if(fSavePMTSoftwareTrigger) + { + // Get PMTSoftwareTriggers + art::Handle> PMTSoftwareTriggerHandle; + e.getByLabel(fPMTSoftwareTriggerModuleLabel, PMTSoftwareTriggerHandle); + if(!PMTSoftwareTriggerHandle.isValid()){ + std::cout << "PMTSoftwareTrigger product " << fPMTSoftwareTriggerModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + std::vector> PMTSoftwareTriggerVec; + art::fill_ptr_vector(PMTSoftwareTriggerVec, PMTSoftwareTriggerHandle); + + // Fill PMTSoftwareTrigger variables + AnalysePMTSoftwareTriggers(e, PMTSoftwareTriggerVec); + } + + fTree->Fill(); +} + +void sbnd::crt::CRTTopHatAnalysis::AnalysePTBs(std::vector> &PTBVec) +{ + unsigned nHLTs = 0; + + for(auto const& ptb : PTBVec) + nHLTs += ptb->GetNHLTriggers(); + + _ptb_hlt_trigger.resize(nHLTs); + _ptb_hlt_timestamp.resize(nHLTs); + + unsigned hlt_i = 0; + + for(auto const& ptb : PTBVec) + { + for(unsigned i = 0; i < ptb->GetNHLTriggers(); ++i) + { + _ptb_hlt_trigger[hlt_i] = ptb->GetHLTrigger(i).trigger_word; + _ptb_hlt_timestamp[hlt_i] = ptb->GetHLTrigger(i).timestamp * 20; + + ++hlt_i; + } + } + + unsigned nLLTs = 0; + + for(auto const& ptb : PTBVec) + nLLTs += ptb->GetNLLTriggers(); + + _ptb_llt_trigger.resize(nLLTs); + _ptb_llt_timestamp.resize(nLLTs); + + unsigned llt_i = 0; + + for(auto const& ptb : PTBVec) + { + for(unsigned i = 0; i < ptb->GetNLLTriggers(); ++i) + { + _ptb_llt_trigger[llt_i] = ptb->GetLLTrigger(i).trigger_word; + _ptb_llt_timestamp[llt_i] = ptb->GetLLTrigger(i).timestamp * 20; + + ++llt_i; + } + } +} + +void sbnd::crt::CRTTopHatAnalysis::AnalyseTDCs(std::vector> &TDCVec) +{ + const unsigned nTDCs = TDCVec.size(); + + _tdc_channel.resize(nTDCs); + _tdc_timestamp.resize(nTDCs); + _tdc_offset.resize(nTDCs); + _tdc_name.resize(nTDCs); + + unsigned tdc_i = 0; + + for(auto const& tdc : TDCVec) + { + _tdc_channel[tdc_i] = tdc->Channel(); + _tdc_timestamp[tdc_i] = tdc->Timestamp(); + _tdc_offset[tdc_i] = tdc->Offset(); + _tdc_name[tdc_i] = tdc->Name(); + + ++tdc_i; + } +} + +void sbnd::crt::CRTTopHatAnalysis::SortReferencing() +{ + _etrig_good = false; _rwm_good = false; _ptb_hlt_beam_gate_good = false; _crt_t1_reset_good = false; + _rwm_etrig_diff = std::numeric_limits::max(); _ptb_hlt_beam_gate_etrig_diff = std::numeric_limits::max(); + _rwm_crt_t1_reset_diff = std::numeric_limits::max(); _ptb_hlt_beam_gate_crt_t1_reset_diff = std::numeric_limits::max(); + _rwm_ptb_hlt_beam_gate_diff = std::numeric_limits::max(); + + int etrig_count = 0, etrig_id = -1, rwm_count = 0, rwm_id = -1, crt_t1_reset_count = 0, crt_t1_reset_id = -1; + + for(unsigned int tdc_i = 0; tdc_i < _tdc_channel.size(); ++tdc_i) + { + if(_tdc_channel[tdc_i] == 4) + { + ++etrig_count; + etrig_id = tdc_i; + } + else if(_tdc_channel[tdc_i] == 2) + { + ++rwm_count; + rwm_id = tdc_i; + } + else if(_tdc_channel[tdc_i] == 0) + { + ++crt_t1_reset_count; + crt_t1_reset_id = tdc_i; + } + } + + uint64_t etrig = std::numeric_limits::max(), rwm = std::numeric_limits::max(), + hlt = std::numeric_limits::max(), crt_t1_reset = std::numeric_limits::max(); + + if(etrig_count == 1) + { + _etrig_good = true; + etrig = _tdc_timestamp[etrig_id]; + } + + if(rwm_count == 1) + { + _rwm_good = true; + rwm = _tdc_timestamp[rwm_id]; + } + + if(etrig_count == 1) + { + double closest_diff = std::numeric_limits::max(); + + for(unsigned int ptb_i = 0; ptb_i < _ptb_hlt_trigger.size(); ++ptb_i) + { + std::bitset<32> hlt_bitmask = std::bitset<32>(_ptb_hlt_trigger[ptb_i]); + + for(uint32_t allowed_hlt : fAllowedPTBHLTs) + { + if(hlt_bitmask[allowed_hlt]) + { + _ptb_hlt_beam_gate_good = true; + + uint64_t temp_hlt = _ptb_hlt_timestamp[ptb_i]; + double diff = etrig > temp_hlt ? etrig - temp_hlt : -1. * (temp_hlt - etrig); + + if(std::abs(diff) < closest_diff) + { + closest_diff = diff; + hlt = temp_hlt; + } + } + } + } + } + + if(crt_t1_reset_count == 1) + { + _crt_t1_reset_good = true; + crt_t1_reset = _tdc_timestamp[crt_t1_reset_id]; + } + + if(_etrig_good && _rwm_good) + _rwm_etrig_diff = etrig > rwm ? etrig - rwm : -1. * (rwm - etrig); + + if(_etrig_good && _ptb_hlt_beam_gate_good) + _ptb_hlt_beam_gate_etrig_diff = etrig > hlt ? etrig - hlt : -1. * (hlt - etrig); + + if(_crt_t1_reset_good && _rwm_good) + _rwm_crt_t1_reset_diff = crt_t1_reset > rwm ? crt_t1_reset - rwm : -1. * (rwm - crt_t1_reset); + + if(_etrig_good && _crt_t1_reset_good && _ptb_hlt_beam_gate_good) + _ptb_hlt_beam_gate_crt_t1_reset_diff = crt_t1_reset > hlt ? crt_t1_reset - hlt : -1. * (hlt - crt_t1_reset); + + if(_etrig_good && _rwm_good && _ptb_hlt_beam_gate_good) + _rwm_ptb_hlt_beam_gate_diff = hlt > rwm ? hlt - rwm : -1. * (rwm - hlt); +} + +void sbnd::crt::CRTTopHatAnalysis::AnalyseCRTStripHits(const art::Event &e, const std::vector> &CRTStripHitVec) +{ + _sh_channel.clear(); + _sh_tagger.clear(); + _sh_ts0.clear(); + _sh_ts0_rwm_ref.clear(); + _sh_ts0_ptb_hlt_beam_gate_ref.clear(); + _sh_ts1.clear(); + _sh_ts1_rwm_ref.clear(); + _sh_ts1_ptb_hlt_beam_gate_ref.clear(); + _sh_unixs.clear(); + _sh_pos.clear(); + _sh_err.clear(); + _sh_adc1.clear(); + _sh_adc2.clear(); + _sh_saturated1.clear(); + _sh_saturated2.clear(); + + for(auto const &hit : CRTStripHitVec) + { + if(fCutT0 && (hit->Ts0() < fMinT0 || hit->Ts0() > fMaxT0)) + continue; + + _sh_channel.push_back(hit->Channel()); + _sh_tagger.push_back(fCRTGeoService->ChannelToTaggerEnum(hit->Channel())); + _sh_ts0.push_back(hit->Ts0()); + _sh_ts0_rwm_ref.push_back(hit->Ts0() + _rwm_etrig_diff); + _sh_ts0_ptb_hlt_beam_gate_ref.push_back(hit->Ts0() + _ptb_hlt_beam_gate_etrig_diff); + _sh_ts1.push_back(hit->Ts1()); + _sh_ts1_rwm_ref.push_back(hit->Ts1() + _rwm_crt_t1_reset_diff); + _sh_ts1_ptb_hlt_beam_gate_ref.push_back(hit->Ts1() + _ptb_hlt_beam_gate_crt_t1_reset_diff); + _sh_unixs.push_back(hit->UnixS()); + _sh_pos.push_back(hit->Pos()); + _sh_err.push_back(hit->Error()); + _sh_adc1.push_back(hit->ADC1()); + _sh_adc2.push_back(hit->ADC2()); + _sh_saturated1.push_back(hit->Saturated1()); + _sh_saturated2.push_back(hit->Saturated2()); + } +} + +void sbnd::crt::CRTTopHatAnalysis::AnalyseCRTClusters(const art::Event &e, const std::vector> &CRTClusterVec, + const art::FindManyP &clustersToSpacePoints) +{ + _cl_ts0.clear(); + _cl_ts0_rwm_ref.clear(); + _cl_ts0_ptb_hlt_beam_gate_ref.clear(); + _cl_ts1.clear(); + _cl_ts1_rwm_ref.clear(); + _cl_ts1_ptb_hlt_beam_gate_ref.clear(); + _cl_unixs.clear(); + _cl_nhits.clear(); + _cl_tagger.clear(); + _cl_composition.clear(); + _cl_has_sp.clear(); + _cl_sp_x.clear(); + _cl_sp_ex.clear(); + _cl_sp_y.clear(); + _cl_sp_ey.clear(); + _cl_sp_z.clear(); + _cl_sp_ez.clear(); + _cl_sp_pe.clear(); + _cl_sp_ts0.clear(); + _cl_sp_ts0_rwm_ref.clear(); + _cl_sp_ts0_ptb_hlt_beam_gate_ref.clear(); + _cl_sp_ets0.clear(); + _cl_sp_ts1.clear(); + _cl_sp_ts1_rwm_ref.clear(); + _cl_sp_ts1_ptb_hlt_beam_gate_ref.clear(); + _cl_sp_ets1.clear(); + _cl_sp_complete.clear(); + + for(auto const &cluster : CRTClusterVec) + { + if(fCutT0 && (cluster->Ts0() < fMinT0 || cluster->Ts0() > fMaxT0)) + continue; + + _cl_ts0.push_back(cluster->Ts0()); + _cl_ts0_rwm_ref.push_back(cluster->Ts0() + _rwm_etrig_diff); + _cl_ts0_ptb_hlt_beam_gate_ref.push_back(cluster->Ts0() + _ptb_hlt_beam_gate_etrig_diff); + _cl_ts1.push_back(cluster->Ts1()); + _cl_ts1_rwm_ref.push_back(cluster->Ts1() + _rwm_crt_t1_reset_diff); + _cl_ts1_ptb_hlt_beam_gate_ref.push_back(cluster->Ts1() + _ptb_hlt_beam_gate_crt_t1_reset_diff); + _cl_unixs.push_back(cluster->UnixS()); + _cl_nhits.push_back(cluster->NHits()); + _cl_tagger.push_back(cluster->Tagger()); + _cl_composition.push_back(cluster->Composition()); + + const auto spacepoints = clustersToSpacePoints.at(cluster.key()); + if(spacepoints.size() == 1) + { + const auto spacepoint = spacepoints[0]; + + _cl_has_sp.push_back(true); + _cl_sp_x.push_back(spacepoint->X()); + _cl_sp_ex.push_back(spacepoint->XErr()); + _cl_sp_y.push_back(spacepoint->Y()); + _cl_sp_ey.push_back(spacepoint->YErr()); + _cl_sp_z.push_back(spacepoint->Z()); + _cl_sp_ez.push_back(spacepoint->ZErr()); + _cl_sp_pe.push_back(spacepoint->PE()); + _cl_sp_ts0.push_back(spacepoint->Ts0()); + _cl_sp_ts0_rwm_ref.push_back(spacepoint->Ts0() + _rwm_etrig_diff); + _cl_sp_ts0_ptb_hlt_beam_gate_ref.push_back(spacepoint->Ts0() + _ptb_hlt_beam_gate_etrig_diff); + _cl_sp_ets0.push_back(spacepoint->Ts0Err()); + _cl_sp_ts1.push_back(spacepoint->Ts1()); + _cl_sp_ts1_rwm_ref.push_back(spacepoint->Ts1() + _rwm_crt_t1_reset_diff); + _cl_sp_ts1_ptb_hlt_beam_gate_ref.push_back(spacepoint->Ts1() + _ptb_hlt_beam_gate_crt_t1_reset_diff); + _cl_sp_ets1.push_back(spacepoint->Ts1Err()); + _cl_sp_complete.push_back(spacepoint->Complete()); + } + else + { + _cl_has_sp.push_back(false); + _cl_sp_x.push_back(-999999.); + _cl_sp_ex.push_back(-999999.); + _cl_sp_y.push_back(-999999.); + _cl_sp_ey.push_back(-999999.); + _cl_sp_z.push_back(-999999.); + _cl_sp_ez.push_back(-999999.); + _cl_sp_pe.push_back(-999999.); + _cl_sp_ts0.push_back(-999999.); + _cl_sp_ts0_rwm_ref.push_back(-999999.); + _cl_sp_ts0_ptb_hlt_beam_gate_ref.push_back(-999999.); + _cl_sp_ets0.push_back(-999999.); + _cl_sp_ts1.push_back(-999999.); + _cl_sp_ts1_rwm_ref.push_back(-999999.); + _cl_sp_ts1_ptb_hlt_beam_gate_ref.push_back(-999999.); + _cl_sp_ets1.push_back(-999999.); + _cl_sp_complete.push_back(false); + } + } +} +void sbnd::crt::CRTTopHatAnalysis::AnalyseCRTTracks(const art::Event &e, const std::vector> &CRTTrackVec) +{ + _tr_start_x.clear(); + _tr_start_y.clear(); + _tr_start_z.clear(); + _tr_end_x.clear(); + _tr_end_y.clear(); + _tr_end_z.clear(); + _tr_dir_x.clear(); + _tr_dir_y.clear(); + _tr_dir_z.clear(); + _tr_ts0.clear(); + _tr_ts0_rwm_ref.clear(); + _tr_ts0_ptb_hlt_beam_gate_ref.clear(); + _tr_ets0.clear(); + _tr_ts1.clear(); + _tr_ts1_rwm_ref.clear(); + _tr_ts1_ptb_hlt_beam_gate_ref.clear(); + _tr_ets1.clear(); + _tr_pe.clear(); + _tr_length.clear(); + _tr_tof.clear(); + _tr_theta.clear(); + _tr_phi.clear(); + _tr_triple.clear(); + _tr_tagger1.clear(); + _tr_tagger2.clear(); + _tr_tagger3.clear(); + + for(auto const& track : CRTTrackVec) + { + if(fCutT0 && (track->Ts0() < fMinT0 || track->Ts0() > fMaxT0)) + continue; + + const geo::Point_t start = track->Start(); + _tr_start_x.push_back(start.X()); + _tr_start_y.push_back(start.Y()); + _tr_start_z.push_back(start.Z()); + + const geo::Point_t end = track->End(); + _tr_end_x.push_back(end.X()); + _tr_end_y.push_back(end.Y()); + _tr_end_z.push_back(end.Z()); + + const geo::Vector_t dir = track->Direction(); + _tr_dir_x.push_back(dir.X()); + _tr_dir_y.push_back(dir.Y()); + _tr_dir_z.push_back(dir.Z()); + + _tr_ts0.push_back(track->Ts0()); + _tr_ts0_rwm_ref.push_back(track->Ts0() + _rwm_etrig_diff); + _tr_ts0_ptb_hlt_beam_gate_ref.push_back(track->Ts0() + _ptb_hlt_beam_gate_etrig_diff); + _tr_ets0.push_back(track->Ts0Err()); + _tr_ts1.push_back(track->Ts1()); + _tr_ts1_rwm_ref.push_back(track->Ts1() + _rwm_crt_t1_reset_diff); + _tr_ts1_ptb_hlt_beam_gate_ref.push_back(track->Ts1() + _ptb_hlt_beam_gate_crt_t1_reset_diff); + _tr_ets1.push_back(track->Ts1Err()); + _tr_pe.push_back(track->PE()); + _tr_length.push_back(track->Length()); + _tr_tof.push_back(track->ToF()); + _tr_theta.push_back(TMath::RadToDeg() * track->Theta()); + _tr_phi.push_back(TMath::RadToDeg() * track->Phi()); + _tr_triple.push_back(track->Triple()); + + unsigned tag_i = 0; + + for(auto const &tagger : track->Taggers()) + { + if(tag_i == 0) + _tr_tagger1.push_back(tagger); + else if(tag_i == 1) + _tr_tagger2.push_back(tagger); + else if(tag_i == 2) + _tr_tagger3.push_back(tagger); + + ++tag_i; + } + } +} + +void sbnd::crt::CRTTopHatAnalysis::AnalysePMTSoftwareTriggers(const art::Event &e, const std::vector> &PMTSoftwareTriggerVec) +{ + _pmt_st_found_trigger = false; + _pmt_st_corrected_peak_time = std::numeric_limits::lowest(); + _pmt_st_corrected_peak_time_rwm_ref = std::numeric_limits::lowest(); + + if(PMTSoftwareTriggerVec.size() != 1) + return; + + _pmt_st_found_trigger = PMTSoftwareTriggerVec[0]->foundBeamTrigger; + _pmt_st_corrected_peak_time = PMTSoftwareTriggerVec[0]->peaktime*1e3 + PMTSoftwareTriggerVec[0]->trig_ts; + _pmt_st_corrected_peak_time_rwm_ref = _pmt_st_corrected_peak_time + _rwm_ptb_hlt_beam_gate_diff; +} + +DEFINE_ART_MODULE(sbnd::crt::CRTTopHatAnalysis) diff --git a/sbndcode/CRT/CRTAna/crttophatana_sbnd.fcl b/sbndcode/CRT/CRTAna/crttophatana_sbnd.fcl new file mode 100644 index 000000000..a82b14e43 --- /dev/null +++ b/sbndcode/CRT/CRTAna/crttophatana_sbnd.fcl @@ -0,0 +1,12 @@ +BEGIN_PROLOG + +crttophatana_data_sbnd: +{ + module_type: "CRTTopHatAnalysis" + CutT0: true + MinT0: -50000 + MaxT0: 50000 + SavePMTSoftwareTrigger: true +} + +END_PROLOG diff --git a/sbndcode/CRT/CRTAna/run_crttophatana_data.fcl b/sbndcode/CRT/CRTAna/run_crttophatana_data.fcl new file mode 100644 index 000000000..cce367369 --- /dev/null +++ b/sbndcode/CRT/CRTAna/run_crttophatana_data.fcl @@ -0,0 +1,28 @@ +#include "services_sbnd.fcl" +#include "crt_services_sbnd.fcl" +#include "crttophatana_sbnd.fcl" + +process_name: CRTTopHatAna + +services: +{ + TFileService: { fileName: "crttophatana_sbnd.root" } + @table::sbnd_basic_services + @table::crt_services_data_sbnd +} + +source: +{ + module_type: RootInput +} + +physics: +{ + analyzers: + { + crttophatana: @local::crttophatana_data_sbnd + } + + ana: [ crttophatana ] + end_paths: [ ana ] +} From c752a9148a7b92b38fcff9c3bfc6c8360df0ad88 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Mon, 23 Feb 2026 08:15:52 -0600 Subject: [PATCH 129/155] Add relevant functions for ADRIFT to GeoService --- .../Geometry/GeometryWrappers/CRTGeoService.h | 4 ++++ .../GeometryWrappers/CRTGeoService_service.cc | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/sbndcode/Geometry/GeometryWrappers/CRTGeoService.h b/sbndcode/Geometry/GeometryWrappers/CRTGeoService.h index 7b76b4fb0..c60b95b80 100644 --- a/sbndcode/Geometry/GeometryWrappers/CRTGeoService.h +++ b/sbndcode/Geometry/GeometryWrappers/CRTGeoService.h @@ -430,6 +430,10 @@ namespace sbnd::crt { bool IsPointInsideCRTLimits(const geo::Point_t &point); + double StripArea(const uint16_t channel); + + double StripAverageY(const uint16_t channel); + private: std::map fTaggers; diff --git a/sbndcode/Geometry/GeometryWrappers/CRTGeoService_service.cc b/sbndcode/Geometry/GeometryWrappers/CRTGeoService_service.cc index a8b64a01b..76be4b46f 100644 --- a/sbndcode/Geometry/GeometryWrappers/CRTGeoService_service.cc +++ b/sbndcode/Geometry/GeometryWrappers/CRTGeoService_service.cc @@ -562,6 +562,24 @@ namespace sbnd::crt { (point.Y() > lims[1] && point.Y() < lims[4]) && (point.Z() > lims[2] && point.Z() < lims[5]); } + + double CRTGeoService::StripArea(const uint16_t channel) + { + CRTStripGeo strip = GetStrip(channel); + const double x = abs(strip.maxX - strip.minX) / 2; + const double y = abs(strip.maxY - strip.minY) / 2; + const double z = abs(strip.maxZ - strip.minZ) / 2; + + // One will be 1cm so this gives the area in cm^2 + return x * y * z; + } + + double CRTGeoService::StripAverageY(const uint16_t channel) + { + CRTStripGeo strip = GetStrip(channel); + + return (strip.maxY + strip.minY) / 2; + } } DEFINE_ART_SERVICE(sbnd::crt::CRTGeoService) From 8693f809df0fc9e8403638e9edefb2388fedf866 Mon Sep 17 00:00:00 2001 From: nathanielerowe <70993723+nathanielerowe@users.noreply.github.com> Date: Mon, 23 Feb 2026 19:42:52 -0600 Subject: [PATCH 130/155] Update sbncode version to v10_15_00 --- ups/product_deps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ups/product_deps b/ups/product_deps index 38979aeb7..29ba0e0fd 100644 --- a/ups/product_deps +++ b/ups/product_deps @@ -253,7 +253,7 @@ wpdir product_dir wire-cell-cfg # #################################### product version qual flags -sbncode v10_14_02_03 - +sbncode v10_15_00 - cetmodules v3_24_01 - only_for_build sbnd_data v01_42_00 - sbndutil v10_06_01 - optional From 263176b4c4c419975ac68a6690febfe7e47d510d Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Tue, 24 Feb 2026 06:47:03 -0600 Subject: [PATCH 131/155] Add skeleton for timing analysis --- sbndcode/CRT/CRTAna/CMakeLists.txt | 1 + .../CRT/CRTAna/CRTTimingAnalysis_module.cc | 666 ++++++++++++++++++ sbndcode/CRT/CRTAna/crttimingana_sbnd.fcl | 19 + 3 files changed, 686 insertions(+) create mode 100644 sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc create mode 100644 sbndcode/CRT/CRTAna/crttimingana_sbnd.fcl diff --git a/sbndcode/CRT/CRTAna/CMakeLists.txt b/sbndcode/CRT/CRTAna/CMakeLists.txt index 2cbcc6327..05de4d016 100644 --- a/sbndcode/CRT/CRTAna/CMakeLists.txt +++ b/sbndcode/CRT/CRTAna/CMakeLists.txt @@ -8,6 +8,7 @@ art_make( sbndaq_artdaq_core::sbndaq-artdaq-core_Obj_SBND sbnobj::SBND_CRT sbnobj::SBND_Timing + sbnobj::Common_Reco sbndcode_CRT_CRTBackTracker ) diff --git a/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc b/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc new file mode 100644 index 000000000..3fa9d0fd6 --- /dev/null +++ b/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc @@ -0,0 +1,666 @@ +//////////////////////////////////////////////////////////////////////// +// Class: CRTTimingAnalysis +// Plugin Type: analyzer +// File: CRTTimingAnalysis_module.cc +// Author: Henry Lay (h.lay@sheffield.ac.uk) +//////////////////////////////////////////////////////////////////////// + +#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 "art_root_io/TFileService.h" +#include "canvas/Persistency/Common/FindManyP.h" +#include "canvas/Persistency/Common/FindOneP.h" + +#include "TTree.h" + +#include "lardataobj/RecoBase/Slice.h" +#include "lardataobj/RecoBase/PFParticle.h" +#include "lardataobj/RecoBase/Track.h" +#include "lardataobj/AnalysisBase/T0.h" + +#include "sbnobj/SBND/CRT/CRTStripHit.hh" +#include "sbnobj/SBND/CRT/CRTCluster.hh" +#include "sbnobj/SBND/CRT/CRTSpacePoint.hh" +#include "sbnobj/SBND/CRT/CRTTrack.hh" +#include "sbnobj/SBND/Timing/DAQTimestamp.hh" +#include "sbnobj/Common/Reco/CorrectedOpFlashTiming.h" + +#include "sbndcode/Geometry/GeometryWrappers/CRTGeoService.h" +#include "sbndcode/Decoders/PTB/sbndptb.h" +#include "sbndcode/Timing/SBNDRawTimingObj.h" + +namespace sbnd::crt { + class CRTTimingAnalysis; +} + +class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { +public: + explicit CRTTimingAnalysis(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. + CRTTimingAnalysis(CRTTimingAnalysis const&) = delete; + CRTTimingAnalysis(CRTTimingAnalysis&&) = delete; + CRTTimingAnalysis& operator=(CRTTimingAnalysis const&) = delete; + CRTTimingAnalysis& operator=(CRTTimingAnalysis&&) = delete; + + // Required functions. + void analyze(art::Event const& e) override; + + void AnalysePTBs(std::vector> &PTBVec); + + void AnalyseTDCs(std::vector> &TDCVec); + + void SortReferencing(); + + void AnalyseCRTSpacePoints(const std::vector> &CRTSpacePointVec, + const art::FindOneP &spacepointsToClusters, + const art::FindManyP &clustersToStripHits); + + void AnalyseCRTTracks(const std::vector> &CRTTrackVec, + const art::FindManyP &tracksToSpacePoints, + const art::FindOneP &spacepointsToClusters, + const art::FindManyP &clustersToStripHits); + + void AnalyseTPCSlices(const std::vector> &TPCSliceVec, + const art::FindManyP &sliceToCorrectedOpFlashes, + const art::FindManyP &sliceToPFPs, + const art::FindOneP &pfpToTrack, + const art::FindOneP &trackToCRTSpacePoint, + const art::FindOneP &spacepointsToClusters, + const art::FindManyP &clustersToStripHits); + +private: + + art::ServiceHandle fCRTGeoService; + + // fcl Controlled Variables + std::string fCRTClusterModuleLabel, fCRTSpacePointModuleLabel, fCRTTrackModuleLabel, + fPTBModuleLabel, fTDCModuleLabel, fTimingReferenceModuleLabel, fTPCSliceModuleLabel, + fCorrectedOpFlashModuleLabel, fTPCTrackModuleLabel, fCRTSpacePointMatchingModuleLabel; + std::vector fAllowedPTBHLTs; + + // Global Storage + std::vector _ptb_hlt_trigger; + std::vector _ptb_hlt_timestamp; + + std::vector _ptb_llt_trigger; + std::vector _ptb_llt_timestamp; + + std::vector _tdc_channel; + std::vector _tdc_timestamp; + std::vector _tdc_offset; + std::vector _tdc_name; + + // Trees + TTree *fSPTree, *fTrTree, *fTPCTree; + + // Tree Variables + int _run; + int _subrun; + int _event; + int _crt_timing_reference_type; + int _crt_timing_reference_channel; + + bool _etrig_good; + bool _rwm_good; + bool _ptb_hlt_beam_gate_good; + bool _crt_t1_reset_good; + double _rwm_etrig_diff; + double _ptb_hlt_beam_gate_etrig_diff; + double _rwm_crt_t1_reset_diff; + double _ptb_hlt_beam_gate_crt_t1_reset_diff; + double _rwm_ptb_hlt_beam_gate_diff; + + uint16_t _sp_nhits; + int16_t _sp_tagger; + double _sp_x; + double _sp_y; + double _sp_z; + double _sp_pe; + double _sp_ts0; + double _sp_ts0_rwm_ref; + double _sp_ts0_ptb_hlt_beam_gate_ref; + double _sp_dts0; + double _sp_ts1; + double _sp_ts1_rwm_ref; + double _sp_ts1_ptb_hlt_beam_gate_ref; + double _sp_dts1; + bool _sp_single_timing_chain; + int16_t _sp_timing_chain; + std::vector _sp_sh_channel_set; + std::vector _sp_sh_mac5_set; + std::vector _sp_sh_timing_chain_set; + std::vector _sp_sh_ts0_set; + std::vector _sp_sh_ts1_set; + std::vector _sp_sh_time_walk_set; + std::vector _sp_sh_prop_delay_set; + std::vector _sp_sh_cable_length_set; + std::vector _sp_sh_calib_offset_ts0_set; + std::vector _sp_sh_calib_offset_ts1_set; + + double _tr_start_x; + double _tr_start_y; + double _tr_start_z; + double _tr_end_x; + double _tr_end_y; + double _tr_end_z; + double _tr_dir_x; + double _tr_dir_y; + double _tr_dir_z; + double _tr_ts0; + double _tr_ts0_rwm_ref; + double _tr_ts0_ptb_hlt_beam_gate_ref; + double _tr_ts1; + double _tr_ts1_rwm_ref; + double _tr_ts1_ptb_hlt_beam_gate_ref; + double _tr_pe; + double _tr_length; + double _tr_length_tof; + double _tr_tof_ts0; + double _tr_tof_diff_ts0; + double _tr_tof_ts1; + double _tr_tof_diff_ts1; + double _tr_theta; + double _tr_phi; + bool _tr_triple; + int16_t _tr_tagger1; + int16_t _tr_tagger2; + int16_t _tr_tagger3; + int16_t _tr_start_tagger; + double _tr_start_dts0; + bool _tr_start_single_timing_chain; + int16_t _tr_start_timing_chain; + int16_t _tr_end_tagger; + double _tr_end_dts0; + bool _tr_end_single_timing_chain; + int16_t _tr_end_timing_chain; + + bool _tpc_has_corrected_opflash; + bool _tpc_has_crt_sp_match; + double _tpc_opflash_t0; + double _tpc_opflash_nutof_light; + double _tpc_opflash_nutof_charge; + double _tpc_opflash_t0_corrected; + double _tpc_opflash_t0_corrected_rwm; + double _tpc_crt_sp_score; + double _tpc_crt_sp_ts0; + double _tpc_crt_sp_ts0_rwm_ref; + double _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref; + double _tpc_crt_sp_dts0; + double _tpc_crt_sp_ts1; + double _tpc_crt_sp_ts1_rwm_ref; + double _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref; + double _tpc_crt_sp_dts1; +}; + +sbnd::crt::CRTTimingAnalysis::CRTTimingAnalysis(fhicl::ParameterSet const& p) + : EDAnalyzer{p} +{ + fCRTClusterModuleLabel = p.get("CRTClusterModuleLabel"); + fCRTSpacePointModuleLabel = p.get("CRTSpacePointModuleLabel"); + fCRTTrackModuleLabel = p.get("CRTTrackModuleLabel"); + fPTBModuleLabel = p.get("PTBModuleLabel"); + fTDCModuleLabel = p.get("TDCModuleLabel"); + fTimingReferenceModuleLabel = p.get("TimingReferenceModuleLabel"); + fTPCSliceModuleLabel = p.get("TPCSliceModuleLabel"); + fCorrectedOpFlashModuleLabel = p.get("CorrectedOpFlashModuleLabel"); + fTPCTrackModuleLabel = p.get("TPCTrackModuleLabel"); + fCRTSpacePointMatchingModuleLabel = p.get("CRTSpacePointMatchingModuleLabel"); + fAllowedPTBHLTs = p.get>("AllowedPTBHLTs"); + + art::ServiceHandle fs; + + fSPTree = fs->make("spacepoints",""); + fSPTree->Branch("run", "int", &_run); + fSPTree->Branch("subrun", "int", &_subrun); + fSPTree->Branch("event", "int", &_event); + fSPTree->Branch("crt_timing_reference_type", "int", &_crt_timing_reference_type); + fSPTree->Branch("crt_timing_reference_channel", "int", &_crt_timing_reference_channel); + + fSPTree->Branch("etrig_good", "bool", &_etrig_good); + fSPTree->Branch("rwm_good", "bool", &_rwm_good); + fSPTree->Branch("ptb_hlt_beam_gate_good", "bool", &_ptb_hlt_beam_gate_good); + fSPTree->Branch("crt_t1_reset_good", "bool", &_crt_t1_reset_good); + fSPTree->Branch("rwm_etrig_diff", "double", &_rwm_etrig_diff); + fSPTree->Branch("ptb_hlt_beam_gate_etrig_diff", "double", &_ptb_hlt_beam_gate_etrig_diff); + fSPTree->Branch("rwm_crt_t1_reset_diff", "double", &_rwm_crt_t1_reset_diff); + fSPTree->Branch("ptb_hlt_beam_gate_crt_t1_reset_diff", "double", &_ptb_hlt_beam_gate_crt_t1_reset_diff); + fSPTree->Branch("rwm_ptb_hlt_beam_gate_diff", "double", &_rwm_ptb_hlt_beam_gate_diff); + + fSPTree->Branch("sp_nhits", "uint16_t", &_sp_nhits); + fSPTree->Branch("sp_tagger", "int16_t", &_sp_tagger); + fSPTree->Branch("sp_x", "double", &_sp_x); + fSPTree->Branch("sp_y", "double", &_sp_y); + fSPTree->Branch("sp_z", "double", &_sp_z); + fSPTree->Branch("sp_pe", "double", &_sp_pe); + fSPTree->Branch("sp_ts0", "double", &_sp_ts0); + fSPTree->Branch("sp_ts0_rwm_ref", "double", &_sp_ts0_rwm_ref); + fSPTree->Branch("sp_ts0_ptb_hlt_beam_gate_ref", "double", &_sp_ts0_ptb_hlt_beam_gate_ref); + fSPTree->Branch("sp_dts0", "double", &_sp_dts0); + fSPTree->Branch("sp_ts1", "double", &_sp_ts1); + fSPTree->Branch("sp_ts1_rwm_ref", "double", &_sp_ts1_rwm_ref); + fSPTree->Branch("sp_ts1_ptb_hlt_beam_gate_ref", "double", &_sp_ts1_ptb_hlt_beam_gate_ref); + fSPTree->Branch("sp_dts1", "double", &_sp_dts1); + fSPTree->Branch("sp_single_timing_chain", "bool", &_sp_single_timing_chain); + fSPTree->Branch("sp_timing_chain", "int16_t", &_sp_timing_chain); + fSPTree->Branch("sp_sh_channel_set", "std::vector", &_sp_sh_channel_set); + fSPTree->Branch("sp_sh_mac5_set", "std::vector", &_sp_sh_mac5_set); + fSPTree->Branch("sp_sh_timing_chain_set", "std::vector", &_sp_sh_timing_chain_set); + fSPTree->Branch("sp_sh_ts0_set", "std::vector", &_sp_sh_ts0_set); + fSPTree->Branch("sp_sh_ts1_set", "std::vector", &_sp_sh_ts1_set); + fSPTree->Branch("sp_sh_time_walk_set", "std::vector", &_sp_sh_time_walk_set); + fSPTree->Branch("sp_sh_prop_delay_set", "std::vector", &_sp_sh_prop_delay_set); + fSPTree->Branch("sp_sh_cable_length_set", "std::vector", &_sp_sh_cable_length_set); + fSPTree->Branch("sp_sh_calib_offset_ts0_set", "std::vector", &_sp_sh_calib_offset_ts0_set); + fSPTree->Branch("sp_sh_calib_offset_ts1_set", "std::vector", &_sp_sh_calib_offset_ts1_set); + + fTrTree = fs->make("tracks",""); + fTrTree->Branch("run", "int", &_run); + fTrTree->Branch("subrun", "int", &_subrun); + fTrTree->Branch("event", "int", &_event); + fTrTree->Branch("crt_timing_reference_type", "int", &_crt_timing_reference_type); + fTrTree->Branch("crt_timing_reference_channel", "int", &_crt_timing_reference_channel); + + fTrTree->Branch("etrig_good", "bool", &_etrig_good); + fTrTree->Branch("rwm_good", "bool", &_rwm_good); + fTrTree->Branch("ptb_hlt_beam_gate_good", "bool", &_ptb_hlt_beam_gate_good); + fTrTree->Branch("crt_t1_reset_good", "bool", &_crt_t1_reset_good); + fTrTree->Branch("rwm_etrig_diff", "double", &_rwm_etrig_diff); + fTrTree->Branch("ptb_hlt_beam_gate_etrig_diff", "double", &_ptb_hlt_beam_gate_etrig_diff); + fTrTree->Branch("rwm_crt_t1_reset_diff", "double", &_rwm_crt_t1_reset_diff); + fTrTree->Branch("ptb_hlt_beam_gate_crt_t1_reset_diff", "double", &_ptb_hlt_beam_gate_crt_t1_reset_diff); + fTrTree->Branch("rwm_ptb_hlt_beam_gate_diff", "double", &_rwm_ptb_hlt_beam_gate_diff); + + fTrTree->Branch("tr_start_x", "double", &_tr_start_x); + fTrTree->Branch("tr_start_y", "double", &_tr_start_y); + fTrTree->Branch("tr_start_z", "double", &_tr_start_z); + fTrTree->Branch("tr_end_x", "double", &_tr_end_x); + fTrTree->Branch("tr_end_y", "double", &_tr_end_y); + fTrTree->Branch("tr_end_z", "double", &_tr_end_z); + fTrTree->Branch("tr_dir_x", "double", &_tr_dir_x); + fTrTree->Branch("tr_dir_y", "double", &_tr_dir_y); + fTrTree->Branch("tr_dir_z", "double", &_tr_dir_z); + fTrTree->Branch("tr_ts0", "double", &_tr_ts0); + fTrTree->Branch("tr_ts0_rwm_ref", "double", &_tr_ts0_rwm_ref); + fTrTree->Branch("tr_ts0_ptb_hlt_beam_gate_ref", "double", &_tr_ts0_ptb_hlt_beam_gate_ref); + fTrTree->Branch("tr_ts1", "double", &_tr_ts1); + fTrTree->Branch("tr_ts1_rwm_ref", "double", &_tr_ts1_rwm_ref); + fTrTree->Branch("tr_ts1_ptb_hlt_beam_gate_ref", "double", &_tr_ts1_ptb_hlt_beam_gate_ref); + fTrTree->Branch("tr_pe", "double", &_tr_pe); + fTrTree->Branch("tr_length", "double", &_tr_length); + fTrTree->Branch("tr_length_tof", "double", &_tr_length_tof); + fTrTree->Branch("tr_tof_ts0", "double", &_tr_tof_ts0); + fTrTree->Branch("tr_tof_diff_ts0", "double", &_tr_tof_diff_ts0); + fTrTree->Branch("tr_tof_ts1", "double", &_tr_tof_ts1); + fTrTree->Branch("tr_tof_diff_ts1", "double", &_tr_tof_diff_ts1); + fTrTree->Branch("tr_theta", "double", &_tr_theta); + fTrTree->Branch("tr_phi", "double", &_tr_phi); + fTrTree->Branch("tr_triple", "bool", &_tr_triple); + fTrTree->Branch("tr_tagger1", "int16_t", &_tr_tagger1); + fTrTree->Branch("tr_tagger2", "int16_t", &_tr_tagger2); + fTrTree->Branch("tr_tagger3", "int16_t", &_tr_tagger3); + fTrTree->Branch("tr_start_tagger", "int16_t", &_tr_start_tagger); + fTrTree->Branch("tr_start_dts0", "double", &_tr_start_dts0); + fTrTree->Branch("tr_start_single_timing_chain", "bool", &_tr_start_single_timing_chain); + fTrTree->Branch("tr_start_timing_chain", "int16_t", &_tr_start_timing_chain); + fTrTree->Branch("tr_end_tagger", "int16_t", &_tr_end_tagger); + fTrTree->Branch("tr_end_dts0", "double", &_tr_end_dts0); + fTrTree->Branch("tr_end_single_timing_chain", "bool", &_tr_end_single_timing_chain); + fTrTree->Branch("tr_end_timing_chain", "int16_t", &_tr_end_timing_chain); + + fTPCTree = fs->make("slices",""); + fTPCTree->Branch("run", "int", &_run); + fTPCTree->Branch("subrun", "int", &_subrun); + fTPCTree->Branch("event", "int", &_event); + fTPCTree->Branch("crt_timing_reference_type", "int", &_crt_timing_reference_type); + fTPCTree->Branch("crt_timing_reference_channel", "int", &_crt_timing_reference_channel); + + fTPCTree->Branch("etrig_good", "bool", &_etrig_good); + fTPCTree->Branch("rwm_good", "bool", &_rwm_good); + fTPCTree->Branch("ptb_hlt_beam_gate_good", "bool", &_ptb_hlt_beam_gate_good); + fTPCTree->Branch("crt_t1_reset_good", "bool", &_crt_t1_reset_good); + fTPCTree->Branch("rwm_etrig_diff", "double", &_rwm_etrig_diff); + fTPCTree->Branch("ptb_hlt_beam_gate_etrig_diff", "double", &_ptb_hlt_beam_gate_etrig_diff); + fTPCTree->Branch("rwm_crt_t1_reset_diff", "double", &_rwm_crt_t1_reset_diff); + fTPCTree->Branch("ptb_hlt_beam_gate_crt_t1_reset_diff", "double", &_ptb_hlt_beam_gate_crt_t1_reset_diff); + fTPCTree->Branch("rwm_ptb_hlt_beam_gate_diff", "double", &_rwm_ptb_hlt_beam_gate_diff); + + fTPCTree->Branch("tpc_has_corrected_opflash", "bool", &_tpc_has_corrected_opflash); + fTPCTree->Branch("tpc_has_crt_sp_match", "bool", &_tpc_has_crt_sp_match); + fTPCTree->Branch("tpc_opflash_t0", "double", &_tpc_opflash_t0); + fTPCTree->Branch("tpc_opflash_nutof_light", "double", &_tpc_opflash_nutof_light); + fTPCTree->Branch("tpc_opflash_nutof_charge", "double", &_tpc_opflash_nutof_charge); + fTPCTree->Branch("tpc_opflash_t0_corrected", "double", &_tpc_opflash_t0_corrected); + fTPCTree->Branch("tpc_opflash_t0_corrected_rwm", "double", &_tpc_opflash_t0_corrected_rwm); + fTPCTree->Branch("tpc_crt_sp_score", "double", &_tpc_crt_sp_score); + fTPCTree->Branch("tpc_crt_sp_ts0", "double", &_tpc_crt_sp_ts0); + fTPCTree->Branch("tpc_crt_sp_ts0_rwm_ref", "double", &_tpc_crt_sp_ts0_rwm_ref); + fTPCTree->Branch("tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref", "double", &_tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref); + fTPCTree->Branch("tpc_crt_sp_dts0", "double", &_tpc_crt_sp_dts0); + fTPCTree->Branch("tpc_crt_sp_ts1", "double", &_tpc_crt_sp_ts1); + fTPCTree->Branch("tpc_crt_sp_ts1_rwm_ref", "double", &_tpc_crt_sp_ts1_rwm_ref); + fTPCTree->Branch("tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref", "double", &_tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref); + fTPCTree->Branch("tpc_crt_sp_dts1", "double", &_tpc_crt_sp_dts1); +} + +void sbnd::crt::CRTTimingAnalysis::analyze(art::Event const& e) +{ + _run = e.id().run(); + _subrun = e.id().subRun(); + _event = e.id().event(); + + _crt_timing_reference_type = -1; + _crt_timing_reference_channel = -1; + + art::Handle TimingReferenceHandle; + e.getByLabel(fTimingReferenceModuleLabel, TimingReferenceHandle); + if(TimingReferenceHandle.isValid()) + { + _crt_timing_reference_type = TimingReferenceHandle->timingType; + _crt_timing_reference_channel = TimingReferenceHandle->timingChannel; + } + + // Get PTBs + art::Handle> PTBHandle; + e.getByLabel(fPTBModuleLabel, PTBHandle); + if(!PTBHandle.isValid()){ + std::cout << "PTB product " << fPTBModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + std::vector> PTBVec; + art::fill_ptr_vector(PTBVec, PTBHandle); + + // Fill PTB variables + AnalysePTBs(PTBVec); + + // Get TDCs + art::Handle> TDCHandle; + e.getByLabel(fTDCModuleLabel, TDCHandle); + if(!TDCHandle.isValid()){ + std::cout << "TDC product " << fTDCModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + std::vector> TDCVec; + art::fill_ptr_vector(TDCVec, TDCHandle); + + // Fill TDC variables + AnalyseTDCs(TDCVec); + + SortReferencing(); + + // Get CRTSpacePoints + art::Handle> CRTSpacePointHandle; + e.getByLabel(fCRTSpacePointModuleLabel, CRTSpacePointHandle); + if(!CRTSpacePointHandle.isValid()){ + std::cout << "CRTSpacePoint product " << fCRTSpacePointModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + std::vector> CRTSpacePointVec; + art::fill_ptr_vector(CRTSpacePointVec, CRTSpacePointHandle); + + // Get CRTSpacePoint to CRTCluster Assns + art::FindOneP spacepointsToClusters(CRTSpacePointHandle, e, fCRTSpacePointModuleLabel); + + // Get CRTClusters + art::Handle> CRTClusterHandle; + e.getByLabel(fCRTClusterModuleLabel, CRTClusterHandle); + if(!CRTClusterHandle.isValid()){ + std::cout << "CRTCluster product " << fCRTClusterModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + + // Get CRTCluster to CRTStripHit Assns + art::FindManyP clustersToStripHits(CRTClusterHandle, e, fCRTClusterModuleLabel); + + // Fill CRTSpacePoint variables + AnalyseCRTSpacePoints(CRTSpacePointVec, spacepointsToClusters, clustersToStripHits); + + // Get CRTTracks + art::Handle> CRTTrackHandle; + e.getByLabel(fCRTTrackModuleLabel, CRTTrackHandle); + if(!CRTTrackHandle.isValid()){ + std::cout << "CRTTrack product " << fCRTTrackModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + std::vector> CRTTrackVec; + art::fill_ptr_vector(CRTTrackVec, CRTTrackHandle); + + // Get CRTTrack to CRTSpacePoint Assns + art::FindManyP tracksToSpacePoints(CRTTrackHandle, e, fCRTTrackModuleLabel); + + // Fill CRTTrack variables + AnalyseCRTTracks(CRTTrackVec, tracksToSpacePoints, spacepointsToClusters, clustersToStripHits); + + // Get TPCSlices + art::Handle> TPCSliceHandle; + e.getByLabel(fTPCSliceModuleLabel, TPCSliceHandle); + if(!TPCSliceHandle.isValid()){ + std::cout << "TPCSlice product " << fTPCSliceModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + std::vector> TPCSliceVec; + art::fill_ptr_vector(TPCSliceVec, TPCSliceHandle); + + // Get TPCSlice to CorrectedOpFlash Assns + art::FindManyP sliceToCorrectedOpFlashes(TPCSliceHandle, e, fCorrectedOpFlashModuleLabel); + + // Get TPCSlice to PFP Assns + art::FindManyP sliceToPFPs(TPCSliceHandle, e, fTPCSliceModuleLabel); + + // Get TPCPFPs + art::Handle> TPCPFPHandle; + e.getByLabel(fTPCSliceModuleLabel, TPCPFPHandle); + if(!TPCPFPHandle.isValid()){ + std::cout << "TPCPFP product " << fTPCSliceModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + + // Get PFP to Track Assns + art::FindOneP pfpToTrack(TPCPFPHandle, e, fTPCTrackModuleLabel); + + // Get TPCTracks + art::Handle> TPCTrackHandle; + e.getByLabel(fTPCTrackModuleLabel, TPCTrackHandle); + if(!TPCTrackHandle.isValid()){ + std::cout << "TPCTrack product " << fTPCTrackModuleLabel << " not found..." << std::endl; + throw std::exception(); + } + + // Get Track to CRTSpacePoint Assns + art::FindOneP trackToCRTSpacePoint(TPCTrackHandle, e, fCRTSpacePointMatchingModuleLabel); + + AnalyseTPCSlices(TPCSliceVec, sliceToCorrectedOpFlashes, sliceToPFPs, pfpToTrack, trackToCRTSpacePoint, spacepointsToClusters, clustersToStripHits); +} + +void sbnd::crt::CRTTimingAnalysis::AnalysePTBs(std::vector> &PTBVec) +{ + unsigned nHLTs = 0; + + for(auto const& ptb : PTBVec) + nHLTs += ptb->GetNHLTriggers(); + + _ptb_hlt_trigger.resize(nHLTs); + _ptb_hlt_timestamp.resize(nHLTs); + + unsigned hlt_i = 0; + + for(auto const& ptb : PTBVec) + { + for(unsigned i = 0; i < ptb->GetNHLTriggers(); ++i) + { + _ptb_hlt_trigger[hlt_i] = ptb->GetHLTrigger(i).trigger_word; + _ptb_hlt_timestamp[hlt_i] = ptb->GetHLTrigger(i).timestamp * 20; + + ++hlt_i; + } + } + + unsigned nLLTs = 0; + + for(auto const& ptb : PTBVec) + nLLTs += ptb->GetNLLTriggers(); + + _ptb_llt_trigger.resize(nLLTs); + _ptb_llt_timestamp.resize(nLLTs); + + unsigned llt_i = 0; + + for(auto const& ptb : PTBVec) + { + for(unsigned i = 0; i < ptb->GetNLLTriggers(); ++i) + { + _ptb_llt_trigger[llt_i] = ptb->GetLLTrigger(i).trigger_word; + _ptb_llt_timestamp[llt_i] = ptb->GetLLTrigger(i).timestamp * 20; + + ++llt_i; + } + } +} + +void sbnd::crt::CRTTimingAnalysis::AnalyseTDCs(std::vector> &TDCVec) +{ + const unsigned nTDCs = TDCVec.size(); + + _tdc_channel.resize(nTDCs); + _tdc_timestamp.resize(nTDCs); + _tdc_offset.resize(nTDCs); + _tdc_name.resize(nTDCs); + + unsigned tdc_i = 0; + + for(auto const& tdc : TDCVec) + { + _tdc_channel[tdc_i] = tdc->Channel(); + _tdc_timestamp[tdc_i] = tdc->Timestamp(); + _tdc_offset[tdc_i] = tdc->Offset(); + _tdc_name[tdc_i] = tdc->Name(); + + ++tdc_i; + } +} + +void sbnd::crt::CRTTimingAnalysis::SortReferencing() +{ + _etrig_good = false; _rwm_good = false; _ptb_hlt_beam_gate_good = false; _crt_t1_reset_good = false; + _rwm_etrig_diff = std::numeric_limits::max(); _ptb_hlt_beam_gate_etrig_diff = std::numeric_limits::max(); + _rwm_crt_t1_reset_diff = std::numeric_limits::max(); _ptb_hlt_beam_gate_crt_t1_reset_diff = std::numeric_limits::max(); + _rwm_ptb_hlt_beam_gate_diff = std::numeric_limits::max(); + + int etrig_count = 0, etrig_id = -1, rwm_count = 0, rwm_id = -1, crt_t1_reset_count = 0, crt_t1_reset_id = -1; + + for(unsigned int tdc_i = 0; tdc_i < _tdc_channel.size(); ++tdc_i) + { + if(_tdc_channel[tdc_i] == 4) + { + ++etrig_count; + etrig_id = tdc_i; + } + else if(_tdc_channel[tdc_i] == 2) + { + ++rwm_count; + rwm_id = tdc_i; + } + else if(_tdc_channel[tdc_i] == 0) + { + ++crt_t1_reset_count; + crt_t1_reset_id = tdc_i; + } + } + + uint64_t etrig = std::numeric_limits::max(), rwm = std::numeric_limits::max(), + hlt = std::numeric_limits::max(), crt_t1_reset = std::numeric_limits::max(); + + if(etrig_count == 1) + { + _etrig_good = true; + etrig = _tdc_timestamp[etrig_id]; + } + + if(rwm_count == 1) + { + _rwm_good = true; + rwm = _tdc_timestamp[rwm_id]; + } + + if(etrig_count == 1) + { + double closest_diff = std::numeric_limits::max(); + + for(unsigned int ptb_i = 0; ptb_i < _ptb_hlt_trigger.size(); ++ptb_i) + { + std::bitset<32> hlt_bitmask = std::bitset<32>(_ptb_hlt_trigger[ptb_i]); + + for(uint32_t allowed_hlt : fAllowedPTBHLTs) + { + if(hlt_bitmask[allowed_hlt]) + { + _ptb_hlt_beam_gate_good = true; + + uint64_t temp_hlt = _ptb_hlt_timestamp[ptb_i]; + double diff = etrig > temp_hlt ? etrig - temp_hlt : -1. * (temp_hlt - etrig); + + if(std::abs(diff) < closest_diff) + { + closest_diff = diff; + hlt = temp_hlt; + } + } + } + } + } + + if(crt_t1_reset_count == 1) + { + _crt_t1_reset_good = true; + crt_t1_reset = _tdc_timestamp[crt_t1_reset_id]; + } + + if(_etrig_good && _rwm_good) + _rwm_etrig_diff = etrig > rwm ? etrig - rwm : -1. * (rwm - etrig); + + if(_etrig_good && _ptb_hlt_beam_gate_good) + _ptb_hlt_beam_gate_etrig_diff = etrig > hlt ? etrig - hlt : -1. * (hlt - etrig); + + if(_crt_t1_reset_good && _rwm_good) + _rwm_crt_t1_reset_diff = crt_t1_reset > rwm ? crt_t1_reset - rwm : -1. * (rwm - crt_t1_reset); + + if(_etrig_good && _crt_t1_reset_good && _ptb_hlt_beam_gate_good) + _ptb_hlt_beam_gate_crt_t1_reset_diff = crt_t1_reset > hlt ? crt_t1_reset - hlt : -1. * (hlt - crt_t1_reset); + + if(_etrig_good && _rwm_good && _ptb_hlt_beam_gate_good) + _rwm_ptb_hlt_beam_gate_diff = hlt > rwm ? hlt - rwm : -1. * (rwm - hlt); +} + +void sbnd::crt::CRTTimingAnalysis::AnalyseCRTSpacePoints(const std::vector> &CRTSpacePointVec, + const art::FindOneP &spacepointsToClusters, + const art::FindManyP &clustersToStripHits) +{ +} + +void sbnd::crt::CRTTimingAnalysis::AnalyseCRTTracks(const std::vector> &CRTTrackVec, + const art::FindManyP &tracksToSpacePoints, + const art::FindOneP &spacepointsToClusters, + const art::FindManyP &clustersToStripHits) +{ +} + +void sbnd::crt::CRTTimingAnalysis::AnalyseTPCSlices(const std::vector> &TPCSliceVec, + const art::FindManyP &sliceToCorrectedOpFlashes, + const art::FindManyP &sliceToPFPs, + const art::FindOneP &pfpToTrack, + const art::FindOneP &trackToCRTSpacePoint, + const art::FindOneP &spacepointsToClusters, + const art::FindManyP &clustersToStripHits) +{ +} + +DEFINE_ART_MODULE(sbnd::crt::CRTTimingAnalysis) diff --git a/sbndcode/CRT/CRTAna/crttimingana_sbnd.fcl b/sbndcode/CRT/CRTAna/crttimingana_sbnd.fcl new file mode 100644 index 000000000..4a9bff36a --- /dev/null +++ b/sbndcode/CRT/CRTAna/crttimingana_sbnd.fcl @@ -0,0 +1,19 @@ +BEGIN_PROLOG + +crttophatana_data_sbnd: +{ + module_type: "CRTTimingAnalysis" + CRTClusterModuleLabel: "crtclustering" + CRTSpacePointModuleLabel: "crtspacepoints" + CRTTrackModuleLabel: "crttracks" + PTBModuleLabel: "ptbdecoder" + TDCModuleLabel: "tdcdecoder" + TimingReferenceModuleLabel: "crtstrips" + TPCSliceModuleLabel: "pandoraSCE" + CorrectedOpFlashModuleLabel: "lightpropagationcorrectionSCE" + TPCTrackModuleLabel: "pandoraSCETrack" + CRTSpacePointMatchingModuleLabel: "crtspacepointmatchingSCE" + AllowedPTBHLTs: [ 26, 27 ] +} + +END_PROLOG From 46bb0a2a5136161c4d4e7577713fef732d0d195b Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Tue, 24 Feb 2026 11:04:27 -0600 Subject: [PATCH 132/155] Refactor cluster characterisation to allow external use of timing corrections --- .../CRTReco/CRTClusterCharacterisationAlg.cc | 31 ++++++++++++------- .../CRTReco/CRTClusterCharacterisationAlg.h | 6 +++- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/sbndcode/CRT/CRTReco/CRTClusterCharacterisationAlg.cc b/sbndcode/CRT/CRTReco/CRTClusterCharacterisationAlg.cc index 1b7e296cd..49c6dbb4c 100644 --- a/sbndcode/CRT/CRTReco/CRTClusterCharacterisationAlg.cc +++ b/sbndcode/CRT/CRTReco/CRTClusterCharacterisationAlg.cc @@ -198,14 +198,8 @@ namespace sbnd::crt { void CRTClusterCharacterisationAlg::CorrectTime(const art::Ptr &hit0, const art::Ptr &hit1, const geo::Point_t &pos, double &t0, double &et0, double &t1, double &et1) { - const double dist0 = fCRTGeoService->DistanceDownStrip(pos, hit0->Channel()); - const double dist1 = fCRTGeoService->DistanceDownStrip(pos, hit1->Channel()); - - const double pe0 = ReconstructPE(hit0, dist0); - const double pe1 = ReconstructPE(hit1, dist1); - - const double corr0 = TimingCorrectionOffset(dist0, pe0); - const double corr1 = TimingCorrectionOffset(dist1, pe1); + const double corr0 = TimingCorrectionOffset(hit0, pos); + const double corr1 = TimingCorrectionOffset(hit1, pos); t0 = (hit0->Ts0() - corr0 + hit1->Ts0() - corr1) / 2.; et0 = std::abs((hit0->Ts0() - corr0) - (hit1->Ts0() - corr1)) / 2.; @@ -214,14 +208,27 @@ namespace sbnd::crt { et1 = std::abs((hit0->Ts1() - corr0) - (hit1->Ts1() - corr1)) / 2.; } - double CRTClusterCharacterisationAlg::TimingCorrectionOffset(const double &dist, const double &pe) + double CRTClusterCharacterisationAlg::TimingCorrectionOffset(const art::Ptr &hit, const geo::Point_t &pos) { - - double t_TimeWalk = fTimeWalkNorm * std::exp(- fTimeWalkScale * pe); - double t_PropDelay = fPropDelay * dist; + double t_TimeWalk = TimeWalk(hit, pos); + double t_PropDelay = PropagationDelay(hit, pos); return t_PropDelay + t_TimeWalk; } + double CRTClusterCharacterisationAlg::TimeWalk(const art::Ptr &hit, const geo::Point_t &pos) + { + const double dist = fCRTGeoService->DistanceDownStrip(pos, hit->Channel()); + const double pe = ReconstructPE(hit, dist); + + return fTimeWalkNorm * std::exp(-fTimeWalkScale * pe); + } + + double CRTClusterCharacterisationAlg::PropagationDelay(const art::Ptr &hit, const geo::Point_t &pos) + { + const double dist = fCRTGeoService->DistanceDownStrip(pos, hit->Channel()); + return fPropDelay * dist; + } + void CRTClusterCharacterisationAlg::AggregatePositions(const std::vector &complete_spacepoints, geo::Point_t &pos, geo::Point_t &err) { double sum_x = 0., sum_y = 0., sum_z = 0.; diff --git a/sbndcode/CRT/CRTReco/CRTClusterCharacterisationAlg.h b/sbndcode/CRT/CRTReco/CRTClusterCharacterisationAlg.h index a622ef28d..373d47ed7 100644 --- a/sbndcode/CRT/CRTReco/CRTClusterCharacterisationAlg.h +++ b/sbndcode/CRT/CRTReco/CRTClusterCharacterisationAlg.h @@ -65,7 +65,11 @@ namespace sbnd::crt { void CorrectTime(const art::Ptr &hit0, const art::Ptr &hit1, const geo::Point_t &pos, double &t0, double &et0, double &t1, double &et1); - double TimingCorrectionOffset(const double &dist, const double &pe); + double TimingCorrectionOffset(const art::Ptr &hit, const geo::Point_t &pos); + + double TimeWalk(const art::Ptr &hit, const geo::Point_t &pos); + + double PropagationDelay(const art::Ptr &hit, const geo::Point_t &pos); void AggregatePositions(const std::vector &complete_spacepoints, geo::Point_t &pos, geo::Point_t &err); From 1459913bec4e7d241082900cad1ffa980ed0ca90 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Tue, 24 Feb 2026 11:10:31 -0600 Subject: [PATCH 133/155] Update channel map service to add timing chains --- .../ChannelMaps/CRT/CRTChannelMapService.h | 12 ++++ .../CRT/CRTChannelMapService_service.cc | 64 ++++++++++++++++--- .../CRT/SBNDCRTTimingChainMap_v1.txt | 20 ++++++ .../CRT/crt_channel_map_service_sbnd.fcl | 3 +- 4 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 sbndcode/ChannelMaps/CRT/SBNDCRTTimingChainMap_v1.txt diff --git a/sbndcode/ChannelMaps/CRT/CRTChannelMapService.h b/sbndcode/ChannelMaps/CRT/CRTChannelMapService.h index fc22880d1..6fce72894 100644 --- a/sbndcode/ChannelMaps/CRT/CRTChannelMapService.h +++ b/sbndcode/ChannelMaps/CRT/CRTChannelMapService.h @@ -59,6 +59,12 @@ class SBND::CRTChannelMapService { unsigned int GetMAC5FromOfflineChannelID(const unsigned int offline_channel_id); + unsigned int GetTimingChainFromOfflineModuleID(unsigned int offline_module_id); + + unsigned int GetTimingChainFromOfflineChannelID(unsigned int offline_channel_id); + + unsigned int GetTimingChainFromMAC5(unsigned int mac5); + private: typedef struct ModuleInfo { @@ -75,6 +81,12 @@ class SBND::CRTChannelMapService { // look up channel info by MAC5 std::unordered_map fModuleInfoFromMAC5; ModuleInfo_t GetModuleInfoFromMAC5(unsigned int mac5) const; + + // look up timing chain by offline module number + std::unordered_map fTimingChainFromOfflineID; + + // look up channel info by MAC5 + std::unordered_map fTimingChainFromMAC5; }; DECLARE_ART_SERVICE(SBND::CRTChannelMapService, LEGACY) diff --git a/sbndcode/ChannelMaps/CRT/CRTChannelMapService_service.cc b/sbndcode/ChannelMaps/CRT/CRTChannelMapService_service.cc index 3e3d45cfa..63f27ad88 100644 --- a/sbndcode/ChannelMaps/CRT/CRTChannelMapService_service.cc +++ b/sbndcode/ChannelMaps/CRT/CRTChannelMapService_service.cc @@ -17,28 +17,30 @@ SBND::CRTChannelMapService::CRTChannelMapService(fhicl::ParameterSet const& pset) { - const std::string channelMapFile = pset.get("FileName"); + const std::string channelMapFile = pset.get("ChannelMapFileName"); + const std::string timingChainMapFile = pset.get("TimingChainMapFileName"); - std::string fullname; + std::string channelMapFileFullName, timingChainMapFileFullName; cet::search_path sp("FW_SEARCH_PATH"); - sp.find_file(channelMapFile, fullname); + sp.find_file(channelMapFile, channelMapFileFullName); + sp.find_file(timingChainMapFile, timingChainMapFileFullName); - if(fullname.empty()) + if(channelMapFileFullName.empty()) { std::cout << "SBND::CRTChannelMapService Input file " << channelMapFile << " not found" << std::endl; throw cet::exception("File not found"); } std::cout << "SBND CRT Channel Map: Building map from file " << channelMapFile << std::endl; - std::ifstream inFile(fullname, std::ios::in); + std::ifstream channelMapInFile(channelMapFileFullName, std::ios::in); std::string line; - while(std::getline(inFile,line)) + while(std::getline(channelMapInFile, line)) { std::stringstream linestream(line); SBND::CRTChannelMapService::ModuleInfo_t m; - linestream + linestream >> m.offline_module_id >> m.mac5 >> m.channel_order_swapped; @@ -49,7 +51,38 @@ SBND::CRTChannelMapService::CRTChannelMapService(fhicl::ParameterSet const& pset fModuleInfoFromMAC5[m.mac5] = m; } - inFile.close(); + channelMapInFile.close(); + + if(timingChainMapFileFullName.empty()) + { + std::cout << "SBND::CRTChannelMapService Input file " << timingChainMapFile << " not found" << std::endl; + throw cet::exception("File not found"); + } + + std::cout << "SBND CRT Channel Map: Building timing chain map from file " << timingChainMapFile << std::endl; + std::ifstream timingChainMapInFile(timingChainMapFileFullName, std::ios::in); + + while(std::getline(timingChainMapInFile, line)) + { + std::stringstream linestream(line); + + unsigned int timing_chain = std::numeric_limits::max(); + unsigned int n = 0; + + linestream + >> timing_chain + >> n; + + for(unsigned int i = 0; i < n; ++i) + { + unsigned int offline_module_id = std::numeric_limits::max(); + linestream >> offline_module_id; + fTimingChainFromOfflineID[offline_module_id] = timing_chain; + fTimingChainFromMAC5[GetMAC5FromOfflineModuleID(offline_module_id)] = timing_chain; + } + } + + timingChainMapInFile.close(); } SBND::CRTChannelMapService::ModuleInfo_t SBND::CRTChannelMapService::GetModuleInfoFromMAC5(unsigned int mac5) const @@ -202,4 +235,19 @@ unsigned int SBND::CRTChannelMapService::GetMAC5FromOfflineChannelID(const unsig return GetMAC5FromOfflineModuleID(GetOfflineModuleIDFromOfflineChannelID(offline_channel_id)); } +unsigned int SBND::CRTChannelMapService::GetTimingChainFromOfflineModuleID(unsigned int offline_module_id) +{ + return fTimingChainFromOfflineID[offline_module_id]; +} + +unsigned int SBND::CRTChannelMapService::GetTimingChainFromOfflineChannelID(unsigned int offline_channel_id) +{ + return GetTimingChainFromOfflineModuleID(GetOfflineModuleIDFromOfflineChannelID(offline_channel_id)); +} + +unsigned int SBND::CRTChannelMapService::GetTimingChainFromMAC5(unsigned int mac5) +{ + return fTimingChainFromMAC5[mac5]; +} + DEFINE_ART_SERVICE(SBND::CRTChannelMapService) diff --git a/sbndcode/ChannelMaps/CRT/SBNDCRTTimingChainMap_v1.txt b/sbndcode/ChannelMaps/CRT/SBNDCRTTimingChainMap_v1.txt new file mode 100644 index 000000000..e37aa53cb --- /dev/null +++ b/sbndcode/ChannelMaps/CRT/SBNDCRTTimingChainMap_v1.txt @@ -0,0 +1,20 @@ +0 8 127 126 125 124 123 122 120 121 +1 6 139 128 137 138 136 135 +2 6 134 133 132 131 130 129 +3 8 63 62 54 55 56 57 58 59 +4 8 64 65 50 51 52 53 61 60 +5 6 81 80 82 79 83 78 +6 6 66 67 68 69 77 76 +7 6 70 71 72 73 74 75 +8 9 115 106 107 108 109 110 111 112 113 +9 9 116 117 118 119 102 103 104 105 114 +10 9 101 84 85 86 87 96 95 94 93 +11 9 100 99 98 97 88 89 90 91 92 +12 6 33 32 31 30 40 41 +13 6 42 43 44 25 26 27 +14 7 37 38 39 29 28 49 48 +15 6 36 35 34 45 46 47 +16 6 21 22 23 24 9 8 +17 6 7 6 5 19 18 17 +18 7 12 11 10 15 16 0 1 +19 6 13 14 20 4 3 2 diff --git a/sbndcode/ChannelMaps/CRT/crt_channel_map_service_sbnd.fcl b/sbndcode/ChannelMaps/CRT/crt_channel_map_service_sbnd.fcl index a34f136cd..35945a2b4 100644 --- a/sbndcode/ChannelMaps/CRT/crt_channel_map_service_sbnd.fcl +++ b/sbndcode/ChannelMaps/CRT/crt_channel_map_service_sbnd.fcl @@ -2,7 +2,8 @@ BEGIN_PROLOG crt_channel_map_sbnd: { - FileName: "SBNDCRTChannelMap_Commissioning_v5.txt" + ChannelMapFileName: "SBNDCRTChannelMap_Commissioning_v5.txt" + TimingChainMapFileName: "SBNDCRTTimingChainMap_v1.txt" } END_PROLOG From 75870c2a5fb1d21a5e805874bb8382eb55d9f49e Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Tue, 24 Feb 2026 11:12:19 -0600 Subject: [PATCH 134/155] Fill space point branches in timing analysis --- sbndcode/CRT/CRTAna/CMakeLists.txt | 2 + .../CRT/CRTAna/CRTTimingAnalysis_module.cc | 154 +++++++++++++++++- 2 files changed, 153 insertions(+), 3 deletions(-) diff --git a/sbndcode/CRT/CRTAna/CMakeLists.txt b/sbndcode/CRT/CRTAna/CMakeLists.txt index 05de4d016..ad4284386 100644 --- a/sbndcode/CRT/CRTAna/CMakeLists.txt +++ b/sbndcode/CRT/CRTAna/CMakeLists.txt @@ -10,6 +10,8 @@ art_make( sbnobj::SBND_Timing sbnobj::Common_Reco sbndcode_CRT_CRTBackTracker + sbndcode_CRT_CRTReco + sbndcode_ChannelMaps_CRT_CRTChannelMapService_service ) install_fhicl() diff --git a/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc b/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc index 3fa9d0fd6..8b23a9699 100644 --- a/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc +++ b/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc @@ -35,6 +35,8 @@ #include "sbndcode/Geometry/GeometryWrappers/CRTGeoService.h" #include "sbndcode/Decoders/PTB/sbndptb.h" #include "sbndcode/Timing/SBNDRawTimingObj.h" +#include "sbndcode/Calibration/CRTDatabaseInterface/CRTCalibrationDatabase.h" +#include "sbndcode/CRT/CRTReco/CRTClusterCharacterisationAlg.h" namespace sbnd::crt { class CRTTimingAnalysis; @@ -65,6 +67,15 @@ class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { const art::FindOneP &spacepointsToClusters, const art::FindManyP &clustersToStripHits); + void ResetSPVariables(); + + void ResizeSPSHVecs(const unsigned n); + + double IntrinsicResolution(const std::vector &_sp_sh_channel_set, + const std::vector &_sp_sh_ts_set, + const std::vector &_sp_sh_time_walk_set, + const std::vector &_sp_sh_prop_delay_set); + void AnalyseCRTTracks(const std::vector> &CRTTrackVec, const art::FindManyP &tracksToSpacePoints, const art::FindOneP &spacepointsToClusters, @@ -80,7 +91,10 @@ class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { private: - art::ServiceHandle fCRTGeoService; + art::ServiceHandle fCRTGeoService; + art::ServiceHandle fCRTChannelMapService; + sbndDB::CRTCalibrationDatabase const *fCRTCalibrationDatabaseService; + CRTClusterCharacterisationAlg fCRTClusterCharacAlg; // fcl Controlled Variables std::string fCRTClusterModuleLabel, fCRTSpacePointModuleLabel, fCRTTrackModuleLabel, @@ -143,8 +157,9 @@ class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { std::vector _sp_sh_ts1_set; std::vector _sp_sh_time_walk_set; std::vector _sp_sh_prop_delay_set; - std::vector _sp_sh_cable_length_set; + std::vector _sp_sh_cable_length_ts0_set; std::vector _sp_sh_calib_offset_ts0_set; + std::vector _sp_sh_cable_length_ts1_set; std::vector _sp_sh_calib_offset_ts1_set; double _tr_start_x; @@ -204,6 +219,7 @@ class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { sbnd::crt::CRTTimingAnalysis::CRTTimingAnalysis(fhicl::ParameterSet const& p) : EDAnalyzer{p} + , fCRTClusterCharacAlg(p.get("CRTClusterCharacterisationAlg", fhicl::ParameterSet())) { fCRTClusterModuleLabel = p.get("CRTClusterModuleLabel"); fCRTSpacePointModuleLabel = p.get("CRTSpacePointModuleLabel"); @@ -259,8 +275,9 @@ sbnd::crt::CRTTimingAnalysis::CRTTimingAnalysis(fhicl::ParameterSet const& p) fSPTree->Branch("sp_sh_ts1_set", "std::vector", &_sp_sh_ts1_set); fSPTree->Branch("sp_sh_time_walk_set", "std::vector", &_sp_sh_time_walk_set); fSPTree->Branch("sp_sh_prop_delay_set", "std::vector", &_sp_sh_prop_delay_set); - fSPTree->Branch("sp_sh_cable_length_set", "std::vector", &_sp_sh_cable_length_set); + fSPTree->Branch("sp_sh_cable_length_ts0_set", "std::vector", &_sp_sh_cable_length_ts0_set); fSPTree->Branch("sp_sh_calib_offset_ts0_set", "std::vector", &_sp_sh_calib_offset_ts0_set); + fSPTree->Branch("sp_sh_cable_length_ts1_set", "std::vector", &_sp_sh_cable_length_ts1_set); fSPTree->Branch("sp_sh_calib_offset_ts1_set", "std::vector", &_sp_sh_calib_offset_ts1_set); fTrTree = fs->make("tracks",""); @@ -644,6 +661,137 @@ void sbnd::crt::CRTTimingAnalysis::AnalyseCRTSpacePoints(const std::vector &spacepointsToClusters, const art::FindManyP &clustersToStripHits) { + for(auto const& sp : CRTSpacePointVec) + { + ResetSPVariables(); + + const art::Ptr cl = spacepointsToClusters.at(sp.key()); + + const std::vector> shs = clustersToStripHits.at(cl.key()); + const unsigned n_shs = shs.size(); + ResizeSPSHVecs(n_shs); + + _sp_nhits = cl->NHits(); + _sp_tagger = cl->Tagger(); + _sp_x = sp->X(); + _sp_y = sp->Y(); + _sp_z = sp->Z(); + _sp_pe = sp->PE(); + _sp_ts0 = sp->Ts0(); + _sp_ts0_rwm_ref = _sp_ts0 + _rwm_etrig_diff; + _sp_ts0_ptb_hlt_beam_gate_ref = _sp_ts0 + _ptb_hlt_beam_gate_etrig_diff; + _sp_ts1 = sp->Ts1(); + _sp_ts1_rwm_ref = _sp_ts1 + _rwm_crt_t1_reset_diff; + _sp_ts1_ptb_hlt_beam_gate_ref = _sp_ts1 + _ptb_hlt_beam_gate_crt_t1_reset_diff; + + for(unsigned i = 0; i < n_shs; ++i) + { + const art::Ptr sh = shs[i]; + + _sp_sh_channel_set[i] = sh->Channel(); + _sp_sh_mac5_set[i] = fCRTChannelMapService->GetMAC5FromOfflineChannelID(_sp_sh_channel_set[i]); + _sp_sh_timing_chain_set[i] = fCRTChannelMapService->GetTimingChainFromOfflineChannelID(_sp_sh_channel_set[i]); + _sp_sh_ts0_set[i] = sh->Ts0(); + _sp_sh_ts1_set[i] = sh->Ts1(); + _sp_sh_time_walk_set[i] = fCRTClusterCharacAlg.TimeWalk(sh, {_sp_x, _sp_y, _sp_z}); + _sp_sh_prop_delay_set[i] = fCRTClusterCharacAlg.PropagationDelay(sh, {_sp_x, _sp_y, _sp_z}); + _sp_sh_cable_length_ts0_set[i] = fCRTCalibrationDatabaseService->getT0CableLengthOffset(_sp_sh_mac5_set[i]); + _sp_sh_calib_offset_ts0_set[i] = fCRTCalibrationDatabaseService->getT0CalibratedOffset(_sp_sh_mac5_set[i]); + _sp_sh_cable_length_ts1_set[i] = fCRTCalibrationDatabaseService->getT1CableLengthOffset(_sp_sh_mac5_set[i]); + _sp_sh_calib_offset_ts1_set[i] = fCRTCalibrationDatabaseService->getT1CalibratedOffset(_sp_sh_mac5_set[i]); + } + + _sp_dts0 = IntrinsicResolution(_sp_sh_channel_set, _sp_sh_ts0_set, _sp_sh_time_walk_set, _sp_sh_prop_delay_set); + _sp_dts1 = IntrinsicResolution(_sp_sh_channel_set, _sp_sh_ts1_set, _sp_sh_time_walk_set, _sp_sh_prop_delay_set); + + std::set timing_chain_set(_sp_sh_timing_chain_set.begin(), _sp_sh_timing_chain_set.end()); + _sp_single_timing_chain = timing_chain_set.size() == 1; + _sp_timing_chain = _sp_single_timing_chain ? *timing_chain_set.begin() : -1; + + fSPTree->Fill(); + } +} + +void sbnd::crt::CRTTimingAnalysis::ResetSPVariables() +{ + _sp_nhits = std::numeric_limits::max(); + + _sp_tagger = CRTTagger::kUndefinedTagger; + + _sp_x = std::numeric_limits::lowest(); + _sp_y = std::numeric_limits::lowest(); + _sp_z = std::numeric_limits::lowest(); + _sp_pe = std::numeric_limits::lowest(); + _sp_ts0 = std::numeric_limits::lowest(); + _sp_ts0_rwm_ref = std::numeric_limits::lowest(); + _sp_ts0_ptb_hlt_beam_gate_ref = std::numeric_limits::lowest(); + _sp_dts0 = std::numeric_limits::lowest(); + _sp_ts1 = std::numeric_limits::lowest(); + _sp_ts1_rwm_ref = std::numeric_limits::lowest(); + _sp_ts1_ptb_hlt_beam_gate_ref = std::numeric_limits::lowest(); + _sp_dts1 = std::numeric_limits::lowest(); + + _sp_single_timing_chain = false; + + _sp_timing_chain = std::numeric_limits::lowest(); + + _sp_sh_channel_set.clear(); + _sp_sh_mac5_set.clear(); + _sp_sh_timing_chain_set.clear(); + _sp_sh_ts0_set.clear(); + _sp_sh_ts1_set.clear(); + _sp_sh_time_walk_set.clear(); + _sp_sh_prop_delay_set.clear(); + _sp_sh_cable_length_ts0_set.clear(); + _sp_sh_calib_offset_ts0_set.clear(); + _sp_sh_cable_length_ts1_set.clear(); + _sp_sh_calib_offset_ts1_set.clear(); +} + +void sbnd::crt::CRTTimingAnalysis::ResizeSPSHVecs(const unsigned n) +{ + _sp_sh_channel_set.resize(n); + _sp_sh_mac5_set.resize(n); + _sp_sh_timing_chain_set.resize(n); + _sp_sh_ts0_set.resize(n); + _sp_sh_ts1_set.resize(n); + _sp_sh_time_walk_set.resize(n); + _sp_sh_prop_delay_set.resize(n); + _sp_sh_cable_length_ts0_set.resize(n); + _sp_sh_calib_offset_ts0_set.resize(n); + _sp_sh_cable_length_ts1_set.resize(n); + _sp_sh_calib_offset_ts1_set.resize(n); +} + +double sbnd::crt::CRTTimingAnalysis::IntrinsicResolution(const std::vector &_sp_sh_channel_set, + const std::vector &_sp_sh_ts_set, + const std::vector &_sp_sh_time_walk_set, + const std::vector &_sp_sh_prop_delay_set) +{ + struct SH { + int32_t channel; + double ts; + }; + + std::vector shs; + + for(unsigned i = 0; i < _sp_sh_channel_set.size(); ++i) + shs.push_back(SH({_sp_sh_channel_set[i], _sp_sh_ts_set[i] - _sp_sh_time_walk_set[i] - _sp_sh_prop_delay_set[i]})); + + std::sort(shs.begin(), shs.end(), [](auto &a, auto &b) + { return a.channel < b.channel; }); + + double sum = 0.; + + for(unsigned int i = 0; i < shs.size(); ++i) + { + for(unsigned int ii = i + 1; ii < shs.size(); ++ii) + sum += (shs[i].ts - shs[ii].ts); + } + + sum /= (shs.size() - 1); + + return sum; } void sbnd::crt::CRTTimingAnalysis::AnalyseCRTTracks(const std::vector> &CRTTrackVec, From 0f58321cb1ad6da6fc22f3de1c1ab63569c8b78c Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Wed, 25 Feb 2026 05:58:47 -0600 Subject: [PATCH 135/155] Add track content to CRTTimingAnalysis module, plus a few bugfixes to make run-able --- .../CRT/CRTAna/CRTTimingAnalysis_module.cc | 400 ++++++++++++------ 1 file changed, 273 insertions(+), 127 deletions(-) diff --git a/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc b/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc index 8b23a9699..482eb5d2d 100644 --- a/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc +++ b/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc @@ -40,6 +40,8 @@ namespace sbnd::crt { class CRTTimingAnalysis; + + constexpr double c = 3.3356e-2; // ns / cm } class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { @@ -57,6 +59,8 @@ class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { // Required functions. void analyze(art::Event const& e) override; + void ResetMaps(); + void AnalysePTBs(std::vector> &PTBVec); void AnalyseTDCs(std::vector> &TDCVec); @@ -77,10 +81,10 @@ class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { const std::vector &_sp_sh_prop_delay_set); void AnalyseCRTTracks(const std::vector> &CRTTrackVec, - const art::FindManyP &tracksToSpacePoints, - const art::FindOneP &spacepointsToClusters, - const art::FindManyP &clustersToStripHits); - + const art::FindManyP &tracksToSpacePoints); + + void ResetTrVariables(); + void AnalyseTPCSlices(const std::vector> &TPCSliceVec, const art::FindManyP &sliceToCorrectedOpFlashes, const art::FindManyP &sliceToPFPs, @@ -192,10 +196,12 @@ class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { int16_t _tr_tagger3; int16_t _tr_start_tagger; double _tr_start_dts0; + double _tr_start_dts1; bool _tr_start_single_timing_chain; int16_t _tr_start_timing_chain; int16_t _tr_end_tagger; double _tr_end_dts0; + double _tr_end_dts1; bool _tr_end_single_timing_chain; int16_t _tr_end_timing_chain; @@ -215,6 +221,12 @@ class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { double _tpc_crt_sp_ts1_rwm_ref; double _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref; double _tpc_crt_sp_dts1; + + // Maps + std::map fSPTaggerMap; + std::map fSPdTs0Map; + std::map fSPdTs1Map; + std::map fSPTimingChainMap; }; sbnd::crt::CRTTimingAnalysis::CRTTimingAnalysis(fhicl::ParameterSet const& p) @@ -233,41 +245,43 @@ sbnd::crt::CRTTimingAnalysis::CRTTimingAnalysis(fhicl::ParameterSet const& p) fCRTSpacePointMatchingModuleLabel = p.get("CRTSpacePointMatchingModuleLabel"); fAllowedPTBHLTs = p.get>("AllowedPTBHLTs"); + fCRTCalibrationDatabaseService = lar::providerFrom(); + art::ServiceHandle fs; fSPTree = fs->make("spacepoints",""); - fSPTree->Branch("run", "int", &_run); - fSPTree->Branch("subrun", "int", &_subrun); - fSPTree->Branch("event", "int", &_event); - fSPTree->Branch("crt_timing_reference_type", "int", &_crt_timing_reference_type); - fSPTree->Branch("crt_timing_reference_channel", "int", &_crt_timing_reference_channel); - - fSPTree->Branch("etrig_good", "bool", &_etrig_good); - fSPTree->Branch("rwm_good", "bool", &_rwm_good); - fSPTree->Branch("ptb_hlt_beam_gate_good", "bool", &_ptb_hlt_beam_gate_good); - fSPTree->Branch("crt_t1_reset_good", "bool", &_crt_t1_reset_good); - fSPTree->Branch("rwm_etrig_diff", "double", &_rwm_etrig_diff); - fSPTree->Branch("ptb_hlt_beam_gate_etrig_diff", "double", &_ptb_hlt_beam_gate_etrig_diff); - fSPTree->Branch("rwm_crt_t1_reset_diff", "double", &_rwm_crt_t1_reset_diff); - fSPTree->Branch("ptb_hlt_beam_gate_crt_t1_reset_diff", "double", &_ptb_hlt_beam_gate_crt_t1_reset_diff); - fSPTree->Branch("rwm_ptb_hlt_beam_gate_diff", "double", &_rwm_ptb_hlt_beam_gate_diff); - - fSPTree->Branch("sp_nhits", "uint16_t", &_sp_nhits); - fSPTree->Branch("sp_tagger", "int16_t", &_sp_tagger); - fSPTree->Branch("sp_x", "double", &_sp_x); - fSPTree->Branch("sp_y", "double", &_sp_y); - fSPTree->Branch("sp_z", "double", &_sp_z); - fSPTree->Branch("sp_pe", "double", &_sp_pe); - fSPTree->Branch("sp_ts0", "double", &_sp_ts0); - fSPTree->Branch("sp_ts0_rwm_ref", "double", &_sp_ts0_rwm_ref); - fSPTree->Branch("sp_ts0_ptb_hlt_beam_gate_ref", "double", &_sp_ts0_ptb_hlt_beam_gate_ref); - fSPTree->Branch("sp_dts0", "double", &_sp_dts0); - fSPTree->Branch("sp_ts1", "double", &_sp_ts1); - fSPTree->Branch("sp_ts1_rwm_ref", "double", &_sp_ts1_rwm_ref); - fSPTree->Branch("sp_ts1_ptb_hlt_beam_gate_ref", "double", &_sp_ts1_ptb_hlt_beam_gate_ref); - fSPTree->Branch("sp_dts1", "double", &_sp_dts1); - fSPTree->Branch("sp_single_timing_chain", "bool", &_sp_single_timing_chain); - fSPTree->Branch("sp_timing_chain", "int16_t", &_sp_timing_chain); + fSPTree->Branch("run", &_run); + fSPTree->Branch("subrun", &_subrun); + fSPTree->Branch("event", &_event); + fSPTree->Branch("crt_timing_reference_type", &_crt_timing_reference_type); + fSPTree->Branch("crt_timing_reference_channel", &_crt_timing_reference_channel); + + fSPTree->Branch("etrig_good", &_etrig_good); + fSPTree->Branch("rwm_good", &_rwm_good); + fSPTree->Branch("ptb_hlt_beam_gate_good", &_ptb_hlt_beam_gate_good); + fSPTree->Branch("crt_t1_reset_good", &_crt_t1_reset_good); + fSPTree->Branch("rwm_etrig_diff", &_rwm_etrig_diff); + fSPTree->Branch("ptb_hlt_beam_gate_etrig_diff", &_ptb_hlt_beam_gate_etrig_diff); + fSPTree->Branch("rwm_crt_t1_reset_diff", &_rwm_crt_t1_reset_diff); + fSPTree->Branch("ptb_hlt_beam_gate_crt_t1_reset_diff", &_ptb_hlt_beam_gate_crt_t1_reset_diff); + fSPTree->Branch("rwm_ptb_hlt_beam_gate_diff", &_rwm_ptb_hlt_beam_gate_diff); + + fSPTree->Branch("sp_nhits", &_sp_nhits); + fSPTree->Branch("sp_tagger", &_sp_tagger); + fSPTree->Branch("sp_x", &_sp_x); + fSPTree->Branch("sp_y", &_sp_y); + fSPTree->Branch("sp_z", &_sp_z); + fSPTree->Branch("sp_pe", &_sp_pe); + fSPTree->Branch("sp_ts0", &_sp_ts0); + fSPTree->Branch("sp_ts0_rwm_ref", &_sp_ts0_rwm_ref); + fSPTree->Branch("sp_ts0_ptb_hlt_beam_gate_ref", &_sp_ts0_ptb_hlt_beam_gate_ref); + fSPTree->Branch("sp_dts0", &_sp_dts0); + fSPTree->Branch("sp_ts1", &_sp_ts1); + fSPTree->Branch("sp_ts1_rwm_ref", &_sp_ts1_rwm_ref); + fSPTree->Branch("sp_ts1_ptb_hlt_beam_gate_ref", &_sp_ts1_ptb_hlt_beam_gate_ref); + fSPTree->Branch("sp_dts1", &_sp_dts1); + fSPTree->Branch("sp_single_timing_chain", &_sp_single_timing_chain); + fSPTree->Branch("sp_timing_chain", &_sp_timing_chain); fSPTree->Branch("sp_sh_channel_set", "std::vector", &_sp_sh_channel_set); fSPTree->Branch("sp_sh_mac5_set", "std::vector", &_sp_sh_mac5_set); fSPTree->Branch("sp_sh_timing_chain_set", "std::vector", &_sp_sh_timing_chain_set); @@ -281,96 +295,100 @@ sbnd::crt::CRTTimingAnalysis::CRTTimingAnalysis(fhicl::ParameterSet const& p) fSPTree->Branch("sp_sh_calib_offset_ts1_set", "std::vector", &_sp_sh_calib_offset_ts1_set); fTrTree = fs->make("tracks",""); - fTrTree->Branch("run", "int", &_run); - fTrTree->Branch("subrun", "int", &_subrun); - fTrTree->Branch("event", "int", &_event); - fTrTree->Branch("crt_timing_reference_type", "int", &_crt_timing_reference_type); - fTrTree->Branch("crt_timing_reference_channel", "int", &_crt_timing_reference_channel); - - fTrTree->Branch("etrig_good", "bool", &_etrig_good); - fTrTree->Branch("rwm_good", "bool", &_rwm_good); - fTrTree->Branch("ptb_hlt_beam_gate_good", "bool", &_ptb_hlt_beam_gate_good); - fTrTree->Branch("crt_t1_reset_good", "bool", &_crt_t1_reset_good); - fTrTree->Branch("rwm_etrig_diff", "double", &_rwm_etrig_diff); - fTrTree->Branch("ptb_hlt_beam_gate_etrig_diff", "double", &_ptb_hlt_beam_gate_etrig_diff); - fTrTree->Branch("rwm_crt_t1_reset_diff", "double", &_rwm_crt_t1_reset_diff); - fTrTree->Branch("ptb_hlt_beam_gate_crt_t1_reset_diff", "double", &_ptb_hlt_beam_gate_crt_t1_reset_diff); - fTrTree->Branch("rwm_ptb_hlt_beam_gate_diff", "double", &_rwm_ptb_hlt_beam_gate_diff); - - fTrTree->Branch("tr_start_x", "double", &_tr_start_x); - fTrTree->Branch("tr_start_y", "double", &_tr_start_y); - fTrTree->Branch("tr_start_z", "double", &_tr_start_z); - fTrTree->Branch("tr_end_x", "double", &_tr_end_x); - fTrTree->Branch("tr_end_y", "double", &_tr_end_y); - fTrTree->Branch("tr_end_z", "double", &_tr_end_z); - fTrTree->Branch("tr_dir_x", "double", &_tr_dir_x); - fTrTree->Branch("tr_dir_y", "double", &_tr_dir_y); - fTrTree->Branch("tr_dir_z", "double", &_tr_dir_z); - fTrTree->Branch("tr_ts0", "double", &_tr_ts0); - fTrTree->Branch("tr_ts0_rwm_ref", "double", &_tr_ts0_rwm_ref); - fTrTree->Branch("tr_ts0_ptb_hlt_beam_gate_ref", "double", &_tr_ts0_ptb_hlt_beam_gate_ref); - fTrTree->Branch("tr_ts1", "double", &_tr_ts1); - fTrTree->Branch("tr_ts1_rwm_ref", "double", &_tr_ts1_rwm_ref); - fTrTree->Branch("tr_ts1_ptb_hlt_beam_gate_ref", "double", &_tr_ts1_ptb_hlt_beam_gate_ref); - fTrTree->Branch("tr_pe", "double", &_tr_pe); - fTrTree->Branch("tr_length", "double", &_tr_length); - fTrTree->Branch("tr_length_tof", "double", &_tr_length_tof); - fTrTree->Branch("tr_tof_ts0", "double", &_tr_tof_ts0); - fTrTree->Branch("tr_tof_diff_ts0", "double", &_tr_tof_diff_ts0); - fTrTree->Branch("tr_tof_ts1", "double", &_tr_tof_ts1); - fTrTree->Branch("tr_tof_diff_ts1", "double", &_tr_tof_diff_ts1); - fTrTree->Branch("tr_theta", "double", &_tr_theta); - fTrTree->Branch("tr_phi", "double", &_tr_phi); - fTrTree->Branch("tr_triple", "bool", &_tr_triple); - fTrTree->Branch("tr_tagger1", "int16_t", &_tr_tagger1); - fTrTree->Branch("tr_tagger2", "int16_t", &_tr_tagger2); - fTrTree->Branch("tr_tagger3", "int16_t", &_tr_tagger3); - fTrTree->Branch("tr_start_tagger", "int16_t", &_tr_start_tagger); - fTrTree->Branch("tr_start_dts0", "double", &_tr_start_dts0); - fTrTree->Branch("tr_start_single_timing_chain", "bool", &_tr_start_single_timing_chain); - fTrTree->Branch("tr_start_timing_chain", "int16_t", &_tr_start_timing_chain); - fTrTree->Branch("tr_end_tagger", "int16_t", &_tr_end_tagger); - fTrTree->Branch("tr_end_dts0", "double", &_tr_end_dts0); - fTrTree->Branch("tr_end_single_timing_chain", "bool", &_tr_end_single_timing_chain); - fTrTree->Branch("tr_end_timing_chain", "int16_t", &_tr_end_timing_chain); + fTrTree->Branch("run", &_run); + fTrTree->Branch("subrun", &_subrun); + fTrTree->Branch("event", &_event); + fTrTree->Branch("crt_timing_reference_type", &_crt_timing_reference_type); + fTrTree->Branch("crt_timing_reference_channel", &_crt_timing_reference_channel); + + fTrTree->Branch("etrig_good", &_etrig_good); + fTrTree->Branch("rwm_good", &_rwm_good); + fTrTree->Branch("ptb_hlt_beam_gate_good", &_ptb_hlt_beam_gate_good); + fTrTree->Branch("crt_t1_reset_good", &_crt_t1_reset_good); + fTrTree->Branch("rwm_etrig_diff", &_rwm_etrig_diff); + fTrTree->Branch("ptb_hlt_beam_gate_etrig_diff", &_ptb_hlt_beam_gate_etrig_diff); + fTrTree->Branch("rwm_crt_t1_reset_diff", &_rwm_crt_t1_reset_diff); + fTrTree->Branch("ptb_hlt_beam_gate_crt_t1_reset_diff", &_ptb_hlt_beam_gate_crt_t1_reset_diff); + fTrTree->Branch("rwm_ptb_hlt_beam_gate_diff", &_rwm_ptb_hlt_beam_gate_diff); + + fTrTree->Branch("tr_start_x", &_tr_start_x); + fTrTree->Branch("tr_start_y", &_tr_start_y); + fTrTree->Branch("tr_start_z", &_tr_start_z); + fTrTree->Branch("tr_end_x", &_tr_end_x); + fTrTree->Branch("tr_end_y", &_tr_end_y); + fTrTree->Branch("tr_end_z", &_tr_end_z); + fTrTree->Branch("tr_dir_x", &_tr_dir_x); + fTrTree->Branch("tr_dir_y", &_tr_dir_y); + fTrTree->Branch("tr_dir_z", &_tr_dir_z); + fTrTree->Branch("tr_ts0", &_tr_ts0); + fTrTree->Branch("tr_ts0_rwm_ref", &_tr_ts0_rwm_ref); + fTrTree->Branch("tr_ts0_ptb_hlt_beam_gate_ref", &_tr_ts0_ptb_hlt_beam_gate_ref); + fTrTree->Branch("tr_ts1", &_tr_ts1); + fTrTree->Branch("tr_ts1_rwm_ref", &_tr_ts1_rwm_ref); + fTrTree->Branch("tr_ts1_ptb_hlt_beam_gate_ref", &_tr_ts1_ptb_hlt_beam_gate_ref); + fTrTree->Branch("tr_pe", &_tr_pe); + fTrTree->Branch("tr_length", &_tr_length); + fTrTree->Branch("tr_length_tof", &_tr_length_tof); + fTrTree->Branch("tr_tof_ts0", &_tr_tof_ts0); + fTrTree->Branch("tr_tof_diff_ts0", &_tr_tof_diff_ts0); + fTrTree->Branch("tr_tof_ts1", &_tr_tof_ts1); + fTrTree->Branch("tr_tof_diff_ts1", &_tr_tof_diff_ts1); + fTrTree->Branch("tr_theta", &_tr_theta); + fTrTree->Branch("tr_phi", &_tr_phi); + fTrTree->Branch("tr_triple", &_tr_triple); + fTrTree->Branch("tr_tagger1", &_tr_tagger1); + fTrTree->Branch("tr_tagger2", &_tr_tagger2); + fTrTree->Branch("tr_tagger3", &_tr_tagger3); + fTrTree->Branch("tr_start_tagger", &_tr_start_tagger); + fTrTree->Branch("tr_start_dts0", &_tr_start_dts0); + fTrTree->Branch("tr_start_dts1", &_tr_start_dts1); + fTrTree->Branch("tr_start_single_timing_chain", &_tr_start_single_timing_chain); + fTrTree->Branch("tr_start_timing_chain", &_tr_start_timing_chain); + fTrTree->Branch("tr_end_tagger", &_tr_end_tagger); + fTrTree->Branch("tr_end_dts0", &_tr_end_dts0); + fTrTree->Branch("tr_end_dts1", &_tr_end_dts1); + fTrTree->Branch("tr_end_single_timing_chain", &_tr_end_single_timing_chain); + fTrTree->Branch("tr_end_timing_chain", &_tr_end_timing_chain); fTPCTree = fs->make("slices",""); - fTPCTree->Branch("run", "int", &_run); - fTPCTree->Branch("subrun", "int", &_subrun); - fTPCTree->Branch("event", "int", &_event); - fTPCTree->Branch("crt_timing_reference_type", "int", &_crt_timing_reference_type); - fTPCTree->Branch("crt_timing_reference_channel", "int", &_crt_timing_reference_channel); - - fTPCTree->Branch("etrig_good", "bool", &_etrig_good); - fTPCTree->Branch("rwm_good", "bool", &_rwm_good); - fTPCTree->Branch("ptb_hlt_beam_gate_good", "bool", &_ptb_hlt_beam_gate_good); - fTPCTree->Branch("crt_t1_reset_good", "bool", &_crt_t1_reset_good); - fTPCTree->Branch("rwm_etrig_diff", "double", &_rwm_etrig_diff); - fTPCTree->Branch("ptb_hlt_beam_gate_etrig_diff", "double", &_ptb_hlt_beam_gate_etrig_diff); - fTPCTree->Branch("rwm_crt_t1_reset_diff", "double", &_rwm_crt_t1_reset_diff); - fTPCTree->Branch("ptb_hlt_beam_gate_crt_t1_reset_diff", "double", &_ptb_hlt_beam_gate_crt_t1_reset_diff); - fTPCTree->Branch("rwm_ptb_hlt_beam_gate_diff", "double", &_rwm_ptb_hlt_beam_gate_diff); - - fTPCTree->Branch("tpc_has_corrected_opflash", "bool", &_tpc_has_corrected_opflash); - fTPCTree->Branch("tpc_has_crt_sp_match", "bool", &_tpc_has_crt_sp_match); - fTPCTree->Branch("tpc_opflash_t0", "double", &_tpc_opflash_t0); - fTPCTree->Branch("tpc_opflash_nutof_light", "double", &_tpc_opflash_nutof_light); - fTPCTree->Branch("tpc_opflash_nutof_charge", "double", &_tpc_opflash_nutof_charge); - fTPCTree->Branch("tpc_opflash_t0_corrected", "double", &_tpc_opflash_t0_corrected); - fTPCTree->Branch("tpc_opflash_t0_corrected_rwm", "double", &_tpc_opflash_t0_corrected_rwm); - fTPCTree->Branch("tpc_crt_sp_score", "double", &_tpc_crt_sp_score); - fTPCTree->Branch("tpc_crt_sp_ts0", "double", &_tpc_crt_sp_ts0); - fTPCTree->Branch("tpc_crt_sp_ts0_rwm_ref", "double", &_tpc_crt_sp_ts0_rwm_ref); - fTPCTree->Branch("tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref", "double", &_tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref); - fTPCTree->Branch("tpc_crt_sp_dts0", "double", &_tpc_crt_sp_dts0); - fTPCTree->Branch("tpc_crt_sp_ts1", "double", &_tpc_crt_sp_ts1); - fTPCTree->Branch("tpc_crt_sp_ts1_rwm_ref", "double", &_tpc_crt_sp_ts1_rwm_ref); - fTPCTree->Branch("tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref", "double", &_tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref); - fTPCTree->Branch("tpc_crt_sp_dts1", "double", &_tpc_crt_sp_dts1); + fTPCTree->Branch("run", &_run); + fTPCTree->Branch("subrun", &_subrun); + fTPCTree->Branch("event", &_event); + fTPCTree->Branch("crt_timing_reference_type", &_crt_timing_reference_type); + fTPCTree->Branch("crt_timing_reference_channel", &_crt_timing_reference_channel); + + fTPCTree->Branch("etrig_good", &_etrig_good); + fTPCTree->Branch("rwm_good", &_rwm_good); + fTPCTree->Branch("ptb_hlt_beam_gate_good", &_ptb_hlt_beam_gate_good); + fTPCTree->Branch("crt_t1_reset_good", &_crt_t1_reset_good); + fTPCTree->Branch("rwm_etrig_diff", &_rwm_etrig_diff); + fTPCTree->Branch("ptb_hlt_beam_gate_etrig_diff", &_ptb_hlt_beam_gate_etrig_diff); + fTPCTree->Branch("rwm_crt_t1_reset_diff", &_rwm_crt_t1_reset_diff); + fTPCTree->Branch("ptb_hlt_beam_gate_crt_t1_reset_diff", &_ptb_hlt_beam_gate_crt_t1_reset_diff); + fTPCTree->Branch("rwm_ptb_hlt_beam_gate_diff", &_rwm_ptb_hlt_beam_gate_diff); + + fTPCTree->Branch("tpc_has_corrected_opflash", &_tpc_has_corrected_opflash); + fTPCTree->Branch("tpc_has_crt_sp_match", &_tpc_has_crt_sp_match); + fTPCTree->Branch("tpc_opflash_t0", &_tpc_opflash_t0); + fTPCTree->Branch("tpc_opflash_nutof_light", &_tpc_opflash_nutof_light); + fTPCTree->Branch("tpc_opflash_nutof_charge", &_tpc_opflash_nutof_charge); + fTPCTree->Branch("tpc_opflash_t0_corrected", &_tpc_opflash_t0_corrected); + fTPCTree->Branch("tpc_opflash_t0_corrected_rwm", &_tpc_opflash_t0_corrected_rwm); + fTPCTree->Branch("tpc_crt_sp_score", &_tpc_crt_sp_score); + fTPCTree->Branch("tpc_crt_sp_ts0", &_tpc_crt_sp_ts0); + fTPCTree->Branch("tpc_crt_sp_ts0_rwm_ref", &_tpc_crt_sp_ts0_rwm_ref); + fTPCTree->Branch("tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref", &_tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref); + fTPCTree->Branch("tpc_crt_sp_dts0", &_tpc_crt_sp_dts0); + fTPCTree->Branch("tpc_crt_sp_ts1", &_tpc_crt_sp_ts1); + fTPCTree->Branch("tpc_crt_sp_ts1_rwm_ref", &_tpc_crt_sp_ts1_rwm_ref); + fTPCTree->Branch("tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref", &_tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref); + fTPCTree->Branch("tpc_crt_sp_dts1", &_tpc_crt_sp_dts1); } void sbnd::crt::CRTTimingAnalysis::analyze(art::Event const& e) { + ResetMaps(); + _run = e.id().run(); _subrun = e.id().subRun(); _event = e.id().event(); @@ -455,7 +473,7 @@ void sbnd::crt::CRTTimingAnalysis::analyze(art::Event const& e) art::FindManyP tracksToSpacePoints(CRTTrackHandle, e, fCRTTrackModuleLabel); // Fill CRTTrack variables - AnalyseCRTTracks(CRTTrackVec, tracksToSpacePoints, spacepointsToClusters, clustersToStripHits); + AnalyseCRTTracks(CRTTrackVec, tracksToSpacePoints); // Get TPCSlices art::Handle> TPCSliceHandle; @@ -498,6 +516,14 @@ void sbnd::crt::CRTTimingAnalysis::analyze(art::Event const& e) AnalyseTPCSlices(TPCSliceVec, sliceToCorrectedOpFlashes, sliceToPFPs, pfpToTrack, trackToCRTSpacePoint, spacepointsToClusters, clustersToStripHits); } +void sbnd::crt::CRTTimingAnalysis::ResetMaps() +{ + fSPTaggerMap.clear(); + fSPdTs0Map.clear(); + fSPdTs1Map.clear(); + fSPTimingChainMap.clear(); +} + void sbnd::crt::CRTTimingAnalysis::AnalysePTBs(std::vector> &PTBVec) { unsigned nHLTs = 0; @@ -709,6 +735,11 @@ void sbnd::crt::CRTTimingAnalysis::AnalyseCRTSpacePoints(const std::vectorFill(); + + fSPTaggerMap[sp.key()] = _sp_tagger; + fSPdTs0Map[sp.key()] = _sp_dts0; + fSPdTs1Map[sp.key()] = _sp_dts1; + fSPTimingChainMap[sp.key()] = _sp_timing_chain; } } @@ -716,7 +747,8 @@ void sbnd::crt::CRTTimingAnalysis::ResetSPVariables() { _sp_nhits = std::numeric_limits::max(); - _sp_tagger = CRTTagger::kUndefinedTagger; + _sp_tagger = std::numeric_limits::lowest(); + _sp_timing_chain = std::numeric_limits::lowest(); _sp_x = std::numeric_limits::lowest(); _sp_y = std::numeric_limits::lowest(); @@ -733,8 +765,6 @@ void sbnd::crt::CRTTimingAnalysis::ResetSPVariables() _sp_single_timing_chain = false; - _sp_timing_chain = std::numeric_limits::lowest(); - _sp_sh_channel_set.clear(); _sp_sh_mac5_set.clear(); _sp_sh_timing_chain_set.clear(); @@ -795,10 +825,126 @@ double sbnd::crt::CRTTimingAnalysis::IntrinsicResolution(const std::vector> &CRTTrackVec, - const art::FindManyP &tracksToSpacePoints, - const art::FindOneP &spacepointsToClusters, - const art::FindManyP &clustersToStripHits) + const art::FindManyP &tracksToSpacePoints) +{ + for(auto const &tr : CRTTrackVec) + { + _tr_start_x = tr->Start().X(); + _tr_start_y = tr->Start().Y(); + _tr_start_z = tr->Start().Z(); + _tr_end_x = tr->End().X(); + _tr_end_y = tr->End().Y(); + _tr_end_z = tr->End().Z(); + _tr_dir_x = tr->Direction().X(); + _tr_dir_y = tr->Direction().Y(); + _tr_dir_z = tr->Direction().Z(); + _tr_ts0 = tr->Ts0(); + _tr_ts0_rwm_ref = _tr_ts0 + _rwm_etrig_diff; + _tr_ts0_ptb_hlt_beam_gate_ref = _tr_ts0 + _ptb_hlt_beam_gate_etrig_diff; + _tr_ts1 = tr->Ts1(); + _tr_ts1_rwm_ref = _tr_ts1 + _rwm_crt_t1_reset_diff; + _tr_ts1_ptb_hlt_beam_gate_ref = _tr_ts1 + _ptb_hlt_beam_gate_crt_t1_reset_diff; + _tr_pe = tr->PE(); + _tr_length = tr->Length(); + _tr_length_tof = _tr_length * c; + _tr_theta = tr->Theta(); + _tr_phi = tr->Phi(); + _tr_triple = tr->Triple(); + _tr_tagger1 = tr->Taggers()[0]; + _tr_tagger2 = tr->Taggers()[1]; + + if(_tr_triple) + _tr_tagger3 = tr->Taggers()[2]; + + std::vector> sps = tracksToSpacePoints.at(tr.key()); + std::sort(sps.begin(), sps.end(), [](auto &a, auto &b) + { return a->Ts0() < b->Ts0(); }); + + if((_tr_triple && sps.size() != 3) || (!_tr_triple && sps.size() != 2)) + { + const int expectation = _tr_triple ? 3 : 2; + std::cout << "CRTSpacePoint vector wrong size (" << sps.size() + << ") for track expectation (" << expectation << ")" << std::endl; + throw std::exception(); + } + + const art::Ptr start = sps[0]; + const art::Ptr end = _tr_triple ? sps[2] : sps[1]; + + _tr_tof_ts0 = end->Ts0() - start->Ts0(); + _tr_tof_diff_ts0 = _tr_tof_ts0 - _tr_length_tof; + _tr_tof_ts1 = end->Ts1() - start->Ts1(); + _tr_tof_diff_ts1 = _tr_tof_ts1 - _tr_length_tof; + _tr_start_tagger = fSPTaggerMap[start.key()]; + _tr_start_dts0 = fSPdTs0Map[start.key()]; + _tr_start_dts1 = fSPdTs1Map[start.key()]; + _tr_start_timing_chain = fSPTimingChainMap[start.key()]; + _tr_start_single_timing_chain = _tr_start_timing_chain != -1; + _tr_end_tagger = fSPTaggerMap[end.key()]; + _tr_end_dts0 = fSPdTs0Map[end.key()]; + _tr_end_dts1 = fSPdTs1Map[end.key()]; + _tr_end_timing_chain = fSPTimingChainMap[end.key()]; + _tr_end_single_timing_chain = _tr_end_timing_chain != -1; + + if(_tr_start_tagger != _tr_tagger1) + { + std::cout << "CRTTrack start tagger inconsistent between direct access (" << _tr_tagger1 + << ") and associated CRTSpacePoint (" << _tr_start_tagger << ")" << std::endl; + throw std::exception(); + } + + if((_tr_triple && _tr_end_tagger != _tr_tagger3) || (!_tr_triple && _tr_end_tagger != _tr_tagger2)) + { + const int expectation = _tr_triple ? _tr_tagger3 : _tr_tagger2; + std::cout << "CRTTrack end tagger inconsistent between direct access (" << expectation + << ") and associated CRTSpacePoint (" << _tr_end_tagger << ")" << std::endl; + throw std::exception(); + } + } +} + +void sbnd::crt::CRTTimingAnalysis::ResetTrVariables() { + _tr_start_x = std::numeric_limits::lowest(); + _tr_start_y = std::numeric_limits::lowest(); + _tr_start_z = std::numeric_limits::lowest(); + _tr_end_x = std::numeric_limits::lowest(); + _tr_end_y = std::numeric_limits::lowest(); + _tr_end_z = std::numeric_limits::lowest(); + _tr_dir_x = std::numeric_limits::lowest(); + _tr_dir_y = std::numeric_limits::lowest(); + _tr_dir_z = std::numeric_limits::lowest(); + _tr_ts0 = std::numeric_limits::lowest(); + _tr_ts0_rwm_ref = std::numeric_limits::lowest(); + _tr_ts0_ptb_hlt_beam_gate_ref = std::numeric_limits::lowest(); + _tr_ts1 = std::numeric_limits::lowest(); + _tr_ts1_rwm_ref = std::numeric_limits::lowest(); + _tr_ts1_ptb_hlt_beam_gate_ref = std::numeric_limits::lowest(); + _tr_pe = std::numeric_limits::lowest(); + _tr_length = std::numeric_limits::lowest(); + _tr_length_tof = std::numeric_limits::lowest(); + _tr_tof_ts0 = std::numeric_limits::lowest(); + _tr_tof_diff_ts0 = std::numeric_limits::lowest(); + _tr_tof_ts1 = std::numeric_limits::lowest(); + _tr_tof_diff_ts1 = std::numeric_limits::lowest(); + _tr_theta = std::numeric_limits::lowest(); + _tr_phi = std::numeric_limits::lowest(); + _tr_start_dts0 = std::numeric_limits::lowest(); + _tr_start_dts1 = std::numeric_limits::lowest(); + _tr_end_dts0 = std::numeric_limits::lowest(); + _tr_end_dts1 = std::numeric_limits::lowest(); + + _tr_triple = false; + _tr_start_single_timing_chain = false; + _tr_end_single_timing_chain = false; + + _tr_tagger1 = std::numeric_limits::lowest(); + _tr_tagger2 = std::numeric_limits::lowest(); + _tr_tagger3 = std::numeric_limits::lowest(); + _tr_start_tagger = std::numeric_limits::lowest(); + _tr_start_timing_chain = std::numeric_limits::lowest(); + _tr_end_tagger = std::numeric_limits::lowest(); + _tr_end_timing_chain = std::numeric_limits::lowest(); } void sbnd::crt::CRTTimingAnalysis::AnalyseTPCSlices(const std::vector> &TPCSliceVec, From 1ca6df619557c004581a6b631c88fdcfce169986 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Wed, 25 Feb 2026 05:59:50 -0600 Subject: [PATCH 136/155] Make fcl changes to run CRTTimingAnalysis --- sbndcode/CRT/CRTAna/crttimingana_sbnd.fcl | 5 +++- sbndcode/CRT/CRTAna/run_crttimingana_data.fcl | 28 +++++++++++++++++++ .../CRT/CRTReco/crtrecoproducers_sbnd.fcl | 5 +++- 3 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 sbndcode/CRT/CRTAna/run_crttimingana_data.fcl diff --git a/sbndcode/CRT/CRTAna/crttimingana_sbnd.fcl b/sbndcode/CRT/CRTAna/crttimingana_sbnd.fcl index 4a9bff36a..406e07264 100644 --- a/sbndcode/CRT/CRTAna/crttimingana_sbnd.fcl +++ b/sbndcode/CRT/CRTAna/crttimingana_sbnd.fcl @@ -1,6 +1,8 @@ +#include "crtrecoproducers_sbnd.fcl" + BEGIN_PROLOG -crttophatana_data_sbnd: +crttimingana_data_sbnd: { module_type: "CRTTimingAnalysis" CRTClusterModuleLabel: "crtclustering" @@ -14,6 +16,7 @@ crttophatana_data_sbnd: TPCTrackModuleLabel: "pandoraSCETrack" CRTSpacePointMatchingModuleLabel: "crtspacepointmatchingSCE" AllowedPTBHLTs: [ 26, 27 ] + CRTClusterCharacterisationAlg: @local::crtclustercharacterisationalg_data_sbnd } END_PROLOG diff --git a/sbndcode/CRT/CRTAna/run_crttimingana_data.fcl b/sbndcode/CRT/CRTAna/run_crttimingana_data.fcl new file mode 100644 index 000000000..bcdcfd52a --- /dev/null +++ b/sbndcode/CRT/CRTAna/run_crttimingana_data.fcl @@ -0,0 +1,28 @@ +#include "services_sbnd.fcl" +#include "crt_services_sbnd.fcl" +#include "crttimingana_sbnd.fcl" + +process_name: CRTTimingAna + +services: +{ + TFileService: { fileName: "crttimingana_sbnd.root" } + @table::sbnd_basic_services + @table::crt_services_data_sbnd +} + +source: +{ + module_type: RootInput +} + +physics: +{ + analyzers: + { + crttimingana: @local::crttimingana_data_sbnd + } + + ana: [ crttimingana ] + end_paths: [ ana ] +} diff --git a/sbndcode/CRT/CRTReco/crtrecoproducers_sbnd.fcl b/sbndcode/CRT/CRTReco/crtrecoproducers_sbnd.fcl index 0b4ca1c3c..cbfd1a765 100644 --- a/sbndcode/CRT/CRTReco/crtrecoproducers_sbnd.fcl +++ b/sbndcode/CRT/CRTReco/crtrecoproducers_sbnd.fcl @@ -54,6 +54,9 @@ crtclustercharacterisationalg_sbnd: TimeWalkScale: @local::sbnd_crtsim.DetSimParams.TDelayScale } +crtclustercharacterisationalg_data_sbnd: @local::crtclustercharacterisationalg_sbnd +crtclustercharacterisationalg_data_sbnd.TimeOffset: 0 + crtspacepointproducer_sbnd: { ClusterCharacterisationAlg: @local::crtclustercharacterisationalg_sbnd @@ -62,7 +65,7 @@ crtspacepointproducer_sbnd: } crtspacepointproducer_data_sbnd: @local::crtspacepointproducer_sbnd -crtspacepointproducer_data_sbnd.ClusterCharacterisationAlg.TimeOffset: 0 +crtspacepointproducer_data_sbnd.ClusterCharacterisationAlg: @local::crtclustercharacterisationalg_data_sbnd crttrackproducer_sbnd: { From 8f8b77b96957c868c88f89574991980af937a8ca Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Wed, 25 Feb 2026 06:00:12 -0600 Subject: [PATCH 137/155] Make sure timing chain map is installed to path --- sbndcode/ChannelMaps/CRT/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbndcode/ChannelMaps/CRT/CMakeLists.txt b/sbndcode/ChannelMaps/CRT/CMakeLists.txt index b67ef20a5..9e6a43cfa 100644 --- a/sbndcode/ChannelMaps/CRT/CMakeLists.txt +++ b/sbndcode/ChannelMaps/CRT/CMakeLists.txt @@ -2,7 +2,7 @@ install_headers() install_fhicl() install_source() -file(GLOB channel_map_file *ChannelMap*.txt) +file(GLOB channel_map_file *Map*.txt) install_fw( LIST ${channel_map_file} ) art_make(SERVICE_LIBRARIES From cacb8d84ef0969173ad11cfa043ec67f633d36ff Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Wed, 25 Feb 2026 08:30:23 -0600 Subject: [PATCH 138/155] Add TPC slice based variables --- .../CRT/CRTAna/CRTTimingAnalysis_module.cc | 98 ++++++++++++++++--- 1 file changed, 84 insertions(+), 14 deletions(-) diff --git a/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc b/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc index 482eb5d2d..bc2795de2 100644 --- a/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc +++ b/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc @@ -41,7 +41,8 @@ namespace sbnd::crt { class CRTTimingAnalysis; - constexpr double c = 3.3356e-2; // ns / cm + constexpr double fSpeedOfLightNanosecondPerCentimeter = 3.3356e-2; // ns / cm + constexpr double fMicrosecondToNanosecond = 1e3; // ns } class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { @@ -86,12 +87,12 @@ class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { void ResetTrVariables(); void AnalyseTPCSlices(const std::vector> &TPCSliceVec, - const art::FindManyP &sliceToCorrectedOpFlashes, + const art::FindOneP &sliceToCorrectedOpFlash, const art::FindManyP &sliceToPFPs, const art::FindOneP &pfpToTrack, - const art::FindOneP &trackToCRTSpacePoint, - const art::FindOneP &spacepointsToClusters, - const art::FindManyP &clustersToStripHits); + const art::FindOneP &trackToCRTSpacePoint); + + void ResetTPCVariables(); private: @@ -211,7 +212,8 @@ class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { double _tpc_opflash_nutof_light; double _tpc_opflash_nutof_charge; double _tpc_opflash_t0_corrected; - double _tpc_opflash_t0_corrected_rwm; + double _tpc_opflash_interaction_time_rwm; + double _tpc_opflash_front_face_rwm; double _tpc_crt_sp_score; double _tpc_crt_sp_ts0; double _tpc_crt_sp_ts0_rwm_ref; @@ -373,7 +375,8 @@ sbnd::crt::CRTTimingAnalysis::CRTTimingAnalysis(fhicl::ParameterSet const& p) fTPCTree->Branch("tpc_opflash_nutof_light", &_tpc_opflash_nutof_light); fTPCTree->Branch("tpc_opflash_nutof_charge", &_tpc_opflash_nutof_charge); fTPCTree->Branch("tpc_opflash_t0_corrected", &_tpc_opflash_t0_corrected); - fTPCTree->Branch("tpc_opflash_t0_corrected_rwm", &_tpc_opflash_t0_corrected_rwm); + fTPCTree->Branch("tpc_opflash_interaction_time_rwm", &_tpc_opflash_interaction_time_rwm); + fTPCTree->Branch("tpc_opflash_front_face_rwm", &_tpc_opflash_front_face_rwm); fTPCTree->Branch("tpc_crt_sp_score", &_tpc_crt_sp_score); fTPCTree->Branch("tpc_crt_sp_ts0", &_tpc_crt_sp_ts0); fTPCTree->Branch("tpc_crt_sp_ts0_rwm_ref", &_tpc_crt_sp_ts0_rwm_ref); @@ -486,7 +489,7 @@ void sbnd::crt::CRTTimingAnalysis::analyze(art::Event const& e) art::fill_ptr_vector(TPCSliceVec, TPCSliceHandle); // Get TPCSlice to CorrectedOpFlash Assns - art::FindManyP sliceToCorrectedOpFlashes(TPCSliceHandle, e, fCorrectedOpFlashModuleLabel); + art::FindOneP sliceToCorrectedOpFlash(TPCSliceHandle, e, fCorrectedOpFlashModuleLabel); // Get TPCSlice to PFP Assns art::FindManyP sliceToPFPs(TPCSliceHandle, e, fTPCSliceModuleLabel); @@ -513,7 +516,7 @@ void sbnd::crt::CRTTimingAnalysis::analyze(art::Event const& e) // Get Track to CRTSpacePoint Assns art::FindOneP trackToCRTSpacePoint(TPCTrackHandle, e, fCRTSpacePointMatchingModuleLabel); - AnalyseTPCSlices(TPCSliceVec, sliceToCorrectedOpFlashes, sliceToPFPs, pfpToTrack, trackToCRTSpacePoint, spacepointsToClusters, clustersToStripHits); + AnalyseTPCSlices(TPCSliceVec, sliceToCorrectedOpFlash, sliceToPFPs, pfpToTrack, trackToCRTSpacePoint); } void sbnd::crt::CRTTimingAnalysis::ResetMaps() @@ -829,6 +832,8 @@ void sbnd::crt::CRTTimingAnalysis::AnalyseCRTTracks(const std::vectorStart().X(); _tr_start_y = tr->Start().Y(); _tr_start_z = tr->Start().Z(); @@ -846,7 +851,7 @@ void sbnd::crt::CRTTimingAnalysis::AnalyseCRTTracks(const std::vectorPE(); _tr_length = tr->Length(); - _tr_length_tof = _tr_length * c; + _tr_length_tof = _tr_length * fSpeedOfLightNanosecondPerCentimeter; _tr_theta = tr->Theta(); _tr_phi = tr->Phi(); _tr_triple = tr->Triple(); @@ -900,6 +905,8 @@ void sbnd::crt::CRTTimingAnalysis::AnalyseCRTTracks(const std::vectorFill(); } } @@ -948,13 +955,76 @@ void sbnd::crt::CRTTimingAnalysis::ResetTrVariables() } void sbnd::crt::CRTTimingAnalysis::AnalyseTPCSlices(const std::vector> &TPCSliceVec, - const art::FindManyP &sliceToCorrectedOpFlashes, + const art::FindOneP &sliceToCorrectedOpFlash, const art::FindManyP &sliceToPFPs, const art::FindOneP &pfpToTrack, - const art::FindOneP &trackToCRTSpacePoint, - const art::FindOneP &spacepointsToClusters, - const art::FindManyP &clustersToStripHits) + const art::FindOneP &trackToCRTSpacePoint) +{ + for(auto const &sl : TPCSliceVec) + { + const art::Ptr copflash = sliceToCorrectedOpFlash.at(sl.key()); + + if(copflash.isNonnull()) + { + _tpc_has_corrected_opflash = true; + _tpc_opflash_t0 = copflash->OpFlashT0 * fMicrosecondToNanosecond; + _tpc_opflash_nutof_light = copflash->NuToFLight * fMicrosecondToNanosecond; + _tpc_opflash_nutof_charge = copflash->NuToFCharge * fMicrosecondToNanosecond; + _tpc_opflash_t0_corrected = copflash->OpFlashT0Corrected * fMicrosecondToNanosecond; + _tpc_opflash_interaction_time_rwm = _tpc_opflash_t0_corrected + 1738.; + _tpc_opflash_front_face_rwm = _tpc_opflash_interaction_time_rwm - _tpc_opflash_nutof_charge; + } + + const std::vector> pfps = sliceToPFPs.at(sl.key()); + + for(auto const &pfp : pfps) + { + const art::Ptr track = pfpToTrack.at(pfp.key()); + + if(track.isNonnull()) + { + const art::Ptr sp = trackToCRTSpacePoint.at(track.key()); + + if(sp.isNonnull()) + { + const anab::T0 spMatch = trackToCRTSpacePoint.data(track.key()).ref(); + + _tpc_has_crt_sp_match = true; + _tpc_crt_sp_score = spMatch.TriggerConfidence(); + _tpc_crt_sp_ts0 = sp->Ts0(); + _tpc_crt_sp_ts0_rwm_ref = _tpc_crt_sp_ts0 + _rwm_etrig_diff; + _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref = _tpc_crt_sp_ts0 + _ptb_hlt_beam_gate_etrig_diff; + _tpc_crt_sp_dts0 = fSPdTs0Map[sp.key()]; + _tpc_crt_sp_ts1 = sp->Ts1(); + _tpc_crt_sp_ts1_rwm_ref = _tpc_crt_sp_ts1 + _rwm_crt_t1_reset_diff; + _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref = _tpc_crt_sp_ts1 + _ptb_hlt_beam_gate_crt_t1_reset_diff; + _tpc_crt_sp_dts1 = fSPdTs1Map[sp.key()]; + } + } + } + } +} + +void sbnd::crt::CRTTimingAnalysis::ResetTPCVariables() { + _tpc_has_corrected_opflash = false; + _tpc_has_crt_sp_match = false; + + _tpc_opflash_t0 = std::numeric_limits::lowest(); + _tpc_opflash_nutof_light = std::numeric_limits::lowest(); + _tpc_opflash_nutof_charge = std::numeric_limits::lowest(); + _tpc_opflash_t0_corrected = std::numeric_limits::lowest(); + _tpc_opflash_interaction_time_rwm = std::numeric_limits::lowest(); + _tpc_opflash_front_face_rwm = std::numeric_limits::lowest(); + _tpc_crt_sp_score = std::numeric_limits::lowest(); + _tpc_crt_sp_ts0 = std::numeric_limits::lowest(); + _tpc_crt_sp_ts0_rwm_ref = std::numeric_limits::lowest(); + _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref = std::numeric_limits::lowest(); + _tpc_crt_sp_dts0 = std::numeric_limits::lowest(); + _tpc_crt_sp_ts1 = std::numeric_limits::lowest(); + _tpc_crt_sp_ts1_rwm_ref = std::numeric_limits::lowest(); + _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref = std::numeric_limits::lowest(); + _tpc_crt_sp_dts1 = std::numeric_limits::lowest(); } DEFINE_ART_MODULE(sbnd::crt::CRTTimingAnalysis) From 5e7f17d22faf8bfb328994a5c9455a2d12b1f487 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Wed, 25 Feb 2026 09:22:20 -0600 Subject: [PATCH 139/155] Add more reference shifts --- .../CRT/CRTAna/CRTTimingAnalysis_module.cc | 193 +++++++++++++----- 1 file changed, 143 insertions(+), 50 deletions(-) diff --git a/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc b/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc index bc2795de2..a1728c95d 100644 --- a/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc +++ b/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc @@ -144,14 +144,19 @@ class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { double _sp_x; double _sp_y; double _sp_z; + double _sp_front_face_adjustment; double _sp_pe; double _sp_ts0; double _sp_ts0_rwm_ref; double _sp_ts0_ptb_hlt_beam_gate_ref; + double _sp_ts0_rwm_ref_front_face; + double _sp_ts0_ptb_hlt_beam_gate_ref_front_face; double _sp_dts0; double _sp_ts1; double _sp_ts1_rwm_ref; double _sp_ts1_ptb_hlt_beam_gate_ref; + double _sp_ts1_rwm_ref_front_face; + double _sp_ts1_ptb_hlt_beam_gate_ref_front_face; double _sp_dts1; bool _sp_single_timing_chain; int16_t _sp_timing_chain; @@ -215,14 +220,26 @@ class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { double _tpc_opflash_interaction_time_rwm; double _tpc_opflash_front_face_rwm; double _tpc_crt_sp_score; + double _tpc_crt_sp_front_face_adjustment; + double _tpc_crt_sp_interaction_time_adjustment; double _tpc_crt_sp_ts0; double _tpc_crt_sp_ts0_rwm_ref; double _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref; + double _tpc_crt_sp_ts0_rwm_ref_front_face; + double _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref_front_face; + double _tpc_crt_sp_ts0_rwm_ref_interaction_time; + double _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref_interaction_time; double _tpc_crt_sp_dts0; double _tpc_crt_sp_ts1; double _tpc_crt_sp_ts1_rwm_ref; double _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref; + double _tpc_crt_sp_ts1_rwm_ref_front_face; + double _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref_front_face; + double _tpc_crt_sp_ts1_rwm_ref_interaction_time; + double _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref_interaction_time; double _tpc_crt_sp_dts1; + double _tpc_crt_ts0_pmt_diff; + double _tpc_crt_ts1_pmt_diff; // Maps std::map fSPTaggerMap; @@ -273,14 +290,19 @@ sbnd::crt::CRTTimingAnalysis::CRTTimingAnalysis(fhicl::ParameterSet const& p) fSPTree->Branch("sp_x", &_sp_x); fSPTree->Branch("sp_y", &_sp_y); fSPTree->Branch("sp_z", &_sp_z); + fSPTree->Branch("sp_front_face_adjustment", &_sp_front_face_adjustment); fSPTree->Branch("sp_pe", &_sp_pe); fSPTree->Branch("sp_ts0", &_sp_ts0); fSPTree->Branch("sp_ts0_rwm_ref", &_sp_ts0_rwm_ref); fSPTree->Branch("sp_ts0_ptb_hlt_beam_gate_ref", &_sp_ts0_ptb_hlt_beam_gate_ref); + fSPTree->Branch("sp_ts0_rwm_ref_front_face", &_sp_ts0_rwm_ref_front_face); + fSPTree->Branch("sp_ts0_ptb_hlt_beam_gate_ref_front_face", &_sp_ts0_ptb_hlt_beam_gate_ref_front_face); fSPTree->Branch("sp_dts0", &_sp_dts0); fSPTree->Branch("sp_ts1", &_sp_ts1); fSPTree->Branch("sp_ts1_rwm_ref", &_sp_ts1_rwm_ref); fSPTree->Branch("sp_ts1_ptb_hlt_beam_gate_ref", &_sp_ts1_ptb_hlt_beam_gate_ref); + fSPTree->Branch("sp_ts1_rwm_ref_front_face", &_sp_ts1_rwm_ref_front_face); + fSPTree->Branch("sp_ts1_ptb_hlt_beam_gate_ref_front_face", &_sp_ts1_ptb_hlt_beam_gate_ref_front_face); fSPTree->Branch("sp_dts1", &_sp_dts1); fSPTree->Branch("sp_single_timing_chain", &_sp_single_timing_chain); fSPTree->Branch("sp_timing_chain", &_sp_timing_chain); @@ -378,14 +400,26 @@ sbnd::crt::CRTTimingAnalysis::CRTTimingAnalysis(fhicl::ParameterSet const& p) fTPCTree->Branch("tpc_opflash_interaction_time_rwm", &_tpc_opflash_interaction_time_rwm); fTPCTree->Branch("tpc_opflash_front_face_rwm", &_tpc_opflash_front_face_rwm); fTPCTree->Branch("tpc_crt_sp_score", &_tpc_crt_sp_score); + fTPCTree->Branch("tpc_crt_sp_front_face_adjustment", &_tpc_crt_sp_front_face_adjustment); + fTPCTree->Branch("tpc_crt_sp_interaction_time_adjustment", &_tpc_crt_sp_interaction_time_adjustment); fTPCTree->Branch("tpc_crt_sp_ts0", &_tpc_crt_sp_ts0); fTPCTree->Branch("tpc_crt_sp_ts0_rwm_ref", &_tpc_crt_sp_ts0_rwm_ref); fTPCTree->Branch("tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref", &_tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref); + fTPCTree->Branch("tpc_crt_sp_ts0_rwm_ref_front_face", &_tpc_crt_sp_ts0_rwm_ref_front_face); + fTPCTree->Branch("tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref_front_face", &_tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref_front_face); + fTPCTree->Branch("tpc_crt_sp_ts0_rwm_ref_interaction_time", &_tpc_crt_sp_ts0_rwm_ref_interaction_time); + fTPCTree->Branch("tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref_interaction_time", &_tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref_interaction_time); fTPCTree->Branch("tpc_crt_sp_dts0", &_tpc_crt_sp_dts0); fTPCTree->Branch("tpc_crt_sp_ts1", &_tpc_crt_sp_ts1); fTPCTree->Branch("tpc_crt_sp_ts1_rwm_ref", &_tpc_crt_sp_ts1_rwm_ref); fTPCTree->Branch("tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref", &_tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref); + fTPCTree->Branch("tpc_crt_sp_ts1_rwm_ref_front_face", &_tpc_crt_sp_ts1_rwm_ref_front_face); + fTPCTree->Branch("tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref_front_face", &_tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref_front_face); + fTPCTree->Branch("tpc_crt_sp_ts1_rwm_ref_interaction_time", &_tpc_crt_sp_ts1_rwm_ref_interaction_time); + fTPCTree->Branch("tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref_interaction_time", &_tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref_interaction_time); fTPCTree->Branch("tpc_crt_sp_dts1", &_tpc_crt_sp_dts1); + fTPCTree->Branch("tpc_crt_ts0_pmt_diff", &_tpc_crt_ts0_pmt_diff); + fTPCTree->Branch("tpc_crt_ts1_pmt_diff", &_tpc_crt_ts1_pmt_diff); } void sbnd::crt::CRTTimingAnalysis::analyze(art::Event const& e) @@ -700,18 +734,23 @@ void sbnd::crt::CRTTimingAnalysis::AnalyseCRTSpacePoints(const std::vectorNHits(); - _sp_tagger = cl->Tagger(); - _sp_x = sp->X(); - _sp_y = sp->Y(); - _sp_z = sp->Z(); - _sp_pe = sp->PE(); - _sp_ts0 = sp->Ts0(); - _sp_ts0_rwm_ref = _sp_ts0 + _rwm_etrig_diff; - _sp_ts0_ptb_hlt_beam_gate_ref = _sp_ts0 + _ptb_hlt_beam_gate_etrig_diff; - _sp_ts1 = sp->Ts1(); - _sp_ts1_rwm_ref = _sp_ts1 + _rwm_crt_t1_reset_diff; - _sp_ts1_ptb_hlt_beam_gate_ref = _sp_ts1 + _ptb_hlt_beam_gate_crt_t1_reset_diff; + _sp_nhits = cl->NHits(); + _sp_tagger = cl->Tagger(); + _sp_x = sp->X(); + _sp_y = sp->Y(); + _sp_z = sp->Z(); + _sp_front_face_adjustment = _sp_z * fSpeedOfLightNanosecondPerCentimeter; + _sp_pe = sp->PE(); + _sp_ts0 = sp->Ts0(); + _sp_ts0_rwm_ref = _sp_ts0 + _rwm_etrig_diff; + _sp_ts0_ptb_hlt_beam_gate_ref = _sp_ts0 + _ptb_hlt_beam_gate_etrig_diff; + _sp_ts0_rwm_ref_front_face = _sp_ts0_rwm_ref - _sp_front_face_adjustment; + _sp_ts0_ptb_hlt_beam_gate_ref_front_face = _sp_ts0_ptb_hlt_beam_gate_ref - _sp_front_face_adjustment; + _sp_ts1 = sp->Ts1(); + _sp_ts1_rwm_ref = _sp_ts1 + _rwm_crt_t1_reset_diff; + _sp_ts1_ptb_hlt_beam_gate_ref = _sp_ts1 + _ptb_hlt_beam_gate_crt_t1_reset_diff; + _sp_ts1_rwm_ref_front_face = _sp_ts1_rwm_ref - _sp_front_face_adjustment; + _sp_ts1_ptb_hlt_beam_gate_ref_front_face = _sp_ts1_ptb_hlt_beam_gate_ref - _sp_front_face_adjustment; for(unsigned i = 0; i < n_shs; ++i) { @@ -753,18 +792,23 @@ void sbnd::crt::CRTTimingAnalysis::ResetSPVariables() _sp_tagger = std::numeric_limits::lowest(); _sp_timing_chain = std::numeric_limits::lowest(); - _sp_x = std::numeric_limits::lowest(); - _sp_y = std::numeric_limits::lowest(); - _sp_z = std::numeric_limits::lowest(); - _sp_pe = std::numeric_limits::lowest(); - _sp_ts0 = std::numeric_limits::lowest(); - _sp_ts0_rwm_ref = std::numeric_limits::lowest(); - _sp_ts0_ptb_hlt_beam_gate_ref = std::numeric_limits::lowest(); - _sp_dts0 = std::numeric_limits::lowest(); - _sp_ts1 = std::numeric_limits::lowest(); - _sp_ts1_rwm_ref = std::numeric_limits::lowest(); - _sp_ts1_ptb_hlt_beam_gate_ref = std::numeric_limits::lowest(); - _sp_dts1 = std::numeric_limits::lowest(); + _sp_x = std::numeric_limits::lowest(); + _sp_y = std::numeric_limits::lowest(); + _sp_z = std::numeric_limits::lowest(); + _sp_front_face_adjustment = std::numeric_limits::lowest(); + _sp_pe = std::numeric_limits::lowest(); + _sp_ts0 = std::numeric_limits::lowest(); + _sp_ts0_rwm_ref = std::numeric_limits::lowest(); + _sp_ts0_ptb_hlt_beam_gate_ref = std::numeric_limits::lowest(); + _sp_ts0_rwm_ref_front_face = std::numeric_limits::lowest(); + _sp_ts0_ptb_hlt_beam_gate_ref_front_face = std::numeric_limits::lowest(); + _sp_dts0 = std::numeric_limits::lowest(); + _sp_ts1 = std::numeric_limits::lowest(); + _sp_ts1_rwm_ref = std::numeric_limits::lowest(); + _sp_ts1_ptb_hlt_beam_gate_ref = std::numeric_limits::lowest(); + _sp_ts1_rwm_ref_front_face = std::numeric_limits::lowest(); + _sp_ts1_ptb_hlt_beam_gate_ref_front_face = std::numeric_limits::lowest(); + _sp_dts1 = std::numeric_limits::lowest(); _sp_single_timing_chain = false; @@ -962,6 +1006,8 @@ void sbnd::crt::CRTTimingAnalysis::AnalyseTPCSlices(const std::vector copflash = sliceToCorrectedOpFlash.at(sl.key()); if(copflash.isNonnull()) @@ -971,7 +1017,7 @@ void sbnd::crt::CRTTimingAnalysis::AnalyseTPCSlices(const std::vectorNuToFLight * fMicrosecondToNanosecond; _tpc_opflash_nutof_charge = copflash->NuToFCharge * fMicrosecondToNanosecond; _tpc_opflash_t0_corrected = copflash->OpFlashT0Corrected * fMicrosecondToNanosecond; - _tpc_opflash_interaction_time_rwm = _tpc_opflash_t0_corrected + 1738.; + _tpc_opflash_interaction_time_rwm = _tpc_opflash_t0_corrected; _tpc_opflash_front_face_rwm = _tpc_opflash_interaction_time_rwm - _tpc_opflash_nutof_charge; } @@ -989,19 +1035,54 @@ void sbnd::crt::CRTTimingAnalysis::AnalyseTPCSlices(const std::vectorTs0(); - _tpc_crt_sp_ts0_rwm_ref = _tpc_crt_sp_ts0 + _rwm_etrig_diff; - _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref = _tpc_crt_sp_ts0 + _ptb_hlt_beam_gate_etrig_diff; - _tpc_crt_sp_dts0 = fSPdTs0Map[sp.key()]; - _tpc_crt_sp_ts1 = sp->Ts1(); - _tpc_crt_sp_ts1_rwm_ref = _tpc_crt_sp_ts1 + _rwm_crt_t1_reset_diff; - _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref = _tpc_crt_sp_ts1 + _ptb_hlt_beam_gate_crt_t1_reset_diff; - _tpc_crt_sp_dts1 = fSPdTs1Map[sp.key()]; + const geo::Point_t track_start = track->Start(); + const geo::Point_t track_end = track->End(); + const geo::Point_t sp_pos = sp->Pos(); + + geo::Point_t interaction_point = (track_start - sp_pos).R() > (track_end - sp_pos).R() ? track_start : track_end; + const double dist = (interaction_point - sp_pos).R(); + + if(_tpc_has_crt_sp_match) + { + const double diff = _tpc_crt_sp_ts0_rwm_ref_interaction_time - _tpc_opflash_interaction_time_rwm - 120; + const double new_crt = sp->Ts0() + _rwm_etrig_diff - dist * fSpeedOfLightNanosecondPerCentimeter; + const double new_diff = new_crt - _tpc_opflash_interaction_time_rwm - 120; + + if(new_diff > diff) + continue; + } + + _tpc_has_crt_sp_match = true; + _tpc_crt_sp_score = spMatch.TriggerConfidence(); + _tpc_crt_sp_front_face_adjustment = sp_pos.Z() * fSpeedOfLightNanosecondPerCentimeter; + _tpc_crt_sp_interaction_time_adjustment = dist * fSpeedOfLightNanosecondPerCentimeter; + _tpc_crt_sp_ts0 = sp->Ts0(); + _tpc_crt_sp_ts0_rwm_ref = _tpc_crt_sp_ts0 + _rwm_etrig_diff; + _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref = _tpc_crt_sp_ts0 + _ptb_hlt_beam_gate_etrig_diff; + _tpc_crt_sp_ts0_rwm_ref_front_face = _tpc_crt_sp_ts0_rwm_ref - _tpc_crt_sp_front_face_adjustment; + _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref_front_face = _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref - _tpc_crt_sp_front_face_adjustment; + _tpc_crt_sp_ts0_rwm_ref_interaction_time = _tpc_crt_sp_ts0_rwm_ref - _tpc_crt_sp_interaction_time_adjustment; + _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref_interaction_time = _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref - _tpc_crt_sp_interaction_time_adjustment; + _tpc_crt_sp_dts0 = fSPdTs0Map[sp.key()]; + _tpc_crt_sp_ts1 = sp->Ts1(); + _tpc_crt_sp_ts1_rwm_ref = _tpc_crt_sp_ts1 + _rwm_crt_t1_reset_diff; + _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref = _tpc_crt_sp_ts1 + _ptb_hlt_beam_gate_crt_t1_reset_diff; + _tpc_crt_sp_ts1_rwm_ref_front_face = _tpc_crt_sp_ts1_rwm_ref - _tpc_crt_sp_front_face_adjustment; + _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref_front_face = _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref - _tpc_crt_sp_front_face_adjustment; + _tpc_crt_sp_ts1_rwm_ref_interaction_time = _tpc_crt_sp_ts1_rwm_ref - _tpc_crt_sp_interaction_time_adjustment; + _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref_interaction_time = _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref - _tpc_crt_sp_interaction_time_adjustment; + _tpc_crt_sp_dts1 = fSPdTs1Map[sp.key()]; } } } + + if(_tpc_has_corrected_opflash && _tpc_has_crt_sp_match) + { + _tpc_crt_ts0_pmt_diff = _tpc_crt_sp_ts0_rwm_ref_interaction_time - _tpc_opflash_interaction_time_rwm; + _tpc_crt_ts1_pmt_diff = _tpc_crt_sp_ts1_rwm_ref_interaction_time - _tpc_opflash_interaction_time_rwm; + } + + fTPCTree->Fill(); } } @@ -1010,21 +1091,33 @@ void sbnd::crt::CRTTimingAnalysis::ResetTPCVariables() _tpc_has_corrected_opflash = false; _tpc_has_crt_sp_match = false; - _tpc_opflash_t0 = std::numeric_limits::lowest(); - _tpc_opflash_nutof_light = std::numeric_limits::lowest(); - _tpc_opflash_nutof_charge = std::numeric_limits::lowest(); - _tpc_opflash_t0_corrected = std::numeric_limits::lowest(); - _tpc_opflash_interaction_time_rwm = std::numeric_limits::lowest(); - _tpc_opflash_front_face_rwm = std::numeric_limits::lowest(); - _tpc_crt_sp_score = std::numeric_limits::lowest(); - _tpc_crt_sp_ts0 = std::numeric_limits::lowest(); - _tpc_crt_sp_ts0_rwm_ref = std::numeric_limits::lowest(); - _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref = std::numeric_limits::lowest(); - _tpc_crt_sp_dts0 = std::numeric_limits::lowest(); - _tpc_crt_sp_ts1 = std::numeric_limits::lowest(); - _tpc_crt_sp_ts1_rwm_ref = std::numeric_limits::lowest(); - _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref = std::numeric_limits::lowest(); - _tpc_crt_sp_dts1 = std::numeric_limits::lowest(); + _tpc_opflash_t0 = std::numeric_limits::lowest(); + _tpc_opflash_nutof_light = std::numeric_limits::lowest(); + _tpc_opflash_nutof_charge = std::numeric_limits::lowest(); + _tpc_opflash_t0_corrected = std::numeric_limits::lowest(); + _tpc_opflash_interaction_time_rwm = std::numeric_limits::lowest(); + _tpc_opflash_front_face_rwm = std::numeric_limits::lowest(); + _tpc_crt_sp_score = std::numeric_limits::lowest(); + _tpc_crt_sp_front_face_adjustment = std::numeric_limits::lowest(); + _tpc_crt_sp_interaction_time_adjustment = std::numeric_limits::lowest(); + _tpc_crt_sp_ts0 = std::numeric_limits::lowest(); + _tpc_crt_sp_ts0_rwm_ref = std::numeric_limits::lowest(); + _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref = std::numeric_limits::lowest(); + _tpc_crt_sp_ts0_rwm_ref_front_face = std::numeric_limits::lowest(); + _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref_front_face = std::numeric_limits::lowest(); + _tpc_crt_sp_ts0_rwm_ref_interaction_time = std::numeric_limits::lowest(); + _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref_interaction_time = std::numeric_limits::lowest(); + _tpc_crt_sp_dts0 = std::numeric_limits::lowest(); + _tpc_crt_sp_ts1 = std::numeric_limits::lowest(); + _tpc_crt_sp_ts1_rwm_ref = std::numeric_limits::lowest(); + _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref = std::numeric_limits::lowest(); + _tpc_crt_sp_ts1_rwm_ref_front_face = std::numeric_limits::lowest(); + _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref_front_face = std::numeric_limits::lowest(); + _tpc_crt_sp_ts1_rwm_ref_interaction_time = std::numeric_limits::lowest(); + _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref_interaction_time = std::numeric_limits::lowest(); + _tpc_crt_sp_dts1 = std::numeric_limits::lowest(); + _tpc_crt_ts0_pmt_diff = std::numeric_limits::lowest(); + _tpc_crt_ts1_pmt_diff = std::numeric_limits::lowest(); } DEFINE_ART_MODULE(sbnd::crt::CRTTimingAnalysis) From 2b8362d60f3ee34413cfe927727b109e4bbc6651 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Thu, 26 Feb 2026 04:02:08 -0600 Subject: [PATCH 140/155] Add a few missing branches --- .../CRT/CRTAna/CRTTimingAnalysis_module.cc | 179 ++++++++++-------- 1 file changed, 105 insertions(+), 74 deletions(-) diff --git a/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc b/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc index a1728c95d..a1bdf11bb 100644 --- a/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc +++ b/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc @@ -172,80 +172,87 @@ class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { std::vector _sp_sh_cable_length_ts1_set; std::vector _sp_sh_calib_offset_ts1_set; - double _tr_start_x; - double _tr_start_y; - double _tr_start_z; - double _tr_end_x; - double _tr_end_y; - double _tr_end_z; - double _tr_dir_x; - double _tr_dir_y; - double _tr_dir_z; - double _tr_ts0; - double _tr_ts0_rwm_ref; - double _tr_ts0_ptb_hlt_beam_gate_ref; - double _tr_ts1; - double _tr_ts1_rwm_ref; - double _tr_ts1_ptb_hlt_beam_gate_ref; - double _tr_pe; - double _tr_length; - double _tr_length_tof; - double _tr_tof_ts0; - double _tr_tof_diff_ts0; - double _tr_tof_ts1; - double _tr_tof_diff_ts1; - double _tr_theta; - double _tr_phi; - bool _tr_triple; - int16_t _tr_tagger1; - int16_t _tr_tagger2; - int16_t _tr_tagger3; - int16_t _tr_start_tagger; - double _tr_start_dts0; - double _tr_start_dts1; - bool _tr_start_single_timing_chain; - int16_t _tr_start_timing_chain; - int16_t _tr_end_tagger; - double _tr_end_dts0; - double _tr_end_dts1; - bool _tr_end_single_timing_chain; - int16_t _tr_end_timing_chain; - - bool _tpc_has_corrected_opflash; - bool _tpc_has_crt_sp_match; - double _tpc_opflash_t0; - double _tpc_opflash_nutof_light; - double _tpc_opflash_nutof_charge; - double _tpc_opflash_t0_corrected; - double _tpc_opflash_interaction_time_rwm; - double _tpc_opflash_front_face_rwm; - double _tpc_crt_sp_score; - double _tpc_crt_sp_front_face_adjustment; - double _tpc_crt_sp_interaction_time_adjustment; - double _tpc_crt_sp_ts0; - double _tpc_crt_sp_ts0_rwm_ref; - double _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref; - double _tpc_crt_sp_ts0_rwm_ref_front_face; - double _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref_front_face; - double _tpc_crt_sp_ts0_rwm_ref_interaction_time; - double _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref_interaction_time; - double _tpc_crt_sp_dts0; - double _tpc_crt_sp_ts1; - double _tpc_crt_sp_ts1_rwm_ref; - double _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref; - double _tpc_crt_sp_ts1_rwm_ref_front_face; - double _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref_front_face; - double _tpc_crt_sp_ts1_rwm_ref_interaction_time; - double _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref_interaction_time; - double _tpc_crt_sp_dts1; - double _tpc_crt_ts0_pmt_diff; - double _tpc_crt_ts1_pmt_diff; + double _tr_start_x; + double _tr_start_y; + double _tr_start_z; + double _tr_end_x; + double _tr_end_y; + double _tr_end_z; + double _tr_dir_x; + double _tr_dir_y; + double _tr_dir_z; + double _tr_ts0; + double _tr_ts0_rwm_ref; + double _tr_ts0_ptb_hlt_beam_gate_ref; + double _tr_ts1; + double _tr_ts1_rwm_ref; + double _tr_ts1_ptb_hlt_beam_gate_ref; + double _tr_pe; + double _tr_length; + double _tr_length_tof; + double _tr_tof_ts0; + double _tr_tof_diff_ts0; + double _tr_tof_ts1; + double _tr_tof_diff_ts1; + double _tr_theta; + double _tr_phi; + bool _tr_triple; + int16_t _tr_tagger1; + int16_t _tr_tagger2; + int16_t _tr_tagger3; + int16_t _tr_start_tagger; + uint16_t _tr_start_nhits; + double _tr_start_dts0; + double _tr_start_dts1; + bool _tr_start_single_timing_chain; + int16_t _tr_start_timing_chain; + int16_t _tr_end_tagger; + uint16_t _tr_end_nhits; + double _tr_end_dts0; + double _tr_end_dts1; + bool _tr_end_single_timing_chain; + int16_t _tr_end_timing_chain; + + bool _tpc_has_corrected_opflash; + bool _tpc_has_crt_sp_match; + double _tpc_opflash_t0; + double _tpc_opflash_nutof_light; + double _tpc_opflash_nutof_charge; + double _tpc_opflash_t0_corrected; + double _tpc_opflash_interaction_time_rwm; + double _tpc_opflash_front_face_rwm; + double _tpc_crt_sp_score; + int16_t _tpc_crt_sp_tagger; + uint16_t _tpc_crt_sp_nhits; + bool _tpc_crt_sp_single_timing_chain; + int16_t _tpc_crt_sp_timing_chain; + double _tpc_crt_sp_front_face_adjustment; + double _tpc_crt_sp_interaction_time_adjustment; + double _tpc_crt_sp_ts0; + double _tpc_crt_sp_ts0_rwm_ref; + double _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref; + double _tpc_crt_sp_ts0_rwm_ref_front_face; + double _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref_front_face; + double _tpc_crt_sp_ts0_rwm_ref_interaction_time; + double _tpc_crt_sp_ts0_ptb_hlt_beam_gate_ref_interaction_time; + double _tpc_crt_sp_dts0; + double _tpc_crt_sp_ts1; + double _tpc_crt_sp_ts1_rwm_ref; + double _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref; + double _tpc_crt_sp_ts1_rwm_ref_front_face; + double _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref_front_face; + double _tpc_crt_sp_ts1_rwm_ref_interaction_time; + double _tpc_crt_sp_ts1_ptb_hlt_beam_gate_ref_interaction_time; + double _tpc_crt_sp_dts1; + double _tpc_crt_ts0_pmt_diff; + double _tpc_crt_ts1_pmt_diff; // Maps - std::map fSPTaggerMap; - std::map fSPdTs0Map; - std::map fSPdTs1Map; - std::map fSPTimingChainMap; + std::map fSPTaggerMap; + std::map fSPNHitsMap; + std::map fSPdTs0Map; + std::map fSPdTs1Map; + std::map fSPTimingChainMap; }; sbnd::crt::CRTTimingAnalysis::CRTTimingAnalysis(fhicl::ParameterSet const& p) @@ -364,11 +371,13 @@ sbnd::crt::CRTTimingAnalysis::CRTTimingAnalysis(fhicl::ParameterSet const& p) fTrTree->Branch("tr_tagger2", &_tr_tagger2); fTrTree->Branch("tr_tagger3", &_tr_tagger3); fTrTree->Branch("tr_start_tagger", &_tr_start_tagger); + fTrTree->Branch("tr_start_nhits", &_tr_start_nhits); fTrTree->Branch("tr_start_dts0", &_tr_start_dts0); fTrTree->Branch("tr_start_dts1", &_tr_start_dts1); fTrTree->Branch("tr_start_single_timing_chain", &_tr_start_single_timing_chain); fTrTree->Branch("tr_start_timing_chain", &_tr_start_timing_chain); fTrTree->Branch("tr_end_tagger", &_tr_end_tagger); + fTrTree->Branch("tr_end_nhits", &_tr_end_nhits); fTrTree->Branch("tr_end_dts0", &_tr_end_dts0); fTrTree->Branch("tr_end_dts1", &_tr_end_dts1); fTrTree->Branch("tr_end_single_timing_chain", &_tr_end_single_timing_chain); @@ -400,6 +409,10 @@ sbnd::crt::CRTTimingAnalysis::CRTTimingAnalysis(fhicl::ParameterSet const& p) fTPCTree->Branch("tpc_opflash_interaction_time_rwm", &_tpc_opflash_interaction_time_rwm); fTPCTree->Branch("tpc_opflash_front_face_rwm", &_tpc_opflash_front_face_rwm); fTPCTree->Branch("tpc_crt_sp_score", &_tpc_crt_sp_score); + fTPCTree->Branch("tpc_crt_sp_tagger", &_tpc_crt_sp_tagger); + fTPCTree->Branch("tpc_crt_sp_nhits", &_tpc_crt_sp_nhits); + fTPCTree->Branch("tpc_crt_sp_single_timing_chain", &_tpc_crt_sp_single_timing_chain); + fTPCTree->Branch("tpc_crt_sp_timing_chain", &_tpc_crt_sp_timing_chain); fTPCTree->Branch("tpc_crt_sp_front_face_adjustment", &_tpc_crt_sp_front_face_adjustment); fTPCTree->Branch("tpc_crt_sp_interaction_time_adjustment", &_tpc_crt_sp_interaction_time_adjustment); fTPCTree->Branch("tpc_crt_sp_ts0", &_tpc_crt_sp_ts0); @@ -556,6 +569,7 @@ void sbnd::crt::CRTTimingAnalysis::analyze(art::Event const& e) void sbnd::crt::CRTTimingAnalysis::ResetMaps() { fSPTaggerMap.clear(); + fSPNHitsMap.clear(); fSPdTs0Map.clear(); fSPdTs1Map.clear(); fSPTimingChainMap.clear(); @@ -779,6 +793,7 @@ void sbnd::crt::CRTTimingAnalysis::AnalyseCRTSpacePoints(const std::vectorFill(); fSPTaggerMap[sp.key()] = _sp_tagger; + fSPNHitsMap[sp.key()] = _sp_nhits; fSPdTs0Map[sp.key()] = _sp_dts0; fSPdTs1Map[sp.key()] = _sp_dts1; fSPTimingChainMap[sp.key()] = _sp_timing_chain; @@ -925,11 +940,13 @@ void sbnd::crt::CRTTimingAnalysis::AnalyseCRTTracks(const std::vectorTs1() - start->Ts1(); _tr_tof_diff_ts1 = _tr_tof_ts1 - _tr_length_tof; _tr_start_tagger = fSPTaggerMap[start.key()]; + _tr_start_nhits = fSPNHitsMap[start.key()]; _tr_start_dts0 = fSPdTs0Map[start.key()]; _tr_start_dts1 = fSPdTs1Map[start.key()]; _tr_start_timing_chain = fSPTimingChainMap[start.key()]; _tr_start_single_timing_chain = _tr_start_timing_chain != -1; _tr_end_tagger = fSPTaggerMap[end.key()]; + _tr_end_nhits = fSPNHitsMap[start.key()]; _tr_end_dts0 = fSPdTs0Map[end.key()]; _tr_end_dts1 = fSPdTs1Map[end.key()]; _tr_end_timing_chain = fSPTimingChainMap[end.key()]; @@ -996,6 +1013,10 @@ void sbnd::crt::CRTTimingAnalysis::ResetTrVariables() _tr_start_timing_chain = std::numeric_limits::lowest(); _tr_end_tagger = std::numeric_limits::lowest(); _tr_end_timing_chain = std::numeric_limits::lowest(); + + _tr_start_nhits = std::numeric_limits::lowest(); + _tr_end_nhits = std::numeric_limits::lowest(); + } void sbnd::crt::CRTTimingAnalysis::AnalyseTPCSlices(const std::vector> &TPCSliceVec, @@ -1054,6 +1075,10 @@ void sbnd::crt::CRTTimingAnalysis::AnalyseTPCSlices(const std::vectorTs0(); @@ -1088,8 +1113,9 @@ void sbnd::crt::CRTTimingAnalysis::AnalyseTPCSlices(const std::vector::lowest(); _tpc_opflash_nutof_light = std::numeric_limits::lowest(); @@ -1118,6 +1144,11 @@ void sbnd::crt::CRTTimingAnalysis::ResetTPCVariables() _tpc_crt_sp_dts1 = std::numeric_limits::lowest(); _tpc_crt_ts0_pmt_diff = std::numeric_limits::lowest(); _tpc_crt_ts1_pmt_diff = std::numeric_limits::lowest(); + + _tpc_crt_sp_tagger = std::numeric_limits::lowest(); + _tpc_crt_sp_timing_chain = std::numeric_limits::lowest(); + + _tpc_crt_sp_nhits = std::numeric_limits::lowest(); } DEFINE_ART_MODULE(sbnd::crt::CRTTimingAnalysis) From 7bc5dee871c6b1ea1dc6a4689cc405e50bdb2439 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Thu, 26 Feb 2026 04:11:49 -0600 Subject: [PATCH 141/155] More sensible default for uint --- sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc b/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc index a1bdf11bb..73846af9c 100644 --- a/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc +++ b/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc @@ -1014,8 +1014,8 @@ void sbnd::crt::CRTTimingAnalysis::ResetTrVariables() _tr_end_tagger = std::numeric_limits::lowest(); _tr_end_timing_chain = std::numeric_limits::lowest(); - _tr_start_nhits = std::numeric_limits::lowest(); - _tr_end_nhits = std::numeric_limits::lowest(); + _tr_start_nhits = std::numeric_limits::max(); + _tr_end_nhits = std::numeric_limits::max(); } @@ -1148,7 +1148,7 @@ void sbnd::crt::CRTTimingAnalysis::ResetTPCVariables() _tpc_crt_sp_tagger = std::numeric_limits::lowest(); _tpc_crt_sp_timing_chain = std::numeric_limits::lowest(); - _tpc_crt_sp_nhits = std::numeric_limits::lowest(); + _tpc_crt_sp_nhits = std::numeric_limits::max(); } DEFINE_ART_MODULE(sbnd::crt::CRTTimingAnalysis) From 44a0672f903903af59406a8ebc4be3f14abd71af Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Fri, 27 Feb 2026 04:54:01 -0600 Subject: [PATCH 142/155] Remove unnecessary tophat analysis module --- .../CRT/CRTAna/CRTTopHatAnalysis_module.cc | 821 ------------------ sbndcode/CRT/CRTAna/crttophatana_sbnd.fcl | 12 - sbndcode/CRT/CRTAna/run_crttophatana_data.fcl | 28 - 3 files changed, 861 deletions(-) delete mode 100644 sbndcode/CRT/CRTAna/CRTTopHatAnalysis_module.cc delete mode 100644 sbndcode/CRT/CRTAna/crttophatana_sbnd.fcl delete mode 100644 sbndcode/CRT/CRTAna/run_crttophatana_data.fcl diff --git a/sbndcode/CRT/CRTAna/CRTTopHatAnalysis_module.cc b/sbndcode/CRT/CRTAna/CRTTopHatAnalysis_module.cc deleted file mode 100644 index f338ce846..000000000 --- a/sbndcode/CRT/CRTAna/CRTTopHatAnalysis_module.cc +++ /dev/null @@ -1,821 +0,0 @@ -//////////////////////////////////////////////////////////////////////// -// Class: CRTTopHatAnalysis -// Plugin Type: analyzer -// File: CRTTopHatAnalysis_module.cc -// Author: Henry Lay (h.lay@sheffield.ac.uk) -//////////////////////////////////////////////////////////////////////// - -#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 "art_root_io/TFileService.h" -#include "canvas/Persistency/Common/FindManyP.h" - -#include "TTree.h" - -#include "lardataobj/AnalysisBase/T0.h" -#include "lardataobj/RecoBase/Track.h" -#include "lardataobj/RecoBase/PFParticle.h" -#include "lardataobj/RecoBase/PFParticleMetadata.h" - -#include "larsim/Utils/TruthMatchUtils.h" -#include "lardata/DetectorInfoServices/DetectorClocksService.h" - -#include "sbndaq-artdaq-core/Obj/SBND/pmtSoftwareTrigger.hh" - -#include "sbnobj/SBND/CRT/FEBData.hh" -#include "sbnobj/SBND/CRT/CRTStripHit.hh" -#include "sbnobj/SBND/CRT/CRTCluster.hh" -#include "sbnobj/SBND/CRT/CRTSpacePoint.hh" -#include "sbnobj/SBND/CRT/CRTTrack.hh" -#include "sbnobj/SBND/Timing/DAQTimestamp.hh" - -#include "sbndcode/Geometry/GeometryWrappers/CRTGeoService.h" -#include "sbndcode/Geometry/GeometryWrappers/TPCGeoAlg.h" -#include "sbndcode/CRT/CRTBackTracker/CRTBackTrackerAlg.h" -#include "sbndcode/CRT/CRTUtils/CRTCommonUtils.h" -#include "sbndcode/Decoders/PTB/sbndptb.h" -#include "sbndcode/Timing/SBNDRawTimingObj.h" - -namespace sbnd::crt { - class CRTTopHatAnalysis; -} - -class sbnd::crt::CRTTopHatAnalysis : public art::EDAnalyzer { -public: - explicit CRTTopHatAnalysis(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. - CRTTopHatAnalysis(CRTTopHatAnalysis const&) = delete; - CRTTopHatAnalysis(CRTTopHatAnalysis&&) = delete; - CRTTopHatAnalysis& operator=(CRTTopHatAnalysis const&) = delete; - CRTTopHatAnalysis& operator=(CRTTopHatAnalysis&&) = delete; - - // Required functions. - void analyze(art::Event const& e) override; - - void AnalysePTBs(std::vector> &PTBVec); - - void AnalyseTDCs(std::vector> &TDCVec); - - void SortReferencing(); - - void AnalyseCRTStripHits(const art::Event &e, const std::vector> &CRTStripHitVec); - - void AnalyseCRTClusters(const art::Event &e, const std::vector> &CRTClusterVec, - const art::FindManyP &clustersToSpacePoints); - - void AnalyseCRTTracks(const art::Event &e, const std::vector> &CRTTrackVec); - - void AnalysePMTSoftwareTriggers(const art::Event &e, const std::vector> &PMTSoftwareTriggerVec); - - -private: - - art::ServiceHandle fCRTGeoService; - TPCGeoAlg fTPCGeoAlg; - - std::string fCRTStripHitModuleLabel, fCRTClusterModuleLabel, fCRTSpacePointModuleLabel, - fCRTTrackModuleLabel, fPTBModuleLabel, fTDCModuleLabel, fTimingReferenceModuleLabel, - fPMTSoftwareTriggerModuleLabel; - bool fDebug, fCutT0, fSavePMTSoftwareTrigger; - double fMinT0, fMaxT0; - std::vector fAllowedPTBHLTs; - - TTree* fTree; - - // Tree variables - - int _run; - int _subrun; - int _event; - int _crt_timing_reference_type; - int _crt_timing_reference_channel; - - //strip hit to select the strip which has ADC above threshold - std::vector _sh_channel; - std::vector _sh_tagger; - std::vector _sh_ts0; - std::vector _sh_ts0_rwm_ref; - std::vector _sh_ts0_ptb_hlt_beam_gate_ref; - std::vector _sh_ts1; - std::vector _sh_ts1_rwm_ref; - std::vector _sh_ts1_ptb_hlt_beam_gate_ref; - std::vector _sh_unixs; - std::vector _sh_pos; - std::vector _sh_err; - std::vector _sh_adc1; - std::vector _sh_adc2; - std::vector _sh_saturated1; - std::vector _sh_saturated2; - std::vector _sh_truth_trackid; - std::vector _sh_truth_completeness; - std::vector _sh_truth_purity; - std::vector _sh_truth_pos; - std::vector _sh_truth_energy; - std::vector _sh_truth_time; - - //cluster from x-y coincidence for CRTSpacePoint - std::vector _cl_ts0; - std::vector _cl_ts0_rwm_ref; - std::vector _cl_ts0_ptb_hlt_beam_gate_ref; - std::vector _cl_ts1; - std::vector _cl_ts1_rwm_ref; - std::vector _cl_ts1_ptb_hlt_beam_gate_ref; - std::vector _cl_unixs; - std::vector _cl_nhits; - std::vector _cl_tagger; - std::vector _cl_composition; - std::vector _cl_has_sp; - std::vector _cl_sp_x; - std::vector _cl_sp_ex; - std::vector _cl_sp_y; - std::vector _cl_sp_ey; - std::vector _cl_sp_z; - std::vector _cl_sp_ez; - std::vector _cl_sp_pe; - std::vector _cl_sp_ts0; - std::vector _cl_sp_ts0_rwm_ref; - std::vector _cl_sp_ts0_ptb_hlt_beam_gate_ref; - std::vector _cl_sp_ets0; - std::vector _cl_sp_ts1; - std::vector _cl_sp_ts1_rwm_ref; - std::vector _cl_sp_ts1_ptb_hlt_beam_gate_ref; - std::vector _cl_sp_ets1; - std::vector _cl_sp_complete; - - //track level information - std::vector _tr_start_x; - std::vector _tr_start_y; - std::vector _tr_start_z; - std::vector _tr_end_x; - std::vector _tr_end_y; - std::vector _tr_end_z; - std::vector _tr_dir_x; - std::vector _tr_dir_y; - std::vector _tr_dir_z; - std::vector _tr_ts0; - std::vector _tr_ts0_rwm_ref; - std::vector _tr_ts0_ptb_hlt_beam_gate_ref; - std::vector _tr_ets0; - std::vector _tr_ts1; - std::vector _tr_ts1_rwm_ref; - std::vector _tr_ts1_ptb_hlt_beam_gate_ref; - std::vector _tr_ets1; - std::vector _tr_pe; - std::vector _tr_length; - std::vector _tr_tof; - std::vector _tr_theta; - std::vector _tr_phi; - std::vector _tr_triple; - std::vector _tr_tagger1; - std::vector _tr_tagger2; - std::vector _tr_tagger3; - - std::vector _ptb_hlt_trigger; - std::vector _ptb_hlt_timestamp; - - std::vector _ptb_llt_trigger; - std::vector _ptb_llt_timestamp; - - std::vector _tdc_channel; - std::vector _tdc_timestamp; - std::vector _tdc_offset; - std::vector _tdc_name; - - bool _etrig_good, _rwm_good, _ptb_hlt_beam_gate_good, _crt_t1_reset_good; - double _rwm_etrig_diff, _ptb_hlt_beam_gate_etrig_diff, _rwm_crt_t1_reset_diff, _ptb_hlt_beam_gate_crt_t1_reset_diff, - _rwm_ptb_hlt_beam_gate_diff; - - bool _pmt_st_found_trigger; - double _pmt_st_corrected_peak_time, _pmt_st_corrected_peak_time_rwm_ref; -}; - -sbnd::crt::CRTTopHatAnalysis::CRTTopHatAnalysis(fhicl::ParameterSet const& p) - : EDAnalyzer{p} -{ - fCRTStripHitModuleLabel = p.get("CRTStripHitModuleLabel", "crtstrips"); - fCRTClusterModuleLabel = p.get("CRTClusterModuleLabel", "crtclustering"); - fCRTSpacePointModuleLabel = p.get("CRTSpacePointModuleLabel", "crtspacepoints"); - fCRTTrackModuleLabel = p.get("CRTTrackModuleLabel", "crttracks"); - fPTBModuleLabel = p.get("PTBModuleLabel", "ptbdecoder"); - fTDCModuleLabel = p.get("TDCModuleLabel", "tdcdecoder"); - fTimingReferenceModuleLabel = p.get("TimingReferenceModuleLabel", "crtstrips"); - fPMTSoftwareTriggerModuleLabel = p.get("PMTSoftwareTriggerModuleLabel", "pmtmetricbnblight"); - fDebug = p.get("Debug", false); - fCutT0 = p.get("CutT0", false); - fSavePMTSoftwareTrigger = p.get("SavePMTSoftwareTrigger", false); - fMinT0 = p.get("MinT0", std::numeric_limits::min()); - fMaxT0 = p.get("MaxT0", std::numeric_limits::max()); - fAllowedPTBHLTs = p.get>("AllowedPTBHLTs", { 26, 27 }); - - art::ServiceHandle fs; - - fTree = fs->make("tree",""); - fTree->Branch("run", &_run); - fTree->Branch("subrun", &_subrun); - fTree->Branch("event", &_event); - fTree->Branch("crt_timing_reference_type", &_crt_timing_reference_type); - fTree->Branch("crt_timing_reference_channel", &_crt_timing_reference_channel); - - fTree->Branch("sh_channel", "std::vector", &_sh_channel); - fTree->Branch("sh_tagger", "std::vector", &_sh_tagger); - fTree->Branch("sh_ts0", "std::vector", &_sh_ts0); - fTree->Branch("sh_ts0_rwm_ref", "std::vector", &_sh_ts0_rwm_ref); - fTree->Branch("sh_ts0_ptb_hlt_beam_gate_ref", "std::vector", &_sh_ts0_ptb_hlt_beam_gate_ref); - fTree->Branch("sh_ts1", "std::vector", &_sh_ts1); - fTree->Branch("sh_ts1_rwm_ref", "std::vector", &_sh_ts1_rwm_ref); - fTree->Branch("sh_ts1_ptb_hlt_beam_gate_ref", "std::vector", &_sh_ts1_ptb_hlt_beam_gate_ref); - fTree->Branch("sh_unixs", "std::vector", &_sh_unixs); - fTree->Branch("sh_pos", "std::vector", &_sh_pos); - fTree->Branch("sh_err", "std::vector", &_sh_err); - fTree->Branch("sh_adc1", "std::vector", &_sh_adc1); - fTree->Branch("sh_adc2", "std::vector", &_sh_adc2); - fTree->Branch("sh_saturated1", "std::vector", &_sh_saturated1); - fTree->Branch("sh_saturated2", "std::vector", &_sh_saturated2); - - fTree->Branch("cl_ts0", "std::vector", &_cl_ts0); - fTree->Branch("cl_ts0_rwm_ref", "std::vector", &_cl_ts0_rwm_ref); - fTree->Branch("cl_ts0_ptb_hlt_beam_gate_ref", "std::vector", &_cl_ts0_ptb_hlt_beam_gate_ref); - fTree->Branch("cl_ts1", "std::vector", &_cl_ts1); - fTree->Branch("cl_ts1_rwm_ref", "std::vector", &_cl_ts1_rwm_ref); - fTree->Branch("cl_ts1_ptb_hlt_beam_gate_ref", "std::vector", &_cl_ts1_ptb_hlt_beam_gate_ref); - fTree->Branch("cl_unixs", "std::vector", &_cl_unixs); - fTree->Branch("cl_nhits", "std::vector", &_cl_nhits); - fTree->Branch("cl_tagger", "std::vector", &_cl_tagger); - fTree->Branch("cl_composition", "std::vector", &_cl_composition); - fTree->Branch("cl_has_sp", "std::vector", &_cl_has_sp); - fTree->Branch("cl_sp_x", "std::vector", &_cl_sp_x); - fTree->Branch("cl_sp_ex", "std::vector", &_cl_sp_ex); - fTree->Branch("cl_sp_y", "std::vector", &_cl_sp_y); - fTree->Branch("cl_sp_ey", "std::vector", &_cl_sp_ey); - fTree->Branch("cl_sp_z", "std::vector", &_cl_sp_z); - fTree->Branch("cl_sp_ez", "std::vector", &_cl_sp_ez); - fTree->Branch("cl_sp_pe", "std::vector", &_cl_sp_pe); - fTree->Branch("cl_sp_ts0", "std::vector", &_cl_sp_ts0); - fTree->Branch("cl_sp_ts0_rwm_ref", "std::vector", &_cl_sp_ts0_rwm_ref); - fTree->Branch("cl_sp_ts0_ptb_hlt_beam_gate_ref", "std::vector", &_cl_sp_ts0_ptb_hlt_beam_gate_ref); - fTree->Branch("cl_sp_ets0", "std::vector", &_cl_sp_ets0); - fTree->Branch("cl_sp_ts1", "std::vector", &_cl_sp_ts1); - fTree->Branch("cl_sp_ts1_rwm_ref", "std::vector", &_cl_sp_ts1_rwm_ref); - fTree->Branch("cl_sp_ts1_ptb_hlt_beam_gate_ref", "std::vector", &_cl_sp_ts1_ptb_hlt_beam_gate_ref); - fTree->Branch("cl_sp_ets1", "std::vector", &_cl_sp_ets1); - fTree->Branch("cl_sp_complete", "std::vector", &_cl_sp_complete); - - fTree->Branch("tr_start_x", "std::vector", &_tr_start_x); - fTree->Branch("tr_start_y", "std::vector", &_tr_start_y); - fTree->Branch("tr_start_z", "std::vector", &_tr_start_z); - fTree->Branch("tr_end_x", "std::vector", &_tr_end_x); - fTree->Branch("tr_end_y", "std::vector", &_tr_end_y); - fTree->Branch("tr_end_z", "std::vector", &_tr_end_z); - fTree->Branch("tr_dir_x", "std::vector", &_tr_dir_x); - fTree->Branch("tr_dir_y", "std::vector", &_tr_dir_y); - fTree->Branch("tr_dir_z", "std::vector", &_tr_dir_z); - fTree->Branch("tr_ts0", "std::vector", &_tr_ts0); - fTree->Branch("tr_ts0_rwm_ref", "std::vector", &_tr_ts0_rwm_ref); - fTree->Branch("tr_ts0_ptb_hlt_beam_gate_ref", "std::vector", &_tr_ts0_ptb_hlt_beam_gate_ref); - fTree->Branch("tr_ets0", "std::vector", &_tr_ets0); - fTree->Branch("tr_ts1", "std::vector", &_tr_ts1); - fTree->Branch("tr_ts1_rwm_ref", "std::vector", &_tr_ts1_rwm_ref); - fTree->Branch("tr_ts1_ptb_hlt_beam_gate_ref", "std::vector", &_tr_ts1_ptb_hlt_beam_gate_ref); - fTree->Branch("tr_ets1", "std::vector", &_tr_ets1); - fTree->Branch("tr_pe", "std::vector", &_tr_pe); - fTree->Branch("tr_length", "std::vector", &_tr_length); - fTree->Branch("tr_tof", "std::vector", &_tr_tof); - fTree->Branch("tr_theta", "std::vector", &_tr_theta); - fTree->Branch("tr_phi", "std::vector", &_tr_phi); - fTree->Branch("tr_triple", "std::vector", &_tr_triple); - fTree->Branch("tr_tagger1", "std::vector", &_tr_tagger1); - fTree->Branch("tr_tagger2", "std::vector", &_tr_tagger2); - fTree->Branch("tr_tagger3", "std::vector", &_tr_tagger3); - - fTree->Branch("ptb_hlt_trigger", "std::vector", &_ptb_hlt_trigger); - fTree->Branch("ptb_hlt_timestamp", "std::vector", &_ptb_hlt_timestamp); - fTree->Branch("ptb_llt_trigger", "std::vector", &_ptb_llt_trigger); - fTree->Branch("ptb_llt_timestamp", "std::vector", &_ptb_llt_timestamp); - - fTree->Branch("tdc_channel", "std::vector", &_tdc_channel); - fTree->Branch("tdc_timestamp", "std::vector", &_tdc_timestamp); - fTree->Branch("tdc_offset", "std::vector", &_tdc_offset); - fTree->Branch("tdc_name", "std::vector", &_tdc_name); - - fTree->Branch("etrig_good", &_etrig_good); - fTree->Branch("rwm_good", &_rwm_good); - fTree->Branch("ptb_hlt_beam_gate_good", &_ptb_hlt_beam_gate_good); - fTree->Branch("crt_t1_reset_good", &_crt_t1_reset_good); - fTree->Branch("rwm_etrig_diff", &_rwm_etrig_diff); - fTree->Branch("ptb_hlt_beam_gate_etrig_diff", &_ptb_hlt_beam_gate_etrig_diff); - fTree->Branch("rwm_crt_t1_reset_diff", &_rwm_crt_t1_reset_diff); - fTree->Branch("ptb_hlt_beam_gate_crt_t1_reset_diff", &_ptb_hlt_beam_gate_crt_t1_reset_diff); - fTree->Branch("rwm_ptb_hlt_beam_gate_diff", &_rwm_ptb_hlt_beam_gate_diff); - - if(fSavePMTSoftwareTrigger) - { - fTree->Branch("pmt_st_found_trigger", &_pmt_st_found_trigger); - fTree->Branch("pmt_st_corrected_peak_time", &_pmt_st_corrected_peak_time); - fTree->Branch("pmt_st_corrected_peak_time", &_pmt_st_corrected_peak_time); - fTree->Branch("pmt_st_corrected_peak_time_rwm_ref", &_pmt_st_corrected_peak_time_rwm_ref); - } -} - -void sbnd::crt::CRTTopHatAnalysis::analyze(art::Event const& e) -{ - _run = e.id().run(); - _subrun = e.id().subRun(); - _event = e.id().event(); - - _crt_timing_reference_type = -1; - _crt_timing_reference_channel = -1; - - art::Handle TimingReferenceHandle; - e.getByLabel(fTimingReferenceModuleLabel, TimingReferenceHandle); - if(TimingReferenceHandle.isValid()) - { - _crt_timing_reference_type = TimingReferenceHandle->timingType; - _crt_timing_reference_channel = TimingReferenceHandle->timingChannel; - } - - // Get PTBs - art::Handle> PTBHandle; - e.getByLabel(fPTBModuleLabel, PTBHandle); - if(!PTBHandle.isValid()){ - std::cout << "PTB product " << fPTBModuleLabel << " not found..." << std::endl; - throw std::exception(); - } - std::vector> PTBVec; - art::fill_ptr_vector(PTBVec, PTBHandle); - - // Fill PTB variables - AnalysePTBs(PTBVec); - - // Get TDCs - art::Handle> TDCHandle; - e.getByLabel(fTDCModuleLabel, TDCHandle); - if(!TDCHandle.isValid()){ - std::cout << "TDC product " << fTDCModuleLabel << " not found..." << std::endl; - throw std::exception(); - } - std::vector> TDCVec; - art::fill_ptr_vector(TDCVec, TDCHandle); - - // Fill TDC variables - AnalyseTDCs(TDCVec); - - SortReferencing(); - - // Get CRTStripHits - art::Handle> CRTStripHitHandle; - e.getByLabel(fCRTStripHitModuleLabel, CRTStripHitHandle); - if(!CRTStripHitHandle.isValid()){ - std::cout << "CRTStripHit product " << fCRTStripHitModuleLabel << " not found..." << std::endl; - throw std::exception(); - } - std::vector> CRTStripHitVec; - art::fill_ptr_vector(CRTStripHitVec, CRTStripHitHandle); - - // Fill CRTStripHit variables - AnalyseCRTStripHits(e, CRTStripHitVec); - - // Get CRTClusters - art::Handle> CRTClusterHandle; - e.getByLabel(fCRTClusterModuleLabel, CRTClusterHandle); - if(!CRTClusterHandle.isValid()){ - std::cout << "CRTCluster product " << fCRTClusterModuleLabel << " not found..." << std::endl; - throw std::exception(); - } - std::vector> CRTClusterVec; - art::fill_ptr_vector(CRTClusterVec, CRTClusterHandle); - - // Get CRTCluster to CRTSpacePoint Assns - art::FindManyP clustersToSpacePoints(CRTClusterHandle, e, fCRTSpacePointModuleLabel); - - // Fill CRTCluster variables - AnalyseCRTClusters(e, CRTClusterVec, clustersToSpacePoints); - - // Get CRTTracks - art::Handle> CRTTrackHandle; - e.getByLabel(fCRTTrackModuleLabel, CRTTrackHandle); - if(!CRTTrackHandle.isValid()){ - std::cout << "CRTTrack product " << fCRTTrackModuleLabel << " not found..." << std::endl; - throw std::exception(); - } - std::vector> CRTTrackVec; - art::fill_ptr_vector(CRTTrackVec, CRTTrackHandle); - - // Fill CRTTrack variables - AnalyseCRTTracks(e, CRTTrackVec); - - if(fSavePMTSoftwareTrigger) - { - // Get PMTSoftwareTriggers - art::Handle> PMTSoftwareTriggerHandle; - e.getByLabel(fPMTSoftwareTriggerModuleLabel, PMTSoftwareTriggerHandle); - if(!PMTSoftwareTriggerHandle.isValid()){ - std::cout << "PMTSoftwareTrigger product " << fPMTSoftwareTriggerModuleLabel << " not found..." << std::endl; - throw std::exception(); - } - std::vector> PMTSoftwareTriggerVec; - art::fill_ptr_vector(PMTSoftwareTriggerVec, PMTSoftwareTriggerHandle); - - // Fill PMTSoftwareTrigger variables - AnalysePMTSoftwareTriggers(e, PMTSoftwareTriggerVec); - } - - fTree->Fill(); -} - -void sbnd::crt::CRTTopHatAnalysis::AnalysePTBs(std::vector> &PTBVec) -{ - unsigned nHLTs = 0; - - for(auto const& ptb : PTBVec) - nHLTs += ptb->GetNHLTriggers(); - - _ptb_hlt_trigger.resize(nHLTs); - _ptb_hlt_timestamp.resize(nHLTs); - - unsigned hlt_i = 0; - - for(auto const& ptb : PTBVec) - { - for(unsigned i = 0; i < ptb->GetNHLTriggers(); ++i) - { - _ptb_hlt_trigger[hlt_i] = ptb->GetHLTrigger(i).trigger_word; - _ptb_hlt_timestamp[hlt_i] = ptb->GetHLTrigger(i).timestamp * 20; - - ++hlt_i; - } - } - - unsigned nLLTs = 0; - - for(auto const& ptb : PTBVec) - nLLTs += ptb->GetNLLTriggers(); - - _ptb_llt_trigger.resize(nLLTs); - _ptb_llt_timestamp.resize(nLLTs); - - unsigned llt_i = 0; - - for(auto const& ptb : PTBVec) - { - for(unsigned i = 0; i < ptb->GetNLLTriggers(); ++i) - { - _ptb_llt_trigger[llt_i] = ptb->GetLLTrigger(i).trigger_word; - _ptb_llt_timestamp[llt_i] = ptb->GetLLTrigger(i).timestamp * 20; - - ++llt_i; - } - } -} - -void sbnd::crt::CRTTopHatAnalysis::AnalyseTDCs(std::vector> &TDCVec) -{ - const unsigned nTDCs = TDCVec.size(); - - _tdc_channel.resize(nTDCs); - _tdc_timestamp.resize(nTDCs); - _tdc_offset.resize(nTDCs); - _tdc_name.resize(nTDCs); - - unsigned tdc_i = 0; - - for(auto const& tdc : TDCVec) - { - _tdc_channel[tdc_i] = tdc->Channel(); - _tdc_timestamp[tdc_i] = tdc->Timestamp(); - _tdc_offset[tdc_i] = tdc->Offset(); - _tdc_name[tdc_i] = tdc->Name(); - - ++tdc_i; - } -} - -void sbnd::crt::CRTTopHatAnalysis::SortReferencing() -{ - _etrig_good = false; _rwm_good = false; _ptb_hlt_beam_gate_good = false; _crt_t1_reset_good = false; - _rwm_etrig_diff = std::numeric_limits::max(); _ptb_hlt_beam_gate_etrig_diff = std::numeric_limits::max(); - _rwm_crt_t1_reset_diff = std::numeric_limits::max(); _ptb_hlt_beam_gate_crt_t1_reset_diff = std::numeric_limits::max(); - _rwm_ptb_hlt_beam_gate_diff = std::numeric_limits::max(); - - int etrig_count = 0, etrig_id = -1, rwm_count = 0, rwm_id = -1, crt_t1_reset_count = 0, crt_t1_reset_id = -1; - - for(unsigned int tdc_i = 0; tdc_i < _tdc_channel.size(); ++tdc_i) - { - if(_tdc_channel[tdc_i] == 4) - { - ++etrig_count; - etrig_id = tdc_i; - } - else if(_tdc_channel[tdc_i] == 2) - { - ++rwm_count; - rwm_id = tdc_i; - } - else if(_tdc_channel[tdc_i] == 0) - { - ++crt_t1_reset_count; - crt_t1_reset_id = tdc_i; - } - } - - uint64_t etrig = std::numeric_limits::max(), rwm = std::numeric_limits::max(), - hlt = std::numeric_limits::max(), crt_t1_reset = std::numeric_limits::max(); - - if(etrig_count == 1) - { - _etrig_good = true; - etrig = _tdc_timestamp[etrig_id]; - } - - if(rwm_count == 1) - { - _rwm_good = true; - rwm = _tdc_timestamp[rwm_id]; - } - - if(etrig_count == 1) - { - double closest_diff = std::numeric_limits::max(); - - for(unsigned int ptb_i = 0; ptb_i < _ptb_hlt_trigger.size(); ++ptb_i) - { - std::bitset<32> hlt_bitmask = std::bitset<32>(_ptb_hlt_trigger[ptb_i]); - - for(uint32_t allowed_hlt : fAllowedPTBHLTs) - { - if(hlt_bitmask[allowed_hlt]) - { - _ptb_hlt_beam_gate_good = true; - - uint64_t temp_hlt = _ptb_hlt_timestamp[ptb_i]; - double diff = etrig > temp_hlt ? etrig - temp_hlt : -1. * (temp_hlt - etrig); - - if(std::abs(diff) < closest_diff) - { - closest_diff = diff; - hlt = temp_hlt; - } - } - } - } - } - - if(crt_t1_reset_count == 1) - { - _crt_t1_reset_good = true; - crt_t1_reset = _tdc_timestamp[crt_t1_reset_id]; - } - - if(_etrig_good && _rwm_good) - _rwm_etrig_diff = etrig > rwm ? etrig - rwm : -1. * (rwm - etrig); - - if(_etrig_good && _ptb_hlt_beam_gate_good) - _ptb_hlt_beam_gate_etrig_diff = etrig > hlt ? etrig - hlt : -1. * (hlt - etrig); - - if(_crt_t1_reset_good && _rwm_good) - _rwm_crt_t1_reset_diff = crt_t1_reset > rwm ? crt_t1_reset - rwm : -1. * (rwm - crt_t1_reset); - - if(_etrig_good && _crt_t1_reset_good && _ptb_hlt_beam_gate_good) - _ptb_hlt_beam_gate_crt_t1_reset_diff = crt_t1_reset > hlt ? crt_t1_reset - hlt : -1. * (hlt - crt_t1_reset); - - if(_etrig_good && _rwm_good && _ptb_hlt_beam_gate_good) - _rwm_ptb_hlt_beam_gate_diff = hlt > rwm ? hlt - rwm : -1. * (rwm - hlt); -} - -void sbnd::crt::CRTTopHatAnalysis::AnalyseCRTStripHits(const art::Event &e, const std::vector> &CRTStripHitVec) -{ - _sh_channel.clear(); - _sh_tagger.clear(); - _sh_ts0.clear(); - _sh_ts0_rwm_ref.clear(); - _sh_ts0_ptb_hlt_beam_gate_ref.clear(); - _sh_ts1.clear(); - _sh_ts1_rwm_ref.clear(); - _sh_ts1_ptb_hlt_beam_gate_ref.clear(); - _sh_unixs.clear(); - _sh_pos.clear(); - _sh_err.clear(); - _sh_adc1.clear(); - _sh_adc2.clear(); - _sh_saturated1.clear(); - _sh_saturated2.clear(); - - for(auto const &hit : CRTStripHitVec) - { - if(fCutT0 && (hit->Ts0() < fMinT0 || hit->Ts0() > fMaxT0)) - continue; - - _sh_channel.push_back(hit->Channel()); - _sh_tagger.push_back(fCRTGeoService->ChannelToTaggerEnum(hit->Channel())); - _sh_ts0.push_back(hit->Ts0()); - _sh_ts0_rwm_ref.push_back(hit->Ts0() + _rwm_etrig_diff); - _sh_ts0_ptb_hlt_beam_gate_ref.push_back(hit->Ts0() + _ptb_hlt_beam_gate_etrig_diff); - _sh_ts1.push_back(hit->Ts1()); - _sh_ts1_rwm_ref.push_back(hit->Ts1() + _rwm_crt_t1_reset_diff); - _sh_ts1_ptb_hlt_beam_gate_ref.push_back(hit->Ts1() + _ptb_hlt_beam_gate_crt_t1_reset_diff); - _sh_unixs.push_back(hit->UnixS()); - _sh_pos.push_back(hit->Pos()); - _sh_err.push_back(hit->Error()); - _sh_adc1.push_back(hit->ADC1()); - _sh_adc2.push_back(hit->ADC2()); - _sh_saturated1.push_back(hit->Saturated1()); - _sh_saturated2.push_back(hit->Saturated2()); - } -} - -void sbnd::crt::CRTTopHatAnalysis::AnalyseCRTClusters(const art::Event &e, const std::vector> &CRTClusterVec, - const art::FindManyP &clustersToSpacePoints) -{ - _cl_ts0.clear(); - _cl_ts0_rwm_ref.clear(); - _cl_ts0_ptb_hlt_beam_gate_ref.clear(); - _cl_ts1.clear(); - _cl_ts1_rwm_ref.clear(); - _cl_ts1_ptb_hlt_beam_gate_ref.clear(); - _cl_unixs.clear(); - _cl_nhits.clear(); - _cl_tagger.clear(); - _cl_composition.clear(); - _cl_has_sp.clear(); - _cl_sp_x.clear(); - _cl_sp_ex.clear(); - _cl_sp_y.clear(); - _cl_sp_ey.clear(); - _cl_sp_z.clear(); - _cl_sp_ez.clear(); - _cl_sp_pe.clear(); - _cl_sp_ts0.clear(); - _cl_sp_ts0_rwm_ref.clear(); - _cl_sp_ts0_ptb_hlt_beam_gate_ref.clear(); - _cl_sp_ets0.clear(); - _cl_sp_ts1.clear(); - _cl_sp_ts1_rwm_ref.clear(); - _cl_sp_ts1_ptb_hlt_beam_gate_ref.clear(); - _cl_sp_ets1.clear(); - _cl_sp_complete.clear(); - - for(auto const &cluster : CRTClusterVec) - { - if(fCutT0 && (cluster->Ts0() < fMinT0 || cluster->Ts0() > fMaxT0)) - continue; - - _cl_ts0.push_back(cluster->Ts0()); - _cl_ts0_rwm_ref.push_back(cluster->Ts0() + _rwm_etrig_diff); - _cl_ts0_ptb_hlt_beam_gate_ref.push_back(cluster->Ts0() + _ptb_hlt_beam_gate_etrig_diff); - _cl_ts1.push_back(cluster->Ts1()); - _cl_ts1_rwm_ref.push_back(cluster->Ts1() + _rwm_crt_t1_reset_diff); - _cl_ts1_ptb_hlt_beam_gate_ref.push_back(cluster->Ts1() + _ptb_hlt_beam_gate_crt_t1_reset_diff); - _cl_unixs.push_back(cluster->UnixS()); - _cl_nhits.push_back(cluster->NHits()); - _cl_tagger.push_back(cluster->Tagger()); - _cl_composition.push_back(cluster->Composition()); - - const auto spacepoints = clustersToSpacePoints.at(cluster.key()); - if(spacepoints.size() == 1) - { - const auto spacepoint = spacepoints[0]; - - _cl_has_sp.push_back(true); - _cl_sp_x.push_back(spacepoint->X()); - _cl_sp_ex.push_back(spacepoint->XErr()); - _cl_sp_y.push_back(spacepoint->Y()); - _cl_sp_ey.push_back(spacepoint->YErr()); - _cl_sp_z.push_back(spacepoint->Z()); - _cl_sp_ez.push_back(spacepoint->ZErr()); - _cl_sp_pe.push_back(spacepoint->PE()); - _cl_sp_ts0.push_back(spacepoint->Ts0()); - _cl_sp_ts0_rwm_ref.push_back(spacepoint->Ts0() + _rwm_etrig_diff); - _cl_sp_ts0_ptb_hlt_beam_gate_ref.push_back(spacepoint->Ts0() + _ptb_hlt_beam_gate_etrig_diff); - _cl_sp_ets0.push_back(spacepoint->Ts0Err()); - _cl_sp_ts1.push_back(spacepoint->Ts1()); - _cl_sp_ts1_rwm_ref.push_back(spacepoint->Ts1() + _rwm_crt_t1_reset_diff); - _cl_sp_ts1_ptb_hlt_beam_gate_ref.push_back(spacepoint->Ts1() + _ptb_hlt_beam_gate_crt_t1_reset_diff); - _cl_sp_ets1.push_back(spacepoint->Ts1Err()); - _cl_sp_complete.push_back(spacepoint->Complete()); - } - else - { - _cl_has_sp.push_back(false); - _cl_sp_x.push_back(-999999.); - _cl_sp_ex.push_back(-999999.); - _cl_sp_y.push_back(-999999.); - _cl_sp_ey.push_back(-999999.); - _cl_sp_z.push_back(-999999.); - _cl_sp_ez.push_back(-999999.); - _cl_sp_pe.push_back(-999999.); - _cl_sp_ts0.push_back(-999999.); - _cl_sp_ts0_rwm_ref.push_back(-999999.); - _cl_sp_ts0_ptb_hlt_beam_gate_ref.push_back(-999999.); - _cl_sp_ets0.push_back(-999999.); - _cl_sp_ts1.push_back(-999999.); - _cl_sp_ts1_rwm_ref.push_back(-999999.); - _cl_sp_ts1_ptb_hlt_beam_gate_ref.push_back(-999999.); - _cl_sp_ets1.push_back(-999999.); - _cl_sp_complete.push_back(false); - } - } -} -void sbnd::crt::CRTTopHatAnalysis::AnalyseCRTTracks(const art::Event &e, const std::vector> &CRTTrackVec) -{ - _tr_start_x.clear(); - _tr_start_y.clear(); - _tr_start_z.clear(); - _tr_end_x.clear(); - _tr_end_y.clear(); - _tr_end_z.clear(); - _tr_dir_x.clear(); - _tr_dir_y.clear(); - _tr_dir_z.clear(); - _tr_ts0.clear(); - _tr_ts0_rwm_ref.clear(); - _tr_ts0_ptb_hlt_beam_gate_ref.clear(); - _tr_ets0.clear(); - _tr_ts1.clear(); - _tr_ts1_rwm_ref.clear(); - _tr_ts1_ptb_hlt_beam_gate_ref.clear(); - _tr_ets1.clear(); - _tr_pe.clear(); - _tr_length.clear(); - _tr_tof.clear(); - _tr_theta.clear(); - _tr_phi.clear(); - _tr_triple.clear(); - _tr_tagger1.clear(); - _tr_tagger2.clear(); - _tr_tagger3.clear(); - - for(auto const& track : CRTTrackVec) - { - if(fCutT0 && (track->Ts0() < fMinT0 || track->Ts0() > fMaxT0)) - continue; - - const geo::Point_t start = track->Start(); - _tr_start_x.push_back(start.X()); - _tr_start_y.push_back(start.Y()); - _tr_start_z.push_back(start.Z()); - - const geo::Point_t end = track->End(); - _tr_end_x.push_back(end.X()); - _tr_end_y.push_back(end.Y()); - _tr_end_z.push_back(end.Z()); - - const geo::Vector_t dir = track->Direction(); - _tr_dir_x.push_back(dir.X()); - _tr_dir_y.push_back(dir.Y()); - _tr_dir_z.push_back(dir.Z()); - - _tr_ts0.push_back(track->Ts0()); - _tr_ts0_rwm_ref.push_back(track->Ts0() + _rwm_etrig_diff); - _tr_ts0_ptb_hlt_beam_gate_ref.push_back(track->Ts0() + _ptb_hlt_beam_gate_etrig_diff); - _tr_ets0.push_back(track->Ts0Err()); - _tr_ts1.push_back(track->Ts1()); - _tr_ts1_rwm_ref.push_back(track->Ts1() + _rwm_crt_t1_reset_diff); - _tr_ts1_ptb_hlt_beam_gate_ref.push_back(track->Ts1() + _ptb_hlt_beam_gate_crt_t1_reset_diff); - _tr_ets1.push_back(track->Ts1Err()); - _tr_pe.push_back(track->PE()); - _tr_length.push_back(track->Length()); - _tr_tof.push_back(track->ToF()); - _tr_theta.push_back(TMath::RadToDeg() * track->Theta()); - _tr_phi.push_back(TMath::RadToDeg() * track->Phi()); - _tr_triple.push_back(track->Triple()); - - unsigned tag_i = 0; - - for(auto const &tagger : track->Taggers()) - { - if(tag_i == 0) - _tr_tagger1.push_back(tagger); - else if(tag_i == 1) - _tr_tagger2.push_back(tagger); - else if(tag_i == 2) - _tr_tagger3.push_back(tagger); - - ++tag_i; - } - } -} - -void sbnd::crt::CRTTopHatAnalysis::AnalysePMTSoftwareTriggers(const art::Event &e, const std::vector> &PMTSoftwareTriggerVec) -{ - _pmt_st_found_trigger = false; - _pmt_st_corrected_peak_time = std::numeric_limits::lowest(); - _pmt_st_corrected_peak_time_rwm_ref = std::numeric_limits::lowest(); - - if(PMTSoftwareTriggerVec.size() != 1) - return; - - _pmt_st_found_trigger = PMTSoftwareTriggerVec[0]->foundBeamTrigger; - _pmt_st_corrected_peak_time = PMTSoftwareTriggerVec[0]->peaktime*1e3 + PMTSoftwareTriggerVec[0]->trig_ts; - _pmt_st_corrected_peak_time_rwm_ref = _pmt_st_corrected_peak_time + _rwm_ptb_hlt_beam_gate_diff; -} - -DEFINE_ART_MODULE(sbnd::crt::CRTTopHatAnalysis) diff --git a/sbndcode/CRT/CRTAna/crttophatana_sbnd.fcl b/sbndcode/CRT/CRTAna/crttophatana_sbnd.fcl deleted file mode 100644 index a82b14e43..000000000 --- a/sbndcode/CRT/CRTAna/crttophatana_sbnd.fcl +++ /dev/null @@ -1,12 +0,0 @@ -BEGIN_PROLOG - -crttophatana_data_sbnd: -{ - module_type: "CRTTopHatAnalysis" - CutT0: true - MinT0: -50000 - MaxT0: 50000 - SavePMTSoftwareTrigger: true -} - -END_PROLOG diff --git a/sbndcode/CRT/CRTAna/run_crttophatana_data.fcl b/sbndcode/CRT/CRTAna/run_crttophatana_data.fcl deleted file mode 100644 index cce367369..000000000 --- a/sbndcode/CRT/CRTAna/run_crttophatana_data.fcl +++ /dev/null @@ -1,28 +0,0 @@ -#include "services_sbnd.fcl" -#include "crt_services_sbnd.fcl" -#include "crttophatana_sbnd.fcl" - -process_name: CRTTopHatAna - -services: -{ - TFileService: { fileName: "crttophatana_sbnd.root" } - @table::sbnd_basic_services - @table::crt_services_data_sbnd -} - -source: -{ - module_type: RootInput -} - -physics: -{ - analyzers: - { - crttophatana: @local::crttophatana_data_sbnd - } - - ana: [ crttophatana ] - end_paths: [ ana ] -} From cb47ee9171633c83ae098ccb6694115edfa91bce Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Fri, 27 Feb 2026 05:32:58 -0600 Subject: [PATCH 143/155] Remove reference to my data area --- sbndcode/CRT/CRTAna/adrift_sbnd.fcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbndcode/CRT/CRTAna/adrift_sbnd.fcl b/sbndcode/CRT/CRTAna/adrift_sbnd.fcl index 0be839450..8113032ed 100644 --- a/sbndcode/CRT/CRTAna/adrift_sbnd.fcl +++ b/sbndcode/CRT/CRTAna/adrift_sbnd.fcl @@ -10,7 +10,7 @@ adrift_data_sbnd: CRTTrackModuleLabel: "crttracks" DAQHeaderModuleLabel: "daq" DAQHeaderInstanceLabel: "RawEventHeader" - TopSaveDirectory: "/exp/sbnd/data/users/hlay/crt_comm_summer_2024/plots/adrift" + TopSaveDirectory: "/ENTER/YOUR/SAVE/DIRECTORY/HERE" Only2HitSpacePoints: false SaveAllFits: false SaveBadFits: false From bdf38e4bdde296074246f68ec0f6189ac1a637b9 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Fri, 27 Feb 2026 05:44:38 -0600 Subject: [PATCH 144/155] Reduce code duplication --- sbndcode/CRT/CRTAna/CRTAnalysis_module.cc | 42 ++++++----------------- sbndcode/CRT/CRTAna/crtana_sbnd.fcl | 24 ++++++------- 2 files changed, 22 insertions(+), 44 deletions(-) diff --git a/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc b/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc index 08b1f8202..4849708f2 100644 --- a/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc +++ b/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc @@ -37,13 +37,13 @@ #include "sbnobj/SBND/Timing/DAQTimestamp.hh" #include "sbndcode/Geometry/GeometryWrappers/CRTGeoService.h" -#include "sbndcode/Geometry/GeometryWrappers/TPCGeoAlg.h" #include "sbndcode/ChannelMaps/CRT/CRTChannelMapService.h" #include "sbndcode/CRT/CRTBackTracker/CRTBackTrackerAlg.h" #include "sbndcode/CRT/CRTUtils/CRTCommonUtils.h" #include "sbndcode/CRT/CRTUtils/TPCGeoUtil.h" #include "sbndcode/Decoders/PTB/sbndptb.h" #include "sbndcode/Timing/SBNDRawTimingObj.h" +#include "sbndcode/CRT/CRTReco/CRTClusterCharacterisationAlg.h" namespace sbnd::crt { class CRTAnalysis; @@ -103,16 +103,14 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { art::ServiceHandle fCRTGeoService; art::ServiceHandle fCRTChannelMapService; - TPCGeoAlg fTPCGeoAlg; - CRTBackTrackerAlg fCRTBackTrackerAlg; + CRTBackTrackerAlg fCRTBackTrackerAlg; + CRTClusterCharacterisationAlg fCRTClusterCharacAlg; std::string fMCParticleModuleLabel, fSimDepositModuleLabel, fFEBDataModuleLabel, fCRTStripHitModuleLabel, fCRTClusterModuleLabel, fCRTSpacePointModuleLabel, fCRTTrackModuleLabel, fCRTBlobModuleLabel, fTPCTrackModuleLabel, fCRTSpacePointMatchingModuleLabel, fCRTTrackMatchingModuleLabel, fPFPModuleLabel, fPTBModuleLabel, fTDCModuleLabel, fTimingReferenceModuleLabel; bool fDebug, fDataMode, fNoTPC, fHasPTB, fHasTDC, fHasBlobs, fTruthMatch; - //! Adding some of the reco parameters to save corrections - double fPEAttenuation, fTimeWalkNorm, fTimeWalkScale, fPropDelay; TTree* fTree; @@ -197,11 +195,11 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { std::vector _cl_composition; std::vector> _cl_channel_set; std::vector> _cl_adc_set; - std::vector> _cl_sh_ts0_set; //! To store t0 from x-y coincidences - std::vector> _cl_sh_ts1_set; //! To store t1 from x-y coincidences - std::vector> _cl_sh_feb_mac5_set; //! MAC5 addresses of StripHit FEBs - std::vector> _cl_sh_time_walk_set; //! Time walk correction - std::vector> _cl_sh_prop_delay_set; //! Light propagation correction + std::vector> _cl_sh_ts0_set; + std::vector> _cl_sh_ts1_set; + std::vector> _cl_sh_feb_mac5_set; + std::vector> _cl_sh_time_walk_set; + std::vector> _cl_sh_prop_delay_set; std::vector _cl_truth_trackid; std::vector _cl_truth_completeness; std::vector _cl_truth_purity; @@ -372,6 +370,7 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { sbnd::crt::CRTAnalysis::CRTAnalysis(fhicl::ParameterSet const& p) : EDAnalyzer{p} , fCRTBackTrackerAlg(p.get("CRTBackTrackerAlg", fhicl::ParameterSet())) + , fCRTClusterCharacAlg(p.get("CRTClusterCharacterisationAlg", fhicl::ParameterSet())) { fMCParticleModuleLabel = p.get("MCParticleModuleLabel", "largeant"); fSimDepositModuleLabel = p.get("SimDepositModuleLabel", "genericcrt"); @@ -395,10 +394,6 @@ sbnd::crt::CRTAnalysis::CRTAnalysis(fhicl::ParameterSet const& p) fHasTDC = p.get("HasTDC", false); fHasBlobs = p.get("HasBlobs", false); fTruthMatch = p.get("TruthMatch", true); - fPEAttenuation = p.get("PEAttenuation", 1.0); - fTimeWalkNorm = p.get("TimeWalkNorm", 0.0); - fTimeWalkScale = p.get("TimeWalkScale", 0.0); - fPropDelay = p.get("PropDelay", 0.0); if(!fDataMode && fTruthMatch) fCRTBackTrackerAlg = CRTBackTrackerAlg(p.get("CRTBackTrackerAlg", fhicl::ParameterSet())); @@ -1328,25 +1323,10 @@ void sbnd::crt::CRTAnalysis::AnalyseCRTClusters(const art::Event &e, const std:: _cl_sh_ts1_set[i][ii] = striphit->Ts1(); _cl_sh_feb_mac5_set[i][ii] = fCRTChannelMapService->GetMAC5FromOfflineChannelID(striphit->Channel()); - /* - * The below segment reimplements the CorrectTime() method - * from CRTReco/CRTClusterCharacterisationAlg.cc . - * Because the Ts0(), Ts1() getters invoked in _cl_sp_ts*, _cl_sh_ts*_set are raw T0/1 - * counters, the time walk and propagation delay are saved as explicit branches here. - */ if(spacepoints.size() == 1) { - double pe0 = fCRTGeoService->GetSiPM( striphit->Channel() ).gain * striphit->ADC1(); - double pe1 = fCRTGeoService->GetSiPM( striphit->Channel() + 1 ).gain * striphit->ADC2(); - double pe = pe0 + pe1; - - double dist = fCRTGeoService->DistanceDownStrip( spacepoints[0]->Pos(), striphit->Channel() ); - - double corr = std::pow( dist - fPEAttenuation, 2.0 ) / std::pow( fPEAttenuation, 2.0 ); - double tw_pe = pe * corr; - - _cl_sh_time_walk_set[i][ii] = fTimeWalkNorm * std::exp( -fTimeWalkScale * tw_pe ); - _cl_sh_prop_delay_set[i][ii] = fPropDelay * dist; + _cl_sh_time_walk_set[i][ii] = fCRTClusterCharacAlg.TimeWalk(striphit, spacepoints[0]->Pos()); + _cl_sh_prop_delay_set[i][ii] = fCRTClusterCharacAlg.PropagationDelay(striphit, spacepoints[0]->Pos()); ts0_set.push_back({_cl_sh_feb_mac5_set[i][ii], _cl_sh_ts0_set[i][ii] - _cl_sh_time_walk_set[i][ii] - _cl_sh_prop_delay_set[i][ii]}); ts1_set.push_back({_cl_sh_feb_mac5_set[i][ii], _cl_sh_ts1_set[i][ii] - _cl_sh_time_walk_set[i][ii] - _cl_sh_prop_delay_set[i][ii]}); diff --git a/sbndcode/CRT/CRTAna/crtana_sbnd.fcl b/sbndcode/CRT/CRTAna/crtana_sbnd.fcl index 1ab588870..f319bc4df 100644 --- a/sbndcode/CRT/CRTAna/crtana_sbnd.fcl +++ b/sbndcode/CRT/CRTAna/crtana_sbnd.fcl @@ -1,24 +1,22 @@ #include "crtbacktrackeralg_sbnd.fcl" -#include "crtsimmodules_sbnd.fcl" +#include "crtrecoproducers_sbnd.fcl" BEGIN_PROLOG crtana_sbnd: { - CRTBackTrackerAlg: @local::crtbacktrackeralg_sbnd - PEAttenuation: @local::sbnd_crtsim.DetSimParams.NpeScaleShift - PropDelay: @local::sbnd_crtsim.DetSimParams.PropDelay - TimeWalkNorm: @local::sbnd_crtsim.DetSimParams.TDelayNorm - TimeWalkScale: @local::sbnd_crtsim.DetSimParams.TDelayScale - TruthMatch: false - module_type: "CRTAnalysis" + CRTBackTrackerAlg: @local::crtbacktrackeralg_sbnd + CRTClusterCharacterisationAlg: @local::crtclustercharacterisationalg_sbnd + TruthMatch: false + module_type: "CRTAnalysis" } crtana_data_sbnd: @local::crtana_sbnd -crtana_data_sbnd.FEBDataModuleLabel: "crtdecoder" -crtana_data_sbnd.DataMode: true -crtana_data_sbnd.NoTPC: false -crtana_data_sbnd.HasPTB: true -crtana_data_sbnd.HasTDC: true +crtana_data_sbnd.FEBDataModuleLabel: "crtdecoder" +crtana_data_sbnd.DataMode: true +crtana_data_sbnd.NoTPC: false +crtana_data_sbnd.HasPTB: true +crtana_data_sbnd.HasTDC: true +crtana_data_sbnd.CRTClusterCharacterisationAlg: @local::crtclustercharacterisationalg_data_sbnd END_PROLOG From 8efaff2023309dda9eee806bbcfdb64b12df2cda Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Fri, 27 Feb 2026 05:56:51 -0600 Subject: [PATCH 145/155] Correct some very old naming problems --- sbndcode/CRT/CRTReco/CRTClusterCharacterisationAlg.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sbndcode/CRT/CRTReco/CRTClusterCharacterisationAlg.h b/sbndcode/CRT/CRTReco/CRTClusterCharacterisationAlg.h index 373d47ed7..97b3133f7 100644 --- a/sbndcode/CRT/CRTReco/CRTClusterCharacterisationAlg.h +++ b/sbndcode/CRT/CRTReco/CRTClusterCharacterisationAlg.h @@ -1,10 +1,9 @@ -#ifndef CRTBACKTRACKERALG_H_SEEN -#define CRTBACKTRACKERALG_H_SEEN +#ifndef CRTCLUSTERCHARACTERISATIONALG_H_SEEN +#define CRTCLUSTERCHARACTERISATIONALG_H_SEEN /////////////////////////////////////////////// // CRTClusterCharacterisationAlg.h // -// Truth Matching Utilities for CRT analysis // Henry Lay (h.lay@lancaster.ac.uk) // November 2022 /////////////////////////////////////////////// From 076fc35a786403595db0e3aacc41c4cbdba03c38 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Tue, 3 Mar 2026 07:25:01 -0600 Subject: [PATCH 146/155] Add rate for tracks of limited angle --- sbndcode/CRT/CRTAna/ADRIFT_module.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sbndcode/CRT/CRTAna/ADRIFT_module.cc b/sbndcode/CRT/CRTAna/ADRIFT_module.cc index 01727c94a..8725c472d 100644 --- a/sbndcode/CRT/CRTAna/ADRIFT_module.cc +++ b/sbndcode/CRT/CRTAna/ADRIFT_module.cc @@ -117,7 +117,7 @@ class sbnd::crt::ADRIFT : public art::EDAnalyzer { uint64_t _unix_start, _unix_end; int _n_events, _channel, _gdml_id, _mac5, _raw_channel, _tagger, _channel_status; double _area, _y_average, _ped_calib, _gain_calib, _ped_fit, _ped_fit_std, _ped_fit_chi2, _ped_peak, - _ped_reset_fit, _ped_reset_fit_std, _ped_reset_fit_chi2, _ped_reset_peak, _raw_max_chan_rate, _sh_rate, _sp_rate, _tr_rate, + _ped_reset_fit, _ped_reset_fit_std, _ped_reset_fit_chi2, _ped_reset_peak, _raw_max_chan_rate, _sh_rate, _sp_rate, _tr_rate, _tr_lim_angle_rate, _sh_peak_fit, _sh_peak_fit_chi2, _sh_peak_peak, _sh_pe_peak_fit, _sh_pe_peak_fit_chi2, _sh_pe_peak_peak, _sh_sat_rate, _sh_sat_ratio_total, _sh_sat_ratio_peak, _sp_peak_fit, _sp_peak_fit_chi2, _sp_peak_peak, _sp_pe_peak_fit, _sp_pe_peak_fit_chi2, _sp_pe_peak_peak, _sp_sat_rate, _sp_sat_ratio_total, _sp_sat_ratio_peak, @@ -270,6 +270,7 @@ sbnd::crt::ADRIFT::ADRIFT(fhicl::ParameterSet const& p) } if(fTrackLA) { + fChannelTree->Branch("tr_lim_angle_rate", &_tr_lim_angle_rate); fChannelTree->Branch("tr_lim_angle_peak_fit", &_tr_lim_angle_peak_fit); fChannelTree->Branch("tr_lim_angle_peak_fit_chi2", &_tr_lim_angle_peak_fit_chi2); fChannelTree->Branch("tr_lim_angle_peak_fit_converged", &_tr_lim_angle_peak_fit_converged); @@ -992,6 +993,8 @@ void sbnd::crt::ADRIFT::ProcessEntry(const int ch, const int window) if(fTrackLA && _tagger != kBottomTagger) { + Rate(hADCTrLA[window][ch], _tr_lim_angle_rate, window, fReconstructionWindow); + PeakPeak(hADCTrLA[window][ch], _ped_calib, _tr_lim_angle_peak_peak); PeakFit(hADCTrLA[window][ch], _tr_lim_angle_peak_peak, _ped_calib, _tr_lim_angle_peak_fit, _tr_lim_angle_peak_fit_chi2, _tr_lim_angle_peak_fit_converged, _channel_status, window); @@ -1302,6 +1305,7 @@ void sbnd::crt::ADRIFT::ResetVars() _tr_by_length_peak_fit = std::numeric_limits::lowest(); _tr_by_length_peak_fit_chi2 = std::numeric_limits::lowest(); _tr_by_length_peak_peak = std::numeric_limits::lowest(); + _tr_lim_angle_rate = std::numeric_limits::lowest(); _tr_lim_angle_peak_fit = std::numeric_limits::lowest(); _tr_lim_angle_peak_fit_chi2 = std::numeric_limits::lowest(); _tr_lim_angle_peak_peak = std::numeric_limits::lowest(); From c505fdaec1a03b3cb95f3e51e55bd86253578de7 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Tue, 3 Mar 2026 07:25:24 -0600 Subject: [PATCH 147/155] Add xshift for CRT-TPC track matching --- sbndcode/CRT/CRTAna/CRTAnalysis_module.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc b/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc index 4849708f2..318553eca 100644 --- a/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc +++ b/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc @@ -342,6 +342,7 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { std::vector _tpc_tr_matchable; std::vector _tpc_tr_matched; std::vector _tpc_tr_good_match; + std::vector _tpc_tr_xshift; std::vector _tpc_tr_ts0; std::vector _tpc_tr_ts1; std::vector> _tpc_tr_taggers; @@ -630,6 +631,7 @@ sbnd::crt::CRTAnalysis::CRTAnalysis(fhicl::ParameterSet const& p) fTree->Branch("tpc_sp_z", "std::vector", &_tpc_sp_z); fTree->Branch("tpc_sp_score", "std::vector", &_tpc_sp_score); fTree->Branch("tpc_tr_matched", "std::vector", &_tpc_tr_matched); + fTree->Branch("tpc_tr_xshift", "std::vector", &_tpc_tr_xshift); fTree->Branch("tpc_tr_ts0", "std::vector", &_tpc_tr_ts0); fTree->Branch("tpc_tr_ts1", "std::vector", &_tpc_tr_ts1); fTree->Branch("tpc_tr_taggers", "std::vector>", &_tpc_tr_taggers); @@ -1685,6 +1687,7 @@ void sbnd::crt::CRTAnalysis::AnalyseTPCMatching(const art::Event &e, const art:: _tpc_tr_matchable.resize(nTracks); _tpc_tr_matched.resize(nTracks); _tpc_tr_good_match.resize(nTracks); + _tpc_tr_xshift.resize(nTracks); _tpc_tr_ts0.resize(nTracks); _tpc_tr_ts1.resize(nTracks); _tpc_tr_taggers.resize(nTracks); @@ -1797,7 +1800,11 @@ void sbnd::crt::CRTAnalysis::AnalyseTPCMatching(const art::Event &e, const art:: { const anab::T0 trackMatch = tracksToTrackMatches.data(track.key()).ref(); + const int driftDirection = TPCGeoUtil::DriftDirectionFromHits(geometryService, trackHits); + const double crtShiftingTime = fDataMode ? crttrack->Ts0() * 1e-3 : crttrack->Ts1() * 1e-3; + _tpc_tr_matched[nActualTracks] = true; + _tpc_tr_xshift[nActualTracks] = driftDirection * crtShiftingTime * detProp.DriftVelocity(); _tpc_tr_ts0[nActualTracks] = crttrack->Ts0(); _tpc_tr_ts1[nActualTracks] = crttrack->Ts1(); _tpc_tr_score[nActualTracks] = trackMatch.TriggerConfidence(); @@ -1821,6 +1828,7 @@ void sbnd::crt::CRTAnalysis::AnalyseTPCMatching(const art::Event &e, const art:: else { _tpc_tr_matched[nActualTracks] = false; + _tpc_tr_xshift[nActualTracks] = -std::numeric_limits::max(); _tpc_tr_ts0[nActualTracks] = -std::numeric_limits::max(); _tpc_tr_ts1[nActualTracks] = -std::numeric_limits::max(); _tpc_tr_score[nActualTracks] = -std::numeric_limits::max(); From 2771a929c487217817ca66e1cda783d68aafcbe1 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Thu, 5 Mar 2026 05:15:09 -0600 Subject: [PATCH 148/155] Add track direction branches to spacepoint timing tree --- .../CRT/CRTAna/CRTTimingAnalysis_module.cc | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc b/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc index 73846af9c..f050cce6c 100644 --- a/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc +++ b/sbndcode/CRT/CRTAna/CRTTimingAnalysis_module.cc @@ -70,7 +70,8 @@ class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { void AnalyseCRTSpacePoints(const std::vector> &CRTSpacePointVec, const art::FindOneP &spacepointsToClusters, - const art::FindManyP &clustersToStripHits); + const art::FindManyP &clustersToStripHits, + const art::FindOneP &spacepointsToTracks); void ResetSPVariables(); @@ -171,6 +172,9 @@ class sbnd::crt::CRTTimingAnalysis : public art::EDAnalyzer { std::vector _sp_sh_calib_offset_ts0_set; std::vector _sp_sh_cable_length_ts1_set; std::vector _sp_sh_calib_offset_ts1_set; + bool _sp_has_track; + double _sp_norm_angle; + double _sp_path_length; double _tr_start_x; double _tr_start_y; @@ -324,6 +328,9 @@ sbnd::crt::CRTTimingAnalysis::CRTTimingAnalysis(fhicl::ParameterSet const& p) fSPTree->Branch("sp_sh_calib_offset_ts0_set", "std::vector", &_sp_sh_calib_offset_ts0_set); fSPTree->Branch("sp_sh_cable_length_ts1_set", "std::vector", &_sp_sh_cable_length_ts1_set); fSPTree->Branch("sp_sh_calib_offset_ts1_set", "std::vector", &_sp_sh_calib_offset_ts1_set); + fSPTree->Branch("sp_has_track", &_sp_has_track); + fSPTree->Branch("sp_norm_angle", &_sp_norm_angle); + fSPTree->Branch("sp_path_length", &_sp_path_length); fTrTree = fs->make("tracks",""); fTrTree->Branch("run", &_run); @@ -495,6 +502,9 @@ void sbnd::crt::CRTTimingAnalysis::analyze(art::Event const& e) // Get CRTSpacePoint to CRTCluster Assns art::FindOneP spacepointsToClusters(CRTSpacePointHandle, e, fCRTSpacePointModuleLabel); + // Get CRTSpacePoint to CRTTrack Assns + art::FindOneP spacepointsToTracks(CRTSpacePointHandle, e, fCRTTrackModuleLabel); + // Get CRTClusters art::Handle> CRTClusterHandle; e.getByLabel(fCRTClusterModuleLabel, CRTClusterHandle); @@ -507,7 +517,7 @@ void sbnd::crt::CRTTimingAnalysis::analyze(art::Event const& e) art::FindManyP clustersToStripHits(CRTClusterHandle, e, fCRTClusterModuleLabel); // Fill CRTSpacePoint variables - AnalyseCRTSpacePoints(CRTSpacePointVec, spacepointsToClusters, clustersToStripHits); + AnalyseCRTSpacePoints(CRTSpacePointVec, spacepointsToClusters, clustersToStripHits, spacepointsToTracks); // Get CRTTracks art::Handle> CRTTrackHandle; @@ -736,13 +746,15 @@ void sbnd::crt::CRTTimingAnalysis::SortReferencing() void sbnd::crt::CRTTimingAnalysis::AnalyseCRTSpacePoints(const std::vector> &CRTSpacePointVec, const art::FindOneP &spacepointsToClusters, - const art::FindManyP &clustersToStripHits) + const art::FindManyP &clustersToStripHits, + const art::FindOneP &spacepointsToTracks) { for(auto const& sp : CRTSpacePointVec) { ResetSPVariables(); const art::Ptr cl = spacepointsToClusters.at(sp.key()); + const art::Ptr tr = spacepointsToTracks.at(sp.key()); const std::vector> shs = clustersToStripHits.at(cl.key()); const unsigned n_shs = shs.size(); @@ -790,6 +802,23 @@ void sbnd::crt::CRTTimingAnalysis::AnalyseCRTSpacePoints(const std::vectorDirection().X(), tr->Direction().Y(), tr->Direction().Z()); + _sp_norm_angle = TMath::RadToDeg() * normal.Angle(tr_dir); + _sp_path_length = 1. / TMath::Cos(normal.Angle(tr_dir)); + } + fSPTree->Fill(); fSPTaggerMap[sp.key()] = _sp_tagger; @@ -824,8 +853,11 @@ void sbnd::crt::CRTTimingAnalysis::ResetSPVariables() _sp_ts1_rwm_ref_front_face = std::numeric_limits::lowest(); _sp_ts1_ptb_hlt_beam_gate_ref_front_face = std::numeric_limits::lowest(); _sp_dts1 = std::numeric_limits::lowest(); + _sp_norm_angle = std::numeric_limits::lowest(); + _sp_path_length = std::numeric_limits::lowest(); _sp_single_timing_chain = false; + _sp_has_track = false; _sp_sh_channel_set.clear(); _sp_sh_mac5_set.clear(); From a8353e26486a6b18c90e1a44f6ff3aa0bee39a48 Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Thu, 5 Mar 2026 05:20:36 -0600 Subject: [PATCH 149/155] If we're going to do comments lets get them right --- sbndcode/CRT/CRTAna/CRTAnalysis_module.cc | 24 ++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc b/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc index 318553eca..7c26b2421 100644 --- a/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc +++ b/sbndcode/CRT/CRTAna/CRTAnalysis_module.cc @@ -122,7 +122,7 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { int _crt_timing_reference_type; int _crt_timing_reference_channel; - //mc truth + // True Particles (from G4) std::vector _mc_trackid; std::vector _mc_pdg; std::vector _mc_status; @@ -145,7 +145,7 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { std::vector _mc_endpz; std::vector _mc_ende; - //G4 detector id + // True Energy Depositions std::vector _ide_trackid; std::vector _ide_e; std::vector _ide_entryx; @@ -157,7 +157,7 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { std::vector _ide_exitz; std::vector _ide_exitt; - //front end mother board + // Raw Readouts (FEBDatas) std::vector _feb_mac5; std::vector _feb_tagger; std::vector _feb_flags; @@ -167,7 +167,7 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { std::vector> _feb_adc; std::vector _feb_coinc; - //strip hit to select the strip which has ADC above threshold + // Strip Hits std::vector _sh_channel; std::vector _sh_tagger; std::vector _sh_ts0; @@ -186,7 +186,7 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { std::vector _sh_truth_energy; std::vector _sh_truth_time; - //cluster from x-y coincidence for CRTSpacePoint , this is what we normally call a CRT hit + // Clusters and their corresponding SpacePoints std::vector _cl_ts0; std::vector _cl_ts1; std::vector _cl_unixs; @@ -232,7 +232,7 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { std::vector _cl_sp_dts1; std::vector _cl_sp_complete; - //backtrack truth information from reco level + // True Deposits per particle per tagger std::vector _td_tag_trackid; std::vector _td_tag_pdg; std::vector _td_tag_tagger; @@ -243,6 +243,7 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { std::vector _td_tag_z; std::vector _td_tag_reco_status; + // True Deposits per particle std::vector _td_trackid; std::vector _td_pdg; std::vector _td_energy; @@ -251,7 +252,7 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { std::vector _td_reco_status; std::vector _td_reco_triple; - //track level information + // Tracks std::vector _tr_start_x; std::vector _tr_start_y; std::vector _tr_start_z; @@ -297,7 +298,7 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { std::vector _tr_truth_theta; std::vector _tr_truth_phi; - // crt blob information + // Blobs std::vector _bl_ts0; std::vector _bl_ets0; std::vector _bl_ts1; @@ -306,7 +307,7 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { std::vector _bl_nsps; std::vector> _bl_nsps_per_tagger; - // tpc track information (including crt matching) + // TPC Tracks and their CRT matches std::vector _tpc_start_x; std::vector _tpc_start_y; std::vector _tpc_start_z; @@ -354,14 +355,15 @@ class sbnd::crt::CRTAnalysis : public art::EDAnalyzer { std::vector _tpc_tr_end_z; std::vector _tpc_tr_score; - // ptb information (trigger board) + // Penn Trigger Board HLTs std::vector _ptb_hlt_trigger; std::vector _ptb_hlt_timestamp; + // Penn Trigger Board LLTs std::vector _ptb_llt_trigger; std::vector _ptb_llt_timestamp; - // spec tdc information (timing board) + // SPEC TDC Timestamps std::vector _tdc_channel; std::vector _tdc_timestamp; std::vector _tdc_offset; From 1dd3071b79f40903c3253879d0b5fa5302546c3c Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Thu, 5 Mar 2026 05:20:53 -0600 Subject: [PATCH 150/155] Add README to point to documentation --- sbndcode/CRT/CRTAna/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 sbndcode/CRT/CRTAna/README.md diff --git a/sbndcode/CRT/CRTAna/README.md b/sbndcode/CRT/CRTAna/README.md new file mode 100644 index 000000000..7b7e26cf3 --- /dev/null +++ b/sbndcode/CRT/CRTAna/README.md @@ -0,0 +1,3 @@ +# CRT Analysis Modules + +Details of these modules and the outputs (trees, branches, histograms) can be found in [docDB#45886](https://sbn-docdb.fnal.gov/cgi-bin/sso/ShowDocument?docid=45886) From 3e9df7916a78ed7c69980398f7efd16b267f8cac Mon Sep 17 00:00:00 2001 From: Henry Lay Date: Thu, 5 Mar 2026 05:30:50 -0600 Subject: [PATCH 151/155] Make safer - at John's suggestion --- sbndcode/CRT/CRTReco/CRTStripHitProducer_module.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbndcode/CRT/CRTReco/CRTStripHitProducer_module.cc b/sbndcode/CRT/CRTReco/CRTStripHitProducer_module.cc index 93eb61bfa..7a4891dab 100644 --- a/sbndcode/CRT/CRTReco/CRTStripHitProducer_module.cc +++ b/sbndcode/CRT/CRTReco/CRTStripHitProducer_module.cc @@ -276,8 +276,8 @@ std::vector sbnd::crt::CRTStripHitProducer::CreateStripH const uint16_t adc2 = sipm2.pedestal < sipm_adcs[adc_i+1] ? sipm_adcs[adc_i+1] - sipm2.pedestal : 0; // Saturated? - const bool sat1 = sipm_adcs[adc_i] == fADCSaturation; - const bool sat2 = sipm_adcs[adc_i+1] == fADCSaturation; + const bool sat1 = sipm_adcs[adc_i] >= fADCSaturation; + const bool sat2 = sipm_adcs[adc_i+1] >= fADCSaturation; // Keep hit if both SiPMs above threshold if(adc1 > fADCThreshold && adc2 > fADCThreshold) From b9c9abf1c71d2e76205e41629ecf587feac19f32 Mon Sep 17 00:00:00 2001 From: Sabrina Brickner Date: Sat, 7 Mar 2026 03:06:21 -0600 Subject: [PATCH 152/155] updating memory and cpu usage error bounds for CI tests --- test/ci/ci_tests.cfg | 68 ++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/test/ci/ci_tests.cfg b/test/ci/ci_tests.cfg index b46e5fb1b..bb48e0c77 100644 --- a/test/ci/ci_tests.cfg +++ b/test/ci/ci_tests.cfg @@ -319,8 +319,8 @@ STAGE_NAME=detsim INPUT_STAGE_NAME=g4 NEVENTS=2 # calibrated on sbndbuild01.fnal.gov on 20180305 -cpu_usage_range=200:700 -mem_usage_range=1000000:3000000 +cpu_usage_range=200:2390 +mem_usage_range=1000000:7232311 script=%(EXPSCRIPT_SBNDCODE)s FHiCL_FILE=%(CI_FHICL_PREFIX_SBNDCODE)ssingle_%(STAGE_NAME)s_quick_test_sbndcode.fcl @@ -383,7 +383,7 @@ STAGE_NAME=caf INPUT_STAGE_NAME=reco2 NEVENTS=5 # calibrated on sbndbuild01.fnal.gov on 20180306 -cpu_usage_range=50:200 +cpu_usage_range=50:213 mem_usage_range=500000:3500000 script=%(EXPSCRIPT_SBNDCODE)s @@ -454,7 +454,7 @@ STAGE_NAME=gen NEVENTS=%(NEVENTS_SEQ_SINGLE_SBNDCODE)s # calibrated on sbndbuild01.fnal.gov on 20180305 cpu_usage_range=10:102 -mem_usage_range=500000:700000 +mem_usage_range=500000:1069026 script=%(EXPSCRIPT_SBNDCODE)s @@ -475,8 +475,8 @@ STAGE_NAME=g4 INPUT_STAGE_NAME=gen NEVENTS=%(NEVENTS_SEQ_SINGLE_SBNDCODE)s # calibrated on sbndbuild01.fnal.gov on 20180305 -cpu_usage_range=1200:1600 -mem_usage_range=3500000:4500000 +cpu_usage_range=812:1600 +mem_usage_range=2543381:4500000 script=%(EXPSCRIPT_SBNDCODE)s requires=single_%(INPUT_STAGE_NAME)s_seq_test_sbndcode @@ -498,8 +498,8 @@ STAGE_NAME=detsim INPUT_STAGE_NAME=g4 NEVENTS=%(NEVENTS_SEQ_SINGLE_SBNDCODE)s # calibrated on sbndbuild01.fnal.gov on 20180305 -cpu_usage_range=1050:1200 -mem_usage_range=3000000:4500000 +cpu_usage_range=1050:3593 +mem_usage_range=3000000:7518172 script=%(EXPSCRIPT_SBNDCODE)s requires=single_%(INPUT_STAGE_NAME)s_seq_test_sbndcode @@ -521,7 +521,7 @@ STAGE_NAME=reco1 INPUT_STAGE_NAME=detsim NEVENTS=%(NEVENTS_SEQ_SINGLE_SBNDCODE)s # calibrated on sbndbuild01.fnal.gov on 20180306 -cpu_usage_range=300:450 +cpu_usage_range=300:1204 mem_usage_range=2500000:4000000 script=%(EXPSCRIPT_SBNDCODE)s @@ -544,8 +544,8 @@ STAGE_NAME=reco2 INPUT_STAGE_NAME=reco1 NEVENTS=%(NEVENTS_SEQ_SINGLE_SBNDCODE)s # calibrated on sbndbuild01.fnal.gov on 20180306 -cpu_usage_range=1900:2200 -mem_usage_range=2000000:3500000 +cpu_usage_range=195:2200 +mem_usage_range=1866932:3500000 script=%(EXPSCRIPT_SBNDCODE)s requires=single_%(INPUT_STAGE_NAME)s_seq_test_sbndcode @@ -684,8 +684,8 @@ STAGE_NAME=detsim INPUT_STAGE_NAME=g4 NEVENTS=2 # calibrated on sbndbuild01.fnal.gov on 20180305 -cpu_usage_range=400:1000 -mem_usage_range=1000000:3000000 +cpu_usage_range=400:2573 +mem_usage_range=1000000:7354036 script=%(EXPSCRIPT_SBNDCODE)s FHiCL_FILE=%(CI_FHICL_PREFIX_SBNDCODE)snucosmics_%(STAGE_NAME)s_quick_test_sbndcode.fcl @@ -728,7 +728,7 @@ STAGE_NAME=reco2 INPUT_STAGE_NAME=reco1 NEVENTS=2 # calibrated on sbndbuild01.fnal.gov on 20180305 -cpu_usage_range=50:1250 +cpu_usage_range=50:1366 mem_usage_range=1000000:3000000 script=%(EXPSCRIPT_SBNDCODE)s @@ -820,8 +820,8 @@ testlist=nucosmics_gen_quick_test_sbndcode nucosmics_g4_quick_test_sbndcode nuco STAGE_NAME=gen NEVENTS=%(NEVENTS_SEQ_NUCOSMICS_SBNDCODE)s # calibrated on sbndbuild01.fnal.gov on 20180305 -cpu_usage_range=600:900 -mem_usage_range=2500000:3500000 +cpu_usage_range=206:900 +mem_usage_range=1290400:3500000 script=%(EXPSCRIPT_SBNDCODE)s FHiCL_FILE=%(CI_FHICL_PREFIX_SBNDCODE)snucosmics_%(STAGE_NAME)s_seq_test_sbndcode.fcl @@ -841,8 +841,8 @@ STAGE_NAME=g4 INPUT_STAGE_NAME=gen NEVENTS=%(NEVENTS_SEQ_NUCOSMICS_SBNDCODE)s # calibrated on sbndbuild01.fnal.gov on 20180305 -cpu_usage_range=3500:4200 -mem_usage_range=4500000:5500000 +cpu_usage_range=1854:4200 +mem_usage_range=3473101:5500000 script=%(EXPSCRIPT_SBNDCODE)s requires=nucosmics_%(INPUT_STAGE_NAME)s_seq_test_sbndcode @@ -864,8 +864,8 @@ STAGE_NAME=detsim INPUT_STAGE_NAME=g4 NEVENTS=%(NEVENTS_SEQ_NUCOSMICS_SBNDCODE)s # calibrated on sbndbuild01.fnal.gov on 20180305 -cpu_usage_range=1100:1400 -mem_usage_range=3500000:4500000 +cpu_usage_range=1100:3809 +mem_usage_range=3500000:7083228 script=%(EXPSCRIPT_SBNDCODE)s requires=nucosmics_%(INPUT_STAGE_NAME)s_seq_test_sbndcode @@ -888,7 +888,7 @@ INPUT_STAGE_NAME=detsim NEVENTS=%(NEVENTS_SEQ_NUCOSMICS_SBNDCODE)s # calibrated on sbndbuild01.fnal.gov on 20180305 cpu_usage_range=600:800 -mem_usage_range=3000000:4000000 +mem_usage_range=1945911:4000000 script=%(EXPSCRIPT_SBNDCODE)s requires=nucosmics_%(INPUT_STAGE_NAME)s_seq_test_sbndcode @@ -910,8 +910,8 @@ STAGE_NAME=reco2 INPUT_STAGE_NAME=reco1 NEVENTS=%(NEVENTS_SEQ_NUCOSMICS_SBNDCODE)s # calibrated on sbndbuild01.fnal.gov on 20180305 -cpu_usage_range=2200:2500 -mem_usage_range=2500000:3500000 +cpu_usage_range=1342:2500 +mem_usage_range=2157647:3500000 script=%(EXPSCRIPT_SBNDCODE)s requires=nucosmics_%(INPUT_STAGE_NAME)s_seq_test_sbndcode @@ -1022,8 +1022,8 @@ output1=%(TFILENAME)s STAGE_NAME=reco1 INPUT_STAGE_NAME=decoders NEVENTS=2 -cpu_usage_range=500:1500 -mem_usage_range=1500000:3000000 +cpu_usage_range=500:2303 +mem_usage_range=1500000:7159462 script=%(EXPSCRIPT_SBNDCODE)s FHiCL_FILE=%(CI_FHICL_PREFIX_SBNDCODE)sdata_offBeamZeroBias_%(STAGE_NAME)s_quick_test_sbndcode.fcl @@ -1043,7 +1043,7 @@ STAGE_NAME=reco2 INPUT_STAGE_NAME=reco1 NEVENTS=2 cpu_usage_range=250:1000 -mem_usage_range=1000000:2000000 +mem_usage_range=1000000:2274627 script=%(EXPSCRIPT_SBNDCODE)s FHiCL_FILE=%(CI_FHICL_PREFIX_SBNDCODE)sdata_offBeamZeroBias_%(STAGE_NAME)s_quick_test_sbndcode.fcl @@ -1062,7 +1062,7 @@ output1=%(TFILENAME)s STAGE_NAME=caf INPUT_STAGE_NAME=reco2 NEVENTS=5 -cpu_usage_range=100:1000 +cpu_usage_range=74:1000 mem_usage_range=1000000:3000000 script=%(EXPSCRIPT_SBNDCODE)s @@ -1090,7 +1090,7 @@ testlist=data_offBeamZeroBias_decoders_quick_test_sbndcode data_offBeamZeroBias_ STAGE_NAME=decoders NEVENTS=%(NEVENTS_SEQ_DATA_SBNDCODE)s cpu_usage_range=10:102 -mem_usage_range=500000:700000 +mem_usage_range=500000:1262633 script=%(EXPSCRIPT_SBNDCODE)s @@ -1110,8 +1110,8 @@ output1=%(TFILENAME)s STAGE_NAME=reco1 INPUT_STAGE_NAME=decoders NEVENTS=%(NEVENTS_SEQ_DATA_SBNDCODE)s -cpu_usage_range=1200:1600 -mem_usage_range=3500000:4500000 +cpu_usage_range=1200:3465 +mem_usage_range=3500000:7417141 script=%(EXPSCRIPT_SBNDCODE)s requires=data_offBeamZeroBias_%(INPUT_STAGE_NAME)s_seq_test_sbndcode @@ -1132,8 +1132,8 @@ output1=%(TFILENAME)s STAGE_NAME=reco2 INPUT_STAGE_NAME=reco1 NEVENTS=%(NEVENTS_SEQ_DATA_SBNDCODE)s -cpu_usage_range=1200:1600 -mem_usage_range=3500000:4500000 +cpu_usage_range=711:1600 +mem_usage_range=2008524:4500000 script=%(EXPSCRIPT_SBNDCODE)s requires=data_offBeamZeroBias_%(INPUT_STAGE_NAME)s_seq_test_sbndcode @@ -1204,7 +1204,7 @@ testlist=compilation_test_sbndcode [test fcl_checks_sbndcode] cpu_usage_range=0:100 -mem_usage_range=10000:60000 +mem_usage_range=10000:66742 script=${SBNDCODE_DIR}/test/fcl_checks.sh STAGE_NAME=fcl EXTRA_DIR=%(FCLCHECK_INPUT_DIRNAME_SBNDCODE)s @@ -1214,7 +1214,7 @@ parse_art_output=False [test update_refs_fcl_checks_sbndcode] cpu_usage_range=0:100 -mem_usage_range=10000:50000 +mem_usage_range=10000:62189 script=${SBNDCODE_DIR}/test/fcl_checks.sh STAGE_NAME=fcl EXTRA_DIR=%(FCLCHECK_INPUT_DIRNAME_SBNDCODE)s From a1cccf88208f97d4e98ea94e0bd298232e863c1d Mon Sep 17 00:00:00 2001 From: nathanielerowe <70993723+nathanielerowe@users.noreply.github.com> Date: Fri, 13 Mar 2026 12:58:05 -0500 Subject: [PATCH 153/155] Update sbncode version to v10_20_03 --- ups/product_deps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ups/product_deps b/ups/product_deps index 29ba0e0fd..8b02783e4 100644 --- a/ups/product_deps +++ b/ups/product_deps @@ -253,7 +253,7 @@ wpdir product_dir wire-cell-cfg # #################################### product version qual flags -sbncode v10_15_00 - +sbncode v10_20_03 - cetmodules v3_24_01 - only_for_build sbnd_data v01_42_00 - sbndutil v10_06_01 - optional From 62fc4d532696353bc6eb83528899424670dcea54 Mon Sep 17 00:00:00 2001 From: Nathaniel Date: Mon, 16 Mar 2026 09:36:13 -0500 Subject: [PATCH 154/155] Update versioning --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f93a660ef..54621576a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ cmake_minimum_required(VERSION 3.20 FATAL_ERROR) -set(${PROJECT_NAME}_CMAKE_PROJECT_VERSION_STRING 10.14.02.02) +set(${PROJECT_NAME}_CMAKE_PROJECT_VERSION_STRING 10.20.03) find_package(cetmodules REQUIRED) project(sbndcode LANGUAGES CXX) From 229cb46ee2916f550dac1b08570b03c8ad961f5e Mon Sep 17 00:00:00 2001 From: Lynn Tung <71307529+lynnt20@users.noreply.github.com> Date: Tue, 14 Apr 2026 14:01:23 -0500 Subject: [PATCH 155/155] Remove LegacyLArG4 from MODULE_LIBRARIES --- sbndcode/Calorimetry/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/sbndcode/Calorimetry/CMakeLists.txt b/sbndcode/Calorimetry/CMakeLists.txt index f674709d4..28452cab4 100644 --- a/sbndcode/Calorimetry/CMakeLists.txt +++ b/sbndcode/Calorimetry/CMakeLists.txt @@ -1,7 +1,6 @@ set (MODULE_LIBRARIES larsim::PhotonPropagation larsim::OpticalPath - larsim::LegacyLArG4 larcorealg::Geometry larcore::Geometry_Geometry_service larevt::CalibrationDBI_Providers