From 3cab2e996b14fa40ee47c19acab276d0e50b6c3c Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Fri, 23 May 2025 00:17:16 +0200 Subject: [PATCH 01/47] fix sim label for PDFastSim --- fcl/g4/PDFastSim_icarus.fcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fcl/g4/PDFastSim_icarus.fcl b/fcl/g4/PDFastSim_icarus.fcl index 1344fa340..d11b2c322 100644 --- a/fcl/g4/PDFastSim_icarus.fcl +++ b/fcl/g4/PDFastSim_icarus.fcl @@ -157,7 +157,7 @@ icarus_vis_timing_parameterization: # standard configuration icarus_pdfastsim_pvs: @local::standard_pdfastsim_pvs -icarus_pdfastsim_pvs.SimulationLabel: "ionization" +icarus_pdfastsim_pvs.SimulationLabel: "ionization:priorSCE" icarus_pdfastsim_pvs.IncludePropTime: true icarus_pdfastsim_pvs.ScintTimeTool.SlowDecayTime: 1300.0 @@ -166,4 +166,4 @@ icarus_pdfastsim_pvs.VUVTiming: @local::photon_propagation_timing_icarus icarus_pdfastsim_pvs.VISTiming: @local::icarus_vis_timing_parameterization -END_PROLOG \ No newline at end of file +END_PROLOG From b6c5c1aac6535c11dc5ff9646eddc1905bc0e36d Mon Sep 17 00:00:00 2001 From: Gianluca Petrillo Date: Fri, 7 Feb 2025 20:59:40 -0600 Subject: [PATCH 02/47] detsim_opdetonly_icarus.fcl: simulate only optical detector digitization --- fcl/detsim/CMakeLists.txt | 1 + fcl/detsim/partial/CMakeLists.txt | 8 ++++ .../partial/detsim_opdetonly_icarus.fcl | 40 +++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 fcl/detsim/partial/CMakeLists.txt create mode 100644 fcl/detsim/partial/detsim_opdetonly_icarus.fcl diff --git a/fcl/detsim/CMakeLists.txt b/fcl/detsim/CMakeLists.txt index f86d7dfc8..88708a770 100644 --- a/fcl/detsim/CMakeLists.txt +++ b/fcl/detsim/CMakeLists.txt @@ -1,5 +1,6 @@ # add underlying subfolders add_subdirectory(SBNNoise) +add_subdirectory(partial) add_subdirectory(commissioning) add_subdirectory(archive) diff --git a/fcl/detsim/partial/CMakeLists.txt b/fcl/detsim/partial/CMakeLists.txt new file mode 100644 index 000000000..6ce4b7b55 --- /dev/null +++ b/fcl/detsim/partial/CMakeLists.txt @@ -0,0 +1,8 @@ +# Install fcl files in /job subdirectory. +install_fhicl() + +# Also put a copy in the source tree. + +FILE(GLOB fcl_files *.fcl) +install_source( EXTRAS ${fcl_files} ) + diff --git a/fcl/detsim/partial/detsim_opdetonly_icarus.fcl b/fcl/detsim/partial/detsim_opdetonly_icarus.fcl new file mode 100644 index 000000000..26e1da570 --- /dev/null +++ b/fcl/detsim/partial/detsim_opdetonly_icarus.fcl @@ -0,0 +1,40 @@ +# +# File: detsim_opdetonly_icarus.fcl +# Purpose: Simulation of the optical detector response. +# Date: January 27, 2025 +# Author: Gianluca Petrillo (petrillo@slac.stanford.edu) +# +# This job configuration runs the standard detector simulation, like +# `detsim_1d_icarus.fcl` does, but only for the optical detector. +# +# +# Output +# ------- +# +# * `std::vector` (`opdaq`): raw PMT waveforms +# +# +# +# +# Changes +# -------- +# +# 20250127 (petrillo@slac.stanford.edu) [v1.0] +# original version (from `detsim_1d_icarus.fcl`) +# + +#include "detsim_1d_icarus.fcl" + +process_name: OpDetSim + +services.DetPedestalService: @erase +services.ChannelStatusService: @erase +services.IICARUSChannelMap: @erase +services.SignalShapingICARUSService: @erase + +# run only the `opdaq` module: +physics.producers: { + opdaq: @local::physics.producers.opdaq # simplify configuration removing all other producers +} +physics.simulate: [ opdaq ] + From ae195e1835914e752bc5f8f44c0d30c8fc1471dd Mon Sep 17 00:00:00 2001 From: Gianluca Petrillo Date: Fri, 7 Feb 2025 21:05:34 -0600 Subject: [PATCH 03/47] Changed determination of the end of single photoelectron response template It used to end when the template SPR goes under 1e-4 ADC#. Now it needs to stay within +/- 1w-4 ADC# for 20 nanoseconds. This should make it possible to include undershootings. All these parameters are currently hard-coded. --- .../Algorithms/DiscretePhotoelectronPulse.cxx | 110 +++++++++++++----- .../Algorithms/DiscretePhotoelectronPulse.h | 25 +++- .../PMT/Algorithms/PMTsimulationAlg.cxx | 14 ++- 3 files changed, 105 insertions(+), 44 deletions(-) diff --git a/icaruscode/PMT/Algorithms/DiscretePhotoelectronPulse.cxx b/icaruscode/PMT/Algorithms/DiscretePhotoelectronPulse.cxx index 89f7cce95..6488278f0 100644 --- a/icaruscode/PMT/Algorithms/DiscretePhotoelectronPulse.cxx +++ b/icaruscode/PMT/Algorithms/DiscretePhotoelectronPulse.cxx @@ -18,17 +18,83 @@ #include "messagefacility/MessageLogger/MessageLogger.h" // C++ standard library +#include // std::abs() #include // std::function #include // std::cref() +// ----------------------------------------------------------------------------- +namespace { + + /** + * Returns `true` after seeing a given number of samples closer to baseline + * than a specified threshold (either direction). + */ + template + class CloseToBaselineForClass { + + // configuration + SampleType fMin, fMax; + unsigned int fCountGoal; + + // cache + unsigned int fCount = 0; + + public: + + /// Constructor: specifies `threshold` and `count` (baseline is in `ops`). + template + CloseToBaselineForClass + (SampleType threshold, unsigned int count, WaveformOperations ops) + : fMin{ ops.shiftFromBaseline(-threshold) } + , fMax{ ops.shiftFromBaseline(+threshold) } + , fCountGoal{ count } + { + if (fMin > fMax) std::swap(fMin, fMax); + } + + /// Returns whether there have been `fCountGoal` calls with `sample` + /// close enough to the baseline (`closeEnough()`). + template + bool operator() (TimeType, SampleType sample) + { + if (closeEnough(sample)) ++fCount; + else fCount = 0; + return fCount >= fCountGoal; + } + + /// Returns whether `sample` is close enough to the stored baseline. + constexpr bool closeEnough(SampleType sample) const noexcept + { return (sample >= fMin) && (sample <= fMax); } + + }; // CloseToBaselineForClass + +} // local namespace + + // ----------------------------------------------------------------------------- // --- icarus::opdet::DiscretePhotoelectronPulse +// ----------------------------------------------------------------------------- +icarus::opdet::DiscretePhotoelectronPulse::DiscretePhotoelectronPulse( + PulseFunction_t const& pulseShape, + gigahertz samplingFreq, unsigned int nSubsamples, + ADCcount samplingThreshold, nanoseconds minTimeBelowThreshold + ) + : fShape(pulseShape) + , fSamplingFreq(samplingFreq) + , fSampledShape(sampleShape( + shape(), fSamplingFreq, nSubsamples, + samplingThreshold, + static_cast(std::ceil(minTimeBelowThreshold * samplingFreq)) + )) + {} + + // ----------------------------------------------------------------------------- auto icarus::opdet::DiscretePhotoelectronPulse::sampleShape( PulseFunction_t const& pulseShape, gigahertz samplingFreq, unsigned int nSubsamples, - ADCcount threshold + ADCcount threshold, unsigned int minSamplesBelowThreshold ) -> SampledFunction_t { using namespace util::quantities::time_literals; @@ -38,43 +104,23 @@ auto icarus::opdet::DiscretePhotoelectronPulse::sampleShape( // the pulse polarity is included in the values, // the two functions (lambda) are of different type, so they are being wrapped // in the common `std::function` type - - // FIXME Clang 7.0.0 can't figure out the parameters of std::function - // (GCC 8.2 can): specifying them explicitly... - auto const isBelowThreshold = (pulseShape.polarity() == +1) -#if defined(__clang__) && (__clang_major__ < 8) - ? std::function( -#else // not Clang <8 - ? std::function( -#endif // defined(__clang__) && (__clang_major__ < 8) - [baseline=pulseShape.baseline(), threshold](nanoseconds, ADCcount s) - { - return - PositivePolarityOperations::subtractBaseline(s, baseline) - < threshold - ; - } - ) -#if defined(__clang__) && (__clang_major__ < 8) - : std::function( -#else // not Clang <8 - : std::function( -#endif // defined(__clang__) && (__clang_major__ < 8) - [baseline=pulseShape.baseline(), threshold](nanoseconds, ADCcount s) - { - return - NegativePolarityOperations::subtractBaseline(s, baseline) - < threshold - ; - } - ) + + auto isCloseToBaseline = (pulseShape.polarity() == +1) + ? CloseToBaselineForClass{ + threshold, minSamplesBelowThreshold, + PositivePolarityOperations{ pulseShape.baseline() } + } + : CloseToBaselineForClass{ + threshold, minSamplesBelowThreshold, + NegativePolarityOperations{ pulseShape.baseline() } + } ; return SampledFunction_t{ std::cref(pulseShape), // function to sample (by reference because abstract) 0.0_ns, // sampling start time 1.0 / samplingFreq, // tick duration - isBelowThreshold, // when to stop the sampling + isCloseToBaseline, // when to stop the sampling static_cast(nSubsamples), // how many subsamples per tick pulseShape.peakTime() // sample at least until here }; diff --git a/icaruscode/PMT/Algorithms/DiscretePhotoelectronPulse.h b/icaruscode/PMT/Algorithms/DiscretePhotoelectronPulse.h index 877b7784b..01d41b351 100644 --- a/icaruscode/PMT/Algorithms/DiscretePhotoelectronPulse.h +++ b/icaruscode/PMT/Algorithms/DiscretePhotoelectronPulse.h @@ -92,17 +92,30 @@ class icarus::opdet::DiscretePhotoelectronPulse { * @param nSubsamples (default: `1`) the number of samples within a tick * @param samplingThreshold (default: 10^-6^) pulse shape ends when its * value is below this threshold + * @param minTimeBelowThreshold (default: one sample worth) how long the + * waveform should be below threshold for the sampling to terminate * * Samples start from time 0, which is the time of the start of the first * tick. This time is expected to be the arrival time of the photoelectron. * - * The length of the sampling is determined by the sampling threshold: - * at the first tick after the peak time where the shape function is below - * threshold, the sampling ends (that tick under threshold itself is also - * discarded). + * The length of the sampling is determined by the sampling threshold. + * The sampling is over after the signal has been close to the baseline + * by at least `minTimeBelowThreshold` (excluding the last tick too). + * The closeness is defined on both sides of the baseline (for example a + * bipolar or undershooting signal will not necessarily terminate at the + * baseline crossing time). * * The ownership of `pulseShape` is acquired by this object. */ + DiscretePhotoelectronPulse( + PulseFunction_t const& pulseShape, + gigahertz samplingFreq, + unsigned int nSubsamples, + ADCcount samplingThreshold, + nanoseconds minTimeBelowThreshold + ); + + // version with the default values DiscretePhotoelectronPulse( PulseFunction_t const& pulseShape, gigahertz samplingFreq, @@ -219,7 +232,7 @@ class icarus::opdet::DiscretePhotoelectronPulse { static SampledFunction_t sampleShape( PulseFunction_t const& pulseShape, gigahertz samplingFreq, unsigned int nSubsamples, - ADCcount threshold + ADCcount threshold, unsigned int minSamplesBelowThreshold ); }; // class DiscretePhotoelectronPulse<> @@ -242,7 +255,7 @@ inline icarus::opdet::DiscretePhotoelectronPulse::DiscretePhotoelectronPulse( : fShape(pulseShape) , fSamplingFreq(samplingFreq) , fSampledShape - (sampleShape(shape(), fSamplingFreq, nSubsamples, samplingThreshold)) + (sampleShape(shape(), fSamplingFreq, nSubsamples, samplingThreshold, 1)) {} diff --git a/icaruscode/PMT/Algorithms/PMTsimulationAlg.cxx b/icaruscode/PMT/Algorithms/PMTsimulationAlg.cxx index 0aa9d96cf..9b27c857a 100644 --- a/icaruscode/PMT/Algorithms/PMTsimulationAlg.cxx +++ b/icaruscode/PMT/Algorithms/PMTsimulationAlg.cxx @@ -37,6 +37,12 @@ #include // std::accumulate +// ----------------------------------------------------------------------------- +using namespace util::quantities::time_literals; +using namespace util::quantities::frequency_literals; +using namespace util::quantities::electronics_literals; + + // ----------------------------------------------------------------------------- #if __cplusplus < 202002L // C++20? namespace util { @@ -106,12 +112,12 @@ icarus::opdet::PMTsimulationAlg::PMTsimulationAlg *(fParams.pulseFunction), fSampling, fParams.pulseSubsamples, // tick subsampling - 1.0e-4_ADCf // stop sampling when ADC counts are below this value + 1.0e-4_ADCf, // stop sampling when signal is closer to baseline than this... + 20_ns // ... for at least this long ) , fPedestalGen(fParams.pedestalGen) , fDiscrAlgo(selectDiscriminationAlgo(fParams.discrimAlgo)) { - using namespace util::quantities::electronics_literals; // mf::LogDebug("PMTsimulationAlg") << "Sampling = " << fSampling << std::endl; @@ -189,9 +195,6 @@ auto icarus::opdet::PMTsimulationAlg::CreateFullWaveform const -> Waveform_t { - using namespace util::quantities::time_literals; - using namespace util::quantities::frequency_literals; - using namespace util::quantities::electronics_literals; using namespace detinfo::timescales; detinfo::DetectorTimings const& timings = *(fParams.detTimings); @@ -972,7 +975,6 @@ auto icarus::opdet::PMTsimulationAlgMaker::makeParams( bool trackSelectedPhotons /* = false */ ) const -> PMTsimulationAlg::ConfigurationParameters_t { - using namespace util::quantities::electronics_literals; // // set the configuration From b129249503bd443600dde2bbea82b745f233a238 Mon Sep 17 00:00:00 2001 From: Gianluca Petrillo Date: Fri, 11 Apr 2025 19:03:54 -0500 Subject: [PATCH 04/47] Updated `FastGaussianNoiseGeneratorAlg` documentation --- .../Algorithms/FastGaussianNoiseGeneratorAlg.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/icaruscode/PMT/Algorithms/FastGaussianNoiseGeneratorAlg.h b/icaruscode/PMT/Algorithms/FastGaussianNoiseGeneratorAlg.h index afb8f97d5..887c44ff7 100644 --- a/icaruscode/PMT/Algorithms/FastGaussianNoiseGeneratorAlg.h +++ b/icaruscode/PMT/Algorithms/FastGaussianNoiseGeneratorAlg.h @@ -39,9 +39,10 @@ namespace icarus::opdet { * Generating for any type `ADCT` other that the CLHEP-native `double` requires * a conversion and slows down the generation. * - * Compared to GaussianNoiseGeneratorAlg(), we use a somehow faster random - * generator; to squeeze the CPU cycles, we avoid the CLHEP interface as much as - * possible; the random number from the engine is immediately converted + * Compared to `icarus::opdet::GaussianNoiseGeneratorAlg`, we use a somehow + * faster Gaussian adaptor, implemented in `util::FastAndPoorGauss`, for random + * number generation; to squeeze the CPU cycles, we avoid the CLHEP interface as + * much as possible; the random number from the engine is immediately converted * to single precision, and the rest of the math happens in there as well. * No virtual interfaces nor indirection is involved within this function * (except for CLHEP random engine and the call to `add()`/`fill()`). We @@ -52,6 +53,12 @@ namespace icarus::opdet { * Note that unless the random engine is multi-thread safe, this function * won't gain anything from multi-threading. * + * @note The cost of the fast adaptor is a resolution worsening on the tails + * of the distribution. With `131072` sampling points (value at the time + * of writing), only 8 values are above 4 standard deviations, with a + * maximum value of `4.62`. With `262144` points there would be 17 values + * above 4 s.d. and a maximum of about `4.76`. + * * @note Despite the name, the generator limits to generate one sample per call. * It may be possible, if this proved to be a limitation, to extend * `util::FastAndPoorGauss` to generate an array of numbers, in the hope @@ -117,7 +124,7 @@ class icarus::opdet::FastGaussianNoiseGeneratorAlg private: - using GaussAdapter_t = util::FastAndPoorGauss<32768U, ADCvalue_t>; + using GaussAdapter_t = util::FastAndPoorGauss<131072U, ADCvalue_t>; // --- BEGIN -- Configuration parameters ------------------------------------- From 3f467fbe20a55e2dbad31c60e1f504e1edac6a41 Mon Sep 17 00:00:00 2001 From: Gianluca Petrillo Date: Tue, 17 Jun 2025 12:32:32 -0500 Subject: [PATCH 05/47] SelectCathodeCrossingGenParticles: selects generated events with particles that might cross cathode --- icaruscode/Generators/CMakeLists.txt | 18 +- ...electCathodeCrossingGenParticles_module.cc | 562 ++++++++++++++++++ 2 files changed, 572 insertions(+), 8 deletions(-) create mode 100644 icaruscode/Generators/SelectCathodeCrossingGenParticles_module.cc diff --git a/icaruscode/Generators/CMakeLists.txt b/icaruscode/Generators/CMakeLists.txt index d3d863b50..cc42c44f5 100644 --- a/icaruscode/Generators/CMakeLists.txt +++ b/icaruscode/Generators/CMakeLists.txt @@ -1,11 +1,3 @@ -#find_ups_product(ifdhc) -#include_directories( $ENV{IFDHC_FQ_DIR}/inc ) -#set( IFDH_AS_SERVICE_LIB_LIST -# art_Framework_Services_Registry -# ${Boost_SYSTEM_LIBRARY} -# ${IFDH_SERVICE} ) -#include_directories ( . ) - cet_build_plugin(HepMCFileGen art::module LIBRARIES larcorealg::Geometry larcore::Geometry_Geometry_service @@ -31,6 +23,16 @@ cet_build_plugin(HepMCFileGen art::module ROOT::Physics ) +cet_build_plugin(SelectCathodeCrossingGenParticles art::module + LIBRARIES sbnalg::Utilities + larcore::Geometry_Geometry_service + larcore::headers + lardataalg::MCDumpers + larcorealg::Geometry + larcorealg::headers + nusimdata::SimulationBase +) + install_headers() install_source() install_fhicl() diff --git a/icaruscode/Generators/SelectCathodeCrossingGenParticles_module.cc b/icaruscode/Generators/SelectCathodeCrossingGenParticles_module.cc new file mode 100644 index 000000000..889498202 --- /dev/null +++ b/icaruscode/Generators/SelectCathodeCrossingGenParticles_module.cc @@ -0,0 +1,562 @@ +/** + * @file icaruscode/Generators/SelectCathodeCrossingGenParticles_module.cc + * @brief Implements `sbn::SelectCathodeCrossingGenParticles` filter module. + * @author Gianluca Petrillo (petrillo@slac.stanford.edu) + * @date June 12, 2025 + * + */ + +// ICARUS/LArSoft libraries +#include "icarusalg/Utilities/AtomicPassCounter.h" +#include "icarusalg/Utilities/PassCounter.h" +#include "sbnalg/Utilities/PlaneCrossers.h" +#include "larcore/Geometry/Geometry.h" +#include "larcore/CoreUtils/ServiceUtil.h" // lar::providerFrom() +#include "larcorealg/Geometry/GeometryCore.h" +#include "larcorealg/Geometry/TPCGeo.h" +#include "larcorealg/Geometry/geo_vectors_utils.h" // geo::vect::convertTo() +// #include "larcorealg/Geometry/geo_vectors_utils_TVector.h" +#include "larcorealg/CoreUtils/enumerate.h" +#include "larcorealg/CoreUtils/counter.h" +#include "lardataalg/MCDumpers/MCDumperUtils.h" +#include "nusimdata/SimulationBase/MCTruth.h" +#include "nusimdata/SimulationBase/MCParticle.h" +// framework libraries +#include "art/Framework/Core/SharedFilter.h" +#include "art/Framework/Core/ModuleMacros.h" +#include "art/Framework/Principal/Event.h" +#include "art/Framework/Principal/Handle.h" +#include "canvas/Utilities/InputTag.h" +// #include "canvas/Utilities/Exception.h" +#include "messagefacility/MessageLogger/MessageLogger.h" +#include "fhiclcpp/types/Sequence.h" +#include "fhiclcpp/types/Atom.h" +// #include "cetlib_except/exception.h" + +// C/C++ standard libraries +// #include // std::count() +#include +#include // std::move() +#include + + +//------------------------------------------------------------------------------ +/** + * @brief Requires the presence of generated particles crossing a cathode. + * + * This module passes only the events with a minimum number of generated + * particles (from `simb::MCTruth`) predicted to cross any cathode. + * + * All particles in the final state (status `1`) of the specified generated + * records are considered. The number of particles whose predicted trajectory + * crosses any of the cathodes of the detector, plus a margin, is compared to + * the configured requirement. + * + * The counts are currently global: if a particle crosses the cathode of + * cryostat 1 and another the cathode of cryostat 2, the event passes the + * requirement of _two_ cathode-crossing particles. + * + * The crossing prediction is based on whether the predicted particle trajectory + * crosses a rectangularly shaped cathode, with some margin. + * The trajectory is built as simple inertial extrapolation of the particle at + * generator time. + * + * Cathode coordinates are not provided by the detector geometry description, + * so for each TPC a cathode is deduced (see below). + * On top of the cathode dimensions, each side of each cathode is extended by + * a configured amount. For example, if a cathode is 9 × 3.4 m² + * (L × H), with `CathodeLengthWiggle` of `0.1` the cathode length (9 m) + * is extended by 0.9 m on one side _and_ 0.9 m on the other side, for a total + * width of 10.8 m (that is, 20% longer). + * + * + * Cathode size + * ------------- + * + * Cathode coordinates are not provided by the detector geometry description, + * so _for each TPC_ a cathode is deduced. + * + * The definition of the cathode surface is as follow: + * * a cross section of the active volume is determined as the rectangle + * with sides along `geo::TPCGeo::LengthDir()` and `geo::TPCGeo::HeightDir()` + * and sizes `geo::TPCGeo::ActiveLength()` and `geo::TPCGeo::ActiveHeight()`, + * respectively, around the central point of the active volume + * (`geo::TPCGeo::GetActiveVolumeCenter()`). + * * cathode surface is set translating that rectangle by + * `geo::TPCGeo::ActiveHalfWidth()` along the direction `geo::TPCGeo::WidthDir()`, + * which is supposed to be opposite to the drift direction. + * + * + * + * + * Configuration parameters + * ========================= + * + * * `GeneratorTags` (input tags, mandatory): list of tags of generated particle + * records to consider. + * * `MinimumCrossingParticles` (integral, default: `1`): minimum number of + * cathode-crossing particles required for the event to pass the filter. + * * `CathodeLengthWiggle`, `CathodeHeightWiggle` (real, default: `0.0`): + * fraction of each dimension the cathode is extended for the purpose of + * determining the crossing of the particle (see the documentation above). + * * `LogCategory` (string, default: `SelectCathodeCrossingGenParticles`): + * message facility stream name where to write console messages to. + * + * + * Input data products + * ==================== + * + * * `std::vector` (`GeneratorTags`, multiple supported): + * the tags of the generated events to be included in the test. + * + * + * Service dependencies + * ===================== + * + * * `Geometry`: to learn the position of the cathodes. + * + * + * + * Output data products + * ===================== + * + * None. + * + */ +class SelectCathodeCrossingGenParticles: public art::SharedFilter { + + public: + + struct Config { + using Name = fhicl::Name; + using Comment = fhicl::Comment; + + fhicl::Sequence GeneratorTags{ + Name{ "GeneratorTags" }, + Comment{ "list of generated particle tags to check" }, + std::vector{ art::InputTag{ "generator" } } + }; + + fhicl::Atom MinimumCrossingParticles{ + Name{ "MinimumCrossingParticles" }, + Comment{ "minimum required number of cathode-crossing particles" }, + 1U + }; + + fhicl::Atom CathodeLengthWiggle{ + Name{ "CathodeLengthWiggle" }, + Comment + { "extend each cathode length by this fraction (negative contracts)" }, + 0.0 + }; + + fhicl::Atom CathodeHeightWiggle{ + Name{ "CathodeHeightWiggle" }, + Comment + { "extend each cathode height by this fraction (negative contracts)" }, + 0.0 + }; + + fhicl::Atom LogCategory{ + Name{ "LogCategory" }, + Comment{ "name of the message facility stream used by the module" }, + "SelectCathodeCrossingGenParticles" + }; + + }; // Config + + using Parameters = art::SharedFilter::Table; + + + SelectCathodeCrossingGenParticles + (Parameters const& params, art::ProcessingFrame const&); + + /// Evaluate the filtering logic. + virtual bool filter(art::Event& event, art::ProcessingFrame const&) override; + + /// Prints a summary. + virtual void endJob(art::ProcessingFrame const&) override; + + private: + + /// The algorithm storing plane geometry and providing intersection with lines. + using PlaneCrosserAlg_t = util::PlaneCrossers; + + /// Information identifying the cathode rectangle of one TPC. + class CathodePlane_t { + + PlaneCrosserAlg_t fCrossFinder; + + geo::TPCGeo const* fTPC = nullptr; + + public: + + CathodePlane_t( + geo::Point_t center, geo::Vector_t length, geo::Vector_t height, + geo::TPCGeo const& TPC + ) + : fCrossFinder{ std::move(center), std::move(length), std::move(height) } + , fTPC{ &TPC } + {} + + geo::Point_t center() const { return fCrossFinder.center(); } + + /// Versor of the length direction. + geo::Vector_t lengthDir() const { return fCrossFinder.Uaxis().unit(); } + /// Versor of the height direction. + geo::Vector_t heightDir() const { return fCrossFinder.Vaxis().unit(); } + + double length() const { return fCrossFinder.Uaxis().R(); } + double height() const { return fCrossFinder.Vaxis().R(); } + + geo::TPCGeo const& TPC() const { return *fTPC; } + + PlaneCrosserAlg_t crossFinder() const + { return fCrossFinder; } + + /// Finds the crossing between the cathode and the specified line. + /// @see util::PlaneCrossers::findCrossing() + PlaneCrosserAlg_t::CrossingInfo findCrossing + (geo::Point_t const& point, geo::Vector_t const& dir) const + { return fCrossFinder.findCrossing(point, dir); } + + }; // CathodePlane_t + + + /// Value returned to represent the possible crossing of a cathode. + struct CathodeCrossInfo { + + /// Which cathode was crossed (if any). + CathodePlane_t const* cathode = nullptr; + + /// Information about the crossing with a line. + PlaneCrosserAlg_t::CrossingInfo crossing; + + /// How many `length()`s the crossing point is from cathode center. + double cathodeLengthUnits() const { return crossing.u; } + /// How many `height()`s the crossing point is from cathode center. + double cathodeHeightUnits() const { return crossing.v; } + /// How many particle direction units the crossing point is from its position. + double particleDirUnits() const { return crossing.line; } + + /// Returns whether any cathode was crossed. + bool crossed() const noexcept { return crossing; } + + /// Returns whether any cathode was crossed. + operator bool() const noexcept { return crossed(); } + + /// Access to the cathode information (undefined behaviour if `crossed()` is `false`). + CathodePlane_t const* operator-> () const { return cathode; } + + /// Returns the cathode/line intersection point (undefined behaviour if none). + geo::Point_t intersectionPoint() const + { + assert(cathode); + return cathode->crossFinder().intersectionPoint(crossing); + } + + }; // CathodeCrossInfo + + + /// Counts of particle categories to determine the satisfaction of requirements. + struct Counters_t { + + /// Number of truth records seen. + unsigned int nTruthRecords = 0; + + /// Number of particles from any interaction crossing any cathode. + icarus::ns::util::PassCounter<> cathodeCrossing; + + }; // Counters_t + + + // --- BEGIN -- Configuration parameters ------------------------------------- + + std::vector const fGeneratorTags; ///< Input data products. + + /// Minimum number of requested cathode-crossing particles. + unsigned int const fMinimumCrossingPartcles; + + double const fCathodeLengthWiggle; ///< Fractional allowance on cathode length. + double const fCathodeHeightWiggle; ///< Fractional allowance on cathode height. + + std::string const fLogCategory; ///< Name of message facility stream. + + // --- END ---- Configuration parameters ------------------------------------- + + // --- BEGIN -- Caches ------------------------------------------------------- + + // we don't really need to group by cryostat/TPC, but it comes for ~free + std::vector const fCathodes; ///< All cathodes. + + // --- END ---- Caches ------------------------------------------------------- + + /// Count of passed and seen events. + icarus::ns::util::AtomicPassCounter<> fPassed; + + /** + * @brief Analyzes the `truth` information and updates the `counts` accordingly. + * @param truth the generated record to extract information from + * @param[out] counters counters to be updated + * + * This method extracts information but does not take any decision. + */ + void parseTruth(simb::MCTruth const& truth, Counters_t& counters) const; + + + /** + * @brief Returns one TPC whose cathode is crossed by a particle. + * @param pos starting position of the particle + * @param dir direction of the particle + * @return information on the crossing, converts to `false` if no crossing + * + * If there are multiple cathodes crossed by the particle, which one is + * returned is undefined. + */ + CathodeCrossInfo findCrossingTPCcathode + (geo::Point_t const& pos, geo::Vector_t const& dir) const; + + + /// Builds and returns information of the cathode of the specified `TPC`. + static CathodePlane_t buildCathode(geo::TPCGeo const& TPC); + + /// Builds and returns all cathodes, one per logical TPC in the geometry. + static std::vector buildCathodePlanes + (geo::GeometryCore const& geom); + +}; // class SelectCathodeCrossingGenParticles + + +//------------------------------------------------------------------------------ + +SelectCathodeCrossingGenParticles::SelectCathodeCrossingGenParticles + (Parameters const& params, art::ProcessingFrame const&) + : art::SharedFilter{ params } + // configuration + , fGeneratorTags { params().GeneratorTags() } + , fMinimumCrossingPartcles{ params().MinimumCrossingParticles() } + , fCathodeLengthWiggle { params().CathodeLengthWiggle() * 2.0 } // x2 for + , fCathodeHeightWiggle { params().CathodeHeightWiggle() * 2.0 } // half lengths + , fLogCategory { params().LogCategory() } + // caches + , fCathodes{ buildCathodePlanes(*lar::providerFrom()) } +{ + + async(); + + // + // consume declaration + // + for (art::InputTag const& tag: fGeneratorTags) + consumes>(tag); + + // + // dump configuration + // + mf::LogInfo log{ fLogCategory }; + log << "Configuration:"; + + log << "\n * check " << fGeneratorTags.size() << " generated data products:"; + for (art::InputTag const& tag: fGeneratorTags) + log << " '" << tag.encode() << "'"; + + log << "\n * minimum number of cathode-crossing particles: " + << fMinimumCrossingPartcles; + + log << "\n * fractional allowance on cathode dimensions: width " + << (fCathodeLengthWiggle / 2 * 100.0) << "%, height " + << (fCathodeHeightWiggle / 2 * 100.0) << "%"; + + // + // debug dump + // + { + mf::LogTrace log{ fLogCategory }; + log << "Found " << fCathodes.size() << " cathode planes:"; + for (CathodePlane_t const& cathode: fCathodes) { + log << "\n - " << cathode.TPC().ID() + << ": ( " << cathode.length() << " x " << cathode.height() << " ) cm at " + << cathode.center(); + } // for + } + +} // SelectCathodeCrossingGenParticles::SelectCathodeCrossingGenParticles() + + +//------------------------------------------------------------------------------ +bool SelectCathodeCrossingGenParticles::filter + (art::Event& event, art::ProcessingFrame const&) +{ + + // + // collect information + // + mf::LogDebug{ fLogCategory } << "Evaluation started."; + + Counters_t counters; + + for (art::InputTag const& truthTag: fGeneratorTags) { + + auto const& truths = event.getProduct>(truthTag); + mf::LogTrace{ fLogCategory } + << "Now serving: " << truthTag.encode() << " (" << truths.size() << " records)"; + + for (auto const& [ iTruth, truth ]: util::enumerate(truths)) { + mf::LogTrace{ fLogCategory } + << "Truth #" << iTruth << " from '" << truthTag.encode() << ": " + << truth.NParticles() << " particles"; + + parseTruth(truth, counters); + + } // for truth record + + } // for truth tags + + + // + // draw conclusions + // + unsigned int const nCathodeCrossing = counters.cathodeCrossing.passed(); + bool const accepted = (nCathodeCrossing >= fMinimumCrossingPartcles); + + mf::LogInfo{ fLogCategory } + << event.id() << ": " << counters.cathodeCrossing.passed() + << " / " << counters.cathodeCrossing.total() + << " generated particles crossed a cathode."; + + fPassed.add(accepted); + + return accepted; + +} // SelectCathodeCrossingGenParticles::filter() + + +//------------------------------------------------------------------------------ +void SelectCathodeCrossingGenParticles::endJob(art::ProcessingFrame const&) { + + if (fPassed.total() > 0) { + mf::LogInfo{ fLogCategory } + << fPassed.passed() << "/" << fPassed.total() + << " events (" << (fPassed.passed() * 100.0 / fPassed.total()) + << "%) passed the requirements."; + } + +} // SelectCathodeCrossingGenParticles::endJob() + + +//------------------------------------------------------------------------------ +void SelectCathodeCrossingGenParticles::parseTruth + (simb::MCTruth const& truth, Counters_t& counters) const +{ + + ++(counters.nTruthRecords); + + for (auto const iPart: util::counter(truth.NParticles())) { + simb::MCParticle const& particle = truth.GetParticle(iPart); + + bool const isFinal = particle.StatusCode() == 1; + if (!isFinal) continue; + + geo::Point_t const pos = geo::vect::toPoint(particle.EndPosition().Vect()); + geo::Vector_t const dir = geo::vect::toVector(particle.EndMomentum().Vect()); + + CathodeCrossInfo const crossedTPCcathode = findCrossingTPCcathode(pos, dir); + + { + mf::LogTrace log{ fLogCategory }; + log << "Particle #" << iPart << " (" << sim::ParticleName(particle.PdgCode()) + << " at " << pos << " toward " << dir << ")"; + if (crossedTPCcathode) log << " crosses " << crossedTPCcathode->TPC().ID(); + else log << " does not cross any TPC cathode"; + } // block + + counters.cathodeCrossing.add(crossedTPCcathode.crossed()); + + } // for particle + +} // SelectCathodeCrossingGenParticles::parseTruth() + + +//------------------------------------------------------------------------------ +SelectCathodeCrossingGenParticles::CathodeCrossInfo +SelectCathodeCrossingGenParticles::findCrossingTPCcathode + (geo::Point_t const& pos, geo::Vector_t const& dir) const +{ + // try all, one after another + mf::LogTrace{ fLogCategory } + << "Testing particle from " << pos << " cm toward " << dir; + + for (CathodePlane_t const& plane: fCathodes) { + CathodeCrossInfo const crossing { + /* .cathode = */ &plane + , /* .crossing = */ plane.findCrossing(pos, dir) + }; + + if (crossing) { + mf::LogTrace{ fLogCategory } << " - TPC " << plane.TPC().ID() + << " met at " << crossing.intersectionPoint() + << " cm (plane: L=" << crossing.cathodeLengthUnits() + << " cm, H=" << crossing.cathodeHeightUnits() + << "; P=" << crossing.particleDirUnits() << " cm)"; + } + else { + mf::LogTrace{ fLogCategory } << " - TPC " << plane.TPC().ID() + << " not crossed"; + } + + if (!crossing) continue; + + // is crossing point contained in the (expanded) cathode area? + if (std::abs(crossing.cathodeHeightUnits()) > 1. + fCathodeLengthWiggle) continue; + if (std::abs(crossing.cathodeHeightUnits()) > 1. + fCathodeHeightWiggle) continue; + + // is the point in the future of the particle? + if (crossing.particleDirUnits() < 0) continue; + + return crossing; + } // for cathode planes + + return {}; +} // SelectCathodeCrossingGenParticles::findCrossingTPCcathode() + + +//------------------------------------------------------------------------------ +SelectCathodeCrossingGenParticles::CathodePlane_t +SelectCathodeCrossingGenParticles::buildCathode(geo::TPCGeo const& TPC) { + + // the width direction is not guaranteed to point from anode to cathode nor + // the opposite, so we use the drift direction, which should be parallel. + return { + // center + TPC.GetActiveVolumeCenter() - TPC.DriftDir() * TPC.ActiveHalfWidth() + // length + , TPC.LengthDir() * TPC.ActiveLength() + // height + , TPC.HeightDir() * TPC.ActiveHeight() + , TPC + }; + +} // SelectCathodeCrossingGenParticles::buildCathode() + + +//------------------------------------------------------------------------------ +std::vector +SelectCathodeCrossingGenParticles::buildCathodePlanes + (geo::GeometryCore const& geom) +{ + std::vector cathodePlanes; + cathodePlanes.reserve(geom.TotalNTPC()); + + for (auto const& TPC: geom.Iterate()) + cathodePlanes.emplace_back(buildCathode(TPC)); + + return cathodePlanes; +} // SelectCathodeCrossingGenParticles::buildCathodePlanes() + + +//------------------------------------------------------------------------------ +DEFINE_ART_MODULE(SelectCathodeCrossingGenParticles) + + +//------------------------------------------------------------------------------ + From 0d3e9ff5c6d8ce023f031d66c1f7ee097cdbd7e1 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Tue, 28 Oct 2025 22:19:08 -0500 Subject: [PATCH 06/47] make MC2-var4 tune standard --- .../PMT/Algorithms/pmtsimulation_icarus.fcl | 76 +++++++++++++++++-- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl b/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl index 7f4f695f8..0c04fcfd7 100644 --- a/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl +++ b/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl @@ -35,7 +35,8 @@ # introduced configuration for SPR 202202 # 20240125 (petrillo@slac.stanford.edu) # introduced experimental setting PMT gain to 7.5 x 10^6 (and q.e. elsewhere) -# +# 202510XX (mvicenzi@bnl.gov) +# introduced configuration for new Run2 SPR (SPRisolHitRun9271) #include "opticalproperties_icarus.fcl" @@ -80,9 +81,24 @@ icarus_settings_opdet_202401patch: { } # icarus_settings_opdet_202401patch +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# the following is based on `icarus_settings_opdet_2022` rescaling it to gain +# 7.0x10^6; this is an empirical choice to reconciliate the single PE region in Run1/2 +# NoiseRMS is also reduced to 2.6 ADC; see e.g. SBN DocDB 41115 +icarus_settings_opdet_run2_2025: { + + @table::icarus_settings_opdet_2022 + + nominalPMTgain: 7.0e6 # PMT multiplication gain factor + + NoiseRMS: 2.6 # in ADC# + +} # icarus_settings_opdet_run2_2025 + + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # settings used in the standard configurations: -icarus_settings_opdet: @local::icarus_settings_opdet_202401patch +icarus_settings_opdet: @local::icarus_settings_opdet_run2_2025 @@ -147,7 +163,8 @@ icarus_photoelectronresponse_exponentials: { # -# Single photoelectron response from data. +# Single photoelectron response from laser data. +# This is valid for Run1/2 cables. # icarus_photoelectronresponse_202202: { @@ -160,6 +177,21 @@ icarus_photoelectronresponse_202202: { } # icarus_photoelectronresponse_202202 +# +# Single photoelectron response from single-PE data. +# This is valid for Run1/2 cables. +# +icarus_photoelectronresponse_run2_2025: { + + tool_type: SampledWaveformFunctionTool + + WaveformData: "Responses/SPRisolHitRun9271_MV.txt" + TransitTime: "14.0 ns" # from peak to response start + Gain: @local::icarus_settings_opdet.nominalPMTgain + +} # icarus_photoelectronresponse_run2_2025 + + # # Custom photoelectron response. # @@ -189,7 +221,7 @@ icarus_photoelectronresponse_customexample: { # # pick one # -icarus_photoelectronresponse_standard: @local::icarus_photoelectronresponse_202202 +icarus_photoelectronresponse_standard: @local::icarus_photoelectronresponse_run2_2025 ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -309,9 +341,10 @@ icarus_pmtsimulationalg_202202_noise: { ReadoutEnablePeriod: "2.0 ms" # PMT enable gate duration: time for which PMT readout is enabled CreateBeamGateTriggers: true #Option to create unbiased readout around beam spill BeamGateTriggerRepPeriod: "2.0 us" # Repetition period and number of repetitions for BeamGateTriggers: - BeamGateTriggerNReps: 10 # should cover -7/+21 us, instead just goes -1 to 21 us) + BeamGateTriggerNReps: 10 # should cover -7/+21 us, instead just goes -1 to 21 us QE: @local::icarus_opticalproperties.ScintPreScale # from opticalproperties_icarus.fcl FluctuateGain: true # apply per-photoelectron gain fluctuations + ApplyTimingDelays: false # legacy value PMTspecs: { DynodeK: 0.75 # gain on a PMT multiplication stage @@ -358,6 +391,36 @@ icarus_pmtsimulationalg_202401patch: { } # icarus_pmtsimulationalg_202401patch +### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +### Configuration Run2-2025: +### * explicitly based on the configuration "2022" above +### * gain adapted to reconciliate signal integral and amplitude in SPE region +### (SBN DocDB 41115) +### * gain updated to 7.0 x 10^6 +### * threshold for digitization scaled down +### + +icarus_pmtsimulationalg_run2_2025: { + + @table::icarus_pmtsimulationalg_202202_noise + + # Apply timing delays (cables, transit time, ..) to the simulated photons + # These delays are extracted from the calibration database + ApplyTimingDelays: true + + # Threshold in ADC counts for a PMT self-trigger + ThresholdADC: 15 # ADC counts + + # arranged ad hoc to get ~40% Poisson fluctuation on gain (effectively: 40.8%) + PMTspecs: { + DynodeK: 0.75 # gain on a PMT multiplication stage + VoltageDistribution: [ 3.0, 3.4, 5.0, 3.33, 1.67, 1.0, 1.2, 1.5, 2.2, 3.0 ] + Gain: @local::icarus_settings_opdet.nominalPMTgain # total PMT gain + } + +} # icarus_pmtsimulationalg_run2_2025 + + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### ### Legacy configuration, pre-2022 @@ -397,6 +460,7 @@ icarus_pmtsimulationalg_2018: { Saturation: 300 #in number of p.e. to see saturation effects in the signal QE: @local::icarus_opticalproperties.ScintPreScale # from opticalproperties_icarus.fcl FluctuateGain: true # apply per-photoelectron gain fluctuations + ApplyTimingDelays: false # legacy value PMTspecs: { DynodeK: 0.75 # gain on a PMT multiplication stage @@ -434,7 +498,7 @@ icarus_pmtsimulationalg_2018_nonoise: { # # Includes noise. # -icarus_pmtsimulationalg_standard: @local::icarus_pmtsimulationalg_202401patch +icarus_pmtsimulationalg_standard: @local::icarus_pmtsimulationalg_run2_2025 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 14285563ce2d80e6691191dafc1dfc79e61d74b4 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 29 Oct 2025 10:45:57 -0500 Subject: [PATCH 07/47] simulate pmt timing delays in mc --- fcl/services/services_icarus_simulation.fcl | 3 +- .../PMT/Algorithms/PMTsimulationAlg.cxx | 36 +++++++++++++++---- icaruscode/PMT/Algorithms/PMTsimulationAlg.h | 25 +++++++++++-- icaruscode/PMT/SimPMTIcarus_module.cc | 2 ++ .../Timing/PMTTimingCorrectionsProvider.cxx | 2 +- 5 files changed, 57 insertions(+), 11 deletions(-) diff --git a/fcl/services/services_icarus_simulation.fcl b/fcl/services/services_icarus_simulation.fcl index b416faa26..bbdc9eeee 100644 --- a/fcl/services/services_icarus_simulation.fcl +++ b/fcl/services/services_icarus_simulation.fcl @@ -39,6 +39,7 @@ #include "calibrationservices_icarus.fcl" #include "signalservices_icarus.fcl" #include "photpropservices_icarus.fcl" +#include "timing_icarus.fcl" BEGIN_PROLOG @@ -116,7 +117,7 @@ icarus_g4_services: { icarus_detsim_services: { @table::icarus_detsim_dark_services - + IPMTTimingCorrectionService: @local::icarus_pmttimingservice # PmtGainService: @local::icarus_pmtgain_service } # icarus_detsim_services diff --git a/icaruscode/PMT/Algorithms/PMTsimulationAlg.cxx b/icaruscode/PMT/Algorithms/PMTsimulationAlg.cxx index 9b27c857a..297896fef 100644 --- a/icaruscode/PMT/Algorithms/PMTsimulationAlg.cxx +++ b/icaruscode/PMT/Algorithms/PMTsimulationAlg.cxx @@ -146,11 +146,11 @@ icarus::opdet::PMTsimulationAlg::PMTsimulationAlg } // check that the sampled waveform has a sufficiently large range, so that - // tails are below 10^-3 ADC counts (absolute value); + // tails are below 5x10^-2 ADC counts (absolute value); // if this test fails, it's better to reduce the threshold in wsp constructor // (for analytical pulses converging to 0) or have a longer sampling that does - // converge to 0 (10^-3 ADC is quite low though). - wsp.checkRange(1.0e-3_ADCf, "PMTsimulationAlg"); + // converge to 0 (5x10^-2 ADC is quite low though). + wsp.checkRange(5.0e-2_ADCf, "PMTsimulationAlg"); } // icarus::opdet::PMTsimulationAlg::PMTsimulationAlg() @@ -204,6 +204,19 @@ auto icarus::opdet::PMTsimulationAlg::CreateFullWaveform raw::Channel_t const channel = photons.OpChannel(); + // + // Preparing the total time delay for this optical channel. + // We get the delay from the timing corrections used in data. + // Corrections are additive, i.e. the service returns negative values. + // Need to flip the sign to use them as delays. + // + double totalDelay = 0; + if(fParams.doTimingDelays) { + totalDelay -= fParams.timingDelays->getLaserCorrections(channel); + totalDelay -= fParams.timingDelays->getCosmicsCorrections(channel); + } + microsecond const timeDelay { totalDelay }; + // // collect the amount of photoelectrons arriving at each subtick; // the waveform is split in groups of photons at the same relative subtick @@ -234,18 +247,21 @@ auto icarus::opdet::PMTsimulationAlg::CreateFullWaveform trigger_time const mytime = timings.toTriggerTime(photonTime) - fParams.triggerOffsetPMT + + timeDelay ; if ((mytime < 0.0_us) || (mytime >= fParams.readoutEnablePeriod)) continue; auto const [ tick, subtick ] = toTickAndSubtick(mytime.quantity() * fSampling); + /* mf::LogTrace("PMTsimulationAlg") << "Photon at " << photonTime << ", optical time " << mytime - << " => tick " << tick_d - << " => sample " << tick << " subsample " << subtick + << " (time delay " << timeDelay << ") " + << " => tick " << tick << " subtick " << subtick ; */ + if (tick >= endSample) continue; ++peMaps[subtick][tick]; } // for photons @@ -272,7 +288,9 @@ auto icarus::opdet::PMTsimulationAlg::CreateFullWaveform simulation_time const photonTime { time_ns + 0.5 }; trigger_time const mytime = timings.toTriggerTime(photonTime) - - fParams.triggerOffsetPMT; + - fParams.triggerOffsetPMT + + timeDelay + ; if ((mytime < 0.0_us) || (mytime >= fParams.readoutEnablePeriod)) continue; auto const [ tick, subtick ] @@ -889,6 +907,7 @@ icarus::opdet::PMTsimulationAlgMaker::PMTsimulationAlgMaker (PMTspecs.VoltageDistribution()); fBaseConfig.PMTspecs.gain = PMTspecs.Gain(); fBaseConfig.doGainFluctuations = config.FluctuateGain(); + fBaseConfig.doTimingDelays = config.ApplyTimingDelays(); // // single photoelectron response @@ -943,6 +962,7 @@ icarus::opdet::PMTsimulationAlgMaker::operator()( std::uint64_t beamGateTimestamp, detinfo::LArProperties const& larProp, detinfo::DetectorClocksData const& clockData, + icarusDB::PMTTimingCorrections const& timingDelays, SinglePhotonResponseFunc_t const& SPRfunction, PedestalGenerator_t& pedestalGenerator, CLHEP::HepRandomEngine& mainRandomEngine, @@ -953,7 +973,7 @@ icarus::opdet::PMTsimulationAlgMaker::operator()( { return std::make_unique(makeParams( beamGateTimestamp, - larProp, clockData, + larProp, clockData, timingDelays, SPRfunction, pedestalGenerator, mainRandomEngine, darkNoiseRandomEngine, elecNoiseRandomEngine, trackSelectedPhotons @@ -967,6 +987,7 @@ auto icarus::opdet::PMTsimulationAlgMaker::makeParams( std::uint64_t beamGateTimestamp, detinfo::LArProperties const& larProp, detinfo::DetectorClocksData const& clockData, + icarusDB::PMTTimingCorrections const& timingDelays, SinglePhotonResponseFunc_t const& SPRfunction, PedestalGenerator_t& pedestalGenerator, CLHEP::HepRandomEngine& mainRandomEngine, @@ -989,6 +1010,7 @@ auto icarus::opdet::PMTsimulationAlgMaker::makeParams( params.larProp = &larProp; params.clockData = &clockData; params.detTimings = detinfo::makeDetectorTimings(params.clockData); + params.timingDelays = &timingDelays; params.pulseFunction = &SPRfunction; params.pedestalGen = &pedestalGenerator; diff --git a/icaruscode/PMT/Algorithms/PMTsimulationAlg.h b/icaruscode/PMT/Algorithms/PMTsimulationAlg.h index 152878a73..a7e49a61c 100644 --- a/icaruscode/PMT/Algorithms/PMTsimulationAlg.h +++ b/icaruscode/PMT/Algorithms/PMTsimulationAlg.h @@ -21,6 +21,7 @@ #include "icaruscode/PMT/Algorithms/PedestalGeneratorAlg.h" #include "icaruscode/Utilities/quantities_utils.h" // util::value_t #include "icarusalg/Utilities/SampledFunction.h" +#include "icaruscode/Timing/PMTTimingCorrections.h" // LArSoft libraries #include "lardataobj/RawData/OpDetWaveform.h" @@ -183,6 +184,11 @@ class icarus::opdet::OpDetWaveformMakerClass { * For each converting photon, a photoelectron is added to the channel by * placing a template waveform shape into the channel waveform. * + * If enabled by `ApplyTimingDelays`, the timing correction service + * `icarusDB::IPMTTimingCorrectionService` is used to simulate the chain of + * delays between the photon hitting the photocathode and the time its signal + * is digitized. The delay is dominated by the signal cable length (~200ns). + * * The timestamp of each waveform is based on the same scale as the trigger * time, as defined by `detinfo::DetectorClocks::TriggerTime()`. * On that scale, the timestamp pins down the time of the first sample of @@ -475,7 +481,8 @@ class icarus::opdet::PMTsimulationAlg { hertz darkNoiseRate; float saturation; //equivalent to the number of p.e. that saturates the electronic signal PMTspecs_t PMTspecs; ///< PMT specifications. - bool doGainFluctuations; ///< Whether to simulate fain fluctuations. + bool doGainFluctuations; ///< Whether to simulate gain fluctuations. + bool doTimingDelays; ///< Whether to simulate timing delays. /// @} /// @{ @@ -487,7 +494,10 @@ class icarus::opdet::PMTsimulationAlg { detinfo::LArProperties const* larProp = nullptr; ///< LarProperties service provider. detinfo::DetectorClocksData const* clockData = nullptr; - + + /// Timing delays service interfacing with database + icarusDB::PMTTimingCorrections const* timingDelays = nullptr; + // detTimings is not really "optional" but it needs delayed construction. /// Detector clocks data wrapper. std::optional detTimings; @@ -998,6 +1008,11 @@ class icarus::opdet::PMTsimulationAlgMaker { Comment("include gain fluctuation in the photoelectron response"), true }; + fhicl::Atom ApplyTimingDelays { + Name("ApplyTimingDelays"), + Comment("add timing delays (cable, transit time) to photon times"), + true + }; // // single photoelectron response @@ -1068,6 +1083,7 @@ class icarus::opdet::PMTsimulationAlgMaker { * @param beamGateTimestamp the time of beam gate opening, in UTC [ns] * @param larProp instance of `detinfo::LArProperties` to be used * @param detClocks instance of `detinfo::DetectorClocks` to be used + * @param timingDelays instance of `icarusDB::PMTTimingCorrections` to be used * @param SPRfunction function to use for the single photon response * @param pedestalGenerator algorithm generating the pedestal plus noise * @param mainRandomEngine main random engine (quantum efficiency, etc.) @@ -1083,6 +1099,7 @@ class icarus::opdet::PMTsimulationAlgMaker { std::uint64_t beamGateTimestamp, detinfo::LArProperties const& larProp, detinfo::DetectorClocksData const& detClocks, + icarusDB::PMTTimingCorrections const& timingDelays, SinglePhotonResponseFunc_t const& SPRfunction, PedestalGenerator_t& pedestalGenerator, CLHEP::HepRandomEngine& mainRandomEngine, @@ -1096,6 +1113,7 @@ class icarus::opdet::PMTsimulationAlgMaker { * @param beamGateTimestamp the time of beam gate opening, in UTC [ns] * @param larProp instance of `detinfo::LArProperties` to be used * @param detClocks instance of `detinfo::DetectorClocks` to be used + * @param timingDelays instance of `icarusDB::PMTTimingCorrections` to be used * @param SPRfunction function to use for the single photon response * @param pedestalGenerator algorithm generating the pedestal plus noise * @param mainRandomEngine main random engine (quantum efficiency, etc.) @@ -1113,6 +1131,7 @@ class icarus::opdet::PMTsimulationAlgMaker { std::uint64_t beamGateTimestamp, detinfo::LArProperties const& larProp, detinfo::DetectorClocksData const& clockData, + icarusDB::PMTTimingCorrections const& timingDelays, SinglePhotonResponseFunc_t const& SPRfunction, PedestalGenerator_t& pedestalGenerator, CLHEP::HepRandomEngine& mainRandomEngine, @@ -1196,6 +1215,8 @@ void icarus::opdet::PMTsimulationAlg::printConfiguration << '\n' << indent << "Saturation: " << fParams.saturation << " p.e." << '\n' << indent << "doGainFluctuations: " << std::boolalpha << fParams.doGainFluctuations + << '\n' << indent << "doTimingDelays: " + << std::boolalpha << fParams.doTimingDelays << '\n' << indent << "PulsePolarity: " << ((fParams.pulsePolarity == 1)? "positive": "negative") << " (=" << fParams.pulsePolarity << ")" << '\n' << indent << "Sampling: " << fSampling; if (fParams.pulseSubsamples > 1U) diff --git a/icaruscode/PMT/SimPMTIcarus_module.cc b/icaruscode/PMT/SimPMTIcarus_module.cc index 98bdaca6c..6da16d173 100644 --- a/icaruscode/PMT/SimPMTIcarus_module.cc +++ b/icaruscode/PMT/SimPMTIcarus_module.cc @@ -16,6 +16,7 @@ #include "icaruscode/PMT/Algorithms/NoiseGeneratorAlg.h" #include "icaruscode/PMT/Algorithms/PhotoelectronPulseFunction.h" #include "icaruscode/IcarusObj/OpDetWaveformMeta.h" +#include "icaruscode/Timing/IPMTTimingCorrectionService.h" // LArSoft libraries #include "larcore/CoreUtils/ServiceUtil.h" @@ -390,6 +391,7 @@ SimPMTIcarus::SimPMTIcarus(Parameters const& config) e.time().value(), // using the event generation time as beam time stamp *(lar::providerFrom()), clockData, + *(lar::providerFrom()), *fSinglePhotonResponseFunc, *fPedestalGen, fEfficiencyEngine, diff --git a/icaruscode/Timing/PMTTimingCorrectionsProvider.cxx b/icaruscode/Timing/PMTTimingCorrectionsProvider.cxx index c2be07204..17dcd12f3 100644 --- a/icaruscode/Timing/PMTTimingCorrectionsProvider.cxx +++ b/icaruscode/Timing/PMTTimingCorrectionsProvider.cxx @@ -34,7 +34,7 @@ icarusDB::PMTTimingCorrectionsProvider::PMTTimingCorrectionsProvider fLaserTag = tags.get("LaserTag"); fCosmicsTag = tags.get("CosmicsTag"); if( fVerbose ) mf::LogInfo(fLogCategory) << "Database tags for timing corrections:\n" - << "Cables corrections " << fCablesTag << "\n" + << "Cable corrections " << fCablesTag << "\n" << "Laser corrections " << fLaserTag << "\n" << "Cosmics corrections " << fCosmicsTag; } From 9d43105a9955f36b00db8017dff53dc2b553828b Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 29 Oct 2025 11:32:08 -0500 Subject: [PATCH 08/47] disable pmt mc noise for overlays --- fcl/detsim/detsim_2d_icarus_refactored_overlay.fcl | 3 +++ .../detsim_2d_icarus_refactored_yzsim_notrigger_overlay.fcl | 3 +++ fcl/detsim/detsim_2d_icarus_refactored_yzsim_overlay.fcl | 3 +++ 3 files changed, 9 insertions(+) diff --git a/fcl/detsim/detsim_2d_icarus_refactored_overlay.fcl b/fcl/detsim/detsim_2d_icarus_refactored_overlay.fcl index bf9754683..e3eab1bdf 100644 --- a/fcl/detsim/detsim_2d_icarus_refactored_overlay.fcl +++ b/fcl/detsim/detsim_2d_icarus_refactored_overlay.fcl @@ -1,3 +1,6 @@ #include "detsim_2d_icarus_refactored.fcl" physics.producers.daq: @local::icarus_simwire_wirecell_shifted_overlay + +# turn off mc noise on pmt waveforms +physics.producers.opdaq: @local::icarus_simpmt_nonoise diff --git a/fcl/detsim/detsim_2d_icarus_refactored_yzsim_notrigger_overlay.fcl b/fcl/detsim/detsim_2d_icarus_refactored_yzsim_notrigger_overlay.fcl index 74147585c..a96116d92 100644 --- a/fcl/detsim/detsim_2d_icarus_refactored_yzsim_notrigger_overlay.fcl +++ b/fcl/detsim/detsim_2d_icarus_refactored_yzsim_notrigger_overlay.fcl @@ -1,3 +1,6 @@ #include "detsim_2d_icarus_refactored_yzsim_notrigger.fcl" physics.producers.daq: @local::icarus_simwire_wirecell_yz_overlay + +# turn off mc noise on pmt waveforms +physics.producers.opdaq: @local::icarus_simpmt_nonoise diff --git a/fcl/detsim/detsim_2d_icarus_refactored_yzsim_overlay.fcl b/fcl/detsim/detsim_2d_icarus_refactored_yzsim_overlay.fcl index ed2f25196..c033a866a 100644 --- a/fcl/detsim/detsim_2d_icarus_refactored_yzsim_overlay.fcl +++ b/fcl/detsim/detsim_2d_icarus_refactored_yzsim_overlay.fcl @@ -1,3 +1,6 @@ #include "detsim_2d_icarus_refactored_yzsim.fcl" physics.producers.daq: @local::icarus_simwire_wirecell_yz_overlay + +# turn off mc noise on pmt waveforms +physics.producers.opdaq: @local::icarus_simpmt_nonoise From d65588888022dea6a69a046a7cd4846f943ac5a6 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 29 Oct 2025 20:48:30 -0500 Subject: [PATCH 09/47] add ophituncorrected + ophit flow for mc --- fcl/reco/Definitions/stage0_icarus_mc_defs.fcl | 8 ++++++-- fcl/reco/Stage0/mc/stage0_run2_icarus_mc.fcl | 3 --- fcl/reco/Stage0/mc/stage0_run2_wc_icarus_mc.fcl | 3 --- .../Stage0/mc/stage0_run2_wc_icarus_mc_notriggersim.fcl | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/fcl/reco/Definitions/stage0_icarus_mc_defs.fcl b/fcl/reco/Definitions/stage0_icarus_mc_defs.fcl index 9052f38f3..7d653306a 100644 --- a/fcl/reco/Definitions/stage0_icarus_mc_defs.fcl +++ b/fcl/reco/Definitions/stage0_icarus_mc_defs.fcl @@ -5,6 +5,7 @@ #include "icarus_flashfinder.fcl" #include "icarus_opana_modules.fcl" #include "recowire_icarus.fcl" +#include "timing_icarus.fcl" #include "crttruehitproducer.fcl" #include "crtsimhitproducer.fcl" @@ -37,7 +38,8 @@ icarus_stage0_mc_producers: pmtbaselines: @local::icarus_opreco_pedestal_fromchannel_MC # from icarus_ophitfinder.fcl opdetonbeam: @local::copyPMTonBeam # from decoderdefs_icarus.fcl - ophit: @local::icarus_ophit_data + ophituncorrected: @local::icarus_ophit_data + ophit: @local::icarus_ophit_timing_correction mcophit: @local::ICARUSMCOpHit ## crt producer @@ -55,6 +57,7 @@ icarus_stage0_mc_trigger: [ icarus_stage0_mc_PMT: [ @sequence::icarus_stage0_mc_trigger, pmtbaselines, + ophituncorrected, ophit, mcophit, opflashCryoE, @@ -68,7 +71,8 @@ icarus_stage0_mc_crtreco: [crttrack, crtpmt] icarus_stage0_mc_producers.emuTrigger.BeamGates: shifted icarus_stage0_mc_producers.triggersimgates.module_type: DummyProducer # Don't rerun. We have already adjusted the BeamGate icarus_stage0_mc_producers.mcophit.SimPhotonsProducer: shifted -icarus_stage0_mc_producers.ophit.InputModule: shifted +icarus_stage0_mc_producers.ophituncorrected.InputModule: shifted +icarus_stage0_mc_producers.ophit.InputLabels: ["ophituncorrected"] icarus_stage0_mc_producers.opdetonbeam.Waveforms: shifted icarus_stage0_mc_producers.opdetonbeam.WaveformBaselineAssns: pmtbaselines icarus_stage0_mc_producers.pmtbaselines.OpticalWaveforms: shifted diff --git a/fcl/reco/Stage0/mc/stage0_run2_icarus_mc.fcl b/fcl/reco/Stage0/mc/stage0_run2_icarus_mc.fcl index 533e5d486..d08281940 100644 --- a/fcl/reco/Stage0/mc/stage0_run2_icarus_mc.fcl +++ b/fcl/reco/Stage0/mc/stage0_run2_icarus_mc.fcl @@ -40,9 +40,6 @@ outputs.rootOutput.outputCommands: ["keep *_*_*_*", "keep *_daqPMT_*_*" ] -# Set the expected input for ophit -physics.producers.ophit.InputModule: "shifted" - # Note the default assumption is that our detector simulation input will come from the WireCell 2D drift simulation, a la 'daq' # If we are running the 1D drift simulation we need to switch to using: # `physics.producers.MCDecodeTPCROI.FragmentsLabelVec: ["daq3:PHYSCRATEDATATPCWW","daq2:PHYSCRATEDATATPCWE","daq1:PHYSCRATEDATATPCEW","daq0:PHYSCRATEDATATPCEE"]` diff --git a/fcl/reco/Stage0/mc/stage0_run2_wc_icarus_mc.fcl b/fcl/reco/Stage0/mc/stage0_run2_wc_icarus_mc.fcl index d0a3118a0..4a8723f3b 100644 --- a/fcl/reco/Stage0/mc/stage0_run2_wc_icarus_mc.fcl +++ b/fcl/reco/Stage0/mc/stage0_run2_wc_icarus_mc.fcl @@ -39,9 +39,6 @@ outputs.rootOutput.outputCommands: ["keep *_*_*_*", "keep *_daqPMT_*_*" ] -# Set the expected input for ophit -physics.producers.ophit.InputModule: "shifted" - # Set up for the single module mutliple TPC mode... physics.producers.MCDecodeTPCROI.FragmentsLabelVec: ["daq:TPCWW","daq:TPCWE","daq:TPCEW","daq:TPCEE"] physics.producers.MCDecodeTPCROI.OutInstanceLabelVec: ["PHYSCRATEDATATPCWW", "PHYSCRATEDATATPCWE", "PHYSCRATEDATATPCEW", "PHYSCRATEDATATPCEE"] diff --git a/fcl/reco/Stage0/mc/stage0_run2_wc_icarus_mc_notriggersim.fcl b/fcl/reco/Stage0/mc/stage0_run2_wc_icarus_mc_notriggersim.fcl index 54f81872a..81780ecef 100644 --- a/fcl/reco/Stage0/mc/stage0_run2_wc_icarus_mc_notriggersim.fcl +++ b/fcl/reco/Stage0/mc/stage0_run2_wc_icarus_mc_notriggersim.fcl @@ -1,7 +1,7 @@ #include "stage0_run2_wc_icarus_mc.fcl" # restore non-shifted labels -physics.producers.ophit.InputModule: "opdaq" +physics.producers.ophituncorrected.InputModule: "opdaq" physics.producers.emuTrigger.BeamGates: "beamgate" physics.producers.mcophit.SimPhotonsProducer: "pdfastsim" physics.producers.opdetonbeam.Waveforms: "opdaq" From 6f0342bad5ffe42f2e7ffcea2c51d46ff4b716df Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 29 Oct 2025 21:09:25 -0500 Subject: [PATCH 10/47] update stage0 flow for overlays --- fcl/reco/Definitions/enable_overlay_sp.fcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fcl/reco/Definitions/enable_overlay_sp.fcl b/fcl/reco/Definitions/enable_overlay_sp.fcl index 8275366c5..5e831f4de 100644 --- a/fcl/reco/Definitions/enable_overlay_sp.fcl +++ b/fcl/reco/Definitions/enable_overlay_sp.fcl @@ -10,6 +10,6 @@ physics.producers.MCDecodeTPCROI.FragmentsLabelVec: ["overlayTPCRawWW", "overlay physics.producers.pmtbaselines.OpticalWaveforms: "overlayOpWaveforms" physics.producers.pmtfixedthr.OpticalWaveforms: "overlayOpWaveforms" physics.producers.opdetonbeam.OpticalWaveforms: "overlayOpWaveforms" -physics.producers.ophit.InputModule: "overlayOpWaveforms" +physics.producers.ophituncorrected.InputModule: "overlayOpWaveforms" physics.producers.crttrack.DataLabelHits: "overlayCRTHit" physics.producers.crtpmt.CrtHitModuleLabel: "overlayCRTHit" From 7e655c6c87de1edabd9db66ce7715f9e5972ab07 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 3 Nov 2025 15:09:00 -0600 Subject: [PATCH 11/47] small fix --- icaruscode/PMT/Algorithms/PMTsimulationAlg.cxx | 2 +- icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/icaruscode/PMT/Algorithms/PMTsimulationAlg.cxx b/icaruscode/PMT/Algorithms/PMTsimulationAlg.cxx index 297896fef..5e3ad9d3f 100644 --- a/icaruscode/PMT/Algorithms/PMTsimulationAlg.cxx +++ b/icaruscode/PMT/Algorithms/PMTsimulationAlg.cxx @@ -256,7 +256,7 @@ auto icarus::opdet::PMTsimulationAlg::CreateFullWaveform /* mf::LogTrace("PMTsimulationAlg") - << "Photon at " << photonTime << ", optical time " << mytime + << "Channel " << channel << ": photon at " << photonTime << ", optical time " << mytime << " (time delay " << timeDelay << ") " << " => tick " << tick << " subtick " << subtick ; diff --git a/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl b/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl index 0c04fcfd7..63c12916b 100644 --- a/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl +++ b/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl @@ -186,7 +186,7 @@ icarus_photoelectronresponse_run2_2025: { tool_type: SampledWaveformFunctionTool WaveformData: "Responses/SPRisolHitRun9271_MV.txt" - TransitTime: "14.0 ns" # from peak to response start + TransitTime: "55.1 ns" Gain: @local::icarus_settings_opdet.nominalPMTgain } # icarus_photoelectronresponse_run2_2025 From 8726590c4d8bf4e6030372f2fe958ce77d19766e Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Tue, 4 Nov 2025 14:19:22 -0600 Subject: [PATCH 12/47] prelimanary reco gain tuning --- icaruscode/PMT/OpReco/fcl/icarus_spe.fcl | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/icaruscode/PMT/OpReco/fcl/icarus_spe.fcl b/icaruscode/PMT/OpReco/fcl/icarus_spe.fcl index d1666f42f..e550d3995 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_spe.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_spe.fcl @@ -22,6 +22,18 @@ SPE202401patch: { # amplitude set to 3.23 mV, gain 7.5x10^6 with R = 50 ohm Shift: 0. } -SPE: @local::SPE202401patch +SPE2025Run2: { + Area: 152.50 # ADC x (2 ns) + Amplitude: 28.50 # ADC + Shift: 0. +} + +SPE2025Run3: { + Area: 132.50 # ADC x (2 ns) + Amplitude: 31.50 # ADC + Shift: 0. +} + +SPE: @local::SPE2025Run2 END_PROLOG From 0fe2b8e973093f4a57bc33b36da47f9e15969dd5 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 10 Nov 2025 10:34:38 -0500 Subject: [PATCH 13/47] add SPRRun3, make SPRRun2 default --- icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl | 2 +- icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl | 4 ++-- icaruscode/PMT/OpReco/fcl/icarus_ophitfinder.fcl | 8 ++++---- icaruscode/PMT/OpReco/fcl/icarus_spe.fcl | 11 ++++++----- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl b/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl index 7d5e6c5b5..c4ef040b7 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl @@ -13,7 +13,7 @@ BEGIN_PROLOG # in the hit reconstruction. # icarus_pmt_calibration.NoCalib: { - SPEAreaGain: @local::SPE.Area + SPEAreaGain: @local::SPERun2.Area } diff --git a/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl b/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl index 628ef5c5d..6d39330ca 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl @@ -25,8 +25,8 @@ ICARUSMCOpHit: { module_type: "ICARUSMCOpHit" MergePeriod: 0.01 SimPhotonsProducer: "pdfastsim" - SPEArea: @local::SPE.Area - SPEAmplitude: @local::SPE.Amplitude + SPEArea: @local::SPERun2.Area + SPEAmplitude: @local::SPERun2.Amplitude } ICARUSMCOpFlash: { diff --git a/icaruscode/PMT/OpReco/fcl/icarus_ophitfinder.fcl b/icaruscode/PMT/OpReco/fcl/icarus_ophitfinder.fcl index 072ab19d5..66ad03349 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_ophitfinder.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_ophitfinder.fcl @@ -193,10 +193,10 @@ icarus_ophit: # some basic configuration ChannelMasks: [] HitThreshold: 0.2 # PE AreaToPE: true # Use area to calculate number of PEs - SPEArea: @local::SPE.Area # If AreaToPE is true, this number is - # used as single PE area (in ADC counts) - SPEShift: @local::SPE.Shift # Used by PhotonCalibratorStandard to compute - # PE = area / SPEArea + SPEShift + SPEArea: @local::SPERun2.Area # If AreaToPE is true, this number is + # used as single PE area (in ADC counts) + SPEShift: @local::SPERun2.Shift # Used by PhotonCalibratorStandard to compute + # PE = area / SPEArea + SPEShift UseStartTime: false # start and peak times each in its own data member reco_man: @local::standard_preco_manager HitAlgoPset: @local::icarus_opreco_hit_slidingwindow_201910 diff --git a/icaruscode/PMT/OpReco/fcl/icarus_spe.fcl b/icaruscode/PMT/OpReco/fcl/icarus_spe.fcl index e550d3995..d845d49eb 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_spe.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_spe.fcl @@ -23,17 +23,18 @@ SPE202401patch: { # amplitude set to 3.23 mV, gain 7.5x10^6 with R = 50 ohm } SPE2025Run2: { - Area: 152.50 # ADC x (2 ns) - Amplitude: 28.50 # ADC + Area: 152.01 # ADC x (2 ns) + Amplitude: 28.08 # ADC Shift: 0. } SPE2025Run3: { - Area: 132.50 # ADC x (2 ns) - Amplitude: 31.50 # ADC + Area: 132.37 # ADC x (2 ns) + Amplitude: 31.36 # ADC Shift: 0. } -SPE: @local::SPE2025Run2 +SPERun2: @local::SPE2025Run2 +SPERun3: @local::SPE2025Run3 END_PROLOG From a138d80e5c63988137c27db06e025322857d331f Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 10 Nov 2025 10:44:22 -0500 Subject: [PATCH 14/47] nullify flash calibration --- icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl | 9 ++++++--- icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl b/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl index c4ef040b7..76474a519 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl @@ -12,10 +12,13 @@ BEGIN_PROLOG # in the hit) needs to be the same value as the single photoelectron area used # in the hit reconstruction. # -icarus_pmt_calibration.NoCalib: { +icarus_pmt_calibration.NoCalibRun2: { SPEAreaGain: @local::SPERun2.Area } +icarus_pmt_calibration.NoCalibRun3: { + SPEAreaGain: @local::SPERun3.Area +} # ------------------------------------------------------------------------------ # `icarus_pmt_calibration.Calib202203`: from March 2021 @@ -27,8 +30,8 @@ icarus_pmt_calibration.Calib202203: { # ------------------------------------------------------------------------------ -icarus_pmt_calibration.CalibStandard: @local::icarus_pmt_calibration.NoCalib - +icarus_pmt_calibration.CalibStandardRun2: @local::icarus_pmt_calibration.NoCalibRun2 +icarus_pmt_calibration.CalibStandardRun3: @local::icarus_pmt_calibration.NoCalibRun3 END_PROLOG diff --git a/icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl b/icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl index 6b76b04c7..9a4e4a49e 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl @@ -9,7 +9,7 @@ ICARUSSimpleFlash: FlashFinderAlgo : "SimpleFlashAlgo" AlgoConfig : @local::SimpleFlashStandard OpHitProducer : "ophit" - PECalib : @local::icarus_pmt_calibration.CalibStandard + PECalib : @local::icarus_pmt_calibration.CalibStandardRun2 } ICARUSSimpleFlashCryoE: @local::ICARUSSimpleFlash From e9a9beaaa8df9fdc85bdbdb3191f2f8e277d49fb Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 10 Nov 2025 11:54:33 -0500 Subject: [PATCH 15/47] add run3 opdet tune, make run2 default --- .../PMT/Algorithms/pmtsimulation_icarus.fcl | 94 +++++++++++++++++-- icaruscode/PMT/Trigger/trigger_icarus.fcl | 4 +- icaruscode/PMT/opdetsim_pmt_icarus.fcl | 22 +++-- 3 files changed, 102 insertions(+), 18 deletions(-) diff --git a/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl b/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl index 63c12916b..7de6bcb6d 100644 --- a/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl +++ b/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl @@ -5,7 +5,9 @@ # Configurations offered: # # * `PMTsimulationAlg` algorithm: -# * `icarus_pmtsimulationalg_standard`: main configuration, expected to be +# * `icarus_pmtsimulationalg_standard_run2`: main configuration for Run1/2, expected to be +# used in production and by the general user +# * `icarus_pmtsimulationalg_standard_run3`: main configuration for Run3/4/5+, expected to be # used in production and by the general user # * `icarus_pmtsimulationalg_202202`: a general use configuration, # including dark and electronics noise; `noise` and `nonoise` variants @@ -13,6 +15,10 @@ # * `icarus_pmtsimulationalg_2018`: legacy configuration (until June 2022), # including dark and electronics noise; `noise` and `nonoise` variants # (the latter with dark and electronics noise disabled) +# * `icarus_pmtsimulationalg_run2_2025`: run1/2 configuration (developed in 2025), +# including noise, new response function and gain tune. +# * `icarus_pmtsimulationalg_run3_2025`: run3/4/5+ configuration (developed in 2025), +# including noise, new response function and gain tune. # # Usage: # @@ -35,8 +41,9 @@ # introduced configuration for SPR 202202 # 20240125 (petrillo@slac.stanford.edu) # introduced experimental setting PMT gain to 7.5 x 10^6 (and q.e. elsewhere) -# 202510XX (mvicenzi@bnl.gov) +# 20251111 (mvicenzi@bnl.gov) # introduced configuration for new Run2 SPR (SPRisolHitRun9271) +# introduced configuration for new Run3 SPR (SPRisolHitRun12715) #include "opticalproperties_icarus.fcl" @@ -95,11 +102,28 @@ icarus_settings_opdet_run2_2025: { } # icarus_settings_opdet_run2_2025 +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# the following is based on `icarus_settings_opdet_2022` rescaling it to gain +# 7.0x10^6; this is an empirical choice to reconciliate the single PE region in Run3/4 +# NoiseRMS is also reduced to 2.6 ADC; see e.g. SBN DocDB 41115 +icarus_settings_opdet_run3_2025: { + + @table::icarus_settings_opdet_2022 + + nominalPMTgain: 7.0e6 # PMT multiplication gain factor + + NoiseRMS: 2.6 # in ADC# + +} # icarus_settings_opdet_run3_2025 + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # settings used in the standard configurations: + icarus_settings_opdet: @local::icarus_settings_opdet_run2_2025 +icarus_settings_opdet_run2: @local::icarus_settings_opdet_run2_2025 +icarus_settings_opdet_run3: @local::icarus_settings_opdet_run3_2025 ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -156,7 +180,7 @@ icarus_photoelectronresponse_exponentials: { TransitTime: "55.1 ns" RaiseTimeConstant: "1.8 ns" FallTimeConstant: "4.2 ns" - Gain: @local::icarus_settings_opdet.nominalPMTgain # Gain = 7.0e6 => PeakCurrent: -0.14144 mA + Gain: @local::icarus_settings_opdet_2022.nominalPMTgain # Gain = 7.0e6 => PeakCurrent: -0.14144 mA ADC: 409.6 # ADC / mA } # icarus_photoelectronresponse_exponentials @@ -172,7 +196,7 @@ icarus_photoelectronresponse_202202: { WaveformData: "Responses/SPR202202.txt" TransitTime: "55.1 ns" - Gain: @local::icarus_settings_opdet.nominalPMTgain + Gain: @local::icarus_settings_opdet_2022.nominalPMTgain } # icarus_photoelectronresponse_202202 @@ -187,11 +211,26 @@ icarus_photoelectronresponse_run2_2025: { WaveformData: "Responses/SPRisolHitRun9271_MV.txt" TransitTime: "55.1 ns" - Gain: @local::icarus_settings_opdet.nominalPMTgain + Gain: @local::icarus_settings_opdet_run2.nominalPMTgain } # icarus_photoelectronresponse_run2_2025 +# +# Single photoelectron response from single-PE data. +# This is valid for Run3/4/5+ cables. +# +icarus_photoelectronresponse_run3_2025: { + + tool_type: SampledWaveformFunctionTool + + WaveformData: "Responses/SPRisolHitRun12715_MV.txt" + TransitTime: "55.1 ns" + Gain: @local::icarus_settings_opdet_run3.nominalPMTgain + +} # icarus_photoelectronresponse_run3_2025 + + # # Custom photoelectron response. # @@ -221,7 +260,9 @@ icarus_photoelectronresponse_customexample: { # # pick one # -icarus_photoelectronresponse_standard: @local::icarus_photoelectronresponse_run2_2025 + +icarus_photoelectronresponse_standard_run2: @local::icarus_photoelectronresponse_run2_2025 +icarus_photoelectronresponse_standard_run3: @local::icarus_photoelectronresponse_run3_2025 ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -318,7 +359,7 @@ icarus_pmtsimulationalg_202202_noise: { Pedestal: @local::icarus_pmt_pedestal_standard - SinglePhotonResponse: @local::icarus_photoelectronresponse_standard + SinglePhotonResponse: @local::icarus_photoelectronresponse_202202 DarkNoiseRate: "1.6 kHz" # per channel, from CERN test stand measurement @@ -404,6 +445,8 @@ icarus_pmtsimulationalg_run2_2025: { @table::icarus_pmtsimulationalg_202202_noise + SinglePhotonResponse: @local::icarus_photoelectronresponse_standard_run2 + # Apply timing delays (cables, transit time, ..) to the simulated photons # These delays are extracted from the calibration database ApplyTimingDelays: true @@ -415,12 +458,42 @@ icarus_pmtsimulationalg_run2_2025: { PMTspecs: { DynodeK: 0.75 # gain on a PMT multiplication stage VoltageDistribution: [ 3.0, 3.4, 5.0, 3.33, 1.67, 1.0, 1.2, 1.5, 2.2, 3.0 ] - Gain: @local::icarus_settings_opdet.nominalPMTgain # total PMT gain + Gain: @local::icarus_settings_opdet_run2.nominalPMTgain # total PMT gain } } # icarus_pmtsimulationalg_run2_2025 +### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +### Configuration Run3-2025: +### * explicitly based on the configuration "2022" above +### * gain adapted to reconciliate signal integral and amplitude in SPE region +### * gain updated to 7.0 x 10^6 +### * threshold for digitization scaled down +### + +icarus_pmtsimulationalg_run3_2025: { + + @table::icarus_pmtsimulationalg_202202_noise + + SinglePhotonResponse: @local::icarus_photoelectronresponse_standard_run3 + + # Apply timing delays (cables, transit time, ..) to the simulated photons + # These delays are extracted from the calibration database + ApplyTimingDelays: true + + # Threshold in ADC counts for a PMT self-trigger + ThresholdADC: 15 # ADC counts + + # arranged ad hoc to get ~40% Poisson fluctuation on gain (effectively: 40.8%) + PMTspecs: { + DynodeK: 0.75 # gain on a PMT multiplication stage + VoltageDistribution: [ 3.0, 3.4, 5.0, 3.33, 1.67, 1.0, 1.2, 1.5, 2.2, 3.0 ] + Gain: @local::icarus_settings_opdet_run3.nominalPMTgain # total PMT gain + } + +} # icarus_pmtsimulationalg_run3_2025 + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### ### Legacy configuration, pre-2022 @@ -435,7 +508,7 @@ icarus_pmtsimulationalg_2018: { } } # Pedestal - SinglePhotonResponse: @local::icarus_photoelectronresponse_standard + SinglePhotonResponse: @local::icarus_photoelectronresponse_202202 DarkNoiseRate: "1.6 kHz" # from CERN test stand measurement @@ -498,7 +571,8 @@ icarus_pmtsimulationalg_2018_nonoise: { # # Includes noise. # -icarus_pmtsimulationalg_standard: @local::icarus_pmtsimulationalg_run2_2025 +icarus_pmtsimulationalg_standard_run2: @local::icarus_pmtsimulationalg_run2_2025 +icarus_pmtsimulationalg_standard_run3: @local::icarus_pmtsimulationalg_run3_2025 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/icaruscode/PMT/Trigger/trigger_icarus.fcl b/icaruscode/PMT/Trigger/trigger_icarus.fcl index 5c8c11bc8..4e6a4d207 100644 --- a/icaruscode/PMT/Trigger/trigger_icarus.fcl +++ b/icaruscode/PMT/Trigger/trigger_icarus.fcl @@ -311,8 +311,8 @@ icarus_enablegate_sim: { BeamGates: [ { - Duration: @local::icarus_pmtsimulationalg_standard.ReadoutEnablePeriod # from pmtsimulation_icarus.fcl - Start: @local::icarus_pmtsimulationalg_standard.TriggerOffsetPMT # from pmtsimulation_icarus.fcl + Duration: @local::icarus_pmtsimulationalg_standard_run2.ReadoutEnablePeriod # from pmtsimulation_icarus.fcl + Start: @local::icarus_pmtsimulationalg_standard_run2.TriggerOffsetPMT # from pmtsimulation_icarus.fcl } ] diff --git a/icaruscode/PMT/opdetsim_pmt_icarus.fcl b/icaruscode/PMT/opdetsim_pmt_icarus.fcl index 06a6f00e9..5d780ec26 100644 --- a/icaruscode/PMT/opdetsim_pmt_icarus.fcl +++ b/icaruscode/PMT/opdetsim_pmt_icarus.fcl @@ -5,23 +5,33 @@ BEGIN_PROLOG -icarus_simpmt: +icarus_simpmt_run2: { module_type: "SimPMTIcarus" InputModule: "pdfastsim" - @table::icarus_pmtsimulationalg_standard + @table::icarus_pmtsimulationalg_standard_run2 } +icarus_simpmt_run3: +{ + module_type: "SimPMTIcarus" + InputModule: "pdfastsim" + + @table::icarus_pmtsimulationalg_standard_run3 +} -icarus_simpmt_nonoise: { - @table::icarus_simpmt +icarus_simpmt_run2_nonoise: { + @table::icarus_simpmt_run2 @table::icarus_pmtsimulation.disable_noise } -icarus_simpmt_noise: { - @table::icarus_simpmt +icarus_simpmt_run3_nonoise: { + @table::icarus_simpmt_run3 + @table::icarus_pmtsimulation.disable_noise } +icarus_simpmt: @local::icarus_simpmt_run2 +icarus_simpmt_nonoise: @local::icarus_simpmt_run2_nonoise END_PROLOG From e918fe86954086cde1f25f0af34cdc75a217c82e Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 12 Nov 2025 17:21:44 -0500 Subject: [PATCH 16/47] change run3->run4, update gain --- .../PMT/Algorithms/pmtsimulation_icarus.fcl | 40 +++++++++---------- .../PMT/OpReco/fcl/icarus_flashcalib.fcl | 5 +++ icaruscode/PMT/OpReco/fcl/icarus_spe.fcl | 11 ++++- icaruscode/PMT/opdetsim_pmt_icarus.fcl | 8 ++-- 4 files changed, 38 insertions(+), 26 deletions(-) diff --git a/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl b/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl index 7de6bcb6d..6d5a71581 100644 --- a/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl +++ b/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl @@ -7,7 +7,7 @@ # * `PMTsimulationAlg` algorithm: # * `icarus_pmtsimulationalg_standard_run2`: main configuration for Run1/2, expected to be # used in production and by the general user -# * `icarus_pmtsimulationalg_standard_run3`: main configuration for Run3/4/5+, expected to be +# * `icarus_pmtsimulationalg_standard_run4`: main configuration for Run3/4/5+, expected to be # used in production and by the general user # * `icarus_pmtsimulationalg_202202`: a general use configuration, # including dark and electronics noise; `noise` and `nonoise` variants @@ -17,7 +17,7 @@ # (the latter with dark and electronics noise disabled) # * `icarus_pmtsimulationalg_run2_2025`: run1/2 configuration (developed in 2025), # including noise, new response function and gain tune. -# * `icarus_pmtsimulationalg_run3_2025`: run3/4/5+ configuration (developed in 2025), +# * `icarus_pmtsimulationalg_run4_2025`: run3/4/5+ configuration (developed in 2025), # including noise, new response function and gain tune. # # Usage: @@ -42,8 +42,8 @@ # 20240125 (petrillo@slac.stanford.edu) # introduced experimental setting PMT gain to 7.5 x 10^6 (and q.e. elsewhere) # 20251111 (mvicenzi@bnl.gov) -# introduced configuration for new Run2 SPR (SPRisolHitRun9271) -# introduced configuration for new Run3 SPR (SPRisolHitRun12715) +# introduced configuration for new Run1/2 SPR (SPRisolHitRun9271) +# introduced configuration for new Run3/4 SPR (SPRisolHitRun12715) #include "opticalproperties_icarus.fcl" @@ -104,17 +104,17 @@ icarus_settings_opdet_run2_2025: { # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # the following is based on `icarus_settings_opdet_2022` rescaling it to gain -# 7.0x10^6; this is an empirical choice to reconciliate the single PE region in Run3/4 +# 4.5x10^6; this is an empirical choice to reconciliate the single PE region in Run3/4 # NoiseRMS is also reduced to 2.6 ADC; see e.g. SBN DocDB 41115 -icarus_settings_opdet_run3_2025: { +icarus_settings_opdet_run4_2025: { @table::icarus_settings_opdet_2022 - nominalPMTgain: 7.0e6 # PMT multiplication gain factor + nominalPMTgain: 4.5e6 # PMT multiplication gain factor NoiseRMS: 2.6 # in ADC# -} # icarus_settings_opdet_run3_2025 +} # icarus_settings_opdet_run4_2025 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -123,7 +123,7 @@ icarus_settings_opdet_run3_2025: { icarus_settings_opdet: @local::icarus_settings_opdet_run2_2025 icarus_settings_opdet_run2: @local::icarus_settings_opdet_run2_2025 -icarus_settings_opdet_run3: @local::icarus_settings_opdet_run3_2025 +icarus_settings_opdet_run4: @local::icarus_settings_opdet_run4_2025 ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -220,15 +220,15 @@ icarus_photoelectronresponse_run2_2025: { # Single photoelectron response from single-PE data. # This is valid for Run3/4/5+ cables. # -icarus_photoelectronresponse_run3_2025: { +icarus_photoelectronresponse_run4_2025: { tool_type: SampledWaveformFunctionTool WaveformData: "Responses/SPRisolHitRun12715_MV.txt" TransitTime: "55.1 ns" - Gain: @local::icarus_settings_opdet_run3.nominalPMTgain + Gain: @local::icarus_settings_opdet_run4.nominalPMTgain -} # icarus_photoelectronresponse_run3_2025 +} # icarus_photoelectronresponse_run4_2025 # @@ -262,7 +262,7 @@ icarus_photoelectronresponse_customexample: { # icarus_photoelectronresponse_standard_run2: @local::icarus_photoelectronresponse_run2_2025 -icarus_photoelectronresponse_standard_run3: @local::icarus_photoelectronresponse_run3_2025 +icarus_photoelectronresponse_standard_run4: @local::icarus_photoelectronresponse_run4_2025 ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -465,18 +465,18 @@ icarus_pmtsimulationalg_run2_2025: { ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -### Configuration Run3-2025: +### Configuration Run4-2025: ### * explicitly based on the configuration "2022" above ### * gain adapted to reconciliate signal integral and amplitude in SPE region -### * gain updated to 7.0 x 10^6 +### * gain updated to 4.5 x 10^6 ### * threshold for digitization scaled down ### -icarus_pmtsimulationalg_run3_2025: { +icarus_pmtsimulationalg_run4_2025: { @table::icarus_pmtsimulationalg_202202_noise - SinglePhotonResponse: @local::icarus_photoelectronresponse_standard_run3 + SinglePhotonResponse: @local::icarus_photoelectronresponse_standard_run4 # Apply timing delays (cables, transit time, ..) to the simulated photons # These delays are extracted from the calibration database @@ -489,10 +489,10 @@ icarus_pmtsimulationalg_run3_2025: { PMTspecs: { DynodeK: 0.75 # gain on a PMT multiplication stage VoltageDistribution: [ 3.0, 3.4, 5.0, 3.33, 1.67, 1.0, 1.2, 1.5, 2.2, 3.0 ] - Gain: @local::icarus_settings_opdet_run3.nominalPMTgain # total PMT gain + Gain: @local::icarus_settings_opdet_run4.nominalPMTgain # total PMT gain } -} # icarus_pmtsimulationalg_run3_2025 +} # icarus_pmtsimulationalg_run4_2025 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### @@ -572,7 +572,7 @@ icarus_pmtsimulationalg_2018_nonoise: { # Includes noise. # icarus_pmtsimulationalg_standard_run2: @local::icarus_pmtsimulationalg_run2_2025 -icarus_pmtsimulationalg_standard_run3: @local::icarus_pmtsimulationalg_run3_2025 +icarus_pmtsimulationalg_standard_run4: @local::icarus_pmtsimulationalg_run4_2025 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl b/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl index 76474a519..66cd84b31 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl @@ -20,6 +20,10 @@ icarus_pmt_calibration.NoCalibRun3: { SPEAreaGain: @local::SPERun3.Area } +icarus_pmt_calibration.NoCalibRun4: { + SPEAreaGain: @local::SPERun4.Area +} + # ------------------------------------------------------------------------------ # `icarus_pmt_calibration.Calib202203`: from March 2021 # @@ -32,6 +36,7 @@ icarus_pmt_calibration.Calib202203: { # ------------------------------------------------------------------------------ icarus_pmt_calibration.CalibStandardRun2: @local::icarus_pmt_calibration.NoCalibRun2 icarus_pmt_calibration.CalibStandardRun3: @local::icarus_pmt_calibration.NoCalibRun3 +icarus_pmt_calibration.CalibStandardRun4: @local::icarus_pmt_calibration.NoCalibRun4 END_PROLOG diff --git a/icaruscode/PMT/OpReco/fcl/icarus_spe.fcl b/icaruscode/PMT/OpReco/fcl/icarus_spe.fcl index d845d49eb..f8f46d202 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_spe.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_spe.fcl @@ -29,12 +29,19 @@ SPE2025Run2: { } SPE2025Run3: { - Area: 132.37 # ADC x (2 ns) - Amplitude: 31.36 # ADC + Area: 127.39 # ADC x (2 ns) + Amplitude: 29.91 # ADC + Shift: 0. +} + +SPE2025Run4: { + Area: 131.83 # ADC x (2 ns) + Amplitude: 31.14 # ADC Shift: 0. } SPERun2: @local::SPE2025Run2 SPERun3: @local::SPE2025Run3 +SPERun4: @local::SPE2025Run4 END_PROLOG diff --git a/icaruscode/PMT/opdetsim_pmt_icarus.fcl b/icaruscode/PMT/opdetsim_pmt_icarus.fcl index 5d780ec26..e441c0e2c 100644 --- a/icaruscode/PMT/opdetsim_pmt_icarus.fcl +++ b/icaruscode/PMT/opdetsim_pmt_icarus.fcl @@ -13,12 +13,12 @@ icarus_simpmt_run2: @table::icarus_pmtsimulationalg_standard_run2 } -icarus_simpmt_run3: +icarus_simpmt_run4: { module_type: "SimPMTIcarus" InputModule: "pdfastsim" - @table::icarus_pmtsimulationalg_standard_run3 + @table::icarus_pmtsimulationalg_standard_run4 } icarus_simpmt_run2_nonoise: { @@ -26,8 +26,8 @@ icarus_simpmt_run2_nonoise: { @table::icarus_pmtsimulation.disable_noise } -icarus_simpmt_run3_nonoise: { - @table::icarus_simpmt_run3 +icarus_simpmt_run4_nonoise: { + @table::icarus_simpmt_run4 @table::icarus_pmtsimulation.disable_noise } From 99f4413a53eb1813150145fa2a9d8788a2342cd0 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 12 Nov 2025 22:29:14 -0500 Subject: [PATCH 17/47] add run4 detsim fhicls --- fcl/detsim/detsim_2d_icarus_refactored_Run4.fcl | 4 ++++ fcl/detsim/detsim_2d_icarus_refactored_overlay_Run4.fcl | 4 ++++ fcl/detsim/detsim_2d_icarus_refactored_yzsim_Run4.fcl | 3 +++ fcl/detsim/detsim_2d_icarus_refactored_yzsim_overlay_Run4.fcl | 3 +++ 4 files changed, 14 insertions(+) create mode 100644 fcl/detsim/detsim_2d_icarus_refactored_Run4.fcl create mode 100644 fcl/detsim/detsim_2d_icarus_refactored_overlay_Run4.fcl diff --git a/fcl/detsim/detsim_2d_icarus_refactored_Run4.fcl b/fcl/detsim/detsim_2d_icarus_refactored_Run4.fcl new file mode 100644 index 000000000..3b681fca5 --- /dev/null +++ b/fcl/detsim/detsim_2d_icarus_refactored_Run4.fcl @@ -0,0 +1,4 @@ +#include "detsim_2d_icarus_refactored.fcl" + +# Run3/4 optical tune +physics.producers.opdaq: @local::icarus_simpmt_run4 diff --git a/fcl/detsim/detsim_2d_icarus_refactored_overlay_Run4.fcl b/fcl/detsim/detsim_2d_icarus_refactored_overlay_Run4.fcl new file mode 100644 index 000000000..78bc947ad --- /dev/null +++ b/fcl/detsim/detsim_2d_icarus_refactored_overlay_Run4.fcl @@ -0,0 +1,4 @@ +#include "detsim_2d_icarus_refactored_overlay.fcl" + +# Run3/4 optical tune (with no noise) +physics.producers.opdaq: @local::icarus_simpmt_run4_nonoise diff --git a/fcl/detsim/detsim_2d_icarus_refactored_yzsim_Run4.fcl b/fcl/detsim/detsim_2d_icarus_refactored_yzsim_Run4.fcl index f2a5339a3..a7d94bbae 100644 --- a/fcl/detsim/detsim_2d_icarus_refactored_yzsim_Run4.fcl +++ b/fcl/detsim/detsim_2d_icarus_refactored_yzsim_Run4.fcl @@ -1,3 +1,6 @@ #include "detsim_2d_icarus_refactored_yzsim.fcl" physics.producers.daq.wcls_main.params.YZScaleMapJson: "yzmap_gain_icarus_v4_run4.json" + +# Run3/4 optical tune +physics.producers.opdaq: @local::icarus_simpmt_run4 diff --git a/fcl/detsim/detsim_2d_icarus_refactored_yzsim_overlay_Run4.fcl b/fcl/detsim/detsim_2d_icarus_refactored_yzsim_overlay_Run4.fcl index 92158743e..762233801 100644 --- a/fcl/detsim/detsim_2d_icarus_refactored_yzsim_overlay_Run4.fcl +++ b/fcl/detsim/detsim_2d_icarus_refactored_yzsim_overlay_Run4.fcl @@ -1,3 +1,6 @@ #include "detsim_2d_icarus_refactored_yzsim_overlay.fcl" physics.producers.daq.wcls_main.params.YZScaleMapJson: "yzmap_gain_icarus_v4_run4.json" + +# Run3/4 optical tune (with no noise) +physics.producers.opdaq: @local::icarus_simpmt_run4_nonoise From b90cfb594aa3c3dc6c911c20a9be0d6538e2ee96 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Tue, 18 Nov 2025 11:11:10 -0500 Subject: [PATCH 18/47] first attempt at detsim reprocessing fhicl --- ...tonly_icarus_overlay_reprocessing_run2.fcl | 94 +++++++++++++++++++ ...tonly_icarus_overlay_reprocessing_run4.fcl | 5 + 2 files changed, 99 insertions(+) create mode 100644 fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl create mode 100644 fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run4.fcl diff --git a/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl b/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl new file mode 100644 index 000000000..5bfdff037 --- /dev/null +++ b/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl @@ -0,0 +1,94 @@ +#include "detsim_2d_icarus_refactored.fcl" + +process_name: OpDetSim + +services.DetPedestalService: @erase +services.ChannelStatusService: @erase +services.SignalShapingICARUSService: @erase + +source.inputCommands: [ + "keep *", + + # `stage0` comes from decoding data: should be kept! + # `MCstage0` comes running stage0 on the overlay products: + # so pmt/trigger/crt stuff should be thrown out! + + "drop raw::OpDetWaveform*_opdaq_*_*", # drop old MC waveforms (if any) + "drop raw::OpDetWaveform*_shifted_*_*", # drop old MC (shifted) waveforms (if any) + "drop *_overlayOpWaveforms_*_*", # drop old Overlay waveforms (if any) + "drop *_ophit*_*_*", # drop MCstage0 ophits + "drop *_mcophit_*_*", # drop MCstageo mcophit + "drop *_opflash*_*_*", # drop MCsstage0 east/west opflashes + + "drop *_pmtfixedthrinit_*_*", # drop triggersim product + "drop *_pmtlvdsgatesinit_*_*", # drop triggersim product + "drop *_pmttriggerwindowsinit_*_*", # drop triggersim product + "drop *_triggersimgatesinit_*_*", # drop triggersim product + "drop *_emuTriggerUnshifted_*_*", # drop triggersim product + "drop *_pmtfixedthr_*_*", # drop MCstage0 trigger product + "drop *_pmtlvdsgates_*_*", # drop MCstage0 trigger product + "drop *_pmtlvdsgates_*_*", # drop MCstage0 trigger product + "drop *_pmtbaselines_*_MCstage0", # drop MCstage0 baselines, not stage0! + "drop *_pmttriggerwindows_*_*", # drop MCstage0 trigger product + drop "*_emuTrigger_*_*", # drop MCstage0 trigger product + + "drop *_crtdaq_*_*", # drop CRT detsim product + "drop *_mccrthit_*_*", # drop CRT mc hits + "drop *_overlayCRTHit_*_*", # drop CRT overlay hits + "drop *_crttrack_*_*", # drop CRT tracks (MCstage0) + "drop *_crtpmt_*_*", # drop CRTPMT matches (MCstage0) +] + +# Running only the optical/trigger/crt modules +# Simplify configuration removing all other producers (tpc) + +physics.producers: { + + # opdaq Run-1/2 tune for overlays (no noise) + opdaq: @local::icarus_simpmt_run2_nonoise + + # triggersim producers + @table::icarus_shifting_triggersim.producers + + # crt hits + crtdaq: @local::icarus_crtsim + +} + +# build waveforms from simPhotons (already shifted) +physics.producers.opdaq.InputModule: "shifted" + +# need to update the shifting module to pick up new labels +# some were regenerated (tag still good), others were previously shifted +# applying a second shift is okay: everything is consistent +# (eg. waveforms made from `shifted` photons) +# NOTE: still shifing energy deposits although tpc info not regenerated +# however forced to use `filtersed` as `shifted` has been consumed + +physics.producers.shifted.InputTriggerLabel: "emuTriggerUnshifted" # this was re-generated, so same tag +physics.producers.shifted.InitAuxDetSimChannelLabel: "shifted" # need to start from previously-shifted, not `genericcrt` +physics.producers.shifted.InitBeamGateInfoLabel: "triggersimgatesinit" # this was re-generated, so same tag +physics.producers.shifted.InitSimEnergyDepositLabel: "filtersed" # need to start from previously-shifted, but `shifted` no longer available +physics.producers.shifted.InitSimEnergyDepositLiteLabel: "filtersed" # need to start from previously-shifted, but `shifted` no longer available +physics.producers.shifted.InitSimPhotonsLabel: "shifted" # need to start from previously-shifted, not `pdfastsim` +physics.producers.shifted.InitWaveformLabel: "opdaq" # this was re-generated, so same tag + +# need to update shiting of priorSCE deposits: +# this is important if future reprocessings will need to regenerate SimPhotons + +physics.producers.shiftedpriorSCE.InputTriggerLabel: "emuTriggerUnshifted" # this was re-generated, so same tag +physics.producers.shiftedpriorSCE.InitSimEnergyDepositLabel: "shiftedpriorSCE" # need to start from previously-shifted, not `ionization:priorSCE` + +# The reprocessing flow is the following: +# - build new pmt waveforms from photons +# - simulate the trigger +# - shift all products to the trigger: +# -- we are shifting photons, pmt waveforms, energy depositis, aux sim channels +# -- note: since tpc is not re-simulated, no longer fully coherent with trigger time +# - build CRT data from aux sim channels + +physics.simulate: [ opdaq, @sequence::icarus_shifting_triggersim.path, crtdaq ] + + + + diff --git a/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run4.fcl b/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run4.fcl new file mode 100644 index 000000000..7c9ec528f --- /dev/null +++ b/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run4.fcl @@ -0,0 +1,5 @@ +#include "detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl" + +# switch to run4 tune +physics.producers.opdaq: @local::icarus_simpmt_run4_nonoise +physics.producers.opdaq.InputModule: "shifted" \ No newline at end of file From 468cb3f67cbeb7f63a9100d6600dbd32cbe97ede Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Tue, 18 Nov 2025 11:04:22 -0600 Subject: [PATCH 19/47] fix typo --- .../detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl b/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl index 5bfdff037..8affd8478 100644 --- a/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl +++ b/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl @@ -30,13 +30,13 @@ source.inputCommands: [ "drop *_pmtlvdsgates_*_*", # drop MCstage0 trigger product "drop *_pmtbaselines_*_MCstage0", # drop MCstage0 baselines, not stage0! "drop *_pmttriggerwindows_*_*", # drop MCstage0 trigger product - drop "*_emuTrigger_*_*", # drop MCstage0 trigger product + "drop *_emuTrigger_*_*", # drop MCstage0 trigger product "drop *_crtdaq_*_*", # drop CRT detsim product "drop *_mccrthit_*_*", # drop CRT mc hits "drop *_overlayCRTHit_*_*", # drop CRT overlay hits "drop *_crttrack_*_*", # drop CRT tracks (MCstage0) - "drop *_crtpmt_*_*", # drop CRTPMT matches (MCstage0) + "drop *_crtpmt_*_*" # drop CRTPMT matches (MCstage0) ] # Running only the optical/trigger/crt modules From 96676570ede57d52572fab961559d46c25a6f637 Mon Sep 17 00:00:00 2001 From: Gianluca Petrillo Date: Tue, 18 Nov 2025 17:50:49 -0600 Subject: [PATCH 20/47] Tell CMake of sbnalg dependency --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 542265963..7bcca8fe0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,7 @@ find_package(ifdhc REQUIRED ) find_package(ifdh_art REQUIRED ) find_package(Range-v3 REQUIRED ) find_package(sbnobj REQUIRED ) +find_package(sbnalg REQUIRED ) find_package(icarus_signal_processing REQUIRED ) find_package(icarusalg REQUIRED ) find_package(icarusutil REQUIRED ) From 8c1e40b2c9b1dd34b1cc028cbddb2e9f5d8fbb08 Mon Sep 17 00:00:00 2001 From: Gianluca Petrillo Date: Tue, 18 Nov 2025 15:58:17 -0600 Subject: [PATCH 21/47] Trigger simulation modules: support input tag with process name --- icaruscode/PMT/Trigger/LVDSgates_module.cc | 42 ++++++++++--------- .../MajorityTriggerSimulation_module.cc | 25 +++++++++-- .../SlidingWindowTriggerSimulation_module.cc | 29 ++++++++++--- .../Trigger/SlidingWindowTrigger_module.cc | 26 ++++++++++-- .../Trigger/TriggerEfficiencyPlotsBase.cxx | 18 +++++++- .../PMT/Trigger/TriggerEfficiencyPlotsBase.h | 10 +++-- .../Trigger/TriggerEfficiencyPlots_module.cc | 27 ++++++++++-- .../TriggerSimulationOnGates_module.cc | 35 ++++++++++------ 8 files changed, 160 insertions(+), 52 deletions(-) diff --git a/icaruscode/PMT/Trigger/LVDSgates_module.cc b/icaruscode/PMT/Trigger/LVDSgates_module.cc index fd447d73f..201209249 100644 --- a/icaruscode/PMT/Trigger/LVDSgates_module.cc +++ b/icaruscode/PMT/Trigger/LVDSgates_module.cc @@ -192,9 +192,9 @@ class icarus::trigger::LVDSgates: public art::EDProducer { { ComboMode::OR, "OR" } }; - fhicl::OptionalAtom TriggerGatesTag { + fhicl::OptionalAtom TriggerGatesTag { Name("TriggerGatesTag"), - Comment("label of trigger gate extraction module (no instance name)") + Comment("tag of trigger gate extraction module (no instance name)") }; fhicl::Sequence Thresholds { @@ -386,11 +386,11 @@ class icarus::trigger::LVDSgates: public art::EDProducer { /// Converts a threshold string into an input tag. static art::InputTag makeTag - (std::string const& thresholdStr, std::string const& defModule); + (std::string const& thresholdStr, art::InputTag const& defModule); /// Converts an input tag into an instance name for the corresponding output. static std::string makeOutputInstanceName - (art::InputTag const& inputTag, std::string const& defModule); + (art::InputTag const& inputTag, art::InputTag const& defModule); }; // class icarus::trigger::LVDSgates @@ -412,11 +412,11 @@ icarus::trigger::LVDSgates::LVDSgates // // more complex parameter parsing // - std::string const discrModuleLabel = config().TriggerGatesTag().value_or(""); + art::InputTag const discrModuleTag = config().TriggerGatesTag().value_or(""); for (std::string const& thresholdStr: config().Thresholds()) { - art::InputTag const inputTag = makeTag(thresholdStr, discrModuleLabel); + art::InputTag const inputTag = makeTag(thresholdStr, discrModuleTag); fADCthresholds[thresholdStr] - = { inputTag, makeOutputInstanceName(inputTag, discrModuleLabel) }; + = { inputTag, makeOutputInstanceName(inputTag, discrModuleTag) }; } // for all thresholds // @@ -863,34 +863,38 @@ auto icarus::trigger::LVDSgates::ReadTriggerGates( //------------------------------------------------------------------------------ art::InputTag icarus::trigger::LVDSgates::makeTag - (std::string const& thresholdStr, std::string const& defModule) + (std::string const& thresholdStr, art::InputTag const& defModule) { auto const isNumber = [pattern=std::regex{ "[+-]?[0-9]+" }] (std::string const& s) -> bool { return std::regex_match(s, pattern); }; - return + if (!thresholdStr.empty() && !defModule.instance().empty()) { + throw art::Exception(art::errors::Configuration) + << "Both the input gate module tag instance name (`TriggerGatesTag`: '" + << defModule.encode() << "') and the threshold '" << thresholdStr + << "' are set. One of them must be empty.\n"; + } + return ((thresholdStr.find(':') != std::string::npos) || !isNumber(thresholdStr)) ? art::InputTag{ thresholdStr } - : defModule.empty() + : defModule.label().empty() ? throw (art::Exception(art::errors::Configuration) - << "No default module label (`TriggerGatesTag`) specified" - ", and it's needed for threshold '" - << thresholdStr << "'.\n") - : art::InputTag{ defModule, thresholdStr } + << "Default module label (`TriggerGatesTag`) specified" + ", and it's needed for threshold '" << thresholdStr << "'.\n") + : art::InputTag{ defModule.label(), thresholdStr, defModule.process() } ; } // icarus::trigger::LVDSgates::makeTag() //------------------------------------------------------------------------------ std::string icarus::trigger::LVDSgates::makeOutputInstanceName - (art::InputTag const& inputTag, std::string const& defModule) + (art::InputTag const& inputTag, art::InputTag const& defModule) { - return (inputTag.label() == defModule) + return (inputTag.label() == defModule.label()) ? inputTag.instance() - : inputTag.instance().empty() - ? inputTag.label(): inputTag.label() + inputTag.instance() + : inputTag.label() + inputTag.instance() ; -} // icarus::trigger::LVDSgates::makeTag() +} // icarus::trigger::LVDSgates::makeOutputInstanceName() //------------------------------------------------------------------------------ diff --git a/icaruscode/PMT/Trigger/MajorityTriggerSimulation_module.cc b/icaruscode/PMT/Trigger/MajorityTriggerSimulation_module.cc index aae0c544d..6654739a2 100644 --- a/icaruscode/PMT/Trigger/MajorityTriggerSimulation_module.cc +++ b/icaruscode/PMT/Trigger/MajorityTriggerSimulation_module.cc @@ -359,7 +359,7 @@ class icarus::trigger::MajorityTriggerSimulation using Name = fhicl::Name; using Comment = fhicl::Comment; - fhicl::Atom TriggerGatesTag { + fhicl::Atom TriggerGatesTag { Name("TriggerGatesTag"), Comment("label of the input trigger gate data product (no instance name)") }; @@ -597,6 +597,11 @@ class icarus::trigger::MajorityTriggerSimulation //@} + /// Returns `defModule` with instance name replaced by `thresholdStr`. + static art::InputTag makeTag + (art::InputTag const& defModule, std::string const& thresholdStr); + + }; // icarus::trigger::MajorityTriggerSimulation @@ -629,10 +634,10 @@ icarus::trigger::MajorityTriggerSimulation::MajorityTriggerSimulation // // more complex parameter parsing // - std::string const discrModuleLabel = config().TriggerGatesTag(); + art::InputTag const& discrModuleTag = config().TriggerGatesTag(); for (raw::ADC_Count_t threshold: config().Thresholds()) { fADCthresholds[icarus::trigger::ADCCounts_t{threshold}] - = art::InputTag{ discrModuleLabel, util::to_string(threshold) }; + = makeTag(discrModuleTag, util::to_string(threshold)); } // initialization of a vector of atomic is not as trivial as it sounds... @@ -943,6 +948,20 @@ icarus::trigger::MajorityTriggerSimulation::triggerInfoToTriggerData } // icarus::trigger::MajorityTriggerSimulation::triggerInfoToTriggerData() +//------------------------------------------------------------------------------ +art::InputTag icarus::trigger::MajorityTriggerSimulation::makeTag + (art::InputTag const& defModule, std::string const& thresholdStr) +{ + if (!thresholdStr.empty() && !defModule.instance().empty()) { + throw art::Exception(art::errors::Configuration) + << "Module tag instance name (`TriggerGatesTag`: '" + << defModule.encode() << "') and the threshold '" << thresholdStr + << "' are both set. One of them must be empty.\n"; + } + return { defModule.label(), thresholdStr, defModule.process() }; +} // icarus::trigger::MajorityTriggerSimulation::makeTag() + + //------------------------------------------------------------------------------ DEFINE_ART_MODULE(icarus::trigger::MajorityTriggerSimulation) diff --git a/icaruscode/PMT/Trigger/SlidingWindowTriggerSimulation_module.cc b/icaruscode/PMT/Trigger/SlidingWindowTriggerSimulation_module.cc index f95638ca3..f356090f7 100644 --- a/icaruscode/PMT/Trigger/SlidingWindowTriggerSimulation_module.cc +++ b/icaruscode/PMT/Trigger/SlidingWindowTriggerSimulation_module.cc @@ -285,9 +285,9 @@ class icarus::trigger::SlidingWindowTriggerSimulation using Name = fhicl::Name; using Comment = fhicl::Comment; - fhicl::Atom TriggerGatesTag { + fhicl::Atom TriggerGatesTag { Name("TriggerGatesTag"), - Comment("label of the input trigger gate data product (no instance name)") + Comment("tag of the input trigger gate data product (no instance name)") }; fhicl::Sequence Thresholds { @@ -573,7 +573,12 @@ class icarus::trigger::SlidingWindowTriggerSimulation static double eventTimestampInSeconds(art::Timestamp const& time); static double eventTimestampInSeconds(art::Event const& event); //@} - + + + /// Returns `defModule` with instance name replaced by `thresholdStr`. + static art::InputTag makeTag + (art::InputTag const& defModule, std::string const& thresholdStr); + }; // icarus::trigger::SlidingWindowTriggerSimulation @@ -622,9 +627,9 @@ icarus::trigger::SlidingWindowTriggerSimulation::SlidingWindowTriggerSimulation // // more complex parameter parsing // - std::string const& discrModuleLabel = config().TriggerGatesTag(); + art::InputTag const& discrModuleTag = config().TriggerGatesTag(); for (std::string const& threshold: config().Thresholds()) - fADCthresholds[threshold] = art::InputTag{ discrModuleLabel, threshold }; + fADCthresholds[threshold] = makeTag(discrModuleTag, threshold); // initialization of a vector of atomic is not as trivial as it sounds... fTriggerCount = std::vector>(fADCthresholds.size()); @@ -1204,6 +1209,20 @@ double icarus::trigger::SlidingWindowTriggerSimulation::eventTimestampInSeconds { return eventTimestampInSeconds(event.time()); } +//------------------------------------------------------------------------------ +art::InputTag icarus::trigger::SlidingWindowTriggerSimulation::makeTag + (art::InputTag const& defModule, std::string const& thresholdStr) +{ + if (!thresholdStr.empty() && !defModule.instance().empty()) { + throw art::Exception(art::errors::Configuration) + << "Module tag instance name (`TriggerGatesTag`: '" + << defModule.encode() << "') and the threshold '" << thresholdStr + << "' are both set. One of them must be empty.\n"; + } + return { defModule.label(), thresholdStr, defModule.process() }; +} // icarus::trigger::SlidingWindowTriggerSimulation::makeTag() + + //------------------------------------------------------------------------------ DEFINE_ART_MODULE(icarus::trigger::SlidingWindowTriggerSimulation) diff --git a/icaruscode/PMT/Trigger/SlidingWindowTrigger_module.cc b/icaruscode/PMT/Trigger/SlidingWindowTrigger_module.cc index ad4e36dd4..4c19ff057 100644 --- a/icaruscode/PMT/Trigger/SlidingWindowTrigger_module.cc +++ b/icaruscode/PMT/Trigger/SlidingWindowTrigger_module.cc @@ -226,9 +226,9 @@ class icarus::trigger::SlidingWindowTrigger: public art::EDProducer { using Comment = fhicl::Comment; - fhicl::Atom TriggerGatesTag { + fhicl::Atom TriggerGatesTag { Name("TriggerGatesTag"), - Comment("label of the input trigger gate data product (no instance name)") + Comment("tag of the input trigger gate data product (no instance name)") }; fhicl::Sequence Thresholds { @@ -385,6 +385,9 @@ class icarus::trigger::SlidingWindowTrigger: public art::EDProducer { art::Assns const& assns ); + static art::InputTag makeTag + (art::InputTag const& defModule, std::string const& thresholdStr); + }; // class icarus::trigger::SlidingWindowTrigger @@ -435,9 +438,9 @@ icarus::trigger::SlidingWindowTrigger::SlidingWindowTrigger // // more complex parameter parsing // - std::string const discrModuleLabel = config().TriggerGatesTag(); + art::InputTag const& discrModuleTag = config().TriggerGatesTag(); for (std::string const& threshold: config().Thresholds()) - fADCthresholds[threshold] = art::InputTag{ discrModuleLabel, threshold }; + fADCthresholds[threshold] = makeTag(discrModuleTag, threshold); // // configuration report (short) @@ -668,6 +671,21 @@ auto icarus::trigger::SlidingWindowTrigger::ReadTriggerGates( } // icarus::trigger::SlidingWindowTrigger::ReadTriggerGates() + +//------------------------------------------------------------------------------ +art::InputTag icarus::trigger::SlidingWindowTrigger::makeTag + (art::InputTag const& defModule, std::string const& thresholdStr) +{ + if (!thresholdStr.empty() && !defModule.instance().empty()) { + throw art::Exception(art::errors::Configuration) + << "Module tag instance name (`TriggerGatesTag`: '" + << defModule.encode() << "') and the threshold '" << thresholdStr + << "' are both set. One of them must be empty.\n"; + } + return { defModule.label(), thresholdStr, defModule.process() }; +} // icarus::trigger::SlidingWindowTrigger::makeTag() + + //------------------------------------------------------------------------------ DEFINE_ART_MODULE(icarus::trigger::SlidingWindowTrigger) diff --git a/icaruscode/PMT/Trigger/TriggerEfficiencyPlotsBase.cxx b/icaruscode/PMT/Trigger/TriggerEfficiencyPlotsBase.cxx index b423ecc66..f769f0c6b 100644 --- a/icaruscode/PMT/Trigger/TriggerEfficiencyPlotsBase.cxx +++ b/icaruscode/PMT/Trigger/TriggerEfficiencyPlotsBase.cxx @@ -531,9 +531,9 @@ icarus::trigger::TriggerEfficiencyPlotsBase::TriggerEfficiencyPlotsBase if (fLogEventDetails.empty()) fLogEventDetails = fLogCategory; } // if EventDetailsLogCategory is specified - std::string const discrModuleLabel = config.TriggerGatesTag(); + art::InputTag const& discrModuleTag = config.TriggerGatesTag(); for (std::string const& threshold: config.Thresholds()) - fADCthresholds[threshold] = art::InputTag{ discrModuleLabel, threshold }; + fADCthresholds[threshold] = makeInputTag(discrModuleTag, threshold); if (config.EventTreeName.hasValue()) { @@ -1497,4 +1497,18 @@ icarus::trigger::TriggerEfficiencyPlotsBase::makeEdepTag( } // icarus::trigger::MakeTriggerSimulationTree::makeEdepTag() +//------------------------------------------------------------------------------ +art::InputTag icarus::trigger::TriggerEfficiencyPlotsBase::makeInputTag + (art::InputTag const& defModule, std::string const& thresholdStr) +{ + if (!thresholdStr.empty() && !defModule.instance().empty()) { + throw art::Exception(art::errors::Configuration) + << "Module tag instance name (`TriggerGatesTag`: '" + << defModule.encode() << "') and the threshold '" << thresholdStr + << "' are both set. One of them must be empty.\n"; + } + return { defModule.label(), thresholdStr, defModule.process() }; +} // icarus::trigger::TriggerEfficiencyPlotsBase::makeInputTag() + + //------------------------------------------------------------------------------ diff --git a/icaruscode/PMT/Trigger/TriggerEfficiencyPlotsBase.h b/icaruscode/PMT/Trigger/TriggerEfficiencyPlotsBase.h index 7741cd726..69b1913a8 100644 --- a/icaruscode/PMT/Trigger/TriggerEfficiencyPlotsBase.h +++ b/icaruscode/PMT/Trigger/TriggerEfficiencyPlotsBase.h @@ -222,7 +222,7 @@ class icarus::trigger::details::TriggerPassCounters { /// Registers a new pattern in the index and returns its index (unchecked). std::size_t registerPattern(std::string const& name); - + }; // icarus::trigger::details::TriggerPassCounters @@ -1010,9 +1010,9 @@ class icarus::trigger::TriggerEfficiencyPlotsBase { Comment("label of energy deposition summary data product") }; - fhicl::Atom TriggerGatesTag { + fhicl::Atom TriggerGatesTag { Name("TriggerGatesTag"), - Comment("label of the input trigger gate data product (no instance name)") + Comment("tag of the input trigger gate data product (no instance name)") }; fhicl::Sequence Thresholds { @@ -1565,6 +1565,10 @@ class icarus::trigger::TriggerEfficiencyPlotsBase { fhicl::OptionalAtom const& EnergyDepositSummaryTag ); + /// Returns `defModule` with instance name replaced by `thresholdStr`. + static art::InputTag makeInputTag + (art::InputTag const& defModule, std::string const& thresholdStr); + }; // icarus::trigger::TriggerEfficiencyPlotsBase diff --git a/icaruscode/PMT/Trigger/TriggerEfficiencyPlots_module.cc b/icaruscode/PMT/Trigger/TriggerEfficiencyPlots_module.cc index 6c47661b9..970dc31b8 100644 --- a/icaruscode/PMT/Trigger/TriggerEfficiencyPlots_module.cc +++ b/icaruscode/PMT/Trigger/TriggerEfficiencyPlots_module.cc @@ -1246,9 +1246,9 @@ class icarus::trigger::TriggerEfficiencyPlots: public art::EDAnalyzer { std::vector{ "largeant:TPCActive" } }; - fhicl::Atom TriggerGatesTag { + fhicl::Atom TriggerGatesTag { Name("TriggerGatesTag"), - Comment("label of the input trigger gate data product (no instance name)") + Comment("tag of the input trigger gate data product (no instance name)") }; fhicl::Sequence Thresholds { @@ -1496,6 +1496,11 @@ class icarus::trigger::TriggerEfficiencyPlots: public art::EDAnalyzer { /// Returns a gate that is `Max()` of all the specified `gates`. template static auto computeMaxGate(TrigGateColl const& gates); + + + /// Returns `defModule` with instance name replaced by `thresholdStr`. + static art::InputTag makeTag + (art::InputTag const& defModule, std::string const& thresholdStr); }; // icarus::trigger::TriggerEfficiencyPlots @@ -1533,10 +1538,10 @@ icarus::trigger::TriggerEfficiencyPlots::TriggerEfficiencyPlots if (fLogEventDetails.empty()) fLogEventDetails = fLogCategory; } // if EventDetailsLogCategory is specified - std::string const discrModuleLabel = config().TriggerGatesTag(); + art::InputTag const& discrModuleTag = config().TriggerGatesTag(); for (raw::ADC_Count_t threshold: config().Thresholds()) { fADCthresholds[icarus::trigger::ADCCounts_t{threshold}] - = art::InputTag{ discrModuleLabel, util::to_string(threshold) }; + = makeTag(discrModuleTag, util::to_string(threshold)); } if (config().EventTreeName.hasValue()) { @@ -2467,6 +2472,20 @@ auto icarus::trigger::TriggerEfficiencyPlots::ReadTriggerGates } // icarus::trigger::TriggerEfficiencyPlots::ReadTriggerGates() +//------------------------------------------------------------------------------ +art::InputTag icarus::trigger::TriggerEfficiencyPlots::makeTag + (art::InputTag const& defModule, std::string const& thresholdStr) +{ + if (!thresholdStr.empty() && !defModule.instance().empty()) { + throw art::Exception(art::errors::Configuration) + << "Module tag instance name (`TriggerGatesTag`: '" + << defModule.encode() << "') and the threshold '" << thresholdStr + << "' are both set. One of them must be empty.\n"; + } + return { defModule.label(), thresholdStr, defModule.process() }; +} // icarus::trigger::TriggerEfficiencyPlots::makeTag() + + //------------------------------------------------------------------------------ //--- EventIDTree //------------------------------------------------------------------------------ diff --git a/icaruscode/PMT/Trigger/TriggerSimulationOnGates_module.cc b/icaruscode/PMT/Trigger/TriggerSimulationOnGates_module.cc index eee5c986a..6c9885eed 100644 --- a/icaruscode/PMT/Trigger/TriggerSimulationOnGates_module.cc +++ b/icaruscode/PMT/Trigger/TriggerSimulationOnGates_module.cc @@ -406,9 +406,9 @@ class icarus::trigger::TriggerSimulationOnGates using Name = fhicl::Name; using Comment = fhicl::Comment; - fhicl::Atom TriggerGatesTag { + fhicl::Atom TriggerGatesTag { Name("TriggerGatesTag"), - Comment("label of the input trigger gate data product (no instance name)") + Comment("tag of the input trigger gate data product (no instance name)") }; fhicl::Sequence Thresholds { @@ -776,6 +776,10 @@ class icarus::trigger::TriggerSimulationOnGates (icarus::trigger::WindowChannelMap::WindowInfo_t const& winfo) { return winfo.composition.cryoid; } + /// Returns `defModule` with instance name replaced by `thresholdStr`. + static art::InputTag makeTag + (art::InputTag const& defModule, std::string const& thresholdStr); + }; // icarus::trigger::TriggerSimulationOnGates @@ -878,9 +882,9 @@ icarus::trigger::TriggerSimulationOnGates::TriggerSimulationOnGates // // more complex parameter parsing // - std::string const& discrModuleLabel = config().TriggerGatesTag(); + art::InputTag const& discrModuleTag = config().TriggerGatesTag(); for (std::string const& threshold: config().Thresholds()) - fADCthresholds[threshold] = art::InputTag{ discrModuleLabel, threshold }; + fADCthresholds[threshold] = makeTag(discrModuleTag, threshold); // initialization of a vector of atomic is not as trivial as it sounds... fTriggerCount = std::vector>(fADCthresholds.size()); @@ -929,19 +933,12 @@ icarus::trigger::TriggerSimulationOnGates::TriggerSimulationOnGates log << "\nConfigured " << fADCthresholds.size() << " thresholds (ADC):"; for (auto const& [ thresholdTag, dataTag ]: fADCthresholds) log << "\n * " << thresholdTag << " (from '" << dataTag.encode() << "')"; -#if 0 // TODO restore after adoption of https://github.com/LArSoft/lardataalg/pull/44 + log << "\nOther parameters:" << "\n * trigger time resolution: " << fTriggerTimeResolution << "\n * input beam gate reference time: " << util::StandardSelectorFor{} .get(fBeamGateReference).name() -#else - util::StandardSelectorFor const timeScaleSelector; - log << "\nOther parameters:" - << "\n * trigger time resolution: " << fTriggerTimeResolution - << "\n * input beam gate reference time: " - << timeScaleSelector.get(fBeamGateReference).name() -#endif ; if (fDeadTime == std::numeric_limits::max()) log << "\n * only one trigger per beam gate (infinite dead time)"; @@ -1775,6 +1772,20 @@ double icarus::trigger::TriggerSimulationOnGates::eventTimestampInSeconds { return eventTimestampInSeconds(event.time()); } +//------------------------------------------------------------------------------ +art::InputTag icarus::trigger::TriggerSimulationOnGates::makeTag + (art::InputTag const& defModule, std::string const& thresholdStr) +{ + if (!thresholdStr.empty() && !defModule.instance().empty()) { + throw art::Exception(art::errors::Configuration) + << "Module tag instance name (`TriggerGatesTag`: '" + << defModule.encode() << "') and the threshold '" << thresholdStr + << "' are both set. One of them must be empty.\n"; + } + return { defModule.label(), thresholdStr, defModule.process() }; +} // icarus::trigger::TriggerSimulationOnGates::makeTag() + + //------------------------------------------------------------------------------ DEFINE_ART_MODULE(icarus::trigger::TriggerSimulationOnGates) From 937b4b6b1b7741934a5cc73f9fe402a9ed10f295 Mon Sep 17 00:00:00 2001 From: Gianluca Petrillo Date: Tue, 18 Nov 2025 16:20:16 -0800 Subject: [PATCH 22/47] Apply suggestions from GIT Copilot code review Good catches on names and strings. Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- icaruscode/PMT/Trigger/LVDSgates_module.cc | 2 +- icaruscode/PMT/Trigger/MajorityTriggerSimulation_module.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/icaruscode/PMT/Trigger/LVDSgates_module.cc b/icaruscode/PMT/Trigger/LVDSgates_module.cc index 201209249..04ca63185 100644 --- a/icaruscode/PMT/Trigger/LVDSgates_module.cc +++ b/icaruscode/PMT/Trigger/LVDSgates_module.cc @@ -879,7 +879,7 @@ art::InputTag icarus::trigger::LVDSgates::makeTag ? art::InputTag{ thresholdStr } : defModule.label().empty() ? throw (art::Exception(art::errors::Configuration) - << "Default module label (`TriggerGatesTag`) specified" + << "No default module label (`TriggerGatesTag`) specified" ", and it's needed for threshold '" << thresholdStr << "'.\n") : art::InputTag{ defModule.label(), thresholdStr, defModule.process() } ; diff --git a/icaruscode/PMT/Trigger/MajorityTriggerSimulation_module.cc b/icaruscode/PMT/Trigger/MajorityTriggerSimulation_module.cc index 6654739a2..fb43c4435 100644 --- a/icaruscode/PMT/Trigger/MajorityTriggerSimulation_module.cc +++ b/icaruscode/PMT/Trigger/MajorityTriggerSimulation_module.cc @@ -361,7 +361,7 @@ class icarus::trigger::MajorityTriggerSimulation fhicl::Atom TriggerGatesTag { Name("TriggerGatesTag"), - Comment("label of the input trigger gate data product (no instance name)") + Comment("tag of the input trigger gate data product") }; fhicl::Sequence Thresholds { From a80e88b2300e948313ccb1497f6a580f4f4e3bf2 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Tue, 18 Nov 2025 21:00:17 -0600 Subject: [PATCH 23/47] fix to detsim reprocessing --- ...tonly_icarus_overlay_reprocessing_run2.fcl | 79 ++++++++++++++----- 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl b/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl index 8affd8478..afde95163 100644 --- a/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl +++ b/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl @@ -12,19 +12,22 @@ source.inputCommands: [ # `stage0` comes from decoding data: should be kept! # `MCstage0` comes running stage0 on the overlay products: # so pmt/trigger/crt stuff should be thrown out! - - "drop raw::OpDetWaveform*_opdaq_*_*", # drop old MC waveforms (if any) + # note: I would really like to drop these things as well: + # "drop raw::OpDetWaveform*_opdaq_*_*", # drop old MC waveforms (if any) + # "drop *_pmtfixedthrinit_*_*", # drop triggersim product + # "drop *_pmtlvdsgatesinit_*_*", # drop triggersim product + # "drop *_pmttriggerwindowsinit_*_*", # drop triggersim product + # "drop *_triggersimgatesinit_*_*", # drop triggersim product + # "drop *_emuTriggerUnshifted_*_*", # drop triggersim product + # but I can't: it triggers art genocidal insticts thus removing all + # downstream products in the dependency tree that we still need. + "drop raw::OpDetWaveform*_shifted_*_*", # drop old MC (shifted) waveforms (if any) "drop *_overlayOpWaveforms_*_*", # drop old Overlay waveforms (if any) "drop *_ophit*_*_*", # drop MCstage0 ophits "drop *_mcophit_*_*", # drop MCstageo mcophit "drop *_opflash*_*_*", # drop MCsstage0 east/west opflashes - - "drop *_pmtfixedthrinit_*_*", # drop triggersim product - "drop *_pmtlvdsgatesinit_*_*", # drop triggersim product - "drop *_pmttriggerwindowsinit_*_*", # drop triggersim product - "drop *_triggersimgatesinit_*_*", # drop triggersim product - "drop *_emuTriggerUnshifted_*_*", # drop triggersim product + "drop *_pmtfixedthr_*_*", # drop MCstage0 trigger product "drop *_pmtlvdsgates_*_*", # drop MCstage0 trigger product "drop *_pmtlvdsgates_*_*", # drop MCstage0 trigger product @@ -55,8 +58,21 @@ physics.producers: { } +# since some "old" products need to be kept in the tree +# we have products with the same tag, and different process_name +# make sure to select exactly what you need! + # build waveforms from simPhotons (already shifted) -physics.producers.opdaq.InputModule: "shifted" +physics.producers.opdaq.InputModule: "shifted::DetSim" + +# make sure the triggersim chain used the "new" products +# instead of the "old" ones which I cannot drop on input +physics.producers.pmtfixedthrinit.OpticalWaveforms: "opdaq::OpDetSim" # this was re-generated with same tag +physics.producers.pmtlvdsgatesinit.TriggerGatesTag: "pmtfixedthrinit::OpDetSim" # this was re-generated with same tag +physics.producers.pmttriggerwindowsinit.TriggerGatesTag: "pmtlvdsgatesinit::OpDetSim" # this was re-generated with same tag +physics.producers.triggersimgatesinit.BeamGateTag: "beamgate" # keep using old Gen product +physics.producers.emuTriggerUnshifted.BeamGates: "triggersimgatesinit::OpDetSim" # this was re-generated with same tag +physics.producers.emuTriggerUnshifted.TriggerGatesTag: "pmttriggerwindowsinit::OpDetSim" # this was re-generated with same tag # need to update the shifting module to pick up new labels # some were regenerated (tag still good), others were previously shifted @@ -65,19 +81,22 @@ physics.producers.opdaq.InputModule: "shifted" # NOTE: still shifing energy deposits although tpc info not regenerated # however forced to use `filtersed` as `shifted` has been consumed -physics.producers.shifted.InputTriggerLabel: "emuTriggerUnshifted" # this was re-generated, so same tag -physics.producers.shifted.InitAuxDetSimChannelLabel: "shifted" # need to start from previously-shifted, not `genericcrt` -physics.producers.shifted.InitBeamGateInfoLabel: "triggersimgatesinit" # this was re-generated, so same tag -physics.producers.shifted.InitSimEnergyDepositLabel: "filtersed" # need to start from previously-shifted, but `shifted` no longer available -physics.producers.shifted.InitSimEnergyDepositLiteLabel: "filtersed" # need to start from previously-shifted, but `shifted` no longer available -physics.producers.shifted.InitSimPhotonsLabel: "shifted" # need to start from previously-shifted, not `pdfastsim` -physics.producers.shifted.InitWaveformLabel: "opdaq" # this was re-generated, so same tag +physics.producers.shifted.InputTriggerLabel: "emuTriggerUnshifted::OpDetSim" # this was re-generated with same tag +physics.producers.shifted.InitAuxDetSimChannelLabel: "shifted::DetSim" # need to start from previously-shifted, not `genericcrt` +physics.producers.shifted.InitBeamGateInfoLabel: "triggersimgatesinit::OpDetSim" # this was re-generated with same tag +physics.producers.shifted.InitSimEnergyDepositLabel: "filtersed::DetSim" # need to start from previously-shifted, but `shifted` no longer available +physics.producers.shifted.InitSimEnergyDepositLiteLabel: "filtersed::DetSim" # need to start from previously-shifted, but `shifted` no longer available +physics.producers.shifted.InitSimPhotonsLabel: "shifted::DetSim" # need to start from previously-shifted, not `pdfastsim` +physics.producers.shifted.InitWaveformLabel: "opdaq::OpDetSim" # this was re-generated with same tag # need to update shiting of priorSCE deposits: # this is important if future reprocessings will need to regenerate SimPhotons -physics.producers.shiftedpriorSCE.InputTriggerLabel: "emuTriggerUnshifted" # this was re-generated, so same tag -physics.producers.shiftedpriorSCE.InitSimEnergyDepositLabel: "shiftedpriorSCE" # need to start from previously-shifted, not `ionization:priorSCE` +physics.producers.shiftedpriorSCE.InputTriggerLabel: "emuTriggerUnshifted::OpDetSim" # this was re-generated with same tag +physics.producers.shiftedpriorSCE.InitSimEnergyDepositLabel: "shiftedpriorSCE::DetSim" # need to start from previously-shifted, not `ionization:priorSCE` + +# and finally make sure the crtsim also uses the newly shifted products +physics.producers.crtsim.G4ModuleLabel: "shifted::OpDetSim" # The reprocessing flow is the following: # - build new pmt waveforms from photons @@ -90,5 +109,29 @@ physics.producers.shiftedpriorSCE.InitSimEnergyDepositLabel: "shiftedpriorSCE" physics.simulate: [ opdaq, @sequence::icarus_shifting_triggersim.path, crtdaq ] +# drop duplicate produtcs in output +# this doesn't trigger art genocidal instincts +outputs.rootoutput.outputCommands: [ + "keep *", + + # drop `opdaq`, but keep `shifted` for overlaying + "drop *_opdaq_*_*", + + # drop old trigger products now that new ones exist + # specify the old process name "DetSim" + "drop *_pmtfixedthrinit_*_DetSim", + "drop *_pmtlvdsgatesinit_*_DetSim", + "drop *_pmttriggerwindowsinit_*_DetSim", + "drop *_triggersimgatesinit_*_DetSim", + "drop *_emuTriggerUnshifted_*_DetSim", + + # drop old "shifted" products since we shifted things again + "drop sim::SimEnergyDeposits_filtersed_*_DetSim", # this has been regenerated into `shifted` + "drop sim::SimEnergyDepositLites_filtersed_*_DetSim", # this has been regenerated into `shifted` + "drop sim::SimEnergyDeposits_shiftedpriorSCE_*_DetSim", # this has been regenerated into the same tag + "drop sim::AuxDetSimChannel_shifted_*_DetSim", # this has been regenerated into the same tag + "drop sim::SimPhotons_shifted_*_DetSim", # this has been regenerated into the same tag + "drop sim::BeamGateInfo_shifted_*_DetSim" # this has been regenerated into the same tag +] From fe5e0726d3c3542383463b41ae149dfb2e84f71d Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 19 Nov 2025 11:49:03 -0500 Subject: [PATCH 24/47] reprocessing opdetonly overlay fhicl --- fcl/overlays/partial/CMakeLists.txt | 8 ++++++ ...erlay_opdetonly_waveforms_reprocessing.fcl | 26 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 fcl/overlays/partial/CMakeLists.txt create mode 100644 fcl/overlays/partial/overlay_opdetonly_waveforms_reprocessing.fcl diff --git a/fcl/overlays/partial/CMakeLists.txt b/fcl/overlays/partial/CMakeLists.txt new file mode 100644 index 000000000..6ce4b7b55 --- /dev/null +++ b/fcl/overlays/partial/CMakeLists.txt @@ -0,0 +1,8 @@ +# Install fcl files in /job subdirectory. +install_fhicl() + +# Also put a copy in the source tree. + +FILE(GLOB fcl_files *.fcl) +install_source( EXTRAS ${fcl_files} ) + diff --git a/fcl/overlays/partial/overlay_opdetonly_waveforms_reprocessing.fcl b/fcl/overlays/partial/overlay_opdetonly_waveforms_reprocessing.fcl new file mode 100644 index 000000000..4b0116d0f --- /dev/null +++ b/fcl/overlays/partial/overlay_opdetonly_waveforms_reprocessing.fcl @@ -0,0 +1,26 @@ +#include "overlay_waveforms.fcl" + +process_name: OpOverlay + +# only perform PMT and CRT overlays after their detsim reprocessing +# previous reprocessing step should have cleaned-up duplicates already +# however make sure we are pointing to the correct OverlayProducts + +physics.producers.mccrthit.CrtModuleLabel: "crtdaq::OpDetSim" # from previous reprocessing +#physics.producers.mccrthit.TriggerLabel: "daqTrigger" + +physics.producers.overlayOpWaveforms.PMTWaveDataLabel: "daqPMT::stage0" # from data decoding +phsyics.producers.overlayOpWaveforms.PMTWaveSimLabel: "shifted::OpDetSim" # from previous reprocessing +phsyics.producers.overlayOpWaveforms.PMTWaveBaseLabel: "pmtbaselines::stage0" # from data decoding + +physics.producers.overlayCRTHit.CRTHitInputLabels: ["crthit::stage0", # from data decoding + "mccrthit::OpOverlay" # from current process + ] + +# process includes: +# - make crt hits on mc +# - overlay pmt waveforms +# - overlay crt hits + +physics.reco: [ mccrthit, overlayOpWaveforms, overlayCRTHit] + From 21424495fa3f23bb423dc274a152f8006648f974 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 19 Nov 2025 11:48:28 -0600 Subject: [PATCH 25/47] leave default tags --- fcl/overlays/CMakeLists.txt | 5 ++++- .../overlay_opdetonly_waveforms_reprocessing.fcl | 15 +++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/fcl/overlays/CMakeLists.txt b/fcl/overlays/CMakeLists.txt index 520ed808b..3e60f0520 100644 --- a/fcl/overlays/CMakeLists.txt +++ b/fcl/overlays/CMakeLists.txt @@ -1,4 +1,7 @@ -# Install fcl files in /job subdirectory. +# add subdirectories +add_subdirectory(partial) + +# Install fcl files install_fhicl() diff --git a/fcl/overlays/partial/overlay_opdetonly_waveforms_reprocessing.fcl b/fcl/overlays/partial/overlay_opdetonly_waveforms_reprocessing.fcl index 4b0116d0f..f700bc0e5 100644 --- a/fcl/overlays/partial/overlay_opdetonly_waveforms_reprocessing.fcl +++ b/fcl/overlays/partial/overlay_opdetonly_waveforms_reprocessing.fcl @@ -4,18 +4,17 @@ process_name: OpOverlay # only perform PMT and CRT overlays after their detsim reprocessing # previous reprocessing step should have cleaned-up duplicates already -# however make sure we are pointing to the correct OverlayProducts +# so technically no need to update any tag names w.r.t the default file -physics.producers.mccrthit.CrtModuleLabel: "crtdaq::OpDetSim" # from previous reprocessing +#physics.producers.mccrthit.CrtModuleLabel: "crtdaq" # from previous reprocessing #physics.producers.mccrthit.TriggerLabel: "daqTrigger" -physics.producers.overlayOpWaveforms.PMTWaveDataLabel: "daqPMT::stage0" # from data decoding -phsyics.producers.overlayOpWaveforms.PMTWaveSimLabel: "shifted::OpDetSim" # from previous reprocessing -phsyics.producers.overlayOpWaveforms.PMTWaveBaseLabel: "pmtbaselines::stage0" # from data decoding +#physics.producers.overlayOpWaveforms.PMTWaveDataLabel: "daqPMT" # from data decoding +#phsyics.producers.overlayOpWaveforms.PMTWaveSimLabel: "shifted" # from previous reprocessing +#phsyics.producers.overlayOpWaveforms.PMTWaveBaseLabel: "pmtbaselines" # from data decoding -physics.producers.overlayCRTHit.CRTHitInputLabels: ["crthit::stage0", # from data decoding - "mccrthit::OpOverlay" # from current process - ] +#physics.producers.overlayCRTHit.CRTHitInputLabels: ["crthit", # from data decoding +# "mccrthit"] # from current process # process includes: # - make crt hits on mc From 0c07aeb0d05500f1624ce05ef9968e91ce3d99d1 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 3 Dec 2025 13:56:30 -0500 Subject: [PATCH 26/47] add initial recalibrator module --- .../Calibration/OpHitRecalibrator_module.cc | 267 ++++++++++++++++++ .../PMT/Calibration/fcl/pmt-calibration.fcl | 11 + 2 files changed, 278 insertions(+) create mode 100644 icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc diff --git a/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc b/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc new file mode 100644 index 000000000..379622749 --- /dev/null +++ b/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc @@ -0,0 +1,267 @@ +/** + * @file icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc + * @brief Recalibrate PEs and times of optical hits. + * @author Matteo Vicenzi (mvicenzi@bnl.gov) + * @date December 03, 2025 + */ + +// ICARUS libraries +//#include "icaruscode/Timing/PMTTimingCorrections.h" +//#include "icaruscode/Timing/IPMTTimingCorrectionService.h" + +// framework libraries +#include "canvas/Utilities/InputTag.h" + +#include "art/Framework/Services/Registry/ServiceHandle.h" +#include "art/Framework/Core/SharedProducer.h" +#include "art/Framework/Core/ModuleMacros.h" +#include "art/Framework/Principal/Event.h" +#include "art/Framework/Principal/Handle.h" +#include "canvas/Utilities/InputTag.h" +#include "canvas/Utilities/Exception.h" +#include "messagefacility/MessageLogger/MessageLogger.h" +#include "fhiclcpp/types/Atom.h" +#include "fhiclcpp/types/Sequence.h" + +// LArSoft libraries +#include "lardataobj/RecoBase/OpHit.h" + +// C/C++ standard libraries +#include +#include // std::unique_ptr<> +#include +#include // std::move() + +// ----------------------------------------------------------------------------- +namespace icarus +{ + class OpHitRecalibrator; +} +/** + * @brief Creates a new collection of optical hits with re-calibrated PEs and times. + * + * This module reads reconstructed optical detector hits, removes previously-applied + * gain and/or timing calibrations, and applies new ones. + * A new collection of hits is produced containing a re-calibrated copy of all the + * hits from the input collections. + * + * Input + * ------ + * * `std::vector` data products (as for `InputLabels`) + * + * Output + * ------- + * * a single `std::vector` data product with the recalibrated hits from the + * input collections; the hits are in the order of the data products specified in input. + * + * Configuration parameters + * ------------------------- + * + * * `InputLabels` (list of input tags, mandatory): the list of optical hit data + * products to recalibrated It must be non-empty. + * * `RecalibratePE` (flag, mandatory): if set, recalibrate hit PE values. + * * `UseGainDatabase` (flag, default: true): if set, use gain values from database + * to re-calibrate hit PEs from hit area. + * * `SPEArea` (double, default: -1): if not using the gain database, single-photoelectron + * area in ADC x tick to be used in the PE calibration. + * * `RecalibrateTime` (flag, mandatory): if set, recalibrate hit times. + * * `Verbose` (flag, default: `false`): verbose printing + * + */ +class icarus::OpHitRecalibrator : public art::SharedProducer +{ + +public: + /// Configuration of the module. + struct Config + { + + fhicl::Sequence InputLabels{ + fhicl::Name("InputLabels"), + fhicl::Comment("list of the input labels to be used")}; + + fhicl::Atom RecalibratePE{ + fhicl::Name("Recalibrate"), + fhicl::Comment("re-compute hit PE values") + }; + + fhicl::Atom UseGainDatabase{ + fhicl::Name("UseGainDatabase"), + fhicl::Comment("whether to use gain database to recalibrate"), + true + }; + + fhicl::Atom SPEArea{ + fhicl::Name("SPEArea"), + fhicl::Comment("single-photoelectron area for calibration for non-database calibration"), + -1. + }; + + fhicl::Atom RecalibrateTime{ + fhicl::Name("RecalibrateTime"), + fhicl::Comment("re-apply timing corrections") + }; + + fhicl::Atom Verbose{ + fhicl::Name("Verbose"), + fhicl::Comment("print the times read and the associated channels"), + false // default + }; + + }; // struct Config + + using Parameters = art::SharedProducer::Table; + + /// Constructor: just reads the configuration. + explicit OpHitRecalibrator(Parameters const &config, art::ProcessingFrame const &); + + /// process the event + void produce(art::Event &event, art::ProcessingFrame const &) override; + +private: + std::vector const fInputLabels; + bool const fRecalibratePE; + bool const fRecalibrateTime; + bool const fUseGainDatabase; + double const fSPEArea; + bool const fVerbose = false; ///< Whether to print the configuration we read. + + /// Pointer to the online pmt corrections service + //icarusDB::PMTTimingCorrections const &fPMTTimingCorrectionsService; +}; + +// ----------------------------------------------------------------------------- +icarus::OpHitRecalibrator::OpHitRecalibrator(Parameters const &config, art::ProcessingFrame const &) + : art::SharedProducer(config), + fInputLabels{config().InputLabels()}, + fRecalibratePE{config().RecalibratePE()}, + fRecalibrateTime{config().RecalibrateTime()}, + fUseGainDatabase{config().UseGainDatabase()}, + fSPEArea{config().SPEArea()}, + fVerbose{config().Verbose()}//, + //fPMTTimingCorrectionsService{*(lar::providerFrom())} +{ + async(); + + // configuration checks + if (fInputLabels.empty()) + { + throw art::Exception{art::errors::Configuration} + << "The list of input hit data products ('" + << config().InputLabels.name() << "') is empty.\n"; + } + + if (!fRecalibratePE && !fRecalibrateTime) + { + throw art::Exception{art::errors::Configuration} + << "No re-calibration selected. Why are you running meeee!?!?! :/\n"; + } + + if (!fUseGainDatabase && (fSPEArea<0)) + { + throw art::Exception{art::errors::Configuration} + << "The gain database for PE recalibration has been disabled ('" + << config().fUseGainDatabase.name() << "'), but '" + << config().fSPEArea.name() << ", has not been set correctly." + << " Fix the configuration!\n"; + } + + //FIXME: temporary since no db exists yet... + if (fUseGainDatabase) + { + throw art::Exception{art::errors::Configuration} + << "Gain database interface doesn't exist yet. Try again later.\n"; + } + + // Consumes + for (auto const &tag : fInputLabels) + consumes>(tag); + + produces>(); +} + +// ----------------------------------------------------------------------------- +void icarus::OpHitRecalibrator::produce(art::Event &event, art::ProcessingFrame const &) +{ + auto log = fVerbose ? std::make_optional("OpHitRecalibrator") : std::nullopt; + + // Create a copy of the OpHits + std::vector recalibratedOpHits; + + for (art::InputTag const &label : fInputLabels) + { + auto const &opHits = event.getProduct>(label); + + for (auto const &opHit : opHits) + { + // read current times + double peakTime = opHit.PeakTime(); + double peakTimeAbs = opHit.PeakTimeAbs(); + double startTime = opHit.StartTime(); + double riseTime = opHit.RiseTime(); + + // read current PE + double hitPE = opHit.PE(); + + // First, recalibrated PE values (if enabled). + // - extract previously-used SPEArea from area/PE ratio + // - if using gain database, fetch new SPEArea for this run/channel + // - if not using gain database, use fSPEArea + // - rescale PE value with new SPE area + if( fRecalibratePE ) + { + double oldSPEArea = opHit.Area()/hitPE; + double newSPEArea = fSPEArea; + + if( fUseGainDatabase ) + { + // soon... + // newSPEArea = get_from_db(opHit.OpChannel()) + } + + double PEcorrection = oldSPEArea/newSPEArea; + if(log) + { + *log << "Channel: " opHit.OpChannel() + << ", Area: " << hitArea << " [ADC x tick]" + << ", PE " << hitPE + << "(old SPEArea: " << oldSPEArea + << ") --> new PE " << hitPE*PEcorrection + << " (new SPEArea: " << newSPEArea << ")"; + } + + hitPE = hitPE*PEcorrection; + } + + // correct PE values + if( fRecalibrateTime ) + { + // soon... + } + + recalibratedHits.emplace_back( + opHit.OpChannel(), // channel + peakTime, // recalibrated peaktime + peakTimeAbs, // recalibrated peaktimeabs + startTime, // recalibrated starttime + riseTime, // recalibrated risetime + opHit.Frame(), // frame + opHit.Width(), // width + opHit.Area(), // area + opHit.Amplitude(), // peakheight + hitPE, // recalibrated pe + opHit.FastToTotal() // fasttototal + ); + } + } + + // The new OpHits collection is also saved in the event stream + event.put( + std::make_unique>(std::move(recalibratedOpHits))); + +} // icarus::OpHitRecalibrator::produce + +// ----------------------------------------------------------------------------- +DEFINE_ART_MODULE(icarus::OpHitRecalibrator) + +// ----------------------------------------------------------------------------- \ No newline at end of file diff --git a/icaruscode/PMT/Calibration/fcl/pmt-calibration.fcl b/icaruscode/PMT/Calibration/fcl/pmt-calibration.fcl index fed4a6092..8adbdf7ca 100644 --- a/icaruscode/PMT/Calibration/fcl/pmt-calibration.fcl +++ b/icaruscode/PMT/Calibration/fcl/pmt-calibration.fcl @@ -27,4 +27,15 @@ pmt_bkgphotons_calibration: IntegralBinning: [ 0., 8., 0.04 ] # in 10^7 electrons } +ophit_recalibrator: +{ + module_type: OpHitRecalibrator + InputLabels: [ "ophit" ] + RecalibratePE: true + UseGainDatabase: true + SPEArea: -1.0 + RecalibrateTime: true + Verbose: false +} + END_PROLOG From 16be4972e696eacccf6e2cf297048f9649afb3ac Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Wed, 3 Dec 2025 13:36:13 -0600 Subject: [PATCH 27/47] fix compilation for recalibrator --- icaruscode/PMT/Calibration/CMakeLists.txt | 5 +++++ .../Calibration/OpHitRecalibrator_module.cc | 18 +++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/icaruscode/PMT/Calibration/CMakeLists.txt b/icaruscode/PMT/Calibration/CMakeLists.txt index c4317a71e..adeb7f9b9 100644 --- a/icaruscode/PMT/Calibration/CMakeLists.txt +++ b/icaruscode/PMT/Calibration/CMakeLists.txt @@ -44,6 +44,11 @@ cet_build_plugin(PMTBackgroundphotonsCalibration art::module Boost::system ) +cet_build_plugin( OpHitRecalibrator art::module + LIBRARIES PUBLIC + lardataobj::RecoBase + lardataobj::RawData + ) art_make_exec( NAME fitPulseDistribution diff --git a/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc b/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc index 379622749..045918c20 100644 --- a/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc +++ b/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc @@ -81,7 +81,7 @@ class icarus::OpHitRecalibrator : public art::SharedProducer fhicl::Comment("list of the input labels to be used")}; fhicl::Atom RecalibratePE{ - fhicl::Name("Recalibrate"), + fhicl::Name("RecalibratePE"), fhicl::Comment("re-compute hit PE values") }; @@ -161,9 +161,9 @@ icarus::OpHitRecalibrator::OpHitRecalibrator(Parameters const &config, art::Proc { throw art::Exception{art::errors::Configuration} << "The gain database for PE recalibration has been disabled ('" - << config().fUseGainDatabase.name() << "'), but '" - << config().fSPEArea.name() << ", has not been set correctly." - << " Fix the configuration!\n"; + << config().UseGainDatabase.name() << "'), but '" + << config().SPEArea.name() << "' (" << fSPEArea + << ") has not been set correctly. Fix the configuration!\n"; } //FIXME: temporary since no db exists yet... @@ -222,12 +222,12 @@ void icarus::OpHitRecalibrator::produce(art::Event &event, art::ProcessingFrame double PEcorrection = oldSPEArea/newSPEArea; if(log) { - *log << "Channel: " opHit.OpChannel() - << ", Area: " << hitArea << " [ADC x tick]" + *log << "Channel: " << opHit.OpChannel() + << ", Area: " << opHit.Area() << " [ADC x tick]" << ", PE " << hitPE << "(old SPEArea: " << oldSPEArea << ") --> new PE " << hitPE*PEcorrection - << " (new SPEArea: " << newSPEArea << ")"; + << " (new SPEArea: " << newSPEArea << ")\n"; } hitPE = hitPE*PEcorrection; @@ -239,7 +239,7 @@ void icarus::OpHitRecalibrator::produce(art::Event &event, art::ProcessingFrame // soon... } - recalibratedHits.emplace_back( + recalibratedOpHits.emplace_back( opHit.OpChannel(), // channel peakTime, // recalibrated peaktime peakTimeAbs, // recalibrated peaktimeabs @@ -264,4 +264,4 @@ void icarus::OpHitRecalibrator::produce(art::Event &event, art::ProcessingFrame // ----------------------------------------------------------------------------- DEFINE_ART_MODULE(icarus::OpHitRecalibrator) -// ----------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------- From 8dfa2dba313261a81b4c4146efa4926bce7aeafa Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Thu, 4 Dec 2025 09:34:38 -0600 Subject: [PATCH 28/47] link online corrections service to recalibrator --- icaruscode/PMT/Calibration/CMakeLists.txt | 1 + .../Calibration/OpHitRecalibrator_module.cc | 54 ++++++++++++++----- icaruscode/Timing/PMTTimingCorrections.h | 6 +++ .../Timing/PMTTimingCorrectionsProvider.h | 28 ++++++---- 4 files changed, 64 insertions(+), 25 deletions(-) diff --git a/icaruscode/PMT/Calibration/CMakeLists.txt b/icaruscode/PMT/Calibration/CMakeLists.txt index adeb7f9b9..b5ef4e2b5 100644 --- a/icaruscode/PMT/Calibration/CMakeLists.txt +++ b/icaruscode/PMT/Calibration/CMakeLists.txt @@ -48,6 +48,7 @@ cet_build_plugin( OpHitRecalibrator art::module LIBRARIES PUBLIC lardataobj::RecoBase lardataobj::RawData + larcore::Geometry_Geometry_service ) art_make_exec( NAME diff --git a/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc b/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc index 045918c20..a61f93868 100644 --- a/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc +++ b/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc @@ -6,8 +6,8 @@ */ // ICARUS libraries -//#include "icaruscode/Timing/PMTTimingCorrections.h" -//#include "icaruscode/Timing/IPMTTimingCorrectionService.h" +#include "icaruscode/Timing/PMTTimingCorrections.h" +#include "icaruscode/Timing/IPMTTimingCorrectionService.h" // framework libraries #include "canvas/Utilities/InputTag.h" @@ -127,7 +127,7 @@ class icarus::OpHitRecalibrator : public art::SharedProducer bool const fVerbose = false; ///< Whether to print the configuration we read. /// Pointer to the online pmt corrections service - //icarusDB::PMTTimingCorrections const &fPMTTimingCorrectionsService; + icarusDB::PMTTimingCorrections const &fPMTTimingCorrectionsService; }; // ----------------------------------------------------------------------------- @@ -138,8 +138,8 @@ icarus::OpHitRecalibrator::OpHitRecalibrator(Parameters const &config, art::Proc fRecalibrateTime{config().RecalibrateTime()}, fUseGainDatabase{config().UseGainDatabase()}, fSPEArea{config().SPEArea()}, - fVerbose{config().Verbose()}//, - //fPMTTimingCorrectionsService{*(lar::providerFrom())} + fVerbose{config().Verbose()}, + fPMTTimingCorrectionsService{*(lar::providerFrom())} { async(); @@ -203,11 +203,10 @@ void icarus::OpHitRecalibrator::produce(art::Event &event, art::ProcessingFrame // read current PE double hitPE = opHit.PE(); - // First, recalibrated PE values (if enabled). - // - extract previously-used SPEArea from area/PE ratio + // First, recalibrate PE values (if enabled). // - if using gain database, fetch new SPEArea for this run/channel // - if not using gain database, use fSPEArea - // - rescale PE value with new SPE area + // - re-compute PE value with new SPE area if( fRecalibratePE ) { double oldSPEArea = opHit.Area()/hitPE; @@ -219,24 +218,51 @@ void icarus::OpHitRecalibrator::produce(art::Event &event, art::ProcessingFrame // newSPEArea = get_from_db(opHit.OpChannel()) } - double PEcorrection = oldSPEArea/newSPEArea; if(log) { *log << "Channel: " << opHit.OpChannel() << ", Area: " << opHit.Area() << " [ADC x tick]" << ", PE " << hitPE << "(old SPEArea: " << oldSPEArea - << ") --> new PE " << hitPE*PEcorrection + << ") --> new PE " << opHit.Area()/newSPEArea << " (new SPEArea: " << newSPEArea << ")\n"; } - - hitPE = hitPE*PEcorrection; + + hitPE = opHit.Area()/newSPEArea; } - // correct PE values + // Second, recalibrate PMT times (if enabled) if( fRecalibrateTime ) { - // soon... + // get the old timing corrections: these will need to be subtracted! + double oldLaserTimeCorrection = 0; + double oldCosmicsCorrection = 0; + double const oldTotalCorrection = oldLaserTimeCorrection + oldCosmicsCorrection; + + // get new/current timing: these will need to be added! + double const laserTimeCorrection = fPMTTimingCorrectionsService.getLaserCorrections(opHit.OpChannel()); + double const cosmicsCorrection = fPMTTimingCorrectionsService.getCosmicsCorrections(opHit.OpChannel()); + double const totalCorrection = laserTimeCorrection + cosmicsCorrection; + + double timeCorr = totalCorrection - oldTotalCorrection; + + if(log) + { + *log << "Channel: " << opHit.OpChannel() + << ", startTime " << startTime << " us" + << ", peakTime " << peakTime << " us" + << ", peakTimeAbs " << peakTimeAbs << " us" + << "(old total correction: " << oldTotalCorrection + << ") --> new startTime " << startTime + timeCorr + << ", new peakTime " << peakTime + timeCorr + << ", new peakTimeAbs " << peakTimeAbs + timeCorr + << " (new total correction: " << totalCorrection << ")\n"; + } + + peakTime = peakTime + timeCorr; + peakTimeAbs = peakTimeAbs + timeCorr; + startTime = startTime + timeCorr; + // NOTE: riseTime is currently relative to the start time, so no correction needed } recalibratedOpHits.emplace_back( diff --git a/icaruscode/Timing/PMTTimingCorrections.h b/icaruscode/Timing/PMTTimingCorrections.h index 098445471..c011673da 100644 --- a/icaruscode/Timing/PMTTimingCorrections.h +++ b/icaruscode/Timing/PMTTimingCorrections.h @@ -19,6 +19,8 @@ #include "art/Framework/Services/Registry/ServiceDeclarationMacros.h" #include "art/Framework/Principal/Run.h" +#include + namespace icarusDB { class PMTTimingCorrections: lar::UncopiableClass @@ -35,6 +37,10 @@ namespace icarusDB { virtual double getCosmicsCorrections( unsigned int channelID ) const = 0; + virtual std::string getLaserDatabaseTag() const = 0; + + virtual std::string getCosmicsDatabaseTag() const = 0; + }; // end class }// end of namespace diff --git a/icaruscode/Timing/PMTTimingCorrectionsProvider.h b/icaruscode/Timing/PMTTimingCorrectionsProvider.h index 85f854063..3ef53a007 100644 --- a/icaruscode/Timing/PMTTimingCorrectionsProvider.h +++ b/icaruscode/Timing/PMTTimingCorrectionsProvider.h @@ -64,29 +64,35 @@ class icarusDB::PMTTimingCorrectionsProvider : public PMTTimingCorrections { PMTTimingCorrectionsProvider(const fhicl::ParameterSet& pset); - /// Read timing corrections from the database + /// Read timing corrections from the database void readTimeCorrectionDatabase(const art::Run& run); - /// Get time delay on the trigger line + /// Get time delay on the trigger line double getTriggerCableDelay( unsigned int channelID ) const override { return getChannelCorrOrDefault(channelID).triggerCableDelay; }; - /// Get time delay on the PPS reset line + /// Get time delay on the PPS reset line double getResetCableDelay( unsigned int channelID ) const override { return getChannelCorrOrDefault(channelID).resetCableDelay; }; - /// Get timing corrections from laser data + /// Get timing corrections from laser data double getLaserCorrections( unsigned int channelID ) const override { return getChannelCorrOrDefault(channelID).laserCableDelay; }; - /// Get timing corrections from cosmics data + /// Get timing corrections from cosmics data double getCosmicsCorrections( unsigned int channelID ) const override { return getChannelCorrOrDefault(channelID).cosmicsCorrections; }; + /// Get current laser corrections database tag + std::string getLaserDatabaseTag() const override { return fLaserTag; } + + /// Get current cosmics corrections database tag + std::string getCosmicsDatabaseTag() const override { return fCosmicsTag; }; + private: using PMTTimeCorrectionsDB = details::PMTTimeCorrectionsDB; @@ -94,11 +100,11 @@ class icarusDB::PMTTimingCorrectionsProvider : public PMTTimingCorrections { bool fVerbose = false; ///< Whether to print the configuration we read. std::string fLogCategory; ///< Category tag for messages. - std::string fCablesTag; ///< Tag for cable corrections database. - std::string fLaserTag; ///< Tag for laser corrections database. - std::string fCosmicsTag; ///< Tag for cosmics corrections database. + std::string fCablesTag; ///< Tag for cable corrections database. + std::string fLaserTag; ///< Tag for laser corrections database. + std::string fCosmicsTag; ///< Tag for cosmics corrections database. - /// Map of corrections by channel + /// Map of corrections by channel std::map fDatabaseTimingCorrections; /// Internal access to the channel correction record; returns defaults if not present. @@ -109,8 +115,8 @@ class icarusDB::PMTTimingCorrectionsProvider : public PMTTimingCorrections { return (it == fDatabaseTimingCorrections.end())? CorrectionDefaults: it->second; } - /// Convert run number to internal database - uint64_t RunToDatabaseTimestamp(uint32_t run) const; + /// Convert run number to internal database + uint64_t RunToDatabaseTimestamp(uint32_t run) const; void ReadPMTCablesCorrections(uint32_t run); From d96f21243ad19f683374cfa9003ef430d100bd68 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Thu, 4 Dec 2025 10:50:20 -0500 Subject: [PATCH 29/47] link locally-provided old timing corrections --- .../Calibration/OpHitRecalibrator_module.cc | 48 ++++++++++++++++--- .../PMT/Calibration/fcl/hit-recalibrator.fcl | 27 +++++++++++ .../PMT/Calibration/fcl/pmt-calibration.fcl | 11 ----- 3 files changed, 69 insertions(+), 17 deletions(-) create mode 100644 icaruscode/PMT/Calibration/fcl/hit-recalibrator.fcl diff --git a/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc b/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc index a61f93868..48f139beb 100644 --- a/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc +++ b/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc @@ -8,6 +8,7 @@ // ICARUS libraries #include "icaruscode/Timing/PMTTimingCorrections.h" #include "icaruscode/Timing/IPMTTimingCorrectionService.h" +#include "icaruscode/Timing/PMTTimingCorrectionsProvider.h" // framework libraries #include "canvas/Utilities/InputTag.h" @@ -99,9 +100,15 @@ class icarus::OpHitRecalibrator : public art::SharedProducer fhicl::Atom RecalibrateTime{ fhicl::Name("RecalibrateTime"), - fhicl::Comment("re-apply timing corrections") + fhicl::Comment("re-apply timing corrections"), + false }; + fhicl::Table OldTimingDBTags{ + fhicl::Name("OldTimingDBTags"), + fhicl::Comment("configuration for old PMT timing correction tags") + }; + fhicl::Atom Verbose{ fhicl::Name("Verbose"), fhicl::Comment("print the times read and the associated channels"), @@ -118,6 +125,9 @@ class icarus::OpHitRecalibrator : public art::SharedProducer /// process the event void produce(art::Event &event, art::ProcessingFrame const &) override; + /// configuration at every run change + void beginRun(const art::Run& run) override; + private: std::vector const fInputLabels; bool const fRecalibratePE; @@ -128,6 +138,10 @@ class icarus::OpHitRecalibrator : public art::SharedProducer /// Pointer to the online pmt corrections service icarusDB::PMTTimingCorrections const &fPMTTimingCorrectionsService; + + /// Pointer to the provider for the old pmt corrections + std::unique_ptr fOldTimingProvider; + }; // ----------------------------------------------------------------------------- @@ -139,7 +153,8 @@ icarus::OpHitRecalibrator::OpHitRecalibrator(Parameters const &config, art::Proc fUseGainDatabase{config().UseGainDatabase()}, fSPEArea{config().SPEArea()}, fVerbose{config().Verbose()}, - fPMTTimingCorrectionsService{*(lar::providerFrom())} + fPMTTimingCorrectionsService{*(lar::providerFrom())}, + fOldTimingProvider{std::make_unique(config().OldTimingTags())} { async(); @@ -157,7 +172,7 @@ icarus::OpHitRecalibrator::OpHitRecalibrator(Parameters const &config, art::Proc << "No re-calibration selected. Why are you running meeee!?!?! :/\n"; } - if (!fUseGainDatabase && (fSPEArea<0)) + if (fRecalibratePE && !fUseGainDatabase && (fSPEArea<0)) { throw art::Exception{art::errors::Configuration} << "The gain database for PE recalibration has been disabled ('" @@ -166,7 +181,16 @@ icarus::OpHitRecalibrator::OpHitRecalibrator(Parameters const &config, art::Proc << ") has not been set correctly. Fix the configuration!\n"; } - //FIXME: temporary since no db exists yet... + if( fRecalibrateTime ) + { + mf::LogInfo("OpHitRecalibrator") << "Re-calibration of timing corrections enabled:\n" + << "LaserTag: old " << fOldTimingProvider->getLaserDatabaseTag() + << " -> new " << fPMTTimingCorrectionsService->getLaserDatabaseTag() + << "\nCosmicsTag: old " << fOldTimingProvider->getCosmicsDatabaseTag() + << " -> new " << fPMTTimingCorrectionsService->getCosmicsDatabaseTag(); + } + + //FIXME: temporary since no gain db exists yet... if (fUseGainDatabase) { throw art::Exception{art::errors::Configuration} @@ -180,6 +204,15 @@ icarus::OpHitRecalibrator::OpHitRecalibrator(Parameters const &config, art::Proc produces>(); } +// ----------------------------------------------------------------------------- +void icarus::OpHitRecalibrator::beginRun(const art::Run& run) +{ + // make sure we are updating the locally-instantiated correction provider + if (fOldTimingProvider) { + fOldTimingProvider->readTimeCorrectionDatabase(run); + } +} + // ----------------------------------------------------------------------------- void icarus::OpHitRecalibrator::produce(art::Event &event, art::ProcessingFrame const &) { @@ -232,11 +265,14 @@ void icarus::OpHitRecalibrator::produce(art::Event &event, art::ProcessingFrame } // Second, recalibrate PMT times (if enabled) + // Previous corrections need to be subtracted + // use locally instantiated provider class to fetch old corrections + // use online pmt corrections servicer to fetch current/new corrections if( fRecalibrateTime ) { // get the old timing corrections: these will need to be subtracted! - double oldLaserTimeCorrection = 0; - double oldCosmicsCorrection = 0; + double const oldLaserTimeCorrection = fOldTimingProvider->getLaserCorrections(opHit.OpChannel()); + double const oldCosmicsCorrection = fOldTimingProvider->getCosmicsCorrections(opHit.OpChannel()); double const oldTotalCorrection = oldLaserTimeCorrection + oldCosmicsCorrection; // get new/current timing: these will need to be added! diff --git a/icaruscode/PMT/Calibration/fcl/hit-recalibrator.fcl b/icaruscode/PMT/Calibration/fcl/hit-recalibrator.fcl new file mode 100644 index 000000000..b0de24dc6 --- /dev/null +++ b/icaruscode/PMT/Calibration/fcl/hit-recalibrator.fcl @@ -0,0 +1,27 @@ +#include "calibration_database_GlobalTags_icarus.fcl" + +BEGIN_PROLOG + +ophit_recalibrator: +{ + module_type: OpHitRecalibrator + InputLabels: [ "ophit" ] + RecalibratePE: true + UseGainDatabase: true + SPEArea: -1.0 + RecalibrateTime: false + + OldTimingTags: { + CorrectionTags: { + CablesTag: @local::ICARUS_Calibration_GlobalTags.pmt_cables_delays_data + LaserTag: @local::ICARUS_Calibration_GlobalTags.pmt_laser_timing_data + CosmicsTag: @local::ICARUS_Calibration_GlobalTags.pmt_cosmics_timing_data + } + Verbose: false + LogCategory: "OldPMTTimingCorrections" + } + + Verbose: false +} + +END_PROLOG \ No newline at end of file diff --git a/icaruscode/PMT/Calibration/fcl/pmt-calibration.fcl b/icaruscode/PMT/Calibration/fcl/pmt-calibration.fcl index 8adbdf7ca..fed4a6092 100644 --- a/icaruscode/PMT/Calibration/fcl/pmt-calibration.fcl +++ b/icaruscode/PMT/Calibration/fcl/pmt-calibration.fcl @@ -27,15 +27,4 @@ pmt_bkgphotons_calibration: IntegralBinning: [ 0., 8., 0.04 ] # in 10^7 electrons } -ophit_recalibrator: -{ - module_type: OpHitRecalibrator - InputLabels: [ "ophit" ] - RecalibratePE: true - UseGainDatabase: true - SPEArea: -1.0 - RecalibrateTime: true - Verbose: false -} - END_PROLOG From 76c5cd028bf793f0ecf7e103e0f8f02c434b9299 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Thu, 4 Dec 2025 15:13:34 -0600 Subject: [PATCH 30/47] fix timing recalibration --- icaruscode/PMT/Calibration/CMakeLists.txt | 5 +- .../Calibration/OpHitRecalibrator_module.cc | 74 ++++++++----------- .../PMT/Calibration/fcl/hit-recalibrator.fcl | 8 +- 3 files changed, 39 insertions(+), 48 deletions(-) diff --git a/icaruscode/PMT/Calibration/CMakeLists.txt b/icaruscode/PMT/Calibration/CMakeLists.txt index b5ef4e2b5..467ad10d2 100644 --- a/icaruscode/PMT/Calibration/CMakeLists.txt +++ b/icaruscode/PMT/Calibration/CMakeLists.txt @@ -6,7 +6,7 @@ cet_build_plugin(PMTLaserCalibration art::module icaruscode_PMT_Algorithms icaruscode_PMT_Calibration_CaloTools icaruscode_IcarusObj - lardataobj::RawData + lardataobj::RawData lardataobj::Simulation lardataobj::RecoBase art::Framework_Core @@ -46,9 +46,10 @@ cet_build_plugin(PMTBackgroundphotonsCalibration art::module cet_build_plugin( OpHitRecalibrator art::module LIBRARIES PUBLIC - lardataobj::RecoBase + lardataobj::RecoBase lardataobj::RawData larcore::Geometry_Geometry_service + icaruscode_Timing ) art_make_exec( NAME diff --git a/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc b/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc index 48f139beb..01f7beb0b 100644 --- a/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc +++ b/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc @@ -77,9 +77,6 @@ class icarus::OpHitRecalibrator : public art::SharedProducer struct Config { - fhicl::Sequence InputLabels{ - fhicl::Name("InputLabels"), - fhicl::Comment("list of the input labels to be used")}; fhicl::Atom RecalibratePE{ fhicl::Name("RecalibratePE"), @@ -117,19 +114,17 @@ class icarus::OpHitRecalibrator : public art::SharedProducer }; // struct Config - using Parameters = art::SharedProducer::Table; - /// Constructor: just reads the configuration. - explicit OpHitRecalibrator(Parameters const &config, art::ProcessingFrame const &); + explicit OpHitRecalibrator(fhicl::ParameterSet const &config, art::ProcessingFrame const &); /// process the event void produce(art::Event &event, art::ProcessingFrame const &) override; /// configuration at every run change - void beginRun(const art::Run& run) override; + void beginRun(art::Run& run, art::ProcessingFrame const&) override; private: - std::vector const fInputLabels; + art::InputTag const fInputLabel; bool const fRecalibratePE; bool const fRecalibrateTime; bool const fUseGainDatabase; @@ -145,25 +140,24 @@ class icarus::OpHitRecalibrator : public art::SharedProducer }; // ----------------------------------------------------------------------------- -icarus::OpHitRecalibrator::OpHitRecalibrator(Parameters const &config, art::ProcessingFrame const &) +icarus::OpHitRecalibrator::OpHitRecalibrator(fhicl::ParameterSet const &config, art::ProcessingFrame const &) : art::SharedProducer(config), - fInputLabels{config().InputLabels()}, - fRecalibratePE{config().RecalibratePE()}, - fRecalibrateTime{config().RecalibrateTime()}, - fUseGainDatabase{config().UseGainDatabase()}, - fSPEArea{config().SPEArea()}, - fVerbose{config().Verbose()}, + fInputLabel{config.get("InputLabel")}, + fRecalibratePE{config.get("RecalibratePE")}, + fRecalibrateTime{config.get("RecalibrateTime")}, + fUseGainDatabase{config.get("UseGainDatabase", false)}, + fSPEArea{config.get("SPEArea", -1.)}, + fVerbose{config.get("Verbose", false)}, fPMTTimingCorrectionsService{*(lar::providerFrom())}, - fOldTimingProvider{std::make_unique(config().OldTimingTags())} + fOldTimingProvider{std::make_unique(config.get("OldTimingDBTags"))} { async(); // configuration checks - if (fInputLabels.empty()) + if (fInputLabel.empty()) { throw art::Exception{art::errors::Configuration} - << "The list of input hit data products ('" - << config().InputLabels.name() << "') is empty.\n"; + << "The list of input hit data products ('InputLabel') is empty.\n"; } if (!fRecalibratePE && !fRecalibrateTime) @@ -175,9 +169,8 @@ icarus::OpHitRecalibrator::OpHitRecalibrator(Parameters const &config, art::Proc if (fRecalibratePE && !fUseGainDatabase && (fSPEArea<0)) { throw art::Exception{art::errors::Configuration} - << "The gain database for PE recalibration has been disabled ('" - << config().UseGainDatabase.name() << "'), but '" - << config().SPEArea.name() << "' (" << fSPEArea + << "The gain database for PE recalibration has been disabled ('UseGainDatabase')," + << " but 'SPEArea' (" << fSPEArea << ") has not been set correctly. Fix the configuration!\n"; } @@ -185,9 +178,9 @@ icarus::OpHitRecalibrator::OpHitRecalibrator(Parameters const &config, art::Proc { mf::LogInfo("OpHitRecalibrator") << "Re-calibration of timing corrections enabled:\n" << "LaserTag: old " << fOldTimingProvider->getLaserDatabaseTag() - << " -> new " << fPMTTimingCorrectionsService->getLaserDatabaseTag() + << " -> new " << fPMTTimingCorrectionsService.getLaserDatabaseTag() << "\nCosmicsTag: old " << fOldTimingProvider->getCosmicsDatabaseTag() - << " -> new " << fPMTTimingCorrectionsService->getCosmicsDatabaseTag(); + << " -> new " << fPMTTimingCorrectionsService.getCosmicsDatabaseTag(); } //FIXME: temporary since no gain db exists yet... @@ -198,17 +191,17 @@ icarus::OpHitRecalibrator::OpHitRecalibrator(Parameters const &config, art::Proc } // Consumes - for (auto const &tag : fInputLabels) - consumes>(tag); - + consumes>(fInputLabel); + // Produces produces>(); } // ----------------------------------------------------------------------------- -void icarus::OpHitRecalibrator::beginRun(const art::Run& run) +void icarus::OpHitRecalibrator::beginRun(art::Run& run, art::ProcessingFrame const&) { // make sure we are updating the locally-instantiated correction provider if (fOldTimingProvider) { + if(fVerbose) mf::LogInfo("OpHitRecalibrator") << "Updating old timing corrections for " << run.id().run(); fOldTimingProvider->readTimeCorrectionDatabase(run); } } @@ -221,11 +214,9 @@ void icarus::OpHitRecalibrator::produce(art::Event &event, art::ProcessingFrame // Create a copy of the OpHits std::vector recalibratedOpHits; - for (art::InputTag const &label : fInputLabels) - { - auto const &opHits = event.getProduct>(label); + auto const &opHits = event.getProduct>(fInputLabel); - for (auto const &opHit : opHits) + for (auto const &opHit : opHits) { // read current times double peakTime = opHit.PeakTime(); @@ -256,7 +247,7 @@ void icarus::OpHitRecalibrator::produce(art::Event &event, art::ProcessingFrame *log << "Channel: " << opHit.OpChannel() << ", Area: " << opHit.Area() << " [ADC x tick]" << ", PE " << hitPE - << "(old SPEArea: " << oldSPEArea + << " (old SPEArea: " << oldSPEArea << ") --> new PE " << opHit.Area()/newSPEArea << " (new SPEArea: " << newSPEArea << ")\n"; } @@ -285,14 +276,14 @@ void icarus::OpHitRecalibrator::produce(art::Event &event, art::ProcessingFrame if(log) { *log << "Channel: " << opHit.OpChannel() - << ", startTime " << startTime << " us" - << ", peakTime " << peakTime << " us" - << ", peakTimeAbs " << peakTimeAbs << " us" - << "(old total correction: " << oldTotalCorrection + << ", startTime " << startTime + << ", peakTime " << peakTime + << ", peakTimeAbs " << peakTimeAbs + << " (total correction: " << oldTotalCorrection << ") --> new startTime " << startTime + timeCorr - << ", new peakTime " << peakTime + timeCorr - << ", new peakTimeAbs " << peakTimeAbs + timeCorr - << " (new total correction: " << totalCorrection << ")\n"; + << ", peakTime " << peakTime + timeCorr + << ", peakTimeAbs " << peakTimeAbs + timeCorr + << " (total correction: " << totalCorrection << ")\n"; } peakTime = peakTime + timeCorr; @@ -315,8 +306,7 @@ void icarus::OpHitRecalibrator::produce(art::Event &event, art::ProcessingFrame opHit.FastToTotal() // fasttototal ); } - } - + // The new OpHits collection is also saved in the event stream event.put( std::make_unique>(std::move(recalibratedOpHits))); diff --git a/icaruscode/PMT/Calibration/fcl/hit-recalibrator.fcl b/icaruscode/PMT/Calibration/fcl/hit-recalibrator.fcl index b0de24dc6..fbdd8b1e7 100644 --- a/icaruscode/PMT/Calibration/fcl/hit-recalibrator.fcl +++ b/icaruscode/PMT/Calibration/fcl/hit-recalibrator.fcl @@ -5,13 +5,13 @@ BEGIN_PROLOG ophit_recalibrator: { module_type: OpHitRecalibrator - InputLabels: [ "ophit" ] + InputLabel: "ophit" RecalibratePE: true UseGainDatabase: true SPEArea: -1.0 - RecalibrateTime: false + RecalibrateTime: true - OldTimingTags: { + OldTimingDBTags: { CorrectionTags: { CablesTag: @local::ICARUS_Calibration_GlobalTags.pmt_cables_delays_data LaserTag: @local::ICARUS_Calibration_GlobalTags.pmt_laser_timing_data @@ -24,4 +24,4 @@ ophit_recalibrator: Verbose: false } -END_PROLOG \ No newline at end of file +END_PROLOG From 46942ec9d6d057341a7d67785718d0d4c83e2cab Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Thu, 4 Dec 2025 16:15:01 -0500 Subject: [PATCH 31/47] remove custom config, fixed indentation --- .../Calibration/OpHitRecalibrator_module.cc | 252 ++++++++---------- 1 file changed, 106 insertions(+), 146 deletions(-) diff --git a/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc b/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc index 01f7beb0b..61d733ad2 100644 --- a/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc +++ b/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc @@ -42,10 +42,10 @@ namespace icarus * @brief Creates a new collection of optical hits with re-calibrated PEs and times. * * This module reads reconstructed optical detector hits, removes previously-applied - * gain and/or timing calibrations, and applies new ones. + * gain and/or timing calibrations, and applies new ones. * A new collection of hits is produced containing a re-calibrated copy of all the * hits from the input collections. - * + * * Input * ------ * * `std::vector` data products (as for `InputLabels`) @@ -60,9 +60,9 @@ namespace icarus * * * `InputLabels` (list of input tags, mandatory): the list of optical hit data * products to recalibrated It must be non-empty. - * * `RecalibratePE` (flag, mandatory): if set, recalibrate hit PE values. + * * `RecalibratePE` (flag, mandatory): if set, recalibrate hit PE values. * * `UseGainDatabase` (flag, default: true): if set, use gain values from database - * to re-calibrate hit PEs from hit area. + * to re-calibrate hit PEs from hit area. * * `SPEArea` (double, default: -1): if not using the gain database, single-photoelectron * area in ADC x tick to be used in the PE calibration. * * `RecalibrateTime` (flag, mandatory): if set, recalibrate hit times. @@ -73,47 +73,6 @@ class icarus::OpHitRecalibrator : public art::SharedProducer { public: - /// Configuration of the module. - struct Config - { - - - fhicl::Atom RecalibratePE{ - fhicl::Name("RecalibratePE"), - fhicl::Comment("re-compute hit PE values") - }; - - fhicl::Atom UseGainDatabase{ - fhicl::Name("UseGainDatabase"), - fhicl::Comment("whether to use gain database to recalibrate"), - true - }; - - fhicl::Atom SPEArea{ - fhicl::Name("SPEArea"), - fhicl::Comment("single-photoelectron area for calibration for non-database calibration"), - -1. - }; - - fhicl::Atom RecalibrateTime{ - fhicl::Name("RecalibrateTime"), - fhicl::Comment("re-apply timing corrections"), - false - }; - - fhicl::Table OldTimingDBTags{ - fhicl::Name("OldTimingDBTags"), - fhicl::Comment("configuration for old PMT timing correction tags") - }; - - fhicl::Atom Verbose{ - fhicl::Name("Verbose"), - fhicl::Comment("print the times read and the associated channels"), - false // default - }; - - }; // struct Config - /// Constructor: just reads the configuration. explicit OpHitRecalibrator(fhicl::ParameterSet const &config, art::ProcessingFrame const &); @@ -121,7 +80,7 @@ class icarus::OpHitRecalibrator : public art::SharedProducer void produce(art::Event &event, art::ProcessingFrame const &) override; /// configuration at every run change - void beginRun(art::Run& run, art::ProcessingFrame const&) override; + void beginRun(art::Run &run, art::ProcessingFrame const &) override; private: art::InputTag const fInputLabel; @@ -134,22 +93,21 @@ class icarus::OpHitRecalibrator : public art::SharedProducer /// Pointer to the online pmt corrections service icarusDB::PMTTimingCorrections const &fPMTTimingCorrectionsService; - /// Pointer to the provider for the old pmt corrections + /// Pointer to the provider for the old pmt corrections std::unique_ptr fOldTimingProvider; - }; // ----------------------------------------------------------------------------- icarus::OpHitRecalibrator::OpHitRecalibrator(fhicl::ParameterSet const &config, art::ProcessingFrame const &) : art::SharedProducer(config), - fInputLabel{config.get("InputLabel")}, - fRecalibratePE{config.get("RecalibratePE")}, - fRecalibrateTime{config.get("RecalibrateTime")}, - fUseGainDatabase{config.get("UseGainDatabase", false)}, - fSPEArea{config.get("SPEArea", -1.)}, - fVerbose{config.get("Verbose", false)}, - fPMTTimingCorrectionsService{*(lar::providerFrom())}, - fOldTimingProvider{std::make_unique(config.get("OldTimingDBTags"))} + fInputLabel{config.get("InputLabel")}, + fRecalibratePE{config.get("RecalibratePE")}, + fRecalibrateTime{config.get("RecalibrateTime")}, + fUseGainDatabase{config.get("UseGainDatabase", false)}, + fSPEArea{config.get("SPEArea", -1.)}, + fVerbose{config.get("Verbose", false)}, + fPMTTimingCorrectionsService{*(lar::providerFrom())}, + fOldTimingProvider{std::make_unique(config.get("OldTimingDBTags"))} { async(); @@ -166,7 +124,7 @@ icarus::OpHitRecalibrator::OpHitRecalibrator(fhicl::ParameterSet const &config, << "No re-calibration selected. Why are you running meeee!?!?! :/\n"; } - if (fRecalibratePE && !fUseGainDatabase && (fSPEArea<0)) + if (fRecalibratePE && !fUseGainDatabase && (fSPEArea < 0)) { throw art::Exception{art::errors::Configuration} << "The gain database for PE recalibration has been disabled ('UseGainDatabase')," @@ -174,7 +132,7 @@ icarus::OpHitRecalibrator::OpHitRecalibrator(fhicl::ParameterSet const &config, << ") has not been set correctly. Fix the configuration!\n"; } - if( fRecalibrateTime ) + if (fRecalibrateTime) { mf::LogInfo("OpHitRecalibrator") << "Re-calibration of timing corrections enabled:\n" << "LaserTag: old " << fOldTimingProvider->getLaserDatabaseTag() @@ -183,7 +141,7 @@ icarus::OpHitRecalibrator::OpHitRecalibrator(fhicl::ParameterSet const &config, << " -> new " << fPMTTimingCorrectionsService.getCosmicsDatabaseTag(); } - //FIXME: temporary since no gain db exists yet... + // FIXME: temporary since no gain db exists yet... if (fUseGainDatabase) { throw art::Exception{art::errors::Configuration} @@ -197,13 +155,15 @@ icarus::OpHitRecalibrator::OpHitRecalibrator(fhicl::ParameterSet const &config, } // ----------------------------------------------------------------------------- -void icarus::OpHitRecalibrator::beginRun(art::Run& run, art::ProcessingFrame const&) +void icarus::OpHitRecalibrator::beginRun(art::Run &run, art::ProcessingFrame const &) { // make sure we are updating the locally-instantiated correction provider - if (fOldTimingProvider) { - if(fVerbose) mf::LogInfo("OpHitRecalibrator") << "Updating old timing corrections for " << run.id().run(); + if (fOldTimingProvider) + { + if (fVerbose) + mf::LogInfo("OpHitRecalibrator") << "Updating old timing corrections for " << run.id().run(); fOldTimingProvider->readTimeCorrectionDatabase(run); - } + } } // ----------------------------------------------------------------------------- @@ -217,96 +177,96 @@ void icarus::OpHitRecalibrator::produce(art::Event &event, art::ProcessingFrame auto const &opHits = event.getProduct>(fInputLabel); for (auto const &opHit : opHits) + { + // read current times + double peakTime = opHit.PeakTime(); + double peakTimeAbs = opHit.PeakTimeAbs(); + double startTime = opHit.StartTime(); + double riseTime = opHit.RiseTime(); + + // read current PE + double hitPE = opHit.PE(); + + // First, recalibrate PE values (if enabled). + // - if using gain database, fetch new SPEArea for this run/channel + // - if not using gain database, use fSPEArea + // - re-compute PE value with new SPE area + if (fRecalibratePE) { - // read current times - double peakTime = opHit.PeakTime(); - double peakTimeAbs = opHit.PeakTimeAbs(); - double startTime = opHit.StartTime(); - double riseTime = opHit.RiseTime(); - - // read current PE - double hitPE = opHit.PE(); - - // First, recalibrate PE values (if enabled). - // - if using gain database, fetch new SPEArea for this run/channel - // - if not using gain database, use fSPEArea - // - re-compute PE value with new SPE area - if( fRecalibratePE ) + double oldSPEArea = opHit.Area() / hitPE; + double newSPEArea = fSPEArea; + + if (fUseGainDatabase) + { + // soon... + // newSPEArea = get_from_db(opHit.OpChannel()) + } + + if (log) { - double oldSPEArea = opHit.Area()/hitPE; - double newSPEArea = fSPEArea; - - if( fUseGainDatabase ) - { - // soon... - // newSPEArea = get_from_db(opHit.OpChannel()) - } - - if(log) - { - *log << "Channel: " << opHit.OpChannel() - << ", Area: " << opHit.Area() << " [ADC x tick]" - << ", PE " << hitPE - << " (old SPEArea: " << oldSPEArea - << ") --> new PE " << opHit.Area()/newSPEArea - << " (new SPEArea: " << newSPEArea << ")\n"; - } - - hitPE = opHit.Area()/newSPEArea; + *log << "Channel: " << opHit.OpChannel() + << ", Area: " << opHit.Area() << " [ADC x tick]" + << ", PE " << hitPE + << " (old SPEArea: " << oldSPEArea + << ") --> new PE " << opHit.Area() / newSPEArea + << " (new SPEArea: " << newSPEArea << ")\n"; } - - // Second, recalibrate PMT times (if enabled) - // Previous corrections need to be subtracted - // use locally instantiated provider class to fetch old corrections - // use online pmt corrections servicer to fetch current/new corrections - if( fRecalibrateTime ) + + hitPE = opHit.Area() / newSPEArea; + } + + // Second, recalibrate PMT times (if enabled) + // Previous corrections need to be subtracted + // use locally instantiated provider class to fetch old corrections + // use online pmt corrections servicer to fetch current/new corrections + if (fRecalibrateTime) + { + // get the old timing corrections: these will need to be subtracted! + double const oldLaserTimeCorrection = fOldTimingProvider->getLaserCorrections(opHit.OpChannel()); + double const oldCosmicsCorrection = fOldTimingProvider->getCosmicsCorrections(opHit.OpChannel()); + double const oldTotalCorrection = oldLaserTimeCorrection + oldCosmicsCorrection; + + // get new/current timing: these will need to be added! + double const laserTimeCorrection = fPMTTimingCorrectionsService.getLaserCorrections(opHit.OpChannel()); + double const cosmicsCorrection = fPMTTimingCorrectionsService.getCosmicsCorrections(opHit.OpChannel()); + double const totalCorrection = laserTimeCorrection + cosmicsCorrection; + + double timeCorr = totalCorrection - oldTotalCorrection; + + if (log) { - // get the old timing corrections: these will need to be subtracted! - double const oldLaserTimeCorrection = fOldTimingProvider->getLaserCorrections(opHit.OpChannel()); - double const oldCosmicsCorrection = fOldTimingProvider->getCosmicsCorrections(opHit.OpChannel()); - double const oldTotalCorrection = oldLaserTimeCorrection + oldCosmicsCorrection; - - // get new/current timing: these will need to be added! - double const laserTimeCorrection = fPMTTimingCorrectionsService.getLaserCorrections(opHit.OpChannel()); - double const cosmicsCorrection = fPMTTimingCorrectionsService.getCosmicsCorrections(opHit.OpChannel()); - double const totalCorrection = laserTimeCorrection + cosmicsCorrection; - - double timeCorr = totalCorrection - oldTotalCorrection; - - if(log) - { - *log << "Channel: " << opHit.OpChannel() - << ", startTime " << startTime - << ", peakTime " << peakTime - << ", peakTimeAbs " << peakTimeAbs - << " (total correction: " << oldTotalCorrection - << ") --> new startTime " << startTime + timeCorr - << ", peakTime " << peakTime + timeCorr - << ", peakTimeAbs " << peakTimeAbs + timeCorr - << " (total correction: " << totalCorrection << ")\n"; - } - - peakTime = peakTime + timeCorr; - peakTimeAbs = peakTimeAbs + timeCorr; - startTime = startTime + timeCorr; - // NOTE: riseTime is currently relative to the start time, so no correction needed + *log << "Channel: " << opHit.OpChannel() + << ", startTime " << startTime + << ", peakTime " << peakTime + << ", peakTimeAbs " << peakTimeAbs + << " (total correction: " << oldTotalCorrection + << ") --> new startTime " << startTime + timeCorr + << ", peakTime " << peakTime + timeCorr + << ", peakTimeAbs " << peakTimeAbs + timeCorr + << " (total correction: " << totalCorrection << ")\n"; } - recalibratedOpHits.emplace_back( - opHit.OpChannel(), // channel - peakTime, // recalibrated peaktime - peakTimeAbs, // recalibrated peaktimeabs - startTime, // recalibrated starttime - riseTime, // recalibrated risetime - opHit.Frame(), // frame - opHit.Width(), // width - opHit.Area(), // area - opHit.Amplitude(), // peakheight - hitPE, // recalibrated pe - opHit.FastToTotal() // fasttototal - ); + peakTime = peakTime + timeCorr; + peakTimeAbs = peakTimeAbs + timeCorr; + startTime = startTime + timeCorr; + // NOTE: riseTime is currently relative to the start time, so no correction needed } - + + recalibratedOpHits.emplace_back( + opHit.OpChannel(), // channel + peakTime, // recalibrated peaktime + peakTimeAbs, // recalibrated peaktimeabs + startTime, // recalibrated starttime + riseTime, // recalibrated risetime + opHit.Frame(), // frame + opHit.Width(), // width + opHit.Area(), // area + opHit.Amplitude(), // peakheight + hitPE, // recalibrated pe + opHit.FastToTotal() // fasttototal + ); + } + // The new OpHits collection is also saved in the event stream event.put( std::make_unique>(std::move(recalibratedOpHits))); From 8d29faa69123f29ac14a298c6081cc6b3dfb4124 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Thu, 4 Dec 2025 17:22:02 -0500 Subject: [PATCH 32/47] chop off flat waveform tail in overlays --- icaruscode/Decode/OverlayProducts_module.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/icaruscode/Decode/OverlayProducts_module.cc b/icaruscode/Decode/OverlayProducts_module.cc index c614a2eba..4c71fc48c 100644 --- a/icaruscode/Decode/OverlayProducts_module.cc +++ b/icaruscode/Decode/OverlayProducts_module.cc @@ -599,7 +599,9 @@ void OverlayProducts::produce(art::Event& e) // and fill in any remaining bins left while ( idxWvfmEntry < wvfm.size() ) { - adcVec.push_back( overlayOpWave.baseline + (wvfm[idxWvfmEntry] - simBaseline) ); + // FIXME FIXME: temporary override to chop off flat tails after data waveform ends + // timing shift between data/mc event should be tuned so that this never (?) happens! + //adcVec.push_back( overlayOpWave.baseline + (wvfm[idxWvfmEntry] - simBaseline) ); idxWvfmEntry+=1; } From 23005d1389438aceb04fb81fc723bce7e6c9ad06 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Thu, 4 Dec 2025 17:32:26 -0500 Subject: [PATCH 33/47] restore legacy defaults for backward compatibility --- icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl | 6 ++++++ icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl | 2 +- icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl | 4 ++-- icaruscode/PMT/OpReco/fcl/icarus_ophitfinder.fcl | 4 ++-- icaruscode/PMT/OpReco/fcl/icarus_spe.fcl | 2 ++ 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl b/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl index 66cd84b31..e53107e81 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl @@ -24,6 +24,10 @@ icarus_pmt_calibration.NoCalibRun4: { SPEAreaGain: @local::SPERun4.Area } +icarus_pmt_calibration.NoCalib: { + SPEAreaGain: @local::SPE.Area +} + # ------------------------------------------------------------------------------ # `icarus_pmt_calibration.Calib202203`: from March 2021 # @@ -34,9 +38,11 @@ icarus_pmt_calibration.Calib202203: { # ------------------------------------------------------------------------------ + icarus_pmt_calibration.CalibStandardRun2: @local::icarus_pmt_calibration.NoCalibRun2 icarus_pmt_calibration.CalibStandardRun3: @local::icarus_pmt_calibration.NoCalibRun3 icarus_pmt_calibration.CalibStandardRun4: @local::icarus_pmt_calibration.NoCalibRun4 +icarus_pmt_calibration.CalibStandard: @local::icarus_pmt_calibration.NoCalib END_PROLOG diff --git a/icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl b/icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl index 9a4e4a49e..6b76b04c7 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl @@ -9,7 +9,7 @@ ICARUSSimpleFlash: FlashFinderAlgo : "SimpleFlashAlgo" AlgoConfig : @local::SimpleFlashStandard OpHitProducer : "ophit" - PECalib : @local::icarus_pmt_calibration.CalibStandardRun2 + PECalib : @local::icarus_pmt_calibration.CalibStandard } ICARUSSimpleFlashCryoE: @local::ICARUSSimpleFlash diff --git a/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl b/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl index 6d39330ca..628ef5c5d 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_opana_modules.fcl @@ -25,8 +25,8 @@ ICARUSMCOpHit: { module_type: "ICARUSMCOpHit" MergePeriod: 0.01 SimPhotonsProducer: "pdfastsim" - SPEArea: @local::SPERun2.Area - SPEAmplitude: @local::SPERun2.Amplitude + SPEArea: @local::SPE.Area + SPEAmplitude: @local::SPE.Amplitude } ICARUSMCOpFlash: { diff --git a/icaruscode/PMT/OpReco/fcl/icarus_ophitfinder.fcl b/icaruscode/PMT/OpReco/fcl/icarus_ophitfinder.fcl index 66ad03349..239f8c655 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_ophitfinder.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_ophitfinder.fcl @@ -193,9 +193,9 @@ icarus_ophit: # some basic configuration ChannelMasks: [] HitThreshold: 0.2 # PE AreaToPE: true # Use area to calculate number of PEs - SPEArea: @local::SPERun2.Area # If AreaToPE is true, this number is + SPEArea: @local::SPE.Area # If AreaToPE is true, this number is # used as single PE area (in ADC counts) - SPEShift: @local::SPERun2.Shift # Used by PhotonCalibratorStandard to compute + SPEShift: @local::SPE.Shift # Used by PhotonCalibratorStandard to compute # PE = area / SPEArea + SPEShift UseStartTime: false # start and peak times each in its own data member reco_man: @local::standard_preco_manager diff --git a/icaruscode/PMT/OpReco/fcl/icarus_spe.fcl b/icaruscode/PMT/OpReco/fcl/icarus_spe.fcl index f8f46d202..a7dba2dc5 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_spe.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_spe.fcl @@ -44,4 +44,6 @@ SPERun2: @local::SPE2025Run2 SPERun3: @local::SPE2025Run3 SPERun4: @local::SPE2025Run4 +SPE: @local::SPE202401patch + END_PROLOG From 2f8cf32d3ad0841aaedc0eed86ea558d25d04ddf Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Thu, 4 Dec 2025 17:52:18 -0500 Subject: [PATCH 34/47] fixed documentation --- .../Calibration/OpHitRecalibrator_module.cc | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc b/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc index 61d733ad2..14c9d5a9a 100644 --- a/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc +++ b/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc @@ -45,7 +45,25 @@ namespace icarus * gain and/or timing calibrations, and applies new ones. * A new collection of hits is produced containing a re-calibrated copy of all the * hits from the input collections. - * + * + * The PE recalibration is simple: for each optical hit, its `PE` value is recomputed + * from its `Area` [ADC x tick] based on a newly determined single-PE area. + * If `UseGainDatabase` is set, the module calls retrieves the SPE area by channel and run number + * using the gain calibration service. If that option is disabled, a single SPE area value + * is used for all channels and run numbers. This value is read from the `SPEArea` paramater + * set in the configuration. + * + * The timing recalibration requires removing previously-applied timing corrections and + * adding the new ones. Unfortunately, however, it's not possible to easily determine + * which timing corrections were previsouly applied to the optical hits. + * The old corrections -- that need to be removed -- are therefore obtained by locally + * definining an instance of `icarusDB::PMTTimingCorrectionsProvider` and manually setting + * in the configuration the database tags that were used originally (`OldTimingDBTags`). + * These need to be deduced by the `icaruscode` version that was used and the corresponding + * settings in `calibration_database_GlobalTags_icarus.fcl` + * On the other hand, the new corrections are obtained from the current timing correction + * service `icarusDB::PMTTimingCorrections` as defined in `timing_icarus.fcl`. + * * Input * ------ * * `std::vector` data products (as for `InputLabels`) @@ -58,14 +76,16 @@ namespace icarus * Configuration parameters * ------------------------- * - * * `InputLabels` (list of input tags, mandatory): the list of optical hit data - * products to recalibrated It must be non-empty. + * * `InputLabel` (art::InputTag, mandatory): optical hit data products to be recalibrated. It must be non-empty. * * `RecalibratePE` (flag, mandatory): if set, recalibrate hit PE values. * * `UseGainDatabase` (flag, default: true): if set, use gain values from database * to re-calibrate hit PEs from hit area. * * `SPEArea` (double, default: -1): if not using the gain database, single-photoelectron * area in ADC x tick to be used in the PE calibration. * * `RecalibrateTime` (flag, mandatory): if set, recalibrate hit times. + * * `OldTimingDBTags` (fhicl::ParameterSet, mandatory): configuration for the previously-applied timing corrections + * that need to be removed/replace by the now ones. It should match what is tipically passed to + * `icarusDB::PMTTimingCorrectionsProvider`, specifying the database tags that were used. * * `Verbose` (flag, default: `false`): verbose printing * */ From d18c7847753756136ad36b91f975a998c9a49cf2 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Fri, 5 Dec 2025 17:49:58 -0500 Subject: [PATCH 35/47] add opdetonly MCstage0 fhicls for reprocessing --- ...tonly_icarus_overlay_reprocessing_run4.fcl | 4 +-- fcl/reco/Stage0/CMakeLists.txt | 1 + fcl/reco/Stage0/partial/CMakeLists.txt | 7 +++++ ..._opdetonly_icarus_overlay_reprocessing.fcl | 26 +++++++++++++++++++ ..._opdetonly_icarus_overlay_reprocessing.fcl | 9 +++++++ ..._opdetonly_icarus_overlay_reprocessing.fcl | 9 +++++++ 6 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 fcl/reco/Stage0/partial/CMakeLists.txt create mode 100644 fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_overlay_reprocessing.fcl create mode 100644 fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_overlay_reprocessing.fcl create mode 100644 fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_overlay_reprocessing.fcl diff --git a/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run4.fcl b/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run4.fcl index 7c9ec528f..ba50bc85c 100644 --- a/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run4.fcl +++ b/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run4.fcl @@ -1,5 +1,5 @@ #include "detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl" -# switch to run4 tune +# switch to Run-4 tune physics.producers.opdaq: @local::icarus_simpmt_run4_nonoise -physics.producers.opdaq.InputModule: "shifted" \ No newline at end of file +physics.producers.opdaq.InputModule: "shifted::DetSim" \ No newline at end of file diff --git a/fcl/reco/Stage0/CMakeLists.txt b/fcl/reco/Stage0/CMakeLists.txt index 178294463..4fcd34c26 100644 --- a/fcl/reco/Stage0/CMakeLists.txt +++ b/fcl/reco/Stage0/CMakeLists.txt @@ -3,3 +3,4 @@ cet_enable_asserts() add_subdirectory(mc) add_subdirectory(data) add_subdirectory(overlay) +add_subdirectory(partial) diff --git a/fcl/reco/Stage0/partial/CMakeLists.txt b/fcl/reco/Stage0/partial/CMakeLists.txt new file mode 100644 index 000000000..4776c013e --- /dev/null +++ b/fcl/reco/Stage0/partial/CMakeLists.txt @@ -0,0 +1,7 @@ +# Install fcl files in /job subdirectory. +install_fhicl() + +# Also put a copy in the source tree. + +FILE(GLOB fcl_files *.fcl) +install_source( EXTRAS ${fcl_files} ) \ No newline at end of file diff --git a/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_overlay_reprocessing.fcl b/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_overlay_reprocessing.fcl new file mode 100644 index 000000000..b24963e1b --- /dev/null +++ b/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_overlay_reprocessing.fcl @@ -0,0 +1,26 @@ +#include "stage0_run2_wcdnn_icarus_overlay" + +process_name: OpMCstage0 + +## only perform PMT/CRT MCstage0 on top of reprocessed MC overlay files +## Notes: +## - previous MCStage0 PMT/CRT products have already been removed +## - new inputs have been re-baked, but with standard tag names +## - need to pick correct reconstruction tune for PMT flow + +# execute PMT/CRT only path +physics.path: [ @sequence::icarus_stage0_mc_PMT, + @sequence::icarus_stage0_mc_crthit, + @sequence::icarus_stage0_mc_crtreco + ] + +# update ophit procedurs to pick up Run-2 SPE tune +icarus_stage0_mc_producers.ophituncorrected.SPEArea: @local::SPERun2.Area +icarus_stage0_mc_producers.ophituncorrected.SPEShift: @local::SPERun2.Shift + +# update flash producers to pick up Run-2 SPE tune +icarus_stage0_producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun2 +icarus_stage0_producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun2 + + + diff --git a/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_overlay_reprocessing.fcl b/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_overlay_reprocessing.fcl new file mode 100644 index 000000000..2a8147ae8 --- /dev/null +++ b/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_overlay_reprocessing.fcl @@ -0,0 +1,9 @@ +#include "stage0_run2_opdetonly_icarus_overlay_reprocessing.fcl" + +# update ophit procedurs to pick up Run-3 SPE tune +icarus_stage0_mc_producers.ophituncorrected.SPEArea: @local::SPERun3.Area +icarus_stage0_mc_producers.ophituncorrected.SPEShift: @local::SPERun3.Shift + +# update flash producers to pick up Run-3 SPE tune +icarus_stage0_producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun3 +icarus_stage0_producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun3 \ No newline at end of file diff --git a/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_overlay_reprocessing.fcl b/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_overlay_reprocessing.fcl new file mode 100644 index 000000000..bf1ed9314 --- /dev/null +++ b/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_overlay_reprocessing.fcl @@ -0,0 +1,9 @@ +#include "stage0_run2_opdetonly_icarus_overlay_reprocessing.fcl" + +# update ophit procedurs to pick up Run-4 SPE tune +icarus_stage0_mc_producers.ophituncorrected.SPEArea: @local::SPERun4.Area +icarus_stage0_mc_producers.ophituncorrected.SPEShift: @local::SPERun4.Shift + +# update flash producers to pick up Run-4 SPE tune +icarus_stage0_producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun4 +icarus_stage0_producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun4 \ No newline at end of file From 28f94e0723fbb513016303c8409357fa128f7b22 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 8 Dec 2025 09:27:35 -0600 Subject: [PATCH 36/47] fix stage0 reprocessing fhicls --- ...n2_opdetonly_icarus_overlay_reprocessing.fcl | 17 ++++++++++------- ...n3_opdetonly_icarus_overlay_reprocessing.fcl | 12 ++++++++---- ...n4_opdetonly_icarus_overlay_reprocessing.fcl | 12 ++++++++---- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_overlay_reprocessing.fcl b/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_overlay_reprocessing.fcl index b24963e1b..25d7e3ca4 100644 --- a/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_overlay_reprocessing.fcl +++ b/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_overlay_reprocessing.fcl @@ -1,4 +1,4 @@ -#include "stage0_run2_wcdnn_icarus_overlay" +#include "stage0_run2_wcdnn_icarus_overlay.fcl" process_name: OpMCstage0 @@ -10,17 +10,20 @@ process_name: OpMCstage0 # execute PMT/CRT only path physics.path: [ @sequence::icarus_stage0_mc_PMT, - @sequence::icarus_stage0_mc_crthit, - @sequence::icarus_stage0_mc_crtreco + @sequence::icarus_stage0_mc_crtreco # only reco, hits from overlay ] # update ophit procedurs to pick up Run-2 SPE tune -icarus_stage0_mc_producers.ophituncorrected.SPEArea: @local::SPERun2.Area -icarus_stage0_mc_producers.ophituncorrected.SPEShift: @local::SPERun2.Shift +physics.producers.ophituncorrected.SPEArea: @local::SPERun2.Area +physics.producers.ophituncorrected.SPEShift: @local::SPERun2.Shift +physics.producers.ophitfulluncorrected.SPEArea: @local::SPERun2.Area +physics.producers.ophitfulluncorrected.SPEShift: @local::SPERun2.Shift +physics.producers.mcophit.SPEArea: @local::SPERun2.Area +physics.producers.mcophit.SPEAmplitude: @local::SPERun2.Amplitude # update flash producers to pick up Run-2 SPE tune -icarus_stage0_producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun2 -icarus_stage0_producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun2 +physics.producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun2 +physics.producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun2 diff --git a/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_overlay_reprocessing.fcl b/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_overlay_reprocessing.fcl index 2a8147ae8..4875fbcd1 100644 --- a/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_overlay_reprocessing.fcl +++ b/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_overlay_reprocessing.fcl @@ -1,9 +1,13 @@ #include "stage0_run2_opdetonly_icarus_overlay_reprocessing.fcl" # update ophit procedurs to pick up Run-3 SPE tune -icarus_stage0_mc_producers.ophituncorrected.SPEArea: @local::SPERun3.Area -icarus_stage0_mc_producers.ophituncorrected.SPEShift: @local::SPERun3.Shift +physics.producers.ophituncorrected.SPEArea: @local::SPERun3.Area +physics.producers.ophituncorrected.SPEShift: @local::SPERun3.Shift +physics.producers.ophitfulluncorrected.SPEArea: @local::SPERun3.Area +physics.producers.ophitfulluncorrected.SPEShift: @local::SPERun3.Shift +physics.producers.mcophit.SPEArea: @local::SPERun3.Area +physics.producers.mcophit.SPEAmplitude: @local::SPERun3.Amplitude # update flash producers to pick up Run-3 SPE tune -icarus_stage0_producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun3 -icarus_stage0_producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun3 \ No newline at end of file +physics.producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun3 +physics.producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun3 diff --git a/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_overlay_reprocessing.fcl b/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_overlay_reprocessing.fcl index bf1ed9314..894213cf5 100644 --- a/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_overlay_reprocessing.fcl +++ b/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_overlay_reprocessing.fcl @@ -1,9 +1,13 @@ #include "stage0_run2_opdetonly_icarus_overlay_reprocessing.fcl" # update ophit procedurs to pick up Run-4 SPE tune -icarus_stage0_mc_producers.ophituncorrected.SPEArea: @local::SPERun4.Area -icarus_stage0_mc_producers.ophituncorrected.SPEShift: @local::SPERun4.Shift +physics.producers.ophituncorrected.SPEArea: @local::SPERun4.Area +physics.producers.ophituncorrected.SPEShift: @local::SPERun4.Shift +physics.producers.ophitfulluncorrected.SPEArea: @local::SPERun4.Area +physics.producers.ophitfulluncorrected.SPEShift: @local::SPERun4.Shift +physics.producers.mcophit.SPEArea: @local::SPERun4.Area +physics.producers.mcophit.SPEAmplitude: @local::SPERun4.Amplitude # update flash producers to pick up Run-4 SPE tune -icarus_stage0_producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun4 -icarus_stage0_producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun4 \ No newline at end of file +physics.producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun4 +physics.producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun4 From 86cb3536645ea299c96e996aa3fa1748bf55875a Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 8 Dec 2025 10:52:36 -0500 Subject: [PATCH 37/47] adjust stage1 compatibility --- .../detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl b/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl index afde95163..9cb7fd043 100644 --- a/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl +++ b/fcl/detsim/partial/detsim_opdetonly_icarus_overlay_reprocessing_run2.fcl @@ -128,7 +128,9 @@ outputs.rootoutput.outputCommands: [ # drop old "shifted" products since we shifted things again "drop sim::SimEnergyDeposits_filtersed_*_DetSim", # this has been regenerated into `shifted` - "drop sim::SimEnergyDepositLites_filtersed_*_DetSim", # this has been regenerated into `shifted` + # mcreco looks for `filtersed` in stage1: potentially can be changed to look for `shifted`? + # however since tpc reco products are not shifted, better to keep old deposits for that matching + # "drop sim::SimEnergyDepositLites_filtersed_*_DetSim", # this has been regenerated into `shifted` "drop sim::SimEnergyDeposits_shiftedpriorSCE_*_DetSim", # this has been regenerated into the same tag "drop sim::AuxDetSimChannel_shifted_*_DetSim", # this has been regenerated into the same tag "drop sim::SimPhotons_shifted_*_DetSim", # this has been regenerated into the same tag From 09ea82eb494ce4b6bd3b0e351b2291c4c6e493c2 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 8 Dec 2025 13:35:07 -0600 Subject: [PATCH 38/47] add data reprocessing fhicl(s) --- fcl/reco/Definitions/stage0_icarus_defs.fcl | 2 +- ...un2_opdetonly_icarus_data_reprocessing.fcl | 46 +++++++++++++++++++ ...un3_opdetonly_icarus_data_reprocessing.fcl | 11 +++++ ...un4_opdetonly_icarus_data_reprocessing.fcl | 16 +++++++ .../Calibration/OpHitRecalibrator_module.cc | 2 +- ...ecalibrator.fcl => ophit-recalibrator.fcl} | 0 6 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_data_reprocessing.fcl create mode 100644 fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_data_reprocessing.fcl create mode 100644 fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_data_reprocessing.fcl rename icaruscode/PMT/Calibration/fcl/{hit-recalibrator.fcl => ophit-recalibrator.fcl} (100%) diff --git a/fcl/reco/Definitions/stage0_icarus_defs.fcl b/fcl/reco/Definitions/stage0_icarus_defs.fcl index 8fa8b5d67..e711320b7 100644 --- a/fcl/reco/Definitions/stage0_icarus_defs.fcl +++ b/fcl/reco/Definitions/stage0_icarus_defs.fcl @@ -12,6 +12,7 @@ #include "timing_icarus.fcl" #include "timing_beam.fcl" #include "icarus_ophitfinder.fcl" +#include "ophit-recalibrator.fcl" #include "icarus_flashfinder.fcl" #include "trigger_emulation_icarus.fcl" #include "crt_decoderdefs_icarus.fcl" @@ -123,7 +124,6 @@ icarus_stage0_producers: ophitfull: @local::icarus_ophit_timing_correction opflashCryoE: @local::ICARUSSimpleFlashDataCryoE opflashCryoW: @local::ICARUSSimpleFlashDataCryoW - daqPMTonbeam: @local::copyPMTonBeam ### Beam timing diff --git a/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_data_reprocessing.fcl b/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_data_reprocessing.fcl new file mode 100644 index 000000000..8ff3a09c8 --- /dev/null +++ b/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_data_reprocessing.fcl @@ -0,0 +1,46 @@ +#include "stage0_run2_wcdnn_icarus.fcl" + +process_name: OpStage0 + +source.inputCommands: [ + "keep *", + + # need to throw out anything that is based on optical hits; + # this means optical flashes and pmt/crt matching stuff! + # note: old hits will also be thrown out in output + "drop *_opflash*_*_*", # drop stage0 east/west opflashes + "drop *_crtpmt_*_*" # drop CRT/PMT matches (stage0) +] + +# running simplified stage0 pmt/crt path: +# recalibrate hits, then run flash matching + pmtcrt matching +# simplify path removing all other producers + +physics.producers.ophit: @local::ophit_recalibrator # force "ophit" name + +physics.path: [ + ophit, + opflashCryoE, + opflashCryoW, + crtpmt + ] + +# recalibrate optical hits +physics.producers.ophit.InputLabel: "ophit::stage0" # start from hits in previous stage0 execution +physics.producers.ophit.RecalibratePE: true # recalibrate PE values +physics.producers.ophit.UseGainDatabase: false # not ready yet +physics.producers.ophit.SPEArea: @local::SPERun2.Area # use fixed value for all channels +physics.producers.ophit.RecalibrateTime: false # not needed for Run2 + +# make sure flashes are using the new ophits +# as well as the correct (non)calibration +physics.producers.opflashCryoE.OpHitProducer: "ophit::OpStage0" +physics.producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun2 +physics.producers.opflashCryoW.OpHitProducer: "ophit::OpStage0" +physics.producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun2 + +# now drop old ophits +outputs.rootOutput.outputCommands: [ + "keep *", + "drop *_ophit_*_stage0" + ] diff --git a/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_data_reprocessing.fcl b/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_data_reprocessing.fcl new file mode 100644 index 000000000..21121770c --- /dev/null +++ b/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_data_reprocessing.fcl @@ -0,0 +1,11 @@ +#include "stage0_run2_opdetonly_icarus_data_reprocessing.fcl" + +# recalibrate optical hits +physics.producers.ophit.RecalibratePE: true # recalibrate PE values +physics.producers.ophit.UseGainDatabase: false # not ready yet +physics.producers.ophit.SPEArea: @local::SPERun3.Area # use fixed value for all channels +physics.producers.ophit.RecalibrateTime: false # not needed for Run3 + +# make sure flashes are using the correct (non)calibration +physics.producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun3 +physics.producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun3 diff --git a/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_data_reprocessing.fcl b/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_data_reprocessing.fcl new file mode 100644 index 000000000..b65bd2763 --- /dev/null +++ b/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_data_reprocessing.fcl @@ -0,0 +1,16 @@ +#include "stage0_run2_opdetonly_icarus_data_reprocessing.fcl" + +# recalibrate optical hits +physics.producers.ophit.RecalibratePE: true # recalibrate PE values +physics.producers.ophit.UseGainDatabase: false # not ready yet +physics.producers.ophit.SPEArea: @local::SPERun4.Area # use fixed value for all channels + +physics.producers.ophit.RecalibrateTime: true # also needed for Run4 +# these were the tags used in the initial data processing (v10_06_00_01p05) +physics.producers.ophit.OldTimingDBTags.CablesTag: @local::PMT_CalibrationTags_Run3_Feb2025.pmt_cables_delays_data +physics.producers.ophit.OldTimingDBTags.LaserTag: @local::PMT_CalibrationTags_Run3_Feb2025.pmt_laser_timing_data +physics.producers.ophit.OldTimingDBTags.CosmicsTag: @local::PMT_CalibrationTags_Run3_Feb2025.pmt_cosmics_timing_data + +# make sure flashes are using the correct (non)calibration +physics.producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun4 +physics.producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun4 diff --git a/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc b/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc index 14c9d5a9a..ba3afa554 100644 --- a/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc +++ b/icaruscode/PMT/Calibration/OpHitRecalibrator_module.cc @@ -108,7 +108,7 @@ class icarus::OpHitRecalibrator : public art::SharedProducer bool const fRecalibrateTime; bool const fUseGainDatabase; double const fSPEArea; - bool const fVerbose = false; ///< Whether to print the configuration we read. + bool const fVerbose; /// Pointer to the online pmt corrections service icarusDB::PMTTimingCorrections const &fPMTTimingCorrectionsService; diff --git a/icaruscode/PMT/Calibration/fcl/hit-recalibrator.fcl b/icaruscode/PMT/Calibration/fcl/ophit-recalibrator.fcl similarity index 100% rename from icaruscode/PMT/Calibration/fcl/hit-recalibrator.fcl rename to icaruscode/PMT/Calibration/fcl/ophit-recalibrator.fcl From 5af5235047115fedb28a4f4cd6622bb93f120828 Mon Sep 17 00:00:00 2001 From: Matteo Vicenzi Date: Mon, 8 Dec 2025 14:50:05 -0600 Subject: [PATCH 39/47] update file names --- icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl b/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl index 6d5a71581..0082653a5 100644 --- a/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl +++ b/icaruscode/PMT/Algorithms/pmtsimulation_icarus.fcl @@ -209,7 +209,7 @@ icarus_photoelectronresponse_run2_2025: { tool_type: SampledWaveformFunctionTool - WaveformData: "Responses/SPRisolHitRun9271_MV.txt" + WaveformData: "Responses/SPRisolHitRun9271.txt" TransitTime: "55.1 ns" Gain: @local::icarus_settings_opdet_run2.nominalPMTgain @@ -224,7 +224,7 @@ icarus_photoelectronresponse_run4_2025: { tool_type: SampledWaveformFunctionTool - WaveformData: "Responses/SPRisolHitRun12715_MV.txt" + WaveformData: "Responses/SPRisolHitRun12715.txt" TransitTime: "55.1 ns" Gain: @local::icarus_settings_opdet_run4.nominalPMTgain From d7b1c3a82efc1bd1e251847ef9b44fa658df33d0 Mon Sep 17 00:00:00 2001 From: Gianluca Petrillo Date: Thu, 18 Dec 2025 11:30:03 -0600 Subject: [PATCH 40/47] ICARUSFlashFinder: added Doxygen-style header --- .../OpReco/FlashFinder/ICARUSFlashFinder_module.cc | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc b/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc index 2a8469978..08a3e6985 100644 --- a/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc +++ b/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc @@ -1,11 +1,9 @@ -//////////////////////////////////////////////////////////////////////// -// Class: ICARUSFlashFinder -// Module Type: producer -// File: ICARUSFlashFinder_module.cc -// -// Generated at Tue Sep 13 22:30:26 2016 by Kazuhiro Terao using artmod -// from cetpkgsupport v1_10_02. -//////////////////////////////////////////////////////////////////////// +/** + * @file icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc + * @brief ICARUS customization of flash reconstruction in LArSoft + * @author modified from Kazuhiro Terao's original module + */ + #include "icaruscode/PMT/OpReco/Algorithms/OpHitTimeSelector.h" From d91e6362e413b35c3e9cf0aea1ed41ec8b1691b7 Mon Sep 17 00:00:00 2001 From: Gianluca Petrillo Date: Thu, 18 Dec 2025 11:30:44 -0600 Subject: [PATCH 41/47] ICARUSFlashFinder: turned into shared module Also requires the replacement of obsolete CreateAssns(). --- .../FlashFinder/ICARUSFlashFinder_module.cc | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc b/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc index 08a3e6985..cdcefd3c4 100644 --- a/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc +++ b/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc @@ -7,19 +7,21 @@ #include "icaruscode/PMT/OpReco/Algorithms/OpHitTimeSelector.h" -#include "art/Framework/Core/EDProducer.h" +#include "art/Framework/Core/SharedProducer.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/Persistency/Common/PtrMaker.h" +#include "canvas/Persistency/Common/Assns.h" +#include "canvas/Persistency/Common/Ptr.h" #include "canvas/Utilities/InputTag.h" #include "fhiclcpp/ParameterSet.h" #include "messagefacility/MessageLogger/MessageLogger.h" #include "lardataobj/RecoBase/OpHit.h" #include "lardataobj/RecoBase/OpFlash.h" -#include "lardata/Utilities/AssociationUtil.h" #include #include @@ -27,22 +29,12 @@ #include "FlashFinderFMWKInterface.h" #include "PECalib.h" -class ICARUSFlashFinder; -class ICARUSFlashFinder : public art::EDProducer { +class ICARUSFlashFinder : public art::SharedProducer { public: - explicit ICARUSFlashFinder(fhicl::ParameterSet const & p); - // The destructor generated by the compiler is fine for classes - // without bare pointers or other resource use. + explicit ICARUSFlashFinder(fhicl::ParameterSet const & p, art::ProcessingFrame const&); - // Plugins should not be copied or assigned. - ICARUSFlashFinder(ICARUSFlashFinder const &) = delete; - ICARUSFlashFinder(ICARUSFlashFinder &&) = delete; - ICARUSFlashFinder & operator = (ICARUSFlashFinder const &) = delete; - ICARUSFlashFinder & operator = (ICARUSFlashFinder &&) = delete; - - // Required functions. - void produce(art::Event & e) override; + void produce(art::Event & e, art::ProcessingFrame const&) override; private: @@ -60,11 +52,13 @@ class ICARUSFlashFinder : public art::EDProducer { }; -ICARUSFlashFinder::ICARUSFlashFinder(pmtana::Config_t const & p) - : EDProducer{p} +ICARUSFlashFinder::ICARUSFlashFinder(Parameters const & p, art::ProcessingFrame const&) + : art::SharedProducer{p} , fHitTime{ recob::opHitTimeType(p.get("TimeType", "Start")) } // Initialize member data here. { + async(); + _hit_producer = p.get("OpHitProducer"); auto const flash_algo = p.get("FlashFinderAlgo"); @@ -79,7 +73,7 @@ ICARUSFlashFinder::ICARUSFlashFinder(pmtana::Config_t const & p) produces< art::Assns >(); } -void ICARUSFlashFinder::produce(art::Event & e) +void ICARUSFlashFinder::produce(art::Event & e, art::ProcessingFrame const&) { // produce OpFlash data-product to be filled within module @@ -110,6 +104,7 @@ void ICARUSFlashFinder::produce(art::Event & e) auto const flash_v = _mgr.RecoFlash(ophits); + art::PtrMaker makeFlaskPtr{ e }; for(const auto& lflash : flash_v) { double Ycenter, Zcenter, Ywidth, Zwidth; @@ -123,9 +118,10 @@ void ICARUSFlashFinder::produce(art::Event & e) Ycenter, Ywidth, Zcenter, Zwidth); opflashes->emplace_back(std::move(flash)); + art::Ptr const flashPtr = makeFlaskPtr(opflashes->size() - 1); for(auto const& hitidx : lflash.asshit_idx) { const art::Ptr hit_ptr(ophit_h, hitidx); - util::CreateAssn(*this, e, *opflashes, hit_ptr, *flash2hit_assn_v); + flash2hit_assn_v->addSingle(hit_ptr, flashPtr); } } From 4a92ddf8694e059fb2c638032bf31ee7adfdf930 Mon Sep 17 00:00:00 2001 From: Gianluca Petrillo Date: Thu, 18 Dec 2025 12:23:13 -0600 Subject: [PATCH 42/47] ICARUSFlashFinder: FHiCL configuration validation --- .../FlashFinder/ICARUSFlashFinder_module.cc | 55 ++++++++++++++++--- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc b/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc index cdcefd3c4..8ab94b518 100644 --- a/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc +++ b/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc @@ -17,7 +17,8 @@ #include "canvas/Persistency/Common/Assns.h" #include "canvas/Persistency/Common/Ptr.h" #include "canvas/Utilities/InputTag.h" -#include "fhiclcpp/ParameterSet.h" +#include "fhiclcpp/types/Atom.h" +#include "fhiclcpp/types/DelegatedParameter.h" #include "messagefacility/MessageLogger/MessageLogger.h" #include "lardataobj/RecoBase/OpHit.h" @@ -32,7 +33,45 @@ class ICARUSFlashFinder : public art::SharedProducer { public: - explicit ICARUSFlashFinder(fhicl::ParameterSet const & p, art::ProcessingFrame const&); + + struct Config { + + using Name = fhicl::Name; + using Comment = fhicl::Comment; + + fhicl::Atom OpHitProducer { + Name{ "OpHitProducer" }, + Comment{ "input tag for the optical hits to build the flashes from" } + }; + + fhicl::Atom FlashFinderAlgo { + Name{ "FlashFinderAlgo" }, + Comment{ "name of the flash finding algorithm" } + }; + + fhicl::Atom TimeType { + Name{ "TimeType" }, + Comment{ "Type of hit time to be used for flash building" }, + "Start" + }; + + fhicl::DelegatedParameter AlgoConfig { + Name{ "AlgoConfig" }, + Comment{ "configuration of the flash finding algorithm" } + }; + + + + fhicl::DelegatedParameter PECalib { + Name{ "PECalib" }, + Comment{ "Configuration of the optical hit recalibration" } + }; + + }; // Config + + using Parameters = art::SharedProducer::Table; + + explicit ICARUSFlashFinder(Parameters const & p, art::ProcessingFrame const&); void produce(art::Event & e, art::ProcessingFrame const&) override; @@ -42,7 +81,7 @@ class ICARUSFlashFinder : public art::SharedProducer { // Declare member data here. ::pmtana::FlashFinderManager _mgr; ::pmtana::PECalib _pecalib; - std::string _hit_producer; + art::InputTag _hit_producer; /// Extracts a configured time from `recob::OpHit`. recob::OpHitTimeSelector const fHitTime; @@ -54,20 +93,20 @@ class ICARUSFlashFinder : public art::SharedProducer { ICARUSFlashFinder::ICARUSFlashFinder(Parameters const & p, art::ProcessingFrame const&) : art::SharedProducer{p} - , fHitTime{ recob::opHitTimeType(p.get("TimeType", "Start")) } + , fHitTime{ recob::opHitTimeType(p().TimeType()) } // Initialize member data here. { async(); - _hit_producer = p.get("OpHitProducer"); + _hit_producer = p().OpHitProducer(); - auto const flash_algo = p.get("FlashFinderAlgo"); - auto const flash_pset = p.get("AlgoConfig"); + auto const flash_algo = p().FlashFinderAlgo(); + auto const flash_pset = p().AlgoConfig.get(); auto algo_ptr = ::pmtana::FlashAlgoFactory::get().create(flash_algo,flash_algo); algo_ptr->Configure(flash_pset); _mgr.SetFlashAlgo(algo_ptr); - _pecalib.Configure(p.get("PECalib")); + _pecalib.Configure(p().PECalib.get()); produces< std::vector >(); produces< art::Assns >(); From e433639a527927e5e1fa3c3c7f3736b6d0d21ea4 Mon Sep 17 00:00:00 2001 From: Gianluca Petrillo Date: Thu, 18 Dec 2025 12:31:06 -0600 Subject: [PATCH 43/47] ICARUSFlashFinder: code updates * removed unused headers and dependencies, added missing ones * updated exception error message * using `make_unique()` instead of `new` --- .../PMT/OpReco/Algorithms/CMakeLists.txt | 4 +- .../PMT/OpReco/FlashFinder/CMakeLists.txt | 63 +++++-------------- .../FlashFinder/FlashFinderFMWKInterface.cxx | 12 +--- .../FlashFinder/FlashFinderFMWKInterface.h | 6 +- .../FlashFinder/ICARUSFlashFinder_module.cc | 16 ++--- 5 files changed, 32 insertions(+), 69 deletions(-) diff --git a/icaruscode/PMT/OpReco/Algorithms/CMakeLists.txt b/icaruscode/PMT/OpReco/Algorithms/CMakeLists.txt index 07daaf9b6..8db18d5e4 100644 --- a/icaruscode/PMT/OpReco/Algorithms/CMakeLists.txt +++ b/icaruscode/PMT/OpReco/Algorithms/CMakeLists.txt @@ -1,8 +1,10 @@ art_make_library( LIBRARIES larana::OpticalDetector_OpHitFinder - sbnobj::ICARUS_PMT_Data + lardataalg::UtilitiesHeaders + lardataalg::DetectorInfo lardataobj::RecoBase + sbnobj::ICARUS_PMT_Data lardataobj::RawData messagefacility::MF_MessageLogger fhiclcpp::fhiclcpp diff --git a/icaruscode/PMT/OpReco/FlashFinder/CMakeLists.txt b/icaruscode/PMT/OpReco/FlashFinder/CMakeLists.txt index c2650c8f8..ec3cafbbd 100644 --- a/icaruscode/PMT/OpReco/FlashFinder/CMakeLists.txt +++ b/icaruscode/PMT/OpReco/FlashFinder/CMakeLists.txt @@ -1,54 +1,21 @@ art_make_library( - LIBRARIES - icarusalg::Geometry - larcore::Geometry_Geometry_service - larcorealg::Geometry - lardataobj::RecoBase - canvas::canvas - cetlib::cetlib - cetlib_except::cetlib_except - 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 - art::Persistency_Provenance - art::Utilities - messagefacility::MF_MessageLogger - fhiclcpp::fhiclcpp - ROOT::Geom - ROOT::XMLIO - ROOT::Gdml + LIBRARIES + INTERFACE + fhiclcpp::fhiclcpp + PUBLIC + icarusalg::Geometry + larcore::Geometry_Geometry_service + larcorealg::Geometry + art::Framework_Services_Registry ) -set( MODULE_LIBRARIES - icaruscode::PMT_OpReco_FlashFinder - icarusalg::Geometry - larcore::Geometry_Geometry_service - larcorealg::Geometry - lardataobj::RecoBase - lardata::Utilities - larcore::Geometry_AuxDetGeometry_service - canvas::canvas - cetlib::cetlib - cetlib_except::cetlib_except - art::Framework_Core - art::Framework_Principal - art::Framework_Services_Registry - art_root_io::tfile_support - art_root_io::TFileService_service - art::Persistency_Common - art::Persistency_Provenance - art::Utilities - messagefacility::MF_MessageLogger - fhiclcpp::fhiclcpp - ROOT::Geom - ROOT::XMLIO - ROOT::Gdml - ROOT::Core -) -cet_build_plugin(ICARUSFlashFinder art::module LIBRARIES ${MODULE_LIBRARIES}) + +cet_build_plugin(ICARUSFlashFinder art::module + LIBRARIES + icaruscode::PMT_OpReco_FlashFinder + icaruscode::PMT_OpReco_Algorithms + lardataobj::RecoBase + ) install_headers() diff --git a/icaruscode/PMT/OpReco/FlashFinder/FlashFinderFMWKInterface.cxx b/icaruscode/PMT/OpReco/FlashFinder/FlashFinderFMWKInterface.cxx index 30f75cef1..4684d9f5e 100644 --- a/icaruscode/PMT/OpReco/FlashFinder/FlashFinderFMWKInterface.cxx +++ b/icaruscode/PMT/OpReco/FlashFinder/FlashFinderFMWKInterface.cxx @@ -1,19 +1,9 @@ #ifndef __FLASHFINDERFMWKINTERFACE_CXX__ #define __FLASHFINDERFMWKINTERFACE_CXX__ -#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" -#include "art_root_io/TFileService.h" #include "larcore/Geometry/WireReadout.h" #include "larcore/Geometry/Geometry.h" - +#include "art/Framework/Services/Registry/ServiceHandle.h" #include "FlashFinderFMWKInterface.h" namespace pmtana { diff --git a/icaruscode/PMT/OpReco/FlashFinder/FlashFinderFMWKInterface.h b/icaruscode/PMT/OpReco/FlashFinder/FlashFinderFMWKInterface.h index 62626852b..c64d3d540 100644 --- a/icaruscode/PMT/OpReco/FlashFinder/FlashFinderFMWKInterface.h +++ b/icaruscode/PMT/OpReco/FlashFinder/FlashFinderFMWKInterface.h @@ -3,8 +3,10 @@ //#include "FhiclLite/ConfigManager.h" #include "fhiclcpp/ParameterSet.h" -#include "larcore/Geometry/Geometry.h" -#include + +#include // std::size_t +#include + namespace pmtana { //typedef ::fcllite::PSet Config_t; diff --git a/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc b/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc index 8ab94b518..1707a4a4f 100644 --- a/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc +++ b/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc @@ -11,23 +11,24 @@ #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/Persistency/Common/PtrMaker.h" #include "canvas/Persistency/Common/Assns.h" #include "canvas/Persistency/Common/Ptr.h" #include "canvas/Utilities/InputTag.h" +#include "canvas/Utilities/Exception.h" #include "fhiclcpp/types/Atom.h" #include "fhiclcpp/types/DelegatedParameter.h" -#include "messagefacility/MessageLogger/MessageLogger.h" #include "lardataobj/RecoBase/OpHit.h" #include "lardataobj/RecoBase/OpFlash.h" +#include // std::cerr #include #include +#include // std::move() +#include #include "FlashFinderManager.h" -#include "FlashFinderFMWKInterface.h" +#include "FlashFinderFMWKInterface.h" // ::pmtana::OpDetCenterFromOpChannel() #include "PECalib.h" @@ -116,8 +117,8 @@ void ICARUSFlashFinder::produce(art::Event & e, art::ProcessingFrame const&) { // produce OpFlash data-product to be filled within module - std::unique_ptr< std::vector > opflashes(new std::vector); - std::unique_ptr< art::Assns > flash2hit_assn_v ( new art::Assns ); + auto opflashes = std::make_unique>(); + auto flash2hit_assn_v = std::make_unique>(); // load OpHits previously created art::Handle > ophit_h; e.getByLabel(_hit_producer,ophit_h); @@ -125,7 +126,8 @@ void ICARUSFlashFinder::produce(art::Event & e, art::ProcessingFrame const&) // make sure hits look good if(!ophit_h.isValid()) { std::cerr<<"\033[93m[ERROR]\033[00m ... could not locate OpHit!"< Date: Thu, 18 Dec 2025 14:07:43 -0600 Subject: [PATCH 44/47] ICARUSFlashFinder: removed hit recalibration (PECalib) Algorithmic code is still there, probably unused. --- ...ge0_run2_opdetonly_icarus_data_reprocessing.fcl | 2 -- ..._run2_opdetonly_icarus_overlay_reprocessing.fcl | 4 ---- ...ge0_run3_opdetonly_icarus_data_reprocessing.fcl | 3 --- ..._run3_opdetonly_icarus_overlay_reprocessing.fcl | 4 ---- ...ge0_run4_opdetonly_icarus_data_reprocessing.fcl | 4 ---- ..._run4_opdetonly_icarus_overlay_reprocessing.fcl | 4 ---- .../OpReco/FlashFinder/ICARUSFlashFinder_module.cc | 14 +------------- icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl | 1 - 8 files changed, 1 insertion(+), 35 deletions(-) diff --git a/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_data_reprocessing.fcl b/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_data_reprocessing.fcl index 8ff3a09c8..b57198082 100644 --- a/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_data_reprocessing.fcl +++ b/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_data_reprocessing.fcl @@ -35,9 +35,7 @@ physics.producers.ophit.RecalibrateTime: false # not needed for Run2 # make sure flashes are using the new ophits # as well as the correct (non)calibration physics.producers.opflashCryoE.OpHitProducer: "ophit::OpStage0" -physics.producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun2 physics.producers.opflashCryoW.OpHitProducer: "ophit::OpStage0" -physics.producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun2 # now drop old ophits outputs.rootOutput.outputCommands: [ diff --git a/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_overlay_reprocessing.fcl b/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_overlay_reprocessing.fcl index 25d7e3ca4..bcd9f7c82 100644 --- a/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_overlay_reprocessing.fcl +++ b/fcl/reco/Stage0/partial/stage0_run2_opdetonly_icarus_overlay_reprocessing.fcl @@ -21,9 +21,5 @@ physics.producers.ophitfulluncorrected.SPEShift: @local::SPERun2.Shift physics.producers.mcophit.SPEArea: @local::SPERun2.Area physics.producers.mcophit.SPEAmplitude: @local::SPERun2.Amplitude -# update flash producers to pick up Run-2 SPE tune -physics.producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun2 -physics.producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun2 - diff --git a/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_data_reprocessing.fcl b/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_data_reprocessing.fcl index 21121770c..1585106e8 100644 --- a/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_data_reprocessing.fcl +++ b/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_data_reprocessing.fcl @@ -6,6 +6,3 @@ physics.producers.ophit.UseGainDatabase: false # not ready yet physics.producers.ophit.SPEArea: @local::SPERun3.Area # use fixed value for all channels physics.producers.ophit.RecalibrateTime: false # not needed for Run3 -# make sure flashes are using the correct (non)calibration -physics.producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun3 -physics.producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun3 diff --git a/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_overlay_reprocessing.fcl b/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_overlay_reprocessing.fcl index 4875fbcd1..89b2f0ecc 100644 --- a/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_overlay_reprocessing.fcl +++ b/fcl/reco/Stage0/partial/stage0_run3_opdetonly_icarus_overlay_reprocessing.fcl @@ -7,7 +7,3 @@ physics.producers.ophitfulluncorrected.SPEArea: @local::SPERun3.Area physics.producers.ophitfulluncorrected.SPEShift: @local::SPERun3.Shift physics.producers.mcophit.SPEArea: @local::SPERun3.Area physics.producers.mcophit.SPEAmplitude: @local::SPERun3.Amplitude - -# update flash producers to pick up Run-3 SPE tune -physics.producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun3 -physics.producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun3 diff --git a/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_data_reprocessing.fcl b/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_data_reprocessing.fcl index b65bd2763..ceb578138 100644 --- a/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_data_reprocessing.fcl +++ b/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_data_reprocessing.fcl @@ -10,7 +10,3 @@ physics.producers.ophit.RecalibrateTime: true # also needed for Run4 physics.producers.ophit.OldTimingDBTags.CablesTag: @local::PMT_CalibrationTags_Run3_Feb2025.pmt_cables_delays_data physics.producers.ophit.OldTimingDBTags.LaserTag: @local::PMT_CalibrationTags_Run3_Feb2025.pmt_laser_timing_data physics.producers.ophit.OldTimingDBTags.CosmicsTag: @local::PMT_CalibrationTags_Run3_Feb2025.pmt_cosmics_timing_data - -# make sure flashes are using the correct (non)calibration -physics.producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun4 -physics.producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun4 diff --git a/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_overlay_reprocessing.fcl b/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_overlay_reprocessing.fcl index 894213cf5..4b44ad644 100644 --- a/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_overlay_reprocessing.fcl +++ b/fcl/reco/Stage0/partial/stage0_run4_opdetonly_icarus_overlay_reprocessing.fcl @@ -7,7 +7,3 @@ physics.producers.ophitfulluncorrected.SPEArea: @local::SPERun4.Area physics.producers.ophitfulluncorrected.SPEShift: @local::SPERun4.Shift physics.producers.mcophit.SPEArea: @local::SPERun4.Area physics.producers.mcophit.SPEAmplitude: @local::SPERun4.Amplitude - -# update flash producers to pick up Run-4 SPE tune -physics.producers.opflashCryoE.PECalib: @local::icarus_pmt_calibration.CalibStandardRun4 -physics.producers.opflashCryoW.PECalib: @local::icarus_pmt_calibration.CalibStandardRun4 diff --git a/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc b/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc index 1707a4a4f..dadecd226 100644 --- a/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc +++ b/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc @@ -29,7 +29,6 @@ #include #include "FlashFinderManager.h" #include "FlashFinderFMWKInterface.h" // ::pmtana::OpDetCenterFromOpChannel() -#include "PECalib.h" class ICARUSFlashFinder : public art::SharedProducer { @@ -61,13 +60,6 @@ class ICARUSFlashFinder : public art::SharedProducer { Comment{ "configuration of the flash finding algorithm" } }; - - - fhicl::DelegatedParameter PECalib { - Name{ "PECalib" }, - Comment{ "Configuration of the optical hit recalibration" } - }; - }; // Config using Parameters = art::SharedProducer::Table; @@ -81,7 +73,6 @@ class ICARUSFlashFinder : public art::SharedProducer { // Declare member data here. ::pmtana::FlashFinderManager _mgr; - ::pmtana::PECalib _pecalib; art::InputTag _hit_producer; /// Extracts a configured time from `recob::OpHit`. @@ -107,8 +98,6 @@ ICARUSFlashFinder::ICARUSFlashFinder(Parameters const & p, art::ProcessingFrame algo_ptr->Configure(flash_pset); _mgr.SetFlashAlgo(algo_ptr); - _pecalib.Configure(p().PECalib.get()); - produces< std::vector >(); produces< art::Assns >(); } @@ -137,8 +126,7 @@ void ICARUSFlashFinder::produce(art::Event & e, art::ProcessingFrame const&) if(trigger_time > 1.e20) trigger_time = oph.PeakTimeAbs() - oph.PeakTime(); loph.peak_time = fHitTime(oph); - size_t opdet = ::pmtana::OpDetFromOpChannel(oph.OpChannel()); - loph.pe = _pecalib.Calibrate(opdet,oph.Area()); + loph.pe = oph.PE(); loph.channel = oph.OpChannel(); ophits.emplace_back(std::move(loph)); } diff --git a/icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl b/icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl index 6b76b04c7..32c1b173b 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl @@ -9,7 +9,6 @@ ICARUSSimpleFlash: FlashFinderAlgo : "SimpleFlashAlgo" AlgoConfig : @local::SimpleFlashStandard OpHitProducer : "ophit" - PECalib : @local::icarus_pmt_calibration.CalibStandard } ICARUSSimpleFlashCryoE: @local::ICARUSSimpleFlash From 4d8d9f423a6fee6f71ba6a8b5053dc5ee05b6ef5 Mon Sep 17 00:00:00 2001 From: Gianluca Petrillo Date: Thu, 18 Dec 2025 15:59:06 -0600 Subject: [PATCH 45/47] dump_opflashes_icarus.fcl: dump reconstructed flashes on text file --- fcl/utilities/dump_opflashes_icarus.fcl | 49 +++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 fcl/utilities/dump_opflashes_icarus.fcl diff --git a/fcl/utilities/dump_opflashes_icarus.fcl b/fcl/utilities/dump_opflashes_icarus.fcl new file mode 100644 index 000000000..89620e28a --- /dev/null +++ b/fcl/utilities/dump_opflashes_icarus.fcl @@ -0,0 +1,49 @@ +# File: dump_opflashes_icarus.fcl +# Purpose: Dump on screen of the standard optical flash data products. +# Author: Gianluca Petrillo (petrillo@slac.stanford.edu) +# Date: December 18, 2025 +# +# This job expects flashes in `opflashCryoE` and `opflashCryoW`. +# The output file `DumpOpFlashes.log` is produced. +# + +process_name: "DumpOpFlashes" + +physics: { + analyzers: { + dumpopflashesE: { + module_type: DumpOpFlashes + OpFlashModuleLabel: "opflashCryoE" + PrintOpHitAssociations: true + OutputCategory: "DumpOpFlashes" + } + dumpopflashesW: { + module_type: DumpOpFlashes + OpFlashModuleLabel: "opflashCryoW" + PrintOpHitAssociations: true + OutputCategory: "DumpOpFlashes" + } + } + dumpers: [ "dumpopflashesE", "dumpopflashesW" ] +} + +services.message.destinations: { + DumpOpFlashes: { + type: "file" + filename: "DumpOpFlashes.log" + threshold: "INFO" + append: false + categories: { + DumpOpFlashes: { limit: -1 } + default: { limit: 0 } + } + } + LogStandardOut: { + type: "cout" + threshold: "WARNING" + categories: { + DumpOpFlashes: { limit: 0 } + default: {} + } + } +} From 15541a4d0a6c0cf701ccbaf9babac4491ee48f8c Mon Sep 17 00:00:00 2001 From: Gianluca Petrillo Date: Thu, 18 Dec 2025 16:37:37 -0600 Subject: [PATCH 46/47] Adopting corrections from GitHub Copilot --- icaruscode/PMT/OpReco/FlashFinder/FlashFinderFMWKInterface.h | 2 +- icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/icaruscode/PMT/OpReco/FlashFinder/FlashFinderFMWKInterface.h b/icaruscode/PMT/OpReco/FlashFinder/FlashFinderFMWKInterface.h index c64d3d540..4ff1fb111 100644 --- a/icaruscode/PMT/OpReco/FlashFinder/FlashFinderFMWKInterface.h +++ b/icaruscode/PMT/OpReco/FlashFinder/FlashFinderFMWKInterface.h @@ -4,7 +4,7 @@ //#include "FhiclLite/ConfigManager.h" #include "fhiclcpp/ParameterSet.h" -#include // std::size_t +#include // std::size_t #include namespace pmtana { diff --git a/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc b/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc index dadecd226..2a63cfa88 100644 --- a/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc +++ b/icaruscode/PMT/OpReco/FlashFinder/ICARUSFlashFinder_module.cc @@ -133,7 +133,7 @@ void ICARUSFlashFinder::produce(art::Event & e, art::ProcessingFrame const&) auto const flash_v = _mgr.RecoFlash(ophits); - art::PtrMaker makeFlaskPtr{ e }; + art::PtrMaker makeFlashPtr{ e }; for(const auto& lflash : flash_v) { double Ycenter, Zcenter, Ywidth, Zwidth; @@ -147,7 +147,7 @@ void ICARUSFlashFinder::produce(art::Event & e, art::ProcessingFrame const&) Ycenter, Ywidth, Zcenter, Zwidth); opflashes->emplace_back(std::move(flash)); - art::Ptr const flashPtr = makeFlaskPtr(opflashes->size() - 1); + art::Ptr const flashPtr = makeFlashPtr(opflashes->size() - 1); for(auto const& hitidx : lflash.asshit_idx) { const art::Ptr hit_ptr(ophit_h, hitidx); flash2hit_assn_v->addSingle(hit_ptr, flashPtr); From a0196544a2fe6245bd8d6386974d748a41f71ee0 Mon Sep 17 00:00:00 2001 From: Gianluca Petrillo Date: Thu, 18 Dec 2025 17:25:15 -0600 Subject: [PATCH 47/47] Removed obsolete icarus_flashcalib.fcl Also fixed a preexisting issue with (obsolete) FHiCL job configurations. --- .../run4642like_detsim_icarus.fcl | 4 +- .../run4759like_detsim_icarus.fcl | 4 +- .../PMT/OpReco/fcl/icarus_flashcalib.fcl | 48 ------------------- .../PMT/OpReco/fcl/icarus_flashfinder.fcl | 1 - 4 files changed, 4 insertions(+), 53 deletions(-) delete mode 100644 icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl diff --git a/fcl/detsim/commissioning/run4642like_detsim_icarus.fcl b/fcl/detsim/commissioning/run4642like_detsim_icarus.fcl index 9c24494ac..7ce90cf49 100644 --- a/fcl/detsim/commissioning/run4642like_detsim_icarus.fcl +++ b/fcl/detsim/commissioning/run4642like_detsim_icarus.fcl @@ -25,7 +25,7 @@ # #include "services_common_icarus.fcl" -#include "opdetsim_pmt_icarus.fcl" +#include "pmtsimulation_icarus.fcl" #include "rootoutput_icarus.fcl" process_name: DetSim4642 @@ -38,7 +38,7 @@ services: @local::icarus_common_services # from services_common_icarus.fcl physics: { producers: { opdaq: { - @table::icarus_simpmt_noise # from opdetsim_pmt_icarus.fcl + @table::icarus_pmtsimulationalg_202202_noise # from pmtsimulation_icarus.fcl # # enabled readout window diff --git a/fcl/detsim/commissioning/run4759like_detsim_icarus.fcl b/fcl/detsim/commissioning/run4759like_detsim_icarus.fcl index e1db032bb..3cec8c4f1 100644 --- a/fcl/detsim/commissioning/run4759like_detsim_icarus.fcl +++ b/fcl/detsim/commissioning/run4759like_detsim_icarus.fcl @@ -25,7 +25,7 @@ # #include "services_common_icarus.fcl" -#include "opdetsim_pmt_icarus.fcl" +#include "pmtsimulation_icarus.fcl" #include "rootoutput_icarus.fcl" process_name: DetSim4759 @@ -38,7 +38,7 @@ services: @local::icarus_common_services # from services_common_icarus.fcl physics: { producers: { opdaq: { - @table::icarus_simpmt_noise # from opdetsim_pmt_icarus.fcl + @table::icarus_pmtsimulationalg_202202_noise # from pmtsimulation_icarus.fcl # # enabled readout window diff --git a/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl b/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl deleted file mode 100644 index e53107e81..000000000 --- a/icaruscode/PMT/OpReco/fcl/icarus_flashcalib.fcl +++ /dev/null @@ -1,48 +0,0 @@ -#include "icarus_spe.fcl" -BEGIN_PROLOG - - -# ------------------------------------------------------------------------------ -# `icarus_pmt_calibration.NoCalib`: no calibration -# -# ICARUS flash reconstruction algorithm requires a calibration. -# To specify a uniform, neutral one, no per-channel calibration must be present, -# and the value of the uniform calibration constant (`SPEAreaGain`, which is -# the area of a single photoelectron, and gets applied to the area reconstructed -# in the hit) needs to be the same value as the single photoelectron area used -# in the hit reconstruction. -# -icarus_pmt_calibration.NoCalibRun2: { - SPEAreaGain: @local::SPERun2.Area -} - -icarus_pmt_calibration.NoCalibRun3: { - SPEAreaGain: @local::SPERun3.Area -} - -icarus_pmt_calibration.NoCalibRun4: { - SPEAreaGain: @local::SPERun4.Area -} - -icarus_pmt_calibration.NoCalib: { - SPEAreaGain: @local::SPE.Area -} - -# ------------------------------------------------------------------------------ -# `icarus_pmt_calibration.Calib202203`: from March 2021 -# -icarus_pmt_calibration.Calib202203: { - SPEAreaGainList: [224.71,198.23,154.69,218.39,238.21,226.8,189.98,88.385,222.74,220.79,185.43,198.98,229.2,224.65,193.04,194.62,236.86,234.61,194.43,215.73,126.42,211.69,179.43,219.68,225.3,210.01,137.62,217.75,225.57,214.77,231.14,219.41,222.46,178.45,202.72,227.86,207.64,192.96,230.19,212.81,211.35,237.02,110.3,152.77,206.04,196.72,216.93,218.24,237.21,245.52,192.8,230.92,198.44,213.29,172.93,225.95,209.04,213.43,237.86,209.36,197.67,230.27,198.49,213.6,220.15,214.87,228.84,174.13,218.41,235.18,212.00,248.12,231.56,196.43,203.63,223.45,214.92,195.28,192.86,225.79,199.11,228.97,190.79,218.85,222.27,239.62,225.06,227.93,224.61,234.47,215.38,219.44,212.73,242.96,244.61,177.73,227.32,195.65,100.48,226.48,219.12,258.86,205.76,222.81,214.16,158.06,212.00,197.28,234.6,211.98,239.79,231.64,150.32,220.72,225.85,214.42,235.73,209.24,200.15,246.71,183.2,207.64,168.28,192.63,242.94,231.86,237.89,226.96,268.3,222.72,172.12,220.36,241.53,217.6,244.78,226.92,205.75,191.26,216.74,201.13,245.61,238.33,209.16,230.68,227.13,237.73,198.57,227.07,238.81,216.39,229.88,224.39,227.83,144.7,221.17,224.97,229.11,257.89,209.14,193.76,202.99,202.58,220.89,192.8,241.04,237.97,221.4,190.61,173.98,230.05,233.6,229.89,210.46,205.01,216.45,189.68,206.79,170.98,227.99,228.59,243.36,234.23,182.01,218.3,227.44,222.65,219.1,214.98,244.06,184.55,221.53,207.17,197.95,202.28,169.44,211.24,218,217.29,178.64,194.82,191.16,210.72,209.46,213.2,218.53,186.48,208.5,174.21,204.95,232.61,218.39,191.14,221.21,207.32,224.88,230.77,203.83,212.00,209.08,190.09,209.31,120.18,218.14,192.27,208.5,227.18,189.34,228.71,170.11,201.98,194.01,237.13,204.44,168.91,212.84,177.22,174.4,192.25,233.12,217.92,216.25,186.88,251.41,198.01,188.71,186.18,230.6,223.84,241.12,126.47,210.76,216.96,207.41,187.7,227.39,191.68,223.61,219.75,195.01,218.12,246.68,170.33,202.68,202.71,180.27,203.78,238.17,228.4,245.86,221.34,114.05,210.85,235.41,218.78,233.84,205.64,190.31,353.47,173.92,206.03,220.24,218.9,177.34,195.85,239.26,227.36,144.55,217.93,193.29,225.07,196.95,215.85,214.71,161.5,204.15,206.98,197.99,195.59,223.56,203.89,213.82,237.94,207.08,211.44,196.66,275.77,209.58,235.03,184.84,232.76,183.93,191.53,225.68,197.71,193.24,220.97,199.82,205.31,185.86,224.14,211.68,220.71,187.16,197.19,201.05,179.91,214.8,181.65,199.92,228.79,230.76,206.95,208,168.79,190.62,219.97,185.73,184.76,220.46,225.44,185.96,197.85,186.5,219.79,216.31,190.62,193.4,206.51,215.88,179.34,184.8,210.46,214.49,169.85,235.33,350.00,106.58,191.15,185.43,170.06] - -} - - -# ------------------------------------------------------------------------------ - -icarus_pmt_calibration.CalibStandardRun2: @local::icarus_pmt_calibration.NoCalibRun2 -icarus_pmt_calibration.CalibStandardRun3: @local::icarus_pmt_calibration.NoCalibRun3 -icarus_pmt_calibration.CalibStandardRun4: @local::icarus_pmt_calibration.NoCalibRun4 - -icarus_pmt_calibration.CalibStandard: @local::icarus_pmt_calibration.NoCalib - -END_PROLOG diff --git a/icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl b/icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl index 32c1b173b..9725c4fc2 100644 --- a/icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl +++ b/icaruscode/PMT/OpReco/fcl/icarus_flashfinder.fcl @@ -1,5 +1,4 @@ #include "icarus_flashalgo.fcl" -#include "icarus_flashcalib.fcl" BEGIN_PROLOG