From 40a6c6763590459b1d80a875ff5bf9e73d8ef645 Mon Sep 17 00:00:00 2001 From: Thomas Wester Date: Tue, 19 May 2026 15:01:40 -0500 Subject: [PATCH 1/4] add scaling to db entries for systematic variations --- .../PMTCalibrationDatabaseProvider.cxx | 44 ++++++++++++++++++- .../PMTCalibrationDatabaseProvider.h | 28 +++++++++++- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.cxx b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.cxx index db0db2814..b0e6e6e91 100644 --- a/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.cxx +++ b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.cxx @@ -216,6 +216,12 @@ void sbndDB::PMTCalibrationDatabaseProvider::ReadPMTCalibration(uint32_t run) _ser.push_back(_ser_component); } fPMTCalibrationData[channel].ser = _ser; + + if (fApplyScales) { + fPMTCalibrationData[channel] = scalePMTCalibrationData( + fPMTCalibrationData[channel], fPMTCalibrationScales[channel] + ); + } } } @@ -240,4 +246,40 @@ void sbndDB::PMTCalibrationDatabaseProvider::readPMTCalibrationDatabase(const ar mf::LogVerbatim(fLogCategory) << key << " " << value.breakoutBox << "," << std::endl; } } -} \ No newline at end of file +} + + +// ----------------------------------------------------------------------------- + +/// Apply scaling factors to the PMT calibrations +sbndDB::PMTCalibrationDatabaseProvider::PMTCalibrationDB sbndDB::PMTCalibrationDatabaseProvider::scalePMTCalibrationData( + const PMTCalibrationDB& db, const PMTCalibrationDBScales& scales) const +{ + PMTCalibrationDB result; + + // copy IDs, no modification + result.breakoutBox = db.breakoutBox; + result.caenDigitizer = db.caenDigitizer; + result.caenDigitizerChannel = db.caenDigitizerChannel; + + // copy and scale calibrations + // bools: use XOR + invert. Scale = True preserves the original value, Scale = False inverts + // TRUE ^ !TRUE = TRUE, FALSE ^ !FALSE = FALSE + // TRUE ^ !FALSE = FALSE, FALSE ^ !FALSE = TRUE + result.onPMT = db.onPMT ^ !scales.onPMT; + result.reconstructChannel = db.reconstructChannel ^ !scales.reconstructChannel; + + result.totalTransitTime = db.totalTransitTime * scales.totalTransitTime; + result.cosmicTimeCorrection = db.cosmicTimeCorrection * scales.cosmicTimeCorrection; + result.spe_amplitude = db.spe_amplitude * scales.spe_amplitude; + result.spe_amplitude_std = db.spe_amplitude_std * scales.spe_amplitude_std; + result.gauss_wc_power = db.gauss_wc_power * scales.gauss_wc_power; + result.gauss_wc = db.gauss_wc * scales.gauss_wc; + result.nonlinearity_pesat = db.nonlinearity_pesat * scales.nonlinearity_pesat; + result.nonlinearity_alpha = db.nonlinearity_alpha * scales.nonlinearity_alpha; + + // TODO not implemented + result.ser = db.ser; + + return result; +} diff --git a/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h index bc26d16ca..b61c8be83 100644 --- a/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h +++ b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h @@ -86,6 +86,7 @@ class sbndDB::PMTCalibrationDatabaseProvider : public PMTCalibrationDatabase { private: bool fVerbose = false; ///< Whether to print the configuration we read. + bool fApplyScales = false; // Apply scalings to DB parameters for systematic variations std::string fLogCategory; ///< Category tag for messages. std::string fPMTCalibrationDatabaseTag; long fDatabaseTimeStamp; @@ -110,10 +111,34 @@ class sbndDB::PMTCalibrationDatabaseProvider : public PMTCalibrationDatabase { double nonlinearity_alpha=0.; std::vector ser={}; }; + + /// Structure for scaling factors to DB values (for syst. studies) + struct PMTCalibrationDBScales { + // bools are OR'd with nominal value + bool onPMT=true; + bool reconstructChannel=true; + + // otherwise multiplicative + double totalTransitTime=1.; + double cosmicTimeCorrection=1.; + double spe_amplitude=1.; + double spe_amplitude_std=1.; + double gauss_wc_power=1.; + double gauss_wc=1.; + double nonlinearity_pesat=1.; + double nonlinearity_alpha=1.; + + std::vector ser={}; + }; const PMTCalibrationDB CorrectionDefaults = {0, 0, 0, true, false, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}}; + const PMTCalibrationDBScales ScaleDefaults = {true, true, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, {}}; + /// Map of corrections by channel std::map fPMTCalibrationData; + + /// per-channel scales + std::map fPMTCalibrationScales; /// Internal access to the channel correction record; returns defaults if not present. PMTCalibrationDB const& getChannelCorrOrDefault @@ -127,8 +152,9 @@ class sbndDB::PMTCalibrationDatabaseProvider : public PMTCalibrationDatabase { uint64_t RunToDatabaseTimestamp(uint32_t run) const; void ReadPMTCalibration(uint32_t run); + PMTCalibrationDB scalePMTCalibrationData(const PMTCalibrationDB&, const PMTCalibrationDBScales&) const; }; // services class -#endif \ No newline at end of file +#endif From 9816f0367e7ce43f11d861b779cfba84eac424ab Mon Sep 17 00:00:00 2001 From: Thomas Wester Date: Thu, 21 May 2026 14:15:19 -0500 Subject: [PATCH 2/4] logging and fixes --- .../PMTCalibrationDatabaseProvider.cxx | 140 ++++++++++++++++-- .../PMTCalibrationDatabaseProvider.h | 49 ++++-- 2 files changed, 163 insertions(+), 26 deletions(-) diff --git a/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.cxx b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.cxx index b0e6e6e91..3dba0fe90 100644 --- a/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.cxx +++ b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.cxx @@ -22,11 +22,13 @@ #include #include + + //-------------------------------------------------------------------------------- sbndDB::PMTCalibrationDatabaseProvider::PMTCalibrationDatabaseProvider( const fhicl::ParameterSet& pset) - : fVerbose{pset.get("Verbose", false)} + : fVerbose{pset.get("Verbose", false)}, fApplyScales{pset.get("ApplyScales", false)} , fLogCategory{pset.get("LogCategory", "PMTTimingCorrection")} { fhicl::ParameterSet const tags{pset.get("CorrectionTags")}; @@ -37,6 +39,49 @@ sbndDB::PMTCalibrationDatabaseProvider::PMTCalibrationDatabaseProvider( if (fVerbose) mf::LogInfo(fLogCategory) << "Database tags for timing corrections:\n" << "Cables corrections " << fPMTCalibrationDatabaseTag << "\n"; + + auto const scales_pset_vec = pset.get>("Scales", {}); + for (auto const& scale_pset : scales_pset_vec) { + PMTCalibrationDBScales scale; + int channel = scale_pset.get("Channel"); + if (channel < 0 && channel != -1) { + // TODO throw an error + } + + // a bit verbose but makes sure optional values aren't set unless + // explicitly written in the fhicl + bool onpmt = true; + if (scale_pset.get_if_present("OnPMT", onpmt)) scale.onPMT = onpmt; + + bool reconstructch = true; + if (scale_pset.get_if_present("ReconstructChannel", reconstructch)) scale.reconstructChannel = reconstructch; + + float totaltransittime; + if (scale_pset.get_if_present("TotalTransitTime", totaltransittime)) scale.totalTransitTime = totaltransittime; + + float cosmictimecorrection; + if (scale_pset.get_if_present("CosmicTimeCorrection", cosmictimecorrection)) scale.cosmicTimeCorrection = cosmictimecorrection; + + float speamplitude; + if (scale_pset.get_if_present("SPEAmplitude", speamplitude)) scale.spe_amplitude = speamplitude; + + float speamplitudestd; + if (scale_pset.get_if_present("SPEAmplitudeStd", speamplitudestd)) scale.spe_amplitude_std = speamplitudestd; + + float gausswcpower; + if (scale_pset.get_if_present("GaussWCPower", gausswcpower)) scale.gauss_wc_power = gausswcpower; + + float gausswc; + if (scale_pset.get_if_present("GaussWC", gausswc)) scale.gauss_wc = gausswc; + + float nonlinearitypesat; + if (scale_pset.get_if_present("NonlinearityPESat", nonlinearitypesat)) scale.nonlinearity_pesat = nonlinearitypesat; + + float nonlinearityalpha; + if (scale_pset.get_if_present("NonlinearityAlpha", nonlinearityalpha)) scale.nonlinearity_alpha = nonlinearityalpha; + + fPMTCalibrationScales[channel] = scale; + } } // ------------------------------------------------------------------------------- @@ -218,10 +263,33 @@ void sbndDB::PMTCalibrationDatabaseProvider::ReadPMTCalibration(uint32_t run) fPMTCalibrationData[channel].ser = _ser; if (fApplyScales) { + // modify the default scale from user settings + PMTCalibrationDBScales final_scale; + + // first overwrite with global scale values + if (auto it = fPMTCalibrationScales.find(-1); it != fPMTCalibrationScales.end()) { + if (fVerbose) { + mf::LogInfo(fLogCategory) << "Applying global scaling...\n"; + } + modifyScale(final_scale, it->second); + } + + // then overwrite with per-channel values + if (auto it = fPMTCalibrationScales.find(channel); it != fPMTCalibrationScales.end()) { + if (fVerbose) { + mf::LogInfo(fLogCategory) << "Applying channel scaling...\n"; + } + modifyScale(final_scale, it->second); + } + fPMTCalibrationData[channel] = scalePMTCalibrationData( - fPMTCalibrationData[channel], fPMTCalibrationScales[channel] + fPMTCalibrationData[channel], final_scale ); } + if (fVerbose) { + mf::LogInfo(fLogCategory) << " --- Calibration information for channel " + << channel << " ---\n" << calibDataStr(fPMTCalibrationData[channel]) << "\n"; + } } } @@ -266,20 +334,66 @@ sbndDB::PMTCalibrationDatabaseProvider::PMTCalibrationDB sbndDB::PMTCalibrationD // bools: use XOR + invert. Scale = True preserves the original value, Scale = False inverts // TRUE ^ !TRUE = TRUE, FALSE ^ !FALSE = FALSE // TRUE ^ !FALSE = FALSE, FALSE ^ !FALSE = TRUE - result.onPMT = db.onPMT ^ !scales.onPMT; - result.reconstructChannel = db.reconstructChannel ^ !scales.reconstructChannel; - - result.totalTransitTime = db.totalTransitTime * scales.totalTransitTime; - result.cosmicTimeCorrection = db.cosmicTimeCorrection * scales.cosmicTimeCorrection; - result.spe_amplitude = db.spe_amplitude * scales.spe_amplitude; - result.spe_amplitude_std = db.spe_amplitude_std * scales.spe_amplitude_std; - result.gauss_wc_power = db.gauss_wc_power * scales.gauss_wc_power; - result.gauss_wc = db.gauss_wc * scales.gauss_wc; - result.nonlinearity_pesat = db.nonlinearity_pesat * scales.nonlinearity_pesat; - result.nonlinearity_alpha = db.nonlinearity_alpha * scales.nonlinearity_alpha; + result.onPMT = db.onPMT ^ !scales.onPMT.value_or(true); + result.reconstructChannel = db.reconstructChannel ^ !scales.reconstructChannel.value_or(true); + + result.totalTransitTime = db.totalTransitTime * scales.totalTransitTime.value_or(1.0); + result.cosmicTimeCorrection = db.cosmicTimeCorrection * scales.cosmicTimeCorrection.value_or(1.0); + result.spe_amplitude = db.spe_amplitude * scales.spe_amplitude.value_or(1.0); + result.spe_amplitude_std = db.spe_amplitude_std * scales.spe_amplitude_std.value_or(1.0); + result.gauss_wc_power = db.gauss_wc_power * scales.gauss_wc_power.value_or(1.0); + result.gauss_wc = db.gauss_wc * scales.gauss_wc.value_or(1.0); + result.nonlinearity_pesat = db.nonlinearity_pesat * scales.nonlinearity_pesat.value_or(1.0); + result.nonlinearity_alpha = db.nonlinearity_alpha * scales.nonlinearity_alpha.value_or(1.0); // TODO not implemented result.ser = db.ser; return result; } + + +/// overwrite fields of target with those from update +void sbndDB::PMTCalibrationDatabaseProvider::modifyScale( + PMTCalibrationDBScales& target, const PMTCalibrationDBScales& update) const +{ + if (update.onPMT) target.onPMT = update.onPMT; + if (update.reconstructChannel) target.reconstructChannel = update.reconstructChannel; + + if (update.totalTransitTime) target.totalTransitTime = update.totalTransitTime; + if (update.cosmicTimeCorrection) target.cosmicTimeCorrection = update.cosmicTimeCorrection; + if (update.spe_amplitude) target.spe_amplitude = update.spe_amplitude; + if (update.spe_amplitude_std) target.spe_amplitude_std = update.spe_amplitude_std; + if (update.gauss_wc_power) target.gauss_wc_power = update.gauss_wc_power; + if (update.gauss_wc) target.gauss_wc = update.gauss_wc; + if (update.nonlinearity_pesat) target.nonlinearity_pesat = update.nonlinearity_pesat; + if (update.nonlinearity_alpha) target.nonlinearity_alpha = update.nonlinearity_alpha; + + // TODO SER not implemented +} + +/// overwrite fields of target with those from update +std::string sbndDB::PMTCalibrationDatabaseProvider::calibDataStr(const PMTCalibrationDB& data) const +{ + static const std::string sep(": "); + static const std::string prefix(" - "); + std::stringstream ss; + + ss << prefix << "breakoutBox" << sep << data.breakoutBox << "\n"; + ss << prefix << "caenDigitizer" << sep << data.caenDigitizer << "\n"; + ss << prefix << "caenDigitizerChannel" << sep << data.caenDigitizerChannel << "\n"; + ss << prefix << "onPMT" << sep << (data.onPMT ? "True" : "False") << "\n"; + ss << prefix << "reconstructChannel" << sep << (data.reconstructChannel ? "True" : "False") << "\n"; + ss << prefix << "totalTransitTime" << sep << data.totalTransitTime << "\n"; + ss << prefix << "cosmicTimeCorrection" << sep << data.cosmicTimeCorrection << "\n"; + ss << prefix << "spe_amplitude" << sep << data.spe_amplitude << "\n"; + ss << prefix << "spe_amplitude_std" << sep << data.spe_amplitude_std << "\n"; + ss << prefix << "gauss_wc_power" << sep << data.gauss_wc_power << "\n"; + ss << prefix << "gauss_wc" << sep << data.gauss_wc << "\n"; + ss << prefix << "nonlinearity_pesat" << sep << data.nonlinearity_pesat << "\n"; + ss << prefix << "nonlinearity_alpha" << sep << data.nonlinearity_alpha << "\n"; + + // TODO SER not implemented + + return ss.str(); +} diff --git a/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h index b61c8be83..055128688 100644 --- a/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h +++ b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h @@ -16,6 +16,10 @@ #include "messagefacility/MessageLogger/MessageLogger.h" #include "cetlib_except/exception.h" #include "fhiclcpp/ParameterSet.h" +#include "fhiclcpp/types/Sequence.h" +#include "fhiclcpp/types/Tuple.h" +#include "fhiclcpp/types/OptionalAtom.h" +#include "fhiclcpp/types/OptionalSequence.h" // Local #include "sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabase.h" @@ -33,6 +37,23 @@ namespace sbndDB{ class PMTCalibrationDatabaseProvider; } * This module reads the PMT timing corrections from the database. * */ + +//-------------------------------------------------------------------------------- + +// PMT Scalings for systematic variations. All scale fields optional +struct PMTScaleConfig { + fhicl::Atom channel { + fhicl::Name("Channel"), + fhicl::Comment("Which channel to apply the scaling to (-1 for all channels)") + }; + + fhicl::OptionalAtom spe_response { + fhicl::Name("SPEAmplitude"), + fhicl::Comment("Multiplicative scaling applied to SPE response") + }; +}; + + class sbndDB::PMTCalibrationDatabaseProvider : public PMTCalibrationDatabase { public: @@ -115,24 +136,24 @@ class sbndDB::PMTCalibrationDatabaseProvider : public PMTCalibrationDatabase { /// Structure for scaling factors to DB values (for syst. studies) struct PMTCalibrationDBScales { // bools are OR'd with nominal value - bool onPMT=true; - bool reconstructChannel=true; + std::optional onPMT; + std::optional reconstructChannel; // otherwise multiplicative - double totalTransitTime=1.; - double cosmicTimeCorrection=1.; - double spe_amplitude=1.; - double spe_amplitude_std=1.; - double gauss_wc_power=1.; - double gauss_wc=1.; - double nonlinearity_pesat=1.; - double nonlinearity_alpha=1.; - - std::vector ser={}; + std::optional totalTransitTime; + std::optional cosmicTimeCorrection; + std::optional spe_amplitude; + std::optional spe_amplitude_std; + std::optional gauss_wc_power; + std::optional gauss_wc; + std::optional nonlinearity_pesat; + std::optional nonlinearity_alpha; + + // SER not implemented }; const PMTCalibrationDB CorrectionDefaults = {0, 0, 0, true, false, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}}; - const PMTCalibrationDBScales ScaleDefaults = {true, true, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, {}}; + // const PMTCalibrationDBScales ScaleDefaults = {true, true, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, {}}; /// Map of corrections by channel std::map fPMTCalibrationData; @@ -153,6 +174,8 @@ class sbndDB::PMTCalibrationDatabaseProvider : public PMTCalibrationDatabase { void ReadPMTCalibration(uint32_t run); PMTCalibrationDB scalePMTCalibrationData(const PMTCalibrationDB&, const PMTCalibrationDBScales&) const; + void modifyScale(PMTCalibrationDBScales&, const PMTCalibrationDBScales&) const; + std::string calibDataStr(const PMTCalibrationDB&) const; }; // services class From 708e979dfd0b85527e256e3bdbc23e3e461ed0f0 Mon Sep 17 00:00:00 2001 From: Thomas Wester Date: Tue, 26 May 2026 13:38:44 -0500 Subject: [PATCH 3/4] add production fhicl --- .../PMTCalibrationDatabaseProvider.h | 1 - .../standard_detsim_sbnd_PMTSPEDecrease.fcl | 9 +++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTSPEDecrease.fcl diff --git a/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h index 055128688..9b6311b6c 100644 --- a/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h +++ b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h @@ -153,7 +153,6 @@ class sbndDB::PMTCalibrationDatabaseProvider : public PMTCalibrationDatabase { }; const PMTCalibrationDB CorrectionDefaults = {0, 0, 0, true, false, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, {}}; - // const PMTCalibrationDBScales ScaleDefaults = {true, true, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, {}}; /// Map of corrections by channel std::map fPMTCalibrationData; diff --git a/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTSPEDecrease.fcl b/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTSPEDecrease.fcl new file mode 100644 index 000000000..d006e3b7a --- /dev/null +++ b/sbndcode/JobConfigurations/standard/detsim/detector_variations/pmt_variations/standard_detsim_sbnd_PMTSPEDecrease.fcl @@ -0,0 +1,9 @@ +#include "detsim_detvar_PDSonly_sbnd.fcl" + +services.IPMTCalibrationDatabaseService.ApplyScales: true +services.IPMTCalibrationDatabaseService.Scales: [ + { + Channel: -1 + SPEAmplitude: 0.94 + } +] From 2bb79c537a1d8d08f77924d5277a05e4ecf232d9 Mon Sep 17 00:00:00 2001 From: Thomas Wester Date: Tue, 26 May 2026 13:58:04 -0500 Subject: [PATCH 4/4] simplify bool logic --- .../PMTCalibrationDatabaseProvider.cxx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.cxx b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.cxx index 3dba0fe90..aa8a8439f 100644 --- a/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.cxx +++ b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.cxx @@ -331,12 +331,11 @@ sbndDB::PMTCalibrationDatabaseProvider::PMTCalibrationDB sbndDB::PMTCalibrationD result.caenDigitizerChannel = db.caenDigitizerChannel; // copy and scale calibrations - // bools: use XOR + invert. Scale = True preserves the original value, Scale = False inverts - // TRUE ^ !TRUE = TRUE, FALSE ^ !FALSE = FALSE - // TRUE ^ !FALSE = FALSE, FALSE ^ !FALSE = TRUE - result.onPMT = db.onPMT ^ !scales.onPMT.value_or(true); - result.reconstructChannel = db.reconstructChannel ^ !scales.reconstructChannel.value_or(true); + // bools: change value if set + if (scales.onPMT) result.onPMT = scales.onPMT.value(); + if (scales.reconstructChannel) result.reconstructChannel = scales.reconstructChannel.value(); + // otherwise multiply result.totalTransitTime = db.totalTransitTime * scales.totalTransitTime.value_or(1.0); result.cosmicTimeCorrection = db.cosmicTimeCorrection * scales.cosmicTimeCorrection.value_or(1.0); result.spe_amplitude = db.spe_amplitude * scales.spe_amplitude.value_or(1.0);