1+ /* *
2+ * @file icaruscode/Timing/PMTTimingCorrectionsProvider.cxx
3+ * @brief Service for the PMT timing corrections.
4+ * @author Andrea Scarpelli (ascarpell@bnl.gov), Matteo Vicenzi (mvicenzi@bnl.gov)
5+ */
6+
7+ // Framework includes
8+ #include " art/Framework/Services/Registry/ServiceDefinitionMacros.h"
9+ #include " art/Framework/Principal/Run.h"
10+ #include " messagefacility/MessageLogger/MessageLogger.h"
11+ #include " cetlib_except/exception.h"
12+
13+ // Local
14+ #include " sbndcode/DatabaseInterface/PMTTimingCorrections.h"
15+ #include " sbndcode/DatabaseInterface/PMTTimingCorrectionsProvider.h"
16+
17+ // Database interface helpers
18+ #include " larevt/CalibrationDBI/Providers/DBFolder.h"
19+ #include " larevt/CalibrationDBI/IOVData/TimeStampDecoder.h"
20+
21+ // C/C++ standard libraries
22+ #include < string>
23+ #include < vector>
24+
25+ // --------------------------------------------------------------------------------
26+
27+ sbndDB::PMTTimingCorrectionsProvider::PMTTimingCorrectionsProvider
28+ (const fhicl::ParameterSet& pset)
29+ : fVerbose { pset.get <bool >(" Verbose" , false ) }
30+ , fLogCategory { pset.get <std::string>(" LogCategory" , " PMTTimingCorrection" ) }
31+ {
32+ fhicl::ParameterSet const tags{ pset.get <fhicl::ParameterSet>(" CorrectionTags" ) };
33+ fCablesTag = tags.get <std::string>(" CablesTag" );
34+ fLaserTag = tags.get <std::string>(" LaserTag" );
35+ fCosmicsTag = tags.get <std::string>(" CosmicsTag" );
36+ if ( fVerbose ) mf::LogInfo (fLogCategory ) << " Database tags for timing corrections:\n "
37+ << " Cables corrections " << fCablesTag << " \n "
38+ << " Laser corrections " << fLaserTag << " \n "
39+ << " Cosmics corrections " << fCosmicsTag ;
40+ }
41+
42+ // -------------------------------------------------------------------------------
43+
44+ uint64_t sbndDB::PMTTimingCorrectionsProvider::RunToDatabaseTimestamp ( uint32_t run ) const {
45+
46+ // Run number to timestamp used in the db
47+ // DBFolder.h only takes 19 digit (= timestamp in nano second),
48+ // but ICARUS tables are currently using run numbers
49+ // Step 1) Add 1000000000 to the run number; e.g., run XXXXX -> 10000XXXXX
50+ // Step 2) Multiply 1000000000
51+ uint64_t runNum = uint64_t (run);
52+ uint64_t timestamp = runNum+1000000000 ;
53+ timestamp *= 1000000000 ;
54+
55+ if ( fVerbose ) mf::LogInfo (fLogCategory ) << " Run " << runNum << " corrections from DB timestamp " << timestamp;
56+
57+ return timestamp;
58+ }
59+
60+ // -------------------------------------------------------------------------------
61+
62+ // / Function to look up the calibration database at the table holding the pmt hardware cables corrections
63+ void sbndDB::PMTTimingCorrectionsProvider::ReadPMTCablesCorrections ( uint32_t run ) {
64+
65+ // pmt_cables_delay: delays of the cables relative to trigger
66+ // and reset distribution
67+ const std::string dbname (" pmt_cables_delays_data" );
68+ lariov::DBFolder db (dbname, " " , " " , fCablesTag , true , false );
69+
70+ bool ret = db.UpdateData ( RunToDatabaseTimestamp (run) ); // select table based on run number
71+ mf::LogDebug (fLogCategory ) << dbname + " corrections" << (ret? " " : " not" ) << " updated for run " << run;
72+ mf::LogTrace (fLogCategory )
73+ << " Fetched IoV [ " << db.CachedStart ().DBStamp () << " ; " << db.CachedEnd ().DBStamp ()
74+ << " ] to cover t=" << RunToDatabaseTimestamp (run)
75+ << " [=" << lariov::TimeStampDecoder::DecodeTimeStamp (RunToDatabaseTimestamp (run)).DBStamp () << " ]" ;
76+
77+ std::vector<unsigned int > channelList;
78+ if (int res = db.GetChannelList (channelList); res != 0 ) {
79+ throw cet::exception
80+ ( " PMTTimingCorrectionsProvider" ) << " GetChannelList() returned " << res << " on run " << run << " query in " << dbname << " \n " ;
81+ }
82+
83+ if (channelList.empty ()) {
84+ throw cet::exception (" PMTTimingCorrectionsProvider" ) << " Got an empty channel list for run " << run << " in " << dbname << " \n " ;
85+ }
86+
87+ for ( auto channel : channelList ) {
88+
89+ // PPS reset correction
90+ double reset_distribution_delay = 0 ;
91+ int error = db.GetNamedChannelData ( channel, " reset_distribution_delay" , reset_distribution_delay );
92+ if ( error ) throw cet::exception (" PMTTimingCorrectionsProvider" ) << " Encountered error (code " << error << " ) while trying to access 'reset_distribution_delay' on table " << dbname << " \n " ;
93+
94+ // Trigger cable delay
95+ double trigger_reference_delay = 0 ;
96+ error = db.GetNamedChannelData ( channel, " trigger_reference_delay" , trigger_reference_delay );
97+ if ( error ) throw cet::exception ( " PMTTimingCorrectionsProvider" ) << " Encountered error (code " << error << " ) while trying to access 'trigger_reference_delay' on table " << dbname << " \n " ;
98+
99+ // Phase correction
100+ double phase_correction = 0 ;
101+ error = db.GetNamedChannelData ( channel, " phase_correction" , phase_correction );
102+ if ( error ) throw cet::exception ( " PMTTimingCorrectionsProvider" ) << " Encountered error (code " << error << " ) while trying to access 'phase_correction' on table " << dbname << " \n " ;
103+
104+ // / This is the delay due to the cables connecting the 'global' trigger crate FPGA to the spare channel of the first digitizer in each VME crates.
105+ // / The phase correction is an additional fudge factor
106+ // / holding local variation due to constant clock offsets (it can be up to 8 ns)
107+ // / It can be absorbed within other corrections if necessary
108+ // / Corrections are saved in ns, but icaruscode wants us
109+ // / Correction are saved with the sing correspoding to their time direction
110+ fDatabaseTimingCorrections [channel].triggerCableDelay = -(trigger_reference_delay-phase_correction)/1000 .;
111+
112+ // / This is the delay along the distribution line of the TTT reset
113+ // / The phase correction is an additional fudge factor
114+ // / holding local variation due to constant clock offsets (it can be up to 8 ns)
115+ // / It can be absorbed within other corrections if necessary
116+ // / Corrections are saved in ns, but icaruscode wants us
117+ // / Corrections are additive!
118+ fDatabaseTimingCorrections [channel].resetCableDelay = (reset_distribution_delay-phase_correction)/1000 .;
119+ }
120+
121+ }
122+
123+
124+ // -----------------------------------------------------------------------------
125+
126+ // / Function to look up the calibration database at the table holding the pmt timing corrections measured using the laser
127+ void sbndDB::PMTTimingCorrectionsProvider::ReadLaserCorrections ( uint32_t run ) {
128+
129+ const std::string dbname (" pmt_laser_timing_data" );
130+ lariov::DBFolder db (dbname, " " , " " , fLaserTag , true , false );
131+
132+ bool ret = db.UpdateData ( RunToDatabaseTimestamp (run) ); // select table based on run number
133+ mf::LogDebug (fLogCategory ) << dbname + " corrections" << (ret? " " : " not" ) << " updated for run " << run;
134+ mf::LogTrace (fLogCategory )
135+ << " Fetched IoV [ " << db.CachedStart ().DBStamp () << " ; " << db.CachedEnd ().DBStamp ()
136+ << " ] to cover t=" << RunToDatabaseTimestamp (run)
137+ << " [=" << lariov::TimeStampDecoder::DecodeTimeStamp (RunToDatabaseTimestamp (run)).DBStamp () << " ]" ;
138+
139+ std::vector<unsigned int > channelList;
140+ if (int res = db.GetChannelList (channelList); res != 0 ) {
141+ throw cet::exception
142+ ( " PMTTimingCorrectionsProvider" ) << " GetChannelList() returned " << res << " on run " << run << " query in " << dbname << " \n " ;
143+ }
144+
145+ if (channelList.empty ()) {
146+ throw cet::exception (" PMTTimingCorrectionsProvider" ) << " got an empty channel list for run " << run << " in " << dbname << " \n " ;
147+ }
148+
149+ for ( auto channel : channelList ) {
150+
151+ // Laser correction
152+ double t_signal = 0 ;
153+ int error = db.GetNamedChannelData ( channel, " t_signal" , t_signal );
154+ if ( error ) throw cet::exception ( " PMTTimingCorrectionsProvider" ) << " Encountered error (code " << error << " ) while trying to access 't_signal' on table " << dbname << " \n " ;
155+
156+ // / pmt_laser_delay: delay from the Electron Transit time inside the PMT
157+ // / and the PMT signal cable
158+ // / corrections are saved in ns, but icaruscode wants us
159+ // / Corrections are additive!
160+ fDatabaseTimingCorrections [channel].laserCableDelay = -t_signal/1000 .;
161+ }
162+ }
163+
164+ // -----------------------------------------------------------------------------
165+
166+ // / Function to look up the calibration database at the table holding the pmt timing corrections measured using cosmic muons
167+ void sbndDB::PMTTimingCorrectionsProvider::ReadCosmicsCorrections ( uint32_t run ) {
168+
169+ const std::string dbname (" pmt_cosmics_timing_data" );
170+ lariov::DBFolder db (dbname, " " , " " , fCosmicsTag , true , false );
171+
172+ bool ret = db.UpdateData ( RunToDatabaseTimestamp (run) ); // select table based on run number
173+ mf::LogDebug (fLogCategory ) << dbname + " corrections" << (ret? " " : " not" ) << " updated for run " << run;
174+ mf::LogTrace (fLogCategory )
175+ << " Fetched IoV [ " << db.CachedStart ().DBStamp () << " ; " << db.CachedEnd ().DBStamp ()
176+ << " ] to cover t=" << RunToDatabaseTimestamp (run)
177+ << " [=" << lariov::TimeStampDecoder::DecodeTimeStamp (RunToDatabaseTimestamp (run)).DBStamp () << " ]" ;
178+
179+ std::vector<unsigned int > channelList;
180+ if (int res = db.GetChannelList (channelList); res != 0 ) {
181+ throw cet::exception
182+ ( " PMTTimingCorrectionsProvider" ) << " GetChannelList() returned " << res << " on run " << run << " query in " << dbname << " \n " ;
183+ }
184+
185+ if (channelList.empty ()) {
186+ throw cet::exception (" PMTTimingCorrectionsProvider" ) << " Got an empty channel list for run " << run << " in " << dbname << " \n " ;
187+ }
188+
189+ for ( auto channel : channelList ) {
190+
191+ // Cosmics correction
192+ double mean_residual_ns = 0 ;
193+ int error = db.GetNamedChannelData ( channel, " mean_residual_ns" , mean_residual_ns );
194+ if ( error ) throw cet::exception ( " PMTTimingCorrectionsProvider" ) << " Encountered error (code " << error << " ) while trying to access 'mean_residual_ns' on table " << dbname << " \n " ;
195+
196+ // / pmt_cosmics_residual: time residuals from downward going cosmics tracks
197+ // / correcting for point-like laser emission and pmts that do not see laser light
198+ // / corrections are saved in ns, but icaruscode wants us
199+ // / Corrections are additive!
200+ fDatabaseTimingCorrections [channel].cosmicsCorrections = -mean_residual_ns/1000 .;
201+ }
202+
203+ }
204+
205+
206+ // -----------------------------------------------------------------------------
207+
208+
209+ // / Read all the corrections from the database and save them inside a map, whose index
210+ // / is the PMT channel number
211+ void sbndDB::PMTTimingCorrectionsProvider::readTimeCorrectionDatabase (const art::Run& run){
212+
213+ // Clear before the run
214+ fDatabaseTimingCorrections .clear ();
215+
216+ ReadPMTCablesCorrections (run.id ().run ());
217+ ReadLaserCorrections (run.id ().run ());
218+ ReadCosmicsCorrections (run.id ().run ());
219+
220+ if ( fVerbose ) {
221+
222+ mf::LogInfo (fLogCategory ) << " Dump information from database " << std::endl;
223+ mf::LogVerbatim (fLogCategory ) << " channel, trigger cable delay, reset cable delay, laser corrections, muons corrections" << std::endl;
224+ for ( auto const & [key, value] : fDatabaseTimingCorrections ){
225+ mf::LogVerbatim (fLogCategory )
226+ << key << " "
227+ << value.triggerCableDelay << " ,"
228+ << value.resetCableDelay << " , "
229+ << value.laserCableDelay << " , "
230+ << value.cosmicsCorrections << " ,"
231+ << std::endl;
232+ }
233+ }
234+
235+ }
0 commit comments