diff --git a/sbndcode/Calibration/CMakeLists.txt b/sbndcode/Calibration/CMakeLists.txt index 91776a677..dbf8cb7e3 100644 --- a/sbndcode/Calibration/CMakeLists.txt +++ b/sbndcode/Calibration/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(OpReco) add_subdirectory(CRT) add_subdirectory(DQM) +add_subdirectory(PDSDatabaseInterface) diff --git a/sbndcode/Calibration/PDSDatabaseInterface/CMakeLists.txt b/sbndcode/Calibration/PDSDatabaseInterface/CMakeLists.txt new file mode 100644 index 000000000..7740dbb6b --- /dev/null +++ b/sbndcode/Calibration/PDSDatabaseInterface/CMakeLists.txt @@ -0,0 +1,28 @@ +cet_enable_asserts() + +set( MODULE_LIBRARIES + art_root_io::TFileService_service + art_root_io::tfile_support +) +set( LIB_LIBRARIES + art::Framework_Services_Registry + messagefacility::MF_MessageLogger + lardata::Utilities + larevt::CalibrationDBI_IOVData + larevt::CalibrationDBI_Providers +) +set( SERVICE_LIBRARIES + sbndcode_Calibration_PDSDatabaseInterface + larcore::Geometry_Geometry_service + lardata::DetectorClocksService +) + +file(GLOB lib_srcs *.cxx) + +art_make_library( SOURCE ${lib_srcs} LIBRARIES PUBLIC ${LIB_LIBRARIES}) + +cet_build_plugin( PMTCalibrationDatabaseService art::service LIBRARIES PUBLIC ${SERVICE_LIBRARIES}) + +install_headers() +install_fhicl() +install_source() \ No newline at end of file diff --git a/sbndcode/Calibration/PDSDatabaseInterface/IPMTCalibrationDatabaseService.h b/sbndcode/Calibration/PDSDatabaseInterface/IPMTCalibrationDatabaseService.h new file mode 100644 index 000000000..5f7e5d96e --- /dev/null +++ b/sbndcode/Calibration/PDSDatabaseInterface/IPMTCalibrationDatabaseService.h @@ -0,0 +1,30 @@ +/** + * @file icaruscode/Timing/IPMTTimingCorrectionService.h + * @brief Wrapper class for 'PMTTimingCorrectionsProvider.h' + * @author Andrea Scarpelli (ascarpell@bnl.gov), Gianluca Petrillo (petrillo@slac.stanford.edu) + */ +// Ported to SBND by Alejandro Sanchez-Castillo, Jan. 2025 + +#ifndef SBNDCCODE_DATABASEINTERFACE_IPMTCALIBRATIONDATABASESERVICE_H +#define SBNDCCODE_DATABASEINTERFACE_IPMTCALIBRATIONDATABASESERVICE_H + +// ICARUS libraries +#include "sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabase.h" + +// LArSoft libraries +#include "larcore/CoreUtils/ServiceProviderWrappers.h" + +// ----------------------------------------------------------------------------- +namespace sbndDB { + /// The only thing this service does is to return its service provider of type + /// `sbndDB::PMTCalibrationDatabase`. + using IPMTCalibrationDatabaseService = + lar::ServiceProviderInterfaceWrapper; +} + +// ----------------------------------------------------------------------------- +DECLARE_ART_SERVICE_INTERFACE(sbndDB::IPMTCalibrationDatabaseService, SHARED) + +// ----------------------------------------------------------------------------- + +#endif \ No newline at end of file diff --git a/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabase.h b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabase.h new file mode 100644 index 000000000..1ce738eca --- /dev/null +++ b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabase.h @@ -0,0 +1,39 @@ +/////////////////////////////////////////////////////////////////////// +/// +/// Interface class between the calibration database and the PMT time corrections +/// +/// A. Scarpelli +/// +/// \mailto ascarpell@bnl.gov +/// +//////////////////////////////////////////////////////////////////////// +// Ported to SBND by Alejandro Sanchez-Castillo, Jan. 2025 + +#ifndef SBNDCCODE_DATABASEINTERFACE_PMTCALIBRATIONDATABASE_H +#define SBNDCCODE_DATABASEINTERFACE_PMTCALIBRATIONDATABASE_H + +#include "larcorealg/CoreUtils/UncopiableAndUnmovableClass.h" + +#include "art/Framework/Principal/Run.h" +#include "art/Framework/Services/Registry/ServiceDeclarationMacros.h" + +namespace sbndDB { + + class PMTCalibrationDatabase : lar::UncopiableClass { + public: + virtual ~PMTCalibrationDatabase() noexcept = default; + virtual int getBreakoutBox(unsigned int channelID) const = 0; + virtual int getCAENDigitizer(unsigned int channelID) const = 0; + virtual int getCAENDigitizerChannel(unsigned int channelID) const = 0; + virtual double getTotalTransitTime(unsigned int channelID) const = 0; + virtual double getSPEAmplitude(unsigned int channelID) const = 0; + virtual double getGaussFilterPower(unsigned int channelID) const = 0; + virtual double getGaussFilterWC(unsigned int channelID) const = 0; + virtual std::vector getSER(unsigned int channelID) const = 0; + }; // end class + +} // end of namespace + +DECLARE_ART_SERVICE_INTERFACE(sbndDB::PMTCalibrationDatabase, SHARED) + +#endif \ No newline at end of file diff --git a/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.cxx b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.cxx new file mode 100644 index 000000000..050f41e34 --- /dev/null +++ b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.cxx @@ -0,0 +1,193 @@ +/* + * Service for the PMT Calibration Database. + * Andrea Scarpelli (ascarpell@bnl.gov), Matteo Vicenzi (mvicenzi@bnl.gov) + */ +// Ported from icaruscode to SBND by Alejandro Sanchez-Castillo, Jan. 2025 + +// Framework includes +#include "art/Framework/Principal/Run.h" +#include "art/Framework/Services/Registry/ServiceDefinitionMacros.h" +#include "cetlib_except/exception.h" +#include "messagefacility/MessageLogger/MessageLogger.h" + +// Local +#include "sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabase.h" +#include "sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h" + +// Database interface helpers +#include "larevt/CalibrationDBI/IOVData/TimeStampDecoder.h" +#include "larevt/CalibrationDBI/Providers/DBFolder.h" + +// C/C++ standard libraries +#include +#include + +//-------------------------------------------------------------------------------- + +sbndDB::PMTCalibrationDatabaseProvider::PMTCalibrationDatabaseProvider( + const fhicl::ParameterSet& pset) + : fVerbose{pset.get("Verbose", false)} + , fLogCategory{pset.get("LogCategory", "PMTTimingCorrection")} +{ + fhicl::ParameterSet const tags{pset.get("CorrectionTags")}; + fPMTCalibrationDatabaseTag = tags.get("PMTCalibrationDatabaseTag"); + fDatabaseTimeStamp = tags.get("DatabaseTimeStamp"); + fTableName = tags.get("TableName"); + fSERLength = tags.get("SERLength"); + if (fVerbose) + mf::LogInfo(fLogCategory) << "Database tags for timing corrections:\n" + << "Cables corrections " << fPMTCalibrationDatabaseTag << "\n"; +} + +// ------------------------------------------------------------------------------- + +uint64_t sbndDB::PMTCalibrationDatabaseProvider::RunToDatabaseTimestamp(uint32_t run) const +{ + + // Run number to timestamp used in the db + // DBFolder.h only takes 19 digit (= timestamp in nano second), + // but SBND tables are currently using run numbers + // Step 1) Add 1000000000 to the run number; e.g., run XXXXX -> 10000XXXXX + // Step 2) Multiply 1000000000 + uint64_t runNum = uint64_t(run); + uint64_t timestamp = runNum + 1000000000; + timestamp *= 1000000000; + + if (fVerbose) + mf::LogInfo(fLogCategory) << "Run " << runNum << " corrections from DB timestamp " << timestamp; + + return timestamp; +} + +// ------------------------------------------------------------------------------- + +/// Function to look up the calibration database at the table holding the pmt hardware cables corrections +void sbndDB::PMTCalibrationDatabaseProvider::ReadPMTCalibration(uint32_t run) +{ + const std::string dbname(fTableName); + lariov::DBFolder db(dbname, "", "", fPMTCalibrationDatabaseTag, true, false); + + bool ret = db.UpdateData(fDatabaseTimeStamp); // select table based on timestamp (this is temporary, once we generate db based on run numbers this should be changed) + mf::LogDebug(fLogCategory) << dbname + " corrections" << (ret ? "" : " not") + << " updated for run " << run; + mf::LogTrace(fLogCategory) + << "Fetched IoV [ " << db.CachedStart().DBStamp() << " ; " << db.CachedEnd().DBStamp() + << " ] to cover t=" << RunToDatabaseTimestamp(run) + << " [=" << lariov::TimeStampDecoder::DecodeTimeStamp(RunToDatabaseTimestamp(run)).DBStamp() + << "]"; + + std::vector channelList; + if (int res = db.GetChannelList(channelList); res != 0) { + throw cet::exception("PMTTimingCorrectionsProvider") + << "GetChannelList() returned " << res << " on run " << run << " query in " << dbname << "\n"; + } + + if (channelList.empty()) { + throw cet::exception("PMTTimingCorrectionsProvider") + << "Got an empty channel list for run " << run << " in " << dbname << "\n"; + } + + for (auto channel : channelList) { + // Read breakout box + long _breakoutbox = 0; + int error = db.GetNamedChannelData(channel, "breakout_box", _breakoutbox); + if (error) + throw cet::exception("PMTTimingCorrectionsProvider") + << "Encountered error (code " << error + << ") while trying to access 'breakout_box' on table " << dbname << "\n"; + fPMTCalibrationData[channel].breakoutBox = static_cast(_breakoutbox); + + // Read caen digitizer + long _caen_digitizer = 0; + error = db.GetNamedChannelData(channel, "caen_digitizer", _caen_digitizer); + if (error) + throw cet::exception("PMTTimingCorrectionsProvider") + << "Encountered error (code " << error + << ") while trying to access 'caen_digitizer' on table " << dbname << "\n"; + fPMTCalibrationData[channel].caenDigitizer = static_cast(_caen_digitizer); + + // Read caen digitizer channel + long _caen_digitizer_channel = 0; + error = db.GetNamedChannelData(channel, "caen_digitizer_channel", _caen_digitizer_channel); + if (error) + throw cet::exception("PMTTimingCorrectionsProvider") + << "Encountered error (code " << error + << ") while trying to access 'caen_digitizer_channel' on table " << dbname << "\n"; + fPMTCalibrationData[channel].caenDigitizerChannel = static_cast(_caen_digitizer_channel); + + // Read total transit time + double _total_transit_time = 0.; + error = db.GetNamedChannelData(channel, "total_transit_time", _total_transit_time); + if (error) + throw cet::exception("PMTTimingCorrectionsProvider") + << "Encountered error (code " << error + << ") while trying to access 'total_transit_time' on table " << dbname << "\n"; + fPMTCalibrationData[channel].totalTransitTime = _total_transit_time; + + // Read spe amplitude + double _spe_amplitude = 0.; + error = db.GetNamedChannelData(channel, "spe_amp", _spe_amplitude); + if (error) + throw cet::exception("PMTTimingCorrectionsProvider") + << "Encountered error (code " << error + << ") while trying to access 'spe_amplitude' on table " << dbname << "\n"; + fPMTCalibrationData[channel].spe_amplitude = _spe_amplitude; + + // Read gauss filter power + double _gauss_w_wc_power = 0; + error = db.GetNamedChannelData(channel, "gauss_w_wc_power", _gauss_w_wc_power); + if (error) + throw cet::exception("PMTTimingCorrectionsProvider") + << "Encountered error (code " << error + << ") while trying to access 'gauss_w_wc_power' on table " << dbname << "\n"; + fPMTCalibrationData[channel].gauss_wc_power = _gauss_w_wc_power; + + // Read gauss filter wc + double _gauss_wc = 0.; + error = db.GetNamedChannelData(channel, "gauss_wc", _gauss_wc); + if (error) + throw cet::exception("PMTTimingCorrectionsProvider") + << "Encountered error (code " << error << ") while trying to access 'gauss_wc' on table " + << dbname << "\n"; + fPMTCalibrationData[channel].gauss_wc = _gauss_wc; + + // Read SER + std::vector _ser; + std::string name_base = "ser_vec_"; + for (size_t i = 0; i < fSERLength; i++) { + std::string entry_num = std::to_string(i); + std::string entry_name = name_base + entry_num; + double _ser_component = 0.; + error = db.GetNamedChannelData(channel, entry_name, _ser_component); + if (error) + throw cet::exception("PMTTimingCorrectionsProvider") + << "Encountered error (code " << error << ") while trying to access 'ser_vec' on table " + << dbname << "\n"; + _ser.push_back(_ser_component); + } + fPMTCalibrationData[channel].ser = _ser; + } +} + +// ----------------------------------------------------------------------------- + +/// Read all the corrections from the database and save them inside a map, whose index +/// is the PMT channel number +void sbndDB::PMTCalibrationDatabaseProvider::readPMTCalibrationDatabase(const art::Run& run) +{ + + // Clear before the run + fPMTCalibrationData.clear(); + + ReadPMTCalibration(run.id().run()); + + if (fVerbose) { + mf::LogInfo(fLogCategory) << "Dump information from database " << std::endl; + mf::LogVerbatim(fLogCategory) + << "channel, trigger cable delay, reset cable delay, laser corrections, muons corrections" + << std::endl; + for (auto const& [key, value] : fPMTCalibrationData) { + mf::LogVerbatim(fLogCategory) << key << " " << value.breakoutBox << "," << std::endl; + } + } +} \ No newline at end of file diff --git a/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h new file mode 100644 index 000000000..5db877ec7 --- /dev/null +++ b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h @@ -0,0 +1,111 @@ +/** + * Service for the PMT timing corrections. + * Andrea Scarpelli (ascarpell@bnl.gov), Matteo Vicenzi (mvicenzi@bnl.gov) + */ +// Ported to SBND by Alejandro Sanchez-Castillo, Jan. 2025 + +#ifndef SBNDCODE_DATABASEINTERFACE_PMTCALIBRATIONDATABASEPROVIDER_H +#define SBNDCODE_DATABASEINTERFACE_PMTCALIBRATIONDATABASEPROVIDER_H + +// Framework includes +#include "art/Framework/Services/Registry/ServiceDefinitionMacros.h" +#include "art/Framework/Services/Registry/ActivityRegistry.h" +#include "art/Framework/Services/Registry/ServiceHandle.h" +#include "art/Framework/Services/Registry/ServiceDeclarationMacros.h" +#include "art/Framework/Principal/Run.h" +#include "messagefacility/MessageLogger/MessageLogger.h" +#include "cetlib_except/exception.h" +#include "fhiclcpp/ParameterSet.h" + +// Local +#include "sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabase.h" + +// C/C++ standard libraries +#include +#include +#include + + +namespace sbndDB{ class PMTCalibrationDatabaseProvider; } +/** + * @brief + * + * This module reads the PMT timing corrections from the database. + * + */ +class sbndDB::PMTCalibrationDatabaseProvider : public PMTCalibrationDatabase { + + public: + + PMTCalibrationDatabaseProvider(const fhicl::ParameterSet& pset); + + void readPMTCalibrationDatabase(const art::Run& run); + + int getBreakoutBox( unsigned int channelID ) const override { + return getChannelCorrOrDefault(channelID).breakoutBox; + }; + int getCAENDigitizer( unsigned int channelID ) const override { + return getChannelCorrOrDefault(channelID).caenDigitizer; + }; + int getCAENDigitizerChannel( unsigned int channelID ) const override { + return getChannelCorrOrDefault(channelID).caenDigitizerChannel; + }; + double getTotalTransitTime( unsigned int channelID ) const override { + return getChannelCorrOrDefault(channelID).totalTransitTime; + }; + double getSPEAmplitude( unsigned int channelID ) const override { + return getChannelCorrOrDefault(channelID).spe_amplitude; + }; + double getGaussFilterPower( unsigned int channelID ) const override { + return getChannelCorrOrDefault(channelID).gauss_wc_power; + }; + double getGaussFilterWC( unsigned int channelID ) const override { + return getChannelCorrOrDefault(channelID).gauss_wc; + }; + std::vector getSER( unsigned int channelID ) const override { + return getChannelCorrOrDefault(channelID).ser; + }; + private: + + bool fVerbose = false; ///< Whether to print the configuration we read. + std::string fLogCategory; ///< Category tag for messages. + std::string fPMTCalibrationDatabaseTag; + long fDatabaseTimeStamp; + std::string fTableName; + size_t fSERLength; + + /// Structure for single channel corrections + struct PMTCalibrationDB { + + size_t breakoutBox=0; + size_t caenDigitizer=0; + size_t caenDigitizerChannel=0; + size_t totalTransitTime=0; + double spe_amplitude=0.; + double gauss_wc_power=0.; + double gauss_wc=0.; + std::vector ser={}; + }; + + const PMTCalibrationDB CorrectionDefaults = {0, 0, 0, 0, 0.0, 0.0, 0.0, {}}; + + /// Map of corrections by channel + std::map fPMTCalibrationData; + + /// Internal access to the channel correction record; returns defaults if not present. + PMTCalibrationDB const& getChannelCorrOrDefault + (unsigned int channelID) const + { + auto const it = fPMTCalibrationData.find(channelID); + return (it == fPMTCalibrationData.end())? CorrectionDefaults: it->second; + } + + /// Convert run number to internal database + uint64_t RunToDatabaseTimestamp(uint32_t run) const; + + void ReadPMTCalibration(uint32_t run); + + +}; // services class + +#endif \ No newline at end of file diff --git a/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseService_service.cc b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseService_service.cc new file mode 100644 index 000000000..2af030301 --- /dev/null +++ b/sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseService_service.cc @@ -0,0 +1,59 @@ +/** + * Wrapper class for 'PMTCalibrationDatabaseProvider.h' + * Andrea Scarpelli (ascarpell@bnl.gov) + */ +// Ported to SBND by Alejandro Sanchez-Castillo, Jan. 2025 + +#include "sbndcode/Calibration/PDSDatabaseInterface/IPMTCalibrationDatabaseService.h" +#include "sbndcode/Calibration/PDSDatabaseInterface/PMTCalibrationDatabaseProvider.h" + +// framework libraries +#include "art/Framework/Principal/Run.h" +#include "art/Framework/Services/Registry/ActivityRegistry.h" +#include "art/Framework/Services/Registry/ServiceDeclarationMacros.h" +#include "art/Framework/Services/Registry/ServiceDefinitionMacros.h" +#include "cetlib_except/exception.h" +#include "fhiclcpp/ParameterSet.h" + +// ----------------------------------------------------------------------------- +namespace sbndDB { + class PMTCalibrationDatabaseService; +} +class sbndDB::PMTCalibrationDatabaseService : public IPMTCalibrationDatabaseService, + private PMTCalibrationDatabaseProvider { + + void preBeginRun(const art::Run& run); + + /// Returns a constant pointer to the service provider + virtual PMTCalibrationDatabaseProvider const* do_provider() const override { return this; } + +public: + PMTCalibrationDatabaseService(const fhicl::ParameterSet& pset, art::ActivityRegistry& reg); + +}; // class sbndDB::PMTCalibrationDatabaseService + +// ----------------------------------------------------------------------------- +// --- Implementation +// ----------------------------------------------------------------------------- +sbndDB::PMTCalibrationDatabaseService::PMTCalibrationDatabaseService( + const fhicl::ParameterSet& pset, + art::ActivityRegistry& reg) + : PMTCalibrationDatabaseProvider(pset) +{ + reg.sPreBeginRun.watch(this, &PMTCalibrationDatabaseService::preBeginRun); +} + +// ----------------------------------------------------------------------------- +void sbndDB::PMTCalibrationDatabaseService::preBeginRun(const art::Run& run) +{ + readPMTCalibrationDatabase(run); +} + +// ----------------------------------------------------------------------------- +DECLARE_ART_SERVICE_INTERFACE_IMPL(sbndDB::PMTCalibrationDatabaseService, + sbndDB::IPMTCalibrationDatabaseService, + SHARED) +DEFINE_ART_SERVICE_INTERFACE_IMPL(sbndDB::PMTCalibrationDatabaseService, + sbndDB::IPMTCalibrationDatabaseService) + +// ----------------------------------------------------------------------------- \ No newline at end of file diff --git a/sbndcode/Calibration/PDSDatabaseInterface/pmtcalibrationdatabase_sbnd.fcl b/sbndcode/Calibration/PDSDatabaseInterface/pmtcalibrationdatabase_sbnd.fcl new file mode 100644 index 000000000..340f70051 --- /dev/null +++ b/sbndcode/Calibration/PDSDatabaseInterface/pmtcalibrationdatabase_sbnd.fcl @@ -0,0 +1,14 @@ +BEGIN_PROLOG + +sbnd_pmtcalibrationdatabaseservice : { + service_provider: "PMTCalibrationDatabaseService" + CorrectionTags: { + PMTCalibrationDatabaseTag: "v1r1" + DatabaseTimeStamp: 1740739388000000000 + TableName: "pds_calibration" + SERLength: 550 + } + Verbose: false +} + +END_PROLOG \ No newline at end of file diff --git a/sbndcode/LArSoftConfigurations/services_sbnd.fcl b/sbndcode/LArSoftConfigurations/services_sbnd.fcl index 4b746351f..6ba1cfe07 100644 --- a/sbndcode/LArSoftConfigurations/services_sbnd.fcl +++ b/sbndcode/LArSoftConfigurations/services_sbnd.fcl @@ -45,6 +45,7 @@ #include "database_sbnd.fcl" #include "sam_sbnd.fcl" #include "spacecharge_sbnd.fcl" +#include "pmtcalibrationdatabase_sbnd.fcl" BEGIN_PROLOG @@ -88,6 +89,7 @@ sbnd_services: ChannelStatusService: @local::sbnd_data_channelstatus DetPedestalService: @local::sbnd_detpedestalservice # from database_sbnd.fcl SpaceCharge: @local::sbnd_spacecharge + IPMTCalibrationDatabaseService: @local::sbnd_pmtcalibrationdatabaseservice } # sbnd_services diff --git a/ups/product_deps b/ups/product_deps index 1cb92bee6..059b2936e 100644 --- a/ups/product_deps +++ b/ups/product_deps @@ -326,6 +326,7 @@ end_qualifier_list table_fragment_begin # currently, XML pandora files are installed in 'scripts': pathPrepend(FW_SEARCH_PATH, ${SBNDCODE_DIR}/scripts) + pathPrepend(FW_SEARCH_PATH, ${SBND_DATA_DIR}/CalibrationDatabase) pathPrepend(FW_SEARCH_PATH, /cvmfs/sbnd.osgstorage.org/pnfs/fnal.gov/usr/sbnd/persistent/stash) pathPrepend(PYTHONPATH, ${UPS_PROD_DIR}/python) # wirecell external data files; cfg path append to wpdir=${SBNDCODE_DIR}/wire-cell-cfg