Belle II Software development
KLMTimeAlgorithm.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9/* Own header. */
10#include <klm/calibration/KLMTimeAlgorithm.h>
11
12/* KLM headers. */
13#include <klm/dataobjects/bklm/BKLMElementNumbers.h>
14
15/* Basf2 headers. */
16#include <framework/database/Database.h>
17#include <framework/database/DBObjPtr.h>
18#include <framework/database/DBStore.h>
19#include <framework/dataobjects/EventMetaData.h>
20#include <framework/gearbox/Const.h>
21#include <framework/logging/Logger.h>
22#include <framework/utilities/MathHelpers.h>
23
24/* ROOT headers. */
25#include <Math/MinimizerOptions.h>
26#include <Math/Vector3D.h>
27#include <TFile.h>
28#include <TFitResult.h>
29#include <TMinuit.h>
30#include <TROOT.h>
31#include <TString.h>
32#include <TTree.h>
33
34/* C++ headers. */
35#include <functional>
36#include <set>
37
38using namespace Belle2;
39using namespace ROOT::Math;
40
42const int c_NBinsTime = 100;
43
45const int c_NBinsDistance = 100;
46
48static double s_BinnedData[c_NBinsTime][c_NBinsDistance];
49
51static double s_LowerTimeBoundary = 0;
52
54static double s_UpperTimeBoundary = 0;
55
57static double s_StripLength = 0;
58
59static bool compareEventNumber(const std::pair<KLMChannelNumber, unsigned int>& pair1,
60 const std::pair<KLMChannelNumber, unsigned int>& pair2)
61{
62 return pair1.second < pair2.second;
63}
64
65static double timeDensity(const double x[2], const double* par)
66{
67 double polynomial, t0, gauss;
68 polynomial = par[0];
69 t0 = par[2] + par[4] * x[1];
70 gauss = par[1] / (sqrt(2.0 * M_PI) * par[3]) *
71 exp(-0.5 * square((x[0] - t0) / par[3]));
72 return fabs(polynomial + gauss);
73}
74
75// the signature is imposed by TMinuit::SetFCN()
76// cppcheck-suppress constParameterCallback
77static void fcn(int& npar, double* grad, double& fval, double* par, int iflag)
78{
79 (void)npar;
80 (void)grad;
81 (void)iflag;
82 double x[2];
83 fval = 0;
84 for (int i = 0; i < c_NBinsTime; ++i) {
85 x[0] = s_LowerTimeBoundary +
86 (s_UpperTimeBoundary - s_LowerTimeBoundary) *
87 (double(i) + 0.5) / c_NBinsTime;
88 for (int j = 0; j < c_NBinsDistance; ++j) {
89 x[1] = s_StripLength * (double(j) + 0.5) / c_NBinsDistance;
90 double f = timeDensity(x, par);
91 if (s_BinnedData[i][j] == 0)
92 fval = fval + 2.0 * f;
93 else
94 fval = fval + 2.0 * (f - s_BinnedData[i][j] *
95 (1.0 - log(s_BinnedData[i][j] / f)));
96 }
97 }
98}
99
101 CalibrationAlgorithm("KLMTimeCollector")
102{
104 m_minimizerOptions = ROOT::Math::MinimizerOptions();
105}
106
110
112{
113 const std::vector<Calibration::ExpRun>& runs = getRunList();
114 int firstExperiment = runs[0].first;
115 int lastExperiment = runs[runs.size() - 1].first;
116 if (firstExperiment != lastExperiment) {
117 B2FATAL("Runs from different experiments are used "
118 "for KLM time calibration (single algorithm run).");
119 }
120 /* DataStore. */
122 StoreObjPtr<EventMetaData> eventMetaData;
123 eventMetaData.registerInDataStore();
125 /* Database. */
126 if (eventMetaData.isValid()) {
127 if (eventMetaData->getExperiment() != firstExperiment) {
128 B2FATAL("Runs from different experiments are used "
129 "for KLM time calibration (consecutive algorithm runs).");
130 }
131 eventMetaData->setExperiment(firstExperiment);
132 eventMetaData->setRun(runs[0].second);
133 } else {
134 eventMetaData.construct(1, runs[0].second, firstExperiment);
135 }
136 DBStore& dbStore = DBStore::Instance();
137 dbStore.update();
138 dbStore.updateEvent();
139 /*
140 * For calibration algorithms, the database is not initialized on class
141 * creation. Do not move the database object to class members.
142 */
143 DBObjPtr<BKLMGeometryPar> bklmGeometry;
146}
147
148// Version 1: Initial check only (don't load data)
150{
151 B2INFO("Read tree entries (initial data check only).");
152 std::shared_ptr<TTree> timeCalibrationData;
153 timeCalibrationData = getObjectPtr<TTree>("time_calibration_data");
154
155 int n = timeCalibrationData->GetEntries();
156 B2INFO(LogVar("Total number of digits:", n));
157
158 if (n < m_MinimalDigitNumber)
160
162}
163
164void KLMTimeAlgorithm::readCalibrationDataCounts(std::map<KLMChannelNumber, unsigned int>& eventCounts)
165{
166 B2INFO("Counting events per channel (lightweight scan)...");
167 Event event;
168 std::shared_ptr<TTree> timeCalibrationData;
169 timeCalibrationData = getObjectPtr<TTree>("time_calibration_data");
170 timeCalibrationData->SetBranchAddress("channelId", &event.channelId);
171
172 eventCounts.clear();
173
174 int n = timeCalibrationData->GetEntries();
175 for (int i = 0; i < n; ++i) {
176 timeCalibrationData->GetEntry(i);
177 eventCounts[event.channelId]++;
178 }
179
180 B2INFO("Event counting complete." << LogVar("Total events", n) << LogVar("Unique channels", eventCounts.size()));
181}
182
184 const std::vector<std::pair<KLMChannelNumber, unsigned int>>& channelsBKLM,
185 const std::vector<std::pair<KLMChannelNumber, unsigned int>>& channelsEKLM)
186{
187 B2INFO("Loading data for 2D fit (top 1000 channels from BKLM and EKLM)...");
188 Event event;
189 std::shared_ptr<TTree> timeCalibrationData;
190 timeCalibrationData = getObjectPtr<TTree>("time_calibration_data");
191 timeCalibrationData->SetBranchAddress("Run", &event.Run);
192 timeCalibrationData->SetBranchAddress("Event", &event.Events);
193 timeCalibrationData->SetBranchAddress("nTrack", &event.nTrack);
194 timeCalibrationData->SetBranchAddress("Track_Charge", &event.Track_Charge);
195
196 timeCalibrationData->SetBranchAddress("t0", &event.t0);
197 timeCalibrationData->SetBranchAddress("t0_uc", &event.t0_uc);
198 timeCalibrationData->SetBranchAddress("flyTime", &event.flyTime);
199 timeCalibrationData->SetBranchAddress("recTime", &event.recTime);
200 timeCalibrationData->SetBranchAddress("dist", &event.dist);
201 timeCalibrationData->SetBranchAddress("diffDistX", &event.diffDistX);
202 timeCalibrationData->SetBranchAddress("diffDistY", &event.diffDistY);
203 timeCalibrationData->SetBranchAddress("diffDistZ", &event.diffDistZ);
204 timeCalibrationData->SetBranchAddress("eDep", &event.eDep);
205 timeCalibrationData->SetBranchAddress("nPE", &event.nPE);
206 timeCalibrationData->SetBranchAddress("channelId", &event.channelId);
207 timeCalibrationData->SetBranchAddress("inRPC", &event.inRPC);
208 timeCalibrationData->SetBranchAddress("isFlipped", &event.isFlipped);
209 timeCalibrationData->SetBranchAddress("isGood", &event.isGood);
210 timeCalibrationData->SetBranchAddress("getADCcount", &event.getADCcount);
211
212 m_evts.clear();
213
214 // Build set of channels we need for 2D fit (top 1000 from each)
215 std::set<KLMChannelNumber> neededChannels;
216 int maxChannels = 1000;
217
218 for (size_t i = 0; i < channelsBKLM.size() && i < static_cast<size_t>(maxChannels); ++i) {
219 neededChannels.insert(channelsBKLM[i].first);
220 }
221 for (size_t i = 0; i < channelsEKLM.size() && i < static_cast<size_t>(maxChannels); ++i) {
222 neededChannels.insert(channelsEKLM[i].first);
223 }
224
225 int n = timeCalibrationData->GetEntries();
226 int loadedEvents = 0;
227
228 for (int i = 0; i < n; ++i) {
229 timeCalibrationData->GetEntry(i);
230
231 if (neededChannels.find(event.channelId) != neededChannels.end()) {
232 m_evts[event.channelId].push_back(event);
233 loadedEvents++;
234 }
235 }
236
237 B2INFO("2D fit data loaded." << LogVar("Events", loadedEvents) << LogVar("Channels", m_evts.size()));
238}
239
240void KLMTimeAlgorithm::readCalibrationDataBatch(std::function<bool(const KLMChannelIndex&)> channelFilter)
241{
242 B2INFO("Loading calibration data batch...");
243 Event event;
244 std::shared_ptr<TTree> timeCalibrationData;
245 timeCalibrationData = getObjectPtr<TTree>("time_calibration_data");
246 timeCalibrationData->SetBranchAddress("Run", &event.Run);
247 timeCalibrationData->SetBranchAddress("Event", &event.Events);
248 timeCalibrationData->SetBranchAddress("nTrack", &event.nTrack);
249 timeCalibrationData->SetBranchAddress("Track_Charge", &event.Track_Charge);
250
251 timeCalibrationData->SetBranchAddress("t0", &event.t0);
252 timeCalibrationData->SetBranchAddress("t0_uc", &event.t0_uc);
253 timeCalibrationData->SetBranchAddress("flyTime", &event.flyTime);
254 timeCalibrationData->SetBranchAddress("recTime", &event.recTime);
255 timeCalibrationData->SetBranchAddress("dist", &event.dist);
256 timeCalibrationData->SetBranchAddress("diffDistX", &event.diffDistX);
257 timeCalibrationData->SetBranchAddress("diffDistY", &event.diffDistY);
258 timeCalibrationData->SetBranchAddress("diffDistZ", &event.diffDistZ);
259 timeCalibrationData->SetBranchAddress("eDep", &event.eDep);
260 timeCalibrationData->SetBranchAddress("nPE", &event.nPE);
261 timeCalibrationData->SetBranchAddress("channelId", &event.channelId);
262 timeCalibrationData->SetBranchAddress("inRPC", &event.inRPC);
263 timeCalibrationData->SetBranchAddress("isFlipped", &event.isFlipped);
264 timeCalibrationData->SetBranchAddress("isGood", &event.isGood);
265 timeCalibrationData->SetBranchAddress("getADCcount", &event.getADCcount);
266
267 m_evts.clear();
268
269 int n = timeCalibrationData->GetEntries();
270 int loadedEvents = 0;
271
272 for (int i = 0; i < n; ++i) {
273 timeCalibrationData->GetEntry(i);
274
275 // Convert channel number to KLMChannelIndex using channelNumberToElementNumbers
276 int subdetector, section, sector, layer, plane, strip;
277 m_ElementNumbers->channelNumberToElementNumbers(
278 event.channelId, &subdetector, &section, &sector, &layer, &plane, &strip);
279 KLMChannelIndex klmChannel(subdetector, section, sector, layer, plane, strip);
280
281 if (channelFilter(klmChannel)) {
282 m_evts[event.channelId].push_back(event);
283 loadedEvents++;
284 }
285 }
286
287 B2INFO("Batch loaded." << LogVar("Events", loadedEvents) << LogVar("Channels", m_evts.size()));
288}
289
291{
292 if (m_mc) {
299 } else {
300 m_LowerTimeBoundaryRPC = -800.0;
301 m_UpperTimeBoundaryRPC = -600.0;
306 }
307
308 // Create directory structure for per-channel histograms
309 // This must be done here (not in setupDatabase) because m_outFile is created just before this function is called
311 TDirectory* dir_channels = m_outFile->mkdir("channels", "Per-channel histograms", true);
312
313 // BKLM directories
314 TDirectory* dir_bklm = dir_channels->mkdir("BKLM", "", true);
315 TString sectionName[2] = {"Backward", "Forward"};
316 TString planeName[2] = {"Z", "Phi"};
317
318 for (int iF = 0; iF < 2; ++iF) {
319 TDirectory* dir_section = dir_bklm->mkdir(sectionName[iF].Data(), "", true);
320 for (int iS = 0; iS < 8; ++iS) {
321 TDirectory* dir_sector = dir_section->mkdir(Form("Sector_%d", iS + 1), "", true);
322 for (int iL = 0; iL < 15; ++iL) {
323 TDirectory* dir_layer = dir_sector->mkdir(Form("Layer_%d", iL + 1), "", true);
324 for (int iP = 0; iP < 2; ++iP) {
325 m_channelHistDir_BKLM[iF][iS][iL][iP] = dir_layer->mkdir(Form("Plane_%s", planeName[iP].Data()), "", true);
326 }
327 }
328 }
329 }
330
331 // EKLM directories
332 TDirectory* dir_eklm = dir_channels->mkdir("EKLM", "", true);
333 for (int iF = 0; iF < 2; ++iF) {
334 TDirectory* dir_section = dir_eklm->mkdir(sectionName[iF].Data(), "", true);
335 for (int iS = 0; iS < 4; ++iS) {
336 TDirectory* dir_sector = dir_section->mkdir(Form("Sector_%d", iS + 1), "", true);
337 int maxLayer = 12 + 2 * iF; // 12 for backward, 14 for forward
338 for (int iL = 0; iL < maxLayer; ++iL) {
339 TDirectory* dir_layer = dir_sector->mkdir(Form("Layer_%d", iL + 1), "", true);
340 for (int iP = 0; iP < 2; ++iP) {
341 m_channelHistDir_EKLM[iF][iS][iL][iP] = dir_layer->mkdir(Form("Plane_%d", iP + 1), "", true);
342 }
343 }
344 }
345 }
346
347 m_outFile->cd(); // Return to root directory
348 B2INFO("Created directory structure for per-channel histograms.");
349 }
350
351 int nBin = 80;
352 int nBin_scint = 80;
353
354 TString iFstring[2] = {"Backward", "Forward"};
355 TString iPstring[2] = {"ZReadout", "PhiReadout"};
356 TString hn, ht;
357
358 h_diff = new TH1F("h_diff", "Position difference between bklmHit2d and extHit;position difference", 100, 0, 10);
359 h_calibrated = new TH1I("h_calibrated_summary", "h_calibrated_summary;calibrated or not", 3, 0, 3);
360 hc_calibrated = new TH1I("hc_calibrated_summary", "hc_calibrated_summary;calibrated or not", 3, 0, 3);
361
362 gre_time_channel_scint = new TGraphErrors();
363 gre_time_channel_rpc = new TGraphErrors();
364 gre_time_channel_scint_end = new TGraphErrors();
365
366 gr_timeShift_channel_scint = new TGraph();
367 gr_timeShift_channel_rpc = new TGraph();
368 gr_timeShift_channel_scint_end = new TGraph();
369
370 gre_ctime_channel_scint = new TGraphErrors();
371 gre_ctime_channel_rpc = new TGraphErrors();
372 gre_ctime_channel_scint_end = new TGraphErrors();
373
374 gr_timeRes_channel_scint = new TGraph();
375 gr_timeRes_channel_rpc = new TGraph();
376 gr_timeRes_channel_scint_end = new TGraph();
377
378 double maximalPhiStripLengthBKLM =
379 m_BKLMGeometry->getMaximalPhiStripLength();
380 double maximalZStripLengthBKLM =
381 m_BKLMGeometry->getMaximalZStripLength();
382 double maximalStripLengthEKLM =
383 m_EKLMGeometry->getMaximalStripLength() / CLHEP::cm * Unit::cm;
384
385 m_ProfileRpcPhi = new TProfile("hprf_rpc_phi_effC",
386 "Time over propagation length for RPCs (Phi_Readout); propagation distance[cm]; T_rec-T_0-T_fly-'T_calibration'[ns]", 50, 0.0,
387 400.0);
388 m_ProfileRpcZ = new TProfile("hprf_rpc_z_effC",
389 "Time over propagation length for RPCs (Z_Readout); propagation distance[cm]; T_rec-T_0-T_fly-'T_calibration'[ns]", 50, 0.0,
390 400.0);
391 m_ProfileBKLMScintillatorPhi = new TProfile("hprf_scint_phi_effC",
392 "Time over propagation length for scintillators (Phi_Readout); propagation distance[cm]; T_rec-T_0-T_fly-'T_calibration'[ns]",
393 50, 0.0, maximalPhiStripLengthBKLM);
394 m_ProfileBKLMScintillatorZ = new TProfile("hprf_scint_z_effC",
395 "Time over propagation length for scintillators (Z_Readout); propagation distance[cm]; T_rec-T_0-T_fly-'T_calibration'[ns]",
396 50, 0.0, maximalZStripLengthBKLM);
397 m_ProfileEKLMScintillatorPlane1 = new TProfile("hprf_scint_plane1_effC_end",
398 "Time over propagation length for scintillators (plane1, Endcap); propagation distance[cm]; T_rec-T_0-T_fly-'T_calibration'[ns]",
399 50, 0.0, maximalStripLengthEKLM);
400 m_ProfileEKLMScintillatorPlane2 = new TProfile("hprf_scint_plane2_effC_end",
401 "Time over propagation length for scintillators (plane2, Endcap); propagation distance[cm]; T_rec-T_0-T_fly-'T_calibration'[ns]",
402 50, 0.0, maximalStripLengthEKLM);
403
404 m_Profile2RpcPhi = new TProfile("hprf2_rpc_phi_effC",
405 "Time over propagation length for RPCs (Phi_Readout); propagation distance[cm]; T_rec-T_0-T_fly-'T_calibration'[ns]", 50, 0.0,
406 400.0);
407 m_Profile2RpcZ = new TProfile("hprf2_rpc_z_effC",
408 "Time over propagation length for RPCs (Z_Readout); propagation distance[cm]; T_rec-T_0-T_fly-'T_calibration'[ns]", 50, 0.0,
409 400.0);
410 m_Profile2BKLMScintillatorPhi = new TProfile("hprf2_scint_phi_effC",
411 "Time over propagation length for scintillators (Phi_Readout); propagation distance[cm]; T_rec-T_0-T_fly-'T_calibration'[ns]",
412 50, 0.0, maximalPhiStripLengthBKLM);
413 m_Profile2BKLMScintillatorZ = new TProfile("hprf2_scint_z_effC",
414 "Time over propagation length for scintillators (Z_Readout); propagation distance[cm]; T_rec-T_0-T_fly-'T_calibration'[ns]",
415 50, 0.0, maximalZStripLengthBKLM);
416 m_Profile2EKLMScintillatorPlane1 = new TProfile("hprf2_scint_plane1_effC_end",
417 "Time over propagation length for scintillators (plane1, Endcap); propagation distance[cm]; T_rec-T_0-T_fly-'T_calibration'[ns]",
418 50, 0.0, maximalStripLengthEKLM);
419 m_Profile2EKLMScintillatorPlane2 = new TProfile("hprf2_scint_plane2_effC_end",
420 "Time over propagation length for scintillators (plane2, Endcap); propagation distance[cm]; T_rec-T_0-T_fly-'T_calibration'[ns]",
421 50, 0.0, maximalStripLengthEKLM);
422
423 h_time_rpc_tc = new TH1F("h_time_rpc_tc", "time distribution for RPC", nBin, m_LowerTimeBoundaryRPC, m_UpperTimeBoundaryRPC);
424 h_time_scint_tc = new TH1F("h_time_scint_tc", "time distribution for Scintillator", nBin_scint,
426 h_time_scint_tc_end = new TH1F("h_time_scint_tc_end", "time distribution for Scintillator (Endcap)", nBin_scint,
429
431 h_time_rpc = new TH1F("h_time_rpc", "time distribution for RPC; T_rec-T_0-T_fly-T_propagation[ns]", nBin, m_LowerTimeBoundaryRPC,
433 h_time_scint = new TH1F("h_time_scint", "time distribution for Scintillator; T_rec-T_0-T_fly-T_propagation[ns]", nBin_scint,
435 h_time_scint_end = new TH1F("h_time_scint_end", "time distribution for Scintillator (Endcap); T_rec-T_0-T_fly-T_propagation[ns]",
437
438 hc_time_rpc = new TH1F("hc_time_rpc", "Calibrated time distribution for RPC; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]",
440 hc_time_scint = new TH1F("hc_time_scint",
441 "Calibrated time distribution for Scintillator; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]", nBin_scint,
444 hc_time_scint_end = new TH1F("hc_time_scint_end",
445 "Calibrated time distribution for Scintillator (Endcap); T_rec-T_0-T_fly-T_propagation-T_calibration[ns]", nBin_scint,
447
448 int nBin_t0 = 100;
449 h_eventT0_rpc = new TH1F("h_eventT0_rpc",
450 "RPC: Event T0; T_{0}[ns]", nBin_t0, -100.0, 100.0);
451 h_eventT0_scint = new TH1F("h_eventT0_scint",
452 "BKLM scintillator: Event T0; T_{0}[ns]", nBin_t0, -100.0, 100.0);
453 h_eventT0_scint_end = new TH1F("h_eventT0_scint_end",
454 "EKLM scintillator: Event T0; T_{0}[ns]", nBin_t0, -100.0, 100.0);
455
456 // Corrected EventT0 distributions between 2 muon tracks in an event.
457 hc_eventT0_rpc = new TH1F("hc_eventT0_rpc",
458 "RPC: corrected Event T0; T_{0}^{+} - T_{0}^{-} [ns]", nBin_t0, -40.0, 40.0);
459 hc_eventT0_scint = new TH1F("hc_eventT0_scint",
460 "BKLM scintillator: corrected Event T0; T_{0}^{+} - T_{0}^{-} [ns]", nBin_t0, -40.0, 40.0);
461 hc_eventT0_scint_end = new TH1F("hc_eventT0_scint_end",
462 "EKLM scintillator: corrected Event T0; T_{0}^{+} - T_{0}^{-} [ns]", nBin_t0, -20.0, 20.0);
463
464 // ==== NEW DIAGNOSTIC PLOTS ====
465
466 // Hit multiplicity distributions
467 h_nHits_plus_rpc = new TH1F("h_nHits_plus_rpc",
468 "RPC: #mu^{+} hit multiplicity;N_{hits};Events", 100, 0, 100);
469 h_nHits_minus_rpc = new TH1F("h_nHits_minus_rpc",
470 "RPC: #mu^{-} hit multiplicity;N_{hits};Events", 100, 0, 100);
471 h_nHits_plus_scint = new TH1F("h_nHits_plus_scint",
472 "BKLM Scint: #mu^{+} hit multiplicity;N_{hits};Events", 30, 0, 30);
473 h_nHits_minus_scint = new TH1F("h_nHits_minus_scint",
474 "BKLM Scint: #mu^{-} hit multiplicity;N_{hits};Events", 30, 0, 30);
475 h_nHits_plus_scint_end = new TH1F("h_nHits_plus_scint_end",
476 "EKLM Scint: #mu^{+} hit multiplicity;N_{hits};Events", 30, 0, 30);
477 h_nHits_minus_scint_end = new TH1F("h_nHits_minus_scint_end",
478 "EKLM Scint: #mu^{-} hit multiplicity;N_{hits};Events", 30, 0, 30);
479
480 // ΔT0 vs variance weight v = 1/N+ + 1/N-
481 h2_deltaT0_vs_v_rpc = new TH2F("h2_deltaT0_vs_v_rpc",
482 "RPC: #DeltaT_{0} vs variance weight;v = 1/N^{+} + 1/N^{-};#DeltaT_{0} [ns]",
483 50, 0, 2.0, 100, -40, 40);
484 h2_deltaT0_vs_v_scint = new TH2F("h2_deltaT0_vs_v_scint",
485 "BKLM Scint: #DeltaT_{0} vs variance weight;v = 1/N^{+} + 1/N^{-};#DeltaT_{0} [ns]",
486 50, 0, 1.0, 100, -40, 40);
487 h2_deltaT0_vs_v_scint_end = new TH2F("h2_deltaT0_vs_v_scint_end",
488 "EKLM Scint: #DeltaT_{0} vs variance weight;v = 1/N^{+} + 1/N^{-};#DeltaT_{0} [ns]",
489 50, 0, 1.0, 100, -20, 20);
490
491 // Profile: RMS(ΔT0) vs v (should scale as √v if model is correct)
492 prof_deltaT0_rms_vs_v_rpc = new TProfile("prof_deltaT0_rms_vs_v_rpc",
493 "RPC: RMS(#DeltaT_{0}) vs v;v = 1/N^{+} + 1/N^{-};RMS(#DeltaT_{0}) [ns]",
494 20, 0, 2.0, "s"); // "s" option for RMS
495 prof_deltaT0_rms_vs_v_scint = new TProfile("prof_deltaT0_rms_vs_v_scint",
496 "BKLM Scint: RMS(#DeltaT_{0}) vs v;v = 1/N^{+} + 1/N^{-};RMS(#DeltaT_{0}) [ns]",
497 20, 0, 1.0, "s");
498 prof_deltaT0_rms_vs_v_scint_end = new TProfile("prof_deltaT0_rms_vs_v_scint_end",
499 "EKLM Scint: RMS(#DeltaT_{0}) vs v;v = 1/N^{+} + 1/N^{-};RMS(#DeltaT_{0}) [ns]",
500 20, 0, 1.0, "s");
501
502 // ΔT0 vs total hits
503 h2_deltaT0_vs_nhits_rpc = new TH2F("h2_deltaT0_vs_nhits_rpc",
504 "RPC: #DeltaT_{0} vs total hits;N^{+} + N^{-};#DeltaT_{0} [ns]",
505 50, 0, 200, 100, -40, 40);
506 h2_deltaT0_vs_nhits_scint = new TH2F("h2_deltaT0_vs_nhits_scint",
507 "BKLM Scint: #DeltaT_{0} vs total hits;N^{+} + N^{-};#DeltaT_{0} [ns]",
508 40, 0, 40, 100, -40, 40);
509 h2_deltaT0_vs_nhits_scint_end = new TH2F("h2_deltaT0_vs_nhits_scint_end",
510 "EKLM Scint: #DeltaT_{0} vs total hits;N^{+} + N^{-};#DeltaT_{0} [ns]",
511 40, 0, 40, 100, -20, 20);
512
513 // ΔT0 separated by hit multiplicity bins
514 hc_eventT0_rpc_lowN = new TH1F("hc_eventT0_rpc_lowN",
515 "RPC: #DeltaT_{0} (N^{+}+N^{-} < 10);#DeltaT_{0} [ns]", nBin_t0, -40.0, 40.0);
516 hc_eventT0_rpc_midN = new TH1F("hc_eventT0_rpc_midN",
517 "RPC: #DeltaT_{0} (10 #leq N^{+}+N^{-} < 30);#DeltaT_{0} [ns]", nBin_t0, -40.0, 40.0);
518 hc_eventT0_rpc_highN = new TH1F("hc_eventT0_rpc_highN",
519 "RPC: #DeltaT_{0} (N^{+}+N^{-} #geq 30);#DeltaT_{0} [ns]", nBin_t0, -40.0, 40.0);
520
521 hc_eventT0_scint_lowN = new TH1F("hc_eventT0_scint_lowN",
522 "BKLM Scint: #DeltaT_{0} (N^{+}+N^{-} < 5);#DeltaT_{0} [ns]", nBin_t0, -40.0, 40.0);
523 hc_eventT0_scint_midN = new TH1F("hc_eventT0_scint_midN",
524 "BKLM Scint: #DeltaT_{0} (5 #leq N^{+}+N^{-} < 15);#DeltaT_{0} [ns]", nBin_t0, -40.0, 40.0);
525 hc_eventT0_scint_highN = new TH1F("hc_eventT0_scint_highN",
526 "BKLM Scint: #DeltaT_{0} (N^{+}+N^{-} #geq 15);#DeltaT_{0} [ns]", nBin_t0, -40.0, 40.0);
527
528 hc_eventT0_scint_end_lowN = new TH1F("hc_eventT0_scint_end_lowN",
529 "EKLM Scint: #DeltaT_{0} (N^{+}+N^{-} < 5);#DeltaT_{0} [ns]", nBin_t0, -20.0, 20.0);
530 hc_eventT0_scint_end_midN = new TH1F("hc_eventT0_scint_end_midN",
531 "EKLM Scint: #DeltaT_{0} (5 #leq N^{+}+N^{-} < 15);#DeltaT_{0} [ns]", nBin_t0, -20.0, 20.0);
532 hc_eventT0_scint_end_highN = new TH1F("hc_eventT0_scint_end_highN",
533 "EKLM Scint: #DeltaT_{0} (N^{+}+N^{-} #geq 15);#DeltaT_{0} [ns]", nBin_t0, -20.0, 20.0);
534
535 if (!m_saveAllPlots) {
536 B2INFO("Skipping debug histogram allocation (m_saveAllPlots = false)");
537 return; // Skip all debugging histogram allocation
538 }
539
540 for (int iF = 0; iF < 2; ++iF) {
541 hn = Form("h_timeF%d_rpc", iF);
542 ht = Form("Time distribution for RPC of %s; T_rec-T_0-T_fly-T_propagation[ns]", iFstring[iF].Data());
543 h_timeF_rpc[iF] = new TH1F(hn.Data(), ht.Data(), nBin, m_LowerTimeBoundaryRPC, m_UpperTimeBoundaryRPC);
544 hn = Form("h_timeF%d_scint", iF);
545 ht = Form("Time distribution for Scintillator of %s; T_rec-T_0-T_fly-T_propagation[ns]", iFstring[iF].Data());
546 h_timeF_scint[iF] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryScintillatorsBKLM,
548 hn = Form("h_timeF%d_scint_end", iF);
549 ht = Form("Time distribution for Scintillator of %s (Endcap); T_rec-T_0-T_fly-T_propagation[ns]", iFstring[iF].Data());
550 h_timeF_scint_end[iF] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryScintillatorsEKLM,
552
553 hn = Form("h2_timeF%d_rpc", iF);
554 ht = Form("Time distribution for RPC of %s; Sector Index; T_rec-T_0-T_fly-T_propagation[ns]", iFstring[iF].Data());
555 h2_timeF_rpc[iF] = new TH2F(hn.Data(), ht.Data(), 8, 0, 8, nBin, m_LowerTimeBoundaryRPC, m_UpperTimeBoundaryRPC);
556 hn = Form("h2_timeF%d_scint", iF);
557 ht = Form("Time distribution for Scintillator of %s; Sector Index; T_rec-T_0-T_fly-T_propagation[ns]", iFstring[iF].Data());
558 h2_timeF_scint[iF] = new TH2F(hn.Data(), ht.Data(), 8, 0, 8, nBin_scint, m_LowerTimeBoundaryScintillatorsBKLM,
560 hn = Form("h2_timeF%d_scint_end", iF);
561 ht = Form("Time distribution for Scintillator of %s (Endcap); Sector Index; T_rec-T_0-T_fly-T_propagation[ns]",
562 iFstring[iF].Data());
563 h2_timeF_scint_end[iF] = new TH2F(hn.Data(), ht.Data(), 4, 0, 4, nBin_scint, m_LowerTimeBoundaryScintillatorsEKLM,
565
566 hn = Form("hc_timeF%d_rpc", iF);
567 ht = Form("Calibrated time distribution for RPC of %s; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]", iFstring[iF].Data());
568 hc_timeF_rpc[iF] = new TH1F(hn.Data(), ht.Data(), nBin, m_LowerTimeBoundaryCalibratedRPC, m_UpperTimeBoundaryCalibratedRPC);
569 hn = Form("hc_timeF%d_scint", iF);
570 ht = Form("Calibrated time distribution for Scintillator of %s; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]",
571 iFstring[iF].Data());
572 hc_timeF_scint[iF] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryCalibratedScintillatorsBKLM,
574 hn = Form("hc_timeF%d_scint_end", iF);
575 ht = Form("Calibrated time distribution for Scintillator of %s (Endcap); T_rec-T_0-T_fly-T_propagation-T_calibration[ns]",
576 iFstring[iF].Data());
577 hc_timeF_scint_end[iF] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryCalibratedScintillatorsEKLM,
579
580 hn = Form("h2c_timeF%d_rpc", iF);
581 ht = Form("Calibrated time distribution for RPC of %s; Sector Index; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]",
582 iFstring[iF].Data());
583 h2c_timeF_rpc[iF] = new TH2F(hn.Data(), ht.Data(), 8, 0, 8, nBin, m_LowerTimeBoundaryCalibratedRPC,
585 hn = Form("h2c_timeF%d_scint", iF);
586 ht = Form("Calibrated time distribution for Scintillator of %s; Sector Index; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]",
587 iFstring[iF].Data());
588 h2c_timeF_scint[iF] = new TH2F(hn.Data(), ht.Data(), 8, 0, 8, nBin_scint, m_LowerTimeBoundaryCalibratedScintillatorsBKLM,
590 hn = Form("h2c_timeF%d_scint_end", iF);
591 ht = Form("Calibrated time distribution for Scintillator of %s (Endcap) ; Sector Index; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]",
592 iFstring[iF].Data());
593 h2c_timeF_scint_end[iF] = new TH2F(hn.Data(), ht.Data(), 4, 0, 4, nBin_scint, m_LowerTimeBoundaryCalibratedScintillatorsEKLM,
595
596 for (int iS = 0; iS < 8; ++iS) {
597 // Barrel parts
598 hn = Form("h_timeF%d_S%d_scint", iF, iS);
599 ht = Form("Time distribution for Scintillator of Sector%d, %s; T_rec-T_0-T_fly-T_propagation[ns]", iS, iFstring[iF].Data());
600 h_timeFS_scint[iF][iS] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryScintillatorsBKLM,
602 hn = Form("h_timeF%d_S%d_rpc", iF, iS);
603 ht = Form("Time distribution for RPC of Sector%d, %s; T_rec-T_0-T_fly-T_propagation[ns]", iS, iFstring[iF].Data());
604 h_timeFS_rpc[iF][iS] = new TH1F(hn.Data(), ht.Data(), nBin, m_LowerTimeBoundaryRPC, m_UpperTimeBoundaryRPC);
605 hn = Form("h2_timeF%d_S%d", iF, iS);
606 ht = Form("Time distribution of Sector%d, %s; Layer Index; T_rec-T_0-T_fly-T_propagation[ns]", iS, iFstring[iF].Data());
607 h2_timeFS[iF][iS] = new TH2F(hn.Data(), ht.Data(), 15, 0, 15, nBin_scint, m_LowerTimeBoundaryRPC,
609
610 hn = Form("hc_timeF%d_S%d_scint", iF, iS);
611 ht = Form("Calibrated time distribution for Scintillator of Sector%d, %s; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]", iS,
612 iFstring[iF].Data());
613 hc_timeFS_scint[iF][iS] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryCalibratedScintillatorsBKLM,
615 hn = Form("hc_timeF%d_S%d_rpc", iF, iS);
616 ht = Form("Calibrated time distribution for RPC of Sector%d, %s; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]", iS,
617 iFstring[iF].Data());
618 hc_timeFS_rpc[iF][iS] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryCalibratedRPC,
620 hn = Form("h2c_timeF%d_S%d", iF, iS);
621 ht = Form("Calibrated time distribution of Sector%d, %s; Layer Index; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]", iS,
622 iFstring[iF].Data());
623 h2c_timeFS[iF][iS] = new TH2F(hn.Data(), ht.Data(), 15, 0, 15, nBin_scint, m_LowerTimeBoundaryCalibratedRPC,
625
626 // Inner 2 layers --> Scintillators
627 for (int iL = 0; iL < 2; ++iL) {
628 hn = Form("h_timeF%d_S%d_L%d", iF, iS, iL);
629 ht = Form("Time distribution for Scintillator of Layer%d, Sector%d, %s; T_rec-T_0-T_fly-T_propagation[ns]", iL, iS,
630 iFstring[iF].Data());
631 h_timeFSL[iF][iS][iL] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryScintillatorsBKLM,
633 hn = Form("hc_timeF%d_S%d_L%d", iF, iS, iL);
634 ht = Form("Calibrated time distribution for Scintillator of Layer%d, Sector%d, %s; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]",
635 iL, iS, iFstring[iF].Data());
636 hc_timeFSL[iF][iS][iL] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryCalibratedScintillatorsBKLM,
638
639 for (int iP = 0; iP < 2; ++iP) {
640 hn = Form("h_timeF%d_S%d_L%d_P%d", iF, iS, iL, iP);
641 ht = Form("Time distribution for Scintillator of %s, Layer%d, Sector%d, %s; T_rec-T_0-T_fly-T_propagation[ns]",
642 iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
643 h_timeFSLP[iF][iS][iL][iP] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryScintillatorsBKLM,
645 hn = Form("h2_timeF%d_S%d_L%d_P%d", iF, iS, iL, iP);
646 ht = Form("Time distribution for Scintillator of %s, Layer%d, Sector%d, %s; Channel Index; T_rec-T_0-T_fly-T_propagation[ns]",
647 iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
648 h2_timeFSLP[iF][iS][iL][iP] = new TH2F(hn.Data(), ht.Data(), 54, 0, 54, nBin_scint, m_LowerTimeBoundaryScintillatorsBKLM,
650
651 hn = Form("hc_timeF%d_S%d_L%d_P%d", iF, iS, iL, iP);
652 ht = Form("Calibrated time distribution for Scintillator of %s, Layer%d, Sector%d, %s; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]",
653 iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
654 hc_timeFSLP[iF][iS][iL][iP] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryCalibratedScintillatorsBKLM,
656 hn = Form("h2c_timeF%d_S%d_L%d_P%d", iF, iS, iL, iP);
657 ht = Form("Calibrated time distribution for Scintillator of %s, Layer%d, Sector%d, %s; Channel Index; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]",
658 iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
659 h2c_timeFSLP[iF][iS][iL][iP] = new TH2F(hn.Data(), ht.Data(), 54, 0, 54, nBin_scint, m_LowerTimeBoundaryCalibratedScintillatorsBKLM,
661 }
662 }
663
664 for (int iL = 2; iL < 15; ++iL) {
665 hn = Form("h_timeF%d_S%d_L%d", iF, iS, iL);
666 ht = Form("time distribution for RPC of Layer%d, Sector%d, %s; T_rec-T_0-T_fly-T_propagation[ns]", iL, iS, iFstring[iF].Data());
667 h_timeFSL[iF][iS][iL] = new TH1F(hn.Data(), ht.Data(), nBin, m_LowerTimeBoundaryRPC, m_UpperTimeBoundaryRPC);
668
669 hn = Form("hc_timeF%d_S%d_L%d", iF, iS, iL);
670 ht = Form("Calibrated time distribution for RPC of Layer%d, Sector%d, %s; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]", iL, iS,
671 iFstring[iF].Data());
672 hc_timeFSL[iF][iS][iL] = new TH1F(hn.Data(), ht.Data(), nBin, m_LowerTimeBoundaryCalibratedRPC, m_UpperTimeBoundaryCalibratedRPC);
673
674 for (int iP = 0; iP < 2; ++iP) {
675 hn = Form("h_timeF%d_S%d_L%d_P%d", iF, iS, iL, iP);
676 ht = Form("time distribution for RPC of %s, Layer%d, Sector%d, %s; T_rec-T_0-T_fly-T_propagation[ns]", iPstring[iP].Data(), iL, iS,
677 iFstring[iF].Data());
678 h_timeFSLP[iF][iS][iL][iP] = new TH1F(hn.Data(), ht.Data(), nBin, m_LowerTimeBoundaryRPC, m_UpperTimeBoundaryRPC);
679
680 hn = Form("h2_timeF%d_S%d_L%d_P%d", iF, iS, iL, iP);
681 ht = Form("time distribution for RPC of %s, Layer%d, Sector%d, %s; Channel Index; T_rec-T_0-T_fly-T_propagation[ns]",
682 iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
683 h2_timeFSLP[iF][iS][iL][iP] = new TH2F(hn.Data(), ht.Data(), 48, 0, 48, nBin, m_LowerTimeBoundaryRPC, m_UpperTimeBoundaryRPC);
684
685 hn = Form("hc_timeF%d_S%d_L%d_P%d", iF, iS, iL, iP);
686 ht = Form("Calibrated time distribution for RPC of %s, Layer%d, Sector%d, %s; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]",
687 iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
688 hc_timeFSLP[iF][iS][iL][iP] = new TH1F(hn.Data(), ht.Data(), nBin, m_LowerTimeBoundaryCalibratedRPC,
690
691 hn = Form("h2c_timeF%d_S%d_L%d_P%d", iF, iS, iL, iP);
692 ht = Form("Calibrated time distribution for RPC of %s, Layer%d, Sector%d, %s; Channel Index; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]",
693 iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
694 h2c_timeFSLP[iF][iS][iL][iP] = new TH2F(hn.Data(), ht.Data(), 48, 0, 48, nBin, m_LowerTimeBoundaryCalibratedRPC,
696 }
697 }
698 }
699 // Endcap part
700 int maxLay = 12 + 2 * iF;
701 for (int iS = 0; iS < 4; ++iS) {
702 hn = Form("h_timeF%d_S%d_scint_end", iF, iS);
703 ht = Form("Time distribution for Scintillator of Sector%d, %s (Endcap); T_rec-T_0-T_fly-T_propagation[ns]", iS,
704 iFstring[iF].Data());
705 h_timeFS_scint_end[iF][iS] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryScintillatorsEKLM,
707 hn = Form("h2_timeF%d_S%d_end", iF, iS);
708 ht = Form("Time distribution of Sector%d, %s (Endcap); Layer Index; T_rec-T_0-T_fly-T_propagation[ns]", iS, iFstring[iF].Data());
709 h2_timeFS_end[iF][iS] = new TH2F(hn.Data(), ht.Data(), maxLay, 0, maxLay, nBin_scint, m_LowerTimeBoundaryScintillatorsEKLM,
711 hn = Form("hc_timeF%d_S%d_scint_end", iF, iS);
712 ht = Form("Calibrated time distribution for Scintillator of Sector%d (Endcap), %s; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]",
713 iS, iFstring[iF].Data());
714 hc_timeFS_scint_end[iF][iS] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryCalibratedScintillatorsEKLM,
716 hn = Form("h2c_timeF%d_S%d_end", iF, iS);
717 ht = Form("Calibrated time distribution of Sector%d, %s (Endcap); Layer Index; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]",
718 iS, iFstring[iF].Data());
719 h2c_timeFS_end[iF][iS] = new TH2F(hn.Data(), ht.Data(), maxLay, 0, maxLay, nBin_scint,
722
723 for (int iL = 0; iL < maxLay; ++iL) {
724 hn = Form("h_timeF%d_S%d_L%d_end", iF, iS, iL);
725 ht = Form("Time distribution for Scintillator of Layer%d, Sector%d, %s (Endcap); T_rec-T_0-T_fly-T_propagation[ns]", iL, iS,
726 iFstring[iF].Data());
727 h_timeFSL_end[iF][iS][iL] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryScintillatorsEKLM,
729 hn = Form("hc_timeF%d_S%d_L%d_end", iF, iS, iL);
730 ht = Form("Calibrated time distribution for Scintillator of Layer%d, Sector%d, %s (Endcap); T_rec-T_0-T_fly-T_propagation-T_calibration[ns]",
731 iL, iS, iFstring[iF].Data());
732 hc_timeFSL_end[iF][iS][iL] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryCalibratedScintillatorsEKLM,
734
735 for (int iP = 0; iP < 2; ++iP) {
736 hn = Form("h_timeF%d_S%d_L%d_P%d_end", iF, iS, iL, iP);
737 ht = Form("Time distribution for Scintillator of %s, Layer%d, Sector%d, %s (Endcap); T_rec-T_0-T_fly-T_propagation[ns]",
738 iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
739 h_timeFSLP_end[iF][iS][iL][iP] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryScintillatorsEKLM,
741
742 hn = Form("h2_timeF%d_S%d_L%d_P%d_end", iF, iS, iL, iP);
743 ht = Form("Time distribution for Scintillator of %s, Layer%d, Sector%d, %s (Endcap); Channel Index; T_rec-T_0-T_fly-T_propagation[ns]",
744 iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
745 h2_timeFSLP_end[iF][iS][iL][iP] = new TH2F(hn.Data(), ht.Data(), 75, 0, 75, nBin_scint, m_LowerTimeBoundaryScintillatorsEKLM,
747
748 hn = Form("hc_timeF%d_S%d_L%d_P%d_end", iF, iS, iL, iP);
749 ht = Form("Calibrated time distribution for Scintillator of %s, Layer%d, Sector%d, %s (Endcap); T_rec-T_0-T_fly-T_propagation-T_calibration[ns]",
750 iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
751 hc_timeFSLP_end[iF][iS][iL][iP] = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryCalibratedScintillatorsEKLM,
753
754 hn = Form("h2c_timeF%d_S%d_L%d_P%d_end", iF, iS, iL, iP);
755 ht = Form("Calibrated time distribution for Scintillator of %s, Layer%d, Sector%d, %s (Endcap); Channel Index; T_rec-T_0-T_fly-T_propagation-T_calibration[ns]",
756 iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
757 h2c_timeFSLP_end[iF][iS][iL][iP] = new TH2F(hn.Data(), ht.Data(), 75, 0, 75, nBin_scint,
760 }
761 }
762 }
763 }
764
765 // NOTE: Directory structure for per-channel histograms is created in createHistograms()
766 // because m_outFile is not yet created when setupDatabase() is called.
767}
768
770 TProfile* profileRpcPhi, TProfile* profileRpcZ,
771 TProfile* profileBKLMScintillatorPhi, TProfile* profileBKLMScintillatorZ,
772 TProfile* profileEKLMScintillatorPlane1,
773 TProfile* profileEKLMScintillatorPlane2, bool fill2dHistograms)
774{
775 B2INFO("Filling time-distance profiles" << (fill2dHistograms ? " with 2D histograms" : "") << " (batched processing)...");
776
777 TString iFstring[2] = {"Backward", "Forward"};
778 TString iPstring[2] = {"ZReadout", "PhiReadout"};
779
780 // Define the 6 batches (same as in calibrate())
781 auto isRPCBackward = [](const KLMChannelIndex & ch) {
782 return ch.getSubdetector() == KLMElementNumbers::c_BKLM &&
783 ch.getLayer() >= BKLMElementNumbers::c_FirstRPCLayer &&
784 ch.getSection() == BKLMElementNumbers::c_BackwardSection;
785 };
786
787 auto isRPCForward = [](const KLMChannelIndex & ch) {
788 return ch.getSubdetector() == KLMElementNumbers::c_BKLM &&
789 ch.getLayer() >= BKLMElementNumbers::c_FirstRPCLayer &&
790 ch.getSection() == BKLMElementNumbers::c_ForwardSection;
791 };
792
793 auto isBKLMScintillatorBackward = [](const KLMChannelIndex & ch) {
794 return ch.getSubdetector() == KLMElementNumbers::c_BKLM &&
795 ch.getLayer() < BKLMElementNumbers::c_FirstRPCLayer &&
796 ch.getSection() == BKLMElementNumbers::c_BackwardSection;
797 };
798
799 auto isBKLMScintillatorForward = [](const KLMChannelIndex & ch) {
800 return ch.getSubdetector() == KLMElementNumbers::c_BKLM &&
801 ch.getLayer() < BKLMElementNumbers::c_FirstRPCLayer &&
802 ch.getSection() == BKLMElementNumbers::c_ForwardSection;
803 };
804
805 auto isEKLMScintillatorBackward = [](const KLMChannelIndex & ch) {
806 return ch.getSubdetector() == KLMElementNumbers::c_EKLM &&
807 ch.getSection() == EKLMElementNumbers::c_BackwardSection;
808 };
809
810 auto isEKLMScintillatorForward = [](const KLMChannelIndex & ch) {
811 return ch.getSubdetector() == KLMElementNumbers::c_EKLM &&
812 ch.getSection() == EKLMElementNumbers::c_ForwardSection;
813 };
814
815 std::vector<std::pair<std::string, std::function<bool(const KLMChannelIndex&)>>> batches = {
816 {"RPC Backward", isRPCBackward},
817 {"RPC Forward", isRPCForward},
818 {"BKLM Scintillator Backward", isBKLMScintillatorBackward},
819 {"BKLM Scintillator Forward", isBKLMScintillatorForward},
820 {"EKLM Scintillator Backward", isEKLMScintillatorBackward},
821 {"EKLM Scintillator Forward", isEKLMScintillatorForward}
822 };
823
824 // Process each batch
825 for (const auto& batch : batches) {
826 B2INFO("Processing batch for profiles: " << batch.first);
827 readCalibrationDataBatch(batch.second);
828
829 // Temporary storage for per-channel 2D histograms (only if fill2dHistograms is true)
830 // Store pairs of (histogram, target directory) so we can write to correct folder
831 std::map<KLMChannelNumber, std::pair<TH2F*, TDirectory*>> tempHistBKLM;
832 std::map<KLMChannelNumber, std::pair<TH2F*, TDirectory*>> tempHistEKLM;
833
834 for (KLMChannelIndex klmChannel = m_klmChannels.begin(); klmChannel != m_klmChannels.end(); ++klmChannel) {
835 KLMChannelNumber channel = klmChannel.getKLMChannelNumber();
836
837 // Skip if not in current batch
838 if (!batch.second(klmChannel))
839 continue;
840
841 if (m_cFlag[channel] == ChannelCalibrationStatus::c_NotEnoughData)
842 continue;
843
844 if (m_evts.find(channel) == m_evts.end())
845 continue;
846
847 std::vector<struct Event> eventsChannel = m_evts[channel];
848 int iSub = klmChannel.getSubdetector();
849
850 // Create 2D histogram for this channel if needed
851 TH2F* hist2d = nullptr;
852 if (fill2dHistograms) {
853 if (iSub == KLMElementNumbers::c_BKLM) {
854 int iL = klmChannel.getLayer() - 1;
855
856 // Only create for scintillators (layers 0-1)
857 if (iL < 2) {
858 int iF = klmChannel.getSection();
859 int iS = klmChannel.getSector() - 1;
860 int iP = klmChannel.getPlane();
861 int iC = klmChannel.getStrip() - 1;
862 TString hn = Form("time_length_bklm_F%d_S%d_L%d_P%d_C%d", iF, iS, iL, iP, iC);
863 double stripLength = 200;
864 hist2d = new TH2F(hn.Data(),
865 "Time versus propagation length; "
866 "propagation distance[cm]; "
867 "T_rec-T_0-T_fly-'T_calibration'[ns]",
868 50, 0.0, stripLength,
871 tempHistBKLM[channel] = std::make_pair(hist2d, m_channelHistDir_BKLM[iF][iS][iL][iP]);
872 }
873 } else { // EKLM
874 int iF = klmChannel.getSection() - 1;
875 int iS = klmChannel.getSector() - 1;
876 int iL = klmChannel.getLayer() - 1;
877 int iP = klmChannel.getPlane() - 1;
878 int iC = klmChannel.getStrip() - 1;
879
880 TString hn = Form("time_length_eklm_F%d_S%d_L%d_P%d_C%d", iF, iS, iL, iP, iC);
881 double stripLength = m_EKLMGeometry->getStripLength(iC + 1) / CLHEP::cm * Unit::cm;
882 hist2d = new TH2F(hn.Data(),
883 "Time versus propagation length; "
884 "propagation distance[cm]; "
885 "T_rec-T_0-T_fly-'T_calibration'[ns]",
886 50, 0.0, stripLength,
889 tempHistEKLM[channel] = std::make_pair(hist2d, m_channelHistDir_EKLM[iF][iS][iL][iP]);
890 }
891 }
892
893 // Fill histograms
894 for (const Event& event : eventsChannel) {
895 double timeHit = event.time() - m_timeShift[channel];
896 if (m_useEventT0)
897 timeHit = timeHit - event.t0;
898 double distHit = event.dist;
899
900 if (timeHit <= -400e3)
901 continue;
902
903 if (iSub == KLMElementNumbers::c_BKLM) {
904 int iL = klmChannel.getLayer() - 1;
905 int iP = klmChannel.getPlane();
906
907 if (iL > 1) {
908 // RPC
909 if (iP) {
910 profileRpcPhi->Fill(distHit, timeHit);
911 } else {
912 profileRpcZ->Fill(distHit, timeHit);
913 }
914 } else {
915 // Scintillator
917 uint16_t Charge = event.getADCcount;
918 if (Charge <= 30 || Charge >= 320) {
919 continue;
920 }
921 }
922
923 if (hist2d)
924 hist2d->Fill(distHit, timeHit);
925
926 if (iP) {
927 profileBKLMScintillatorPhi->Fill(distHit, timeHit);
928 } else {
929 profileBKLMScintillatorZ->Fill(distHit, timeHit);
930 }
931 }
932 } else {
933 // EKLM
935 uint16_t Charge = event.getADCcount;
936 if (Charge <= 40 || Charge >= 350) {
937 continue;
938 }
939 }
940
941 int iP = klmChannel.getPlane() - 1;
942
943 if (hist2d)
944 hist2d->Fill(distHit, timeHit);
945
946 if (iP) {
947 profileEKLMScintillatorPlane1->Fill(distHit, timeHit);
948 } else {
949 profileEKLMScintillatorPlane2->Fill(distHit, timeHit);
950 }
951 }
952 }
953 }
954
955 // Write and delete 2D histograms for this batch
956 // Use m_saveChannelHists (not m_saveAllPlots) since these are per-channel histograms
957 // and the directories are created based on m_saveChannelHists
958 if (fill2dHistograms) {
959 for (auto& entry : tempHistBKLM) {
960 writeThenDelete_(entry.second.first, m_saveChannelHists, entry.second.second);
961 }
962 for (auto& entry : tempHistEKLM) {
963 writeThenDelete_(entry.second.first, m_saveChannelHists, entry.second.second);
964 }
965 }
966
967 m_evts.clear();
968 B2INFO("Batch processed and cleared: " << batch.first);
969 }
970
971 B2INFO("Time-distance profile filling complete.");
972}
973
975 const std::vector< std::pair<KLMChannelNumber, unsigned int> >& channels,
976 double& delay, double& delayError)
977{
978 int nFits = 1000;
979 int nConvergedFits = 0;
980 delay = 0;
981 delayError = 0;
982 if (nFits > (int)channels.size())
983 nFits = channels.size();
984 for (int i = 0; i < nFits; ++i) {
985 int subdetector, section, sector, layer, plane, strip;
986 m_ElementNumbers->channelNumberToElementNumbers(
987 channels[i].first, &subdetector, &section, &sector, &layer, &plane,
988 &strip);
989 if (subdetector == KLMElementNumbers::c_BKLM) {
990 s_LowerTimeBoundary = m_LowerTimeBoundaryScintillatorsBKLM;
991 s_UpperTimeBoundary = m_UpperTimeBoundaryScintillatorsBKLM;
992 const bklm::Module* module =
993 m_BKLMGeometry->findModule(section, sector, layer);
994 s_StripLength = module->getStripLength(plane, strip);
995 } else {
996 s_LowerTimeBoundary = m_LowerTimeBoundaryScintillatorsEKLM;
997 s_UpperTimeBoundary = m_UpperTimeBoundaryScintillatorsEKLM;
998 s_StripLength = m_EKLMGeometry->getStripLength(strip) /
999 CLHEP::cm * Unit::cm;
1000 }
1001 for (int j = 0; j < c_NBinsTime; ++j) {
1002 for (int k = 0; k < c_NBinsDistance; ++k)
1003 s_BinnedData[j][k] = 0;
1004 }
1005 std::vector<struct Event> eventsChannel = m_evts[channels[i].first];
1006 double averageTime = 0;
1007 for (const Event& event : eventsChannel) {
1008 double timeHit = event.time();
1009 if (m_useEventT0)
1010 timeHit = timeHit - event.t0;
1011
1012 if (timeHit <= -400e3) {
1013 continue;
1014 }
1015
1016 averageTime = averageTime + timeHit;
1017 int timeBin = std::floor((timeHit - s_LowerTimeBoundary) * c_NBinsTime /
1018 (s_UpperTimeBoundary - s_LowerTimeBoundary));
1019 if (timeBin < 0 || timeBin >= c_NBinsTime)
1020 continue;
1021 int distanceBin = std::floor(event.dist * c_NBinsDistance / s_StripLength);
1022 if (distanceBin < 0 || distanceBin >= c_NBinsDistance) {
1023 B2ERROR("The distance to SiPM is greater than the strip length.");
1024 continue;
1025 }
1026 s_BinnedData[timeBin][distanceBin] += 1;
1027 }
1028 averageTime = averageTime / eventsChannel.size();
1029 TMinuit minuit(5);
1030 minuit.SetPrintLevel(-1);
1031 int minuitResult;
1032 minuit.mnparm(0, "P0", 1, 0.001, 0, 0, minuitResult);
1033 minuit.mnparm(1, "N", 10, 0.001, 0, 0, minuitResult);
1034 minuit.mnparm(2, "T0", averageTime, 0.001, 0, 0, minuitResult);
1035 minuit.mnparm(3, "SIGMA", 10, 0.001, 0, 0, minuitResult);
1036 minuit.mnparm(4, "DELAY", 0.0, 0.001, 0, 0, minuitResult);
1037 minuit.SetFCN(fcn);
1038 minuit.mncomd("FIX 2 3 4 5", minuitResult);
1039 minuit.mncomd("MIGRAD 10000", minuitResult);
1040 minuit.mncomd("RELEASE 2", minuitResult);
1041 minuit.mncomd("MIGRAD 10000", minuitResult);
1042 minuit.mncomd("RELEASE 3", minuitResult);
1043 minuit.mncomd("MIGRAD 10000", minuitResult);
1044 minuit.mncomd("RELEASE 4", minuitResult);
1045 minuit.mncomd("MIGRAD 10000", minuitResult);
1046 minuit.mncomd("RELEASE 5", minuitResult);
1047 minuit.mncomd("MIGRAD 10000", minuitResult);
1048 /* Require converged fit with accurate error matrix. */
1049 if (minuit.fISW[1] != 3)
1050 continue;
1051 nConvergedFits++;
1052 double channelDelay, channelDelayError;
1053 minuit.GetParameter(4, channelDelay, channelDelayError);
1054 delay = delay + channelDelay;
1055 delayError = delayError + channelDelayError * channelDelayError;
1056 }
1057 delay = delay / nConvergedFits;
1058 delayError = sqrt(delayError) / (nConvergedFits - 1);
1059}
1060
1061void KLMTimeAlgorithm::writeThenDelete_(TH1* h, bool write, TDirectory* dir)
1062{
1063 if (h == nullptr)
1064 return;
1065 if (write && m_outFile) {
1066 // Follow the pattern from saveHist(): cd into directory, then SetDirectory, then Write
1067 if (dir) {
1068 dir->cd();
1069 h->SetDirectory(dir);
1070 } else {
1071 m_outFile->cd();
1072 h->SetDirectory(m_outFile);
1073 }
1074 h->Write();
1075 m_outFile->cd(); // Return to root directory
1076 }
1077 delete h;
1078}
1079
1080void KLMTimeAlgorithm::writeThenDelete_(TH2* h, bool write, TDirectory* dir)
1081{
1082 if (h == nullptr)
1083 return;
1084 if (write && m_outFile) {
1085 // Follow the pattern from saveHist(): cd into directory, then SetDirectory, then Write
1086 if (dir) {
1087 dir->cd();
1088 h->SetDirectory(dir);
1089 } else {
1090 m_outFile->cd();
1091 h->SetDirectory(m_outFile);
1092 }
1093 h->Write();
1094 m_outFile->cd(); // Return to root directory
1095 }
1096 delete h;
1097}
1098
1099bool KLMTimeAlgorithm::passesADCCut(const Event& event, int subdetector, int layer_0indexed) const
1100{
1101 // If charge restriction is disabled, accept all hits
1103 return true;
1104 }
1105
1106 uint16_t charge = event.getADCcount;
1107
1108 if (subdetector == KLMElementNumbers::c_BKLM) {
1109 // FIXED: Use constant for RPC check (0-indexed comparison)
1110 if (layer_0indexed >= (BKLMElementNumbers::c_FirstRPCLayer - 1)) {
1111 return true; // RPC - no ADC cut
1112 } else {
1113 return (charge > 30 && charge < 320); // Scintillator
1114 }
1115 } else {
1116 return (charge > 40 && charge < 350); // EKLM
1117 }
1118}
1119
1121{
1122 int channelId;
1123 gROOT->SetBatch(kTRUE);
1124 setupDatabase();
1129
1130 fcn_gaus = new TF1("fcn_gaus", "gaus");
1131 fcn_land = new TF1("fcn_land", "landau");
1132 fcn_pol1 = new TF1("fcn_pol1", "pol1");
1133 fcn_const = new TF1("fcn_const", "pol0");
1134
1135 // Initial validation only - DON'T load all data yet
1137 if (result != CalibrationAlgorithm::c_OK)
1138 return result;
1139
1140 /* Choose non-existing file name. */
1141 std::string name = "time_calibration.root";
1142 int i = 1;
1143 while (1) {
1144 struct stat buffer;
1145 if (stat(name.c_str(), &buffer) != 0)
1146 break;
1147 name = "time_calibration_" + std::to_string(i) + ".root";
1148 i = i + 1;
1149 if (i < 0)
1150 break;
1151 }
1152 m_outFile = new TFile(name.c_str(), "recreate");
1154
1155 std::vector<struct Event> eventsChannel;
1156 eventsChannel.clear();
1157 m_cFlag.clear();
1158 m_minimizerOptions.SetDefaultStrategy(2);
1159
1160 B2INFO("Counting events per channel...");
1161 std::map<KLMChannelNumber, unsigned int> eventCounts;
1162 readCalibrationDataCounts(eventCounts);
1163
1164 /* Sort channels by number of events and initialize flags. */
1165 std::vector< std::pair<KLMChannelNumber, unsigned int> > channelsBKLM;
1166 std::vector< std::pair<KLMChannelNumber, unsigned int> > channelsEKLM;
1167 KLMChannelIndex klmChannels;
1168
1169 for (const KLMChannelIndex& klmChannel : klmChannels) {
1170 KLMChannelNumber channel = klmChannel.getKLMChannelNumber();
1171 m_cFlag[channel] = ChannelCalibrationStatus::c_NotEnoughData;
1172
1173 if (eventCounts.find(channel) == eventCounts.end())
1174 continue;
1175
1176 int nEvents = eventCounts[channel];
1177 if (nEvents < m_lower_limit_counts) {
1178 B2WARNING("Not enough calibration data collected."
1179 << LogVar("channel", channel)
1180 << LogVar("number of digit", nEvents));
1181 continue;
1182 }
1183
1184 m_cFlag[channel] = ChannelCalibrationStatus::c_FailedFit;
1185
1186 if (klmChannel.getSubdetector() == KLMElementNumbers::c_BKLM &&
1187 klmChannel.getLayer() < BKLMElementNumbers::c_FirstRPCLayer) {
1188 channelsBKLM.push_back(std::pair<KLMChannelNumber, unsigned int>(channel, nEvents));
1189 }
1190 if (klmChannel.getSubdetector() == KLMElementNumbers::c_EKLM) {
1191 channelsEKLM.push_back(std::pair<KLMChannelNumber, unsigned int>(channel, nEvents));
1192 }
1193 }
1194
1195 std::sort(channelsBKLM.begin(), channelsBKLM.end(), compareEventNumber);
1196 std::sort(channelsEKLM.begin(), channelsEKLM.end(), compareEventNumber);
1197
1198 /* Two-dimensional fit using top channels only. */
1199 double delayBKLM, delayBKLMError;
1200 double delayEKLM, delayEKLMError;
1201
1202 /* Load data for 2D fit channels only. */
1203 readCalibrationDataFor2DFit(channelsBKLM, channelsEKLM);
1204 timeDistance2dFit(channelsBKLM, delayBKLM, delayBKLMError);
1205 timeDistance2dFit(channelsEKLM, delayEKLM, delayEKLMError);
1206 m_evts.clear();
1207
1208 B2INFO("2D fits complete, data cleared.");
1209
1210 /* Define processing batches for channel calibration. */
1211 auto isRPCBackward = [](const KLMChannelIndex & ch) {
1212 return ch.getSubdetector() == KLMElementNumbers::c_BKLM &&
1213 ch.getLayer() >= BKLMElementNumbers::c_FirstRPCLayer &&
1214 ch.getSection() == BKLMElementNumbers::c_BackwardSection;
1215 };
1216
1217 auto isRPCForward = [](const KLMChannelIndex & ch) {
1218 return ch.getSubdetector() == KLMElementNumbers::c_BKLM &&
1219 ch.getLayer() >= BKLMElementNumbers::c_FirstRPCLayer &&
1220 ch.getSection() == BKLMElementNumbers::c_ForwardSection;
1221 };
1222
1223 auto isBKLMScintillatorBackward = [](const KLMChannelIndex & ch) {
1224 return ch.getSubdetector() == KLMElementNumbers::c_BKLM &&
1225 ch.getLayer() < BKLMElementNumbers::c_FirstRPCLayer &&
1226 ch.getSection() == BKLMElementNumbers::c_BackwardSection;
1227 };
1228
1229 auto isBKLMScintillatorForward = [](const KLMChannelIndex & ch) {
1230 return ch.getSubdetector() == KLMElementNumbers::c_BKLM &&
1231 ch.getLayer() < BKLMElementNumbers::c_FirstRPCLayer &&
1232 ch.getSection() == BKLMElementNumbers::c_ForwardSection;
1233 };
1234
1235 auto isEKLMScintillatorBackward = [](const KLMChannelIndex & ch) {
1236 return ch.getSubdetector() == KLMElementNumbers::c_EKLM &&
1237 ch.getSection() == EKLMElementNumbers::c_BackwardSection;
1238 };
1239
1240 auto isEKLMScintillatorForward = [](const KLMChannelIndex & ch) {
1241 return ch.getSubdetector() == KLMElementNumbers::c_EKLM &&
1242 ch.getSection() == EKLMElementNumbers::c_ForwardSection;
1243 };
1244
1245 std::vector<std::pair<std::string, std::function<bool(const KLMChannelIndex&)>>> batches = {
1246 {"RPC Backward", isRPCBackward},
1247 {"RPC Forward", isRPCForward},
1248 {"BKLM Scintillator Backward", isBKLMScintillatorBackward},
1249 {"BKLM Scintillator Forward", isBKLMScintillatorForward},
1250 {"EKLM Scintillator Backward", isEKLMScintillatorBackward},
1251 {"EKLM Scintillator Forward", isEKLMScintillatorForward}
1252 };
1253
1254 /**********************************
1255 * FIRST LOOP (BATCHED)
1256 * Fill global histograms to compute global means
1257 **********************************/
1258 B2INFO("First loop: Computing global statistics (batched processing)...");
1259
1260 TString iFstring[2] = {"Backward", "Forward"};
1261 TString iPstring[2] = {"ZReadout", "PhiReadout"};
1262 int nBin = 80;
1263 int nBin_scint = 80;
1264
1265 for (const auto& batch : batches) {
1266 B2INFO("Processing batch for global stats: " << batch.first);
1267 readCalibrationDataBatch(batch.second);
1268
1269 for (KLMChannelIndex klmChannel = m_klmChannels.begin(); klmChannel != m_klmChannels.end(); ++klmChannel) {
1270 channelId = klmChannel.getKLMChannelNumber();
1271
1272 if (!batch.second(klmChannel))
1273 continue;
1274
1275 if (m_cFlag[channelId] == ChannelCalibrationStatus::c_NotEnoughData)
1276 continue;
1277
1278 if (m_evts.find(channelId) == m_evts.end())
1279 continue;
1280
1281 eventsChannel = m_evts[channelId];
1282 int iSub = klmChannel.getSubdetector();
1283 int iL = (iSub == KLMElementNumbers::c_BKLM) ? klmChannel.getLayer() - 1 : -1;
1284
1285 // Fill global histograms only
1286 for (const Event& event : eventsChannel) {
1287 // Apply ADC cut early
1288 if (!passesADCCut(event, iSub, iL))
1289 continue;
1290
1291 XYZVector diffD = XYZVector(event.diffDistX, event.diffDistY, event.diffDistZ);
1292 h_diff->Fill(diffD.R());
1293
1294 double timeHit = event.time();
1295 if (m_useEventT0)
1296 timeHit = timeHit - event.t0;
1297
1298 if (timeHit <= -400e3)
1299 continue;
1300
1301 if (iSub == KLMElementNumbers::c_BKLM) {
1302 // FIXED: Use constant instead of hardcoded value
1303 if (iL >= (BKLMElementNumbers::c_FirstRPCLayer - 1)) {
1304 h_time_rpc_tc->Fill(timeHit);
1305 } else {
1306 h_time_scint_tc->Fill(timeHit);
1307 }
1308 } else {
1309 h_time_scint_tc_end->Fill(timeHit);
1310 }
1311 }
1312 }
1313
1314 m_evts.clear();
1315 B2INFO("Batch processed and cleared: " << batch.first);
1316 }
1317
1318 // Compute global means
1319 m_timeShift.clear();
1320 double tmpMean_rpc_global = h_time_rpc_tc->GetMean();
1321 double tmpMean_scint_global = h_time_scint_tc->GetMean();
1322 double tmpMean_scint_global_end = h_time_scint_tc_end->GetMean();
1323
1324 B2INFO("Global Mean for Raw." << LogVar("RPC", tmpMean_rpc_global)
1325 << LogVar("Scint BKLM", tmpMean_scint_global)
1326 << LogVar("Scint EKLM", tmpMean_scint_global_end));
1327
1328 /**********************************
1329 * SECOND PASS (BATCHED)
1330 * Compute per-channel time shifts
1331 **********************************/
1332 B2INFO("Second pass: Computing per-channel time shifts (batched processing)...");
1333
1334 for (const auto& batch : batches) {
1335 B2INFO("Processing batch for time shifts: " << batch.first);
1336 readCalibrationDataBatch(batch.second);
1337
1338 for (KLMChannelIndex klmChannel = m_klmChannels.begin(); klmChannel != m_klmChannels.end(); ++klmChannel) {
1339 channelId = klmChannel.getKLMChannelNumber();
1340
1341 if (!batch.second(klmChannel))
1342 continue;
1343
1344 if (m_cFlag[channelId] == ChannelCalibrationStatus::c_NotEnoughData)
1345 continue;
1346
1347 if (m_evts.find(channelId) == m_evts.end())
1348 continue;
1349
1350 eventsChannel = m_evts[channelId];
1351 int iSub = klmChannel.getSubdetector();
1352 int iF, iS, iL, iP, iC;
1353
1354 if (iSub == KLMElementNumbers::c_BKLM) {
1355 iF = klmChannel.getSection();
1356 iS = klmChannel.getSector() - 1;
1357 iL = klmChannel.getLayer() - 1;
1358 iP = klmChannel.getPlane();
1359 iC = klmChannel.getStrip() - 1;
1360 } else {
1361 iF = klmChannel.getSection() - 1;
1362 iS = klmChannel.getSector() - 1;
1363 iL = klmChannel.getLayer() - 1;
1364 iP = klmChannel.getPlane() - 1;
1365 iC = klmChannel.getStrip() - 1;
1366 }
1367
1368 // Create and fill temp histogram
1369 TString hn, ht;
1370 TH1F* h_temp_tc = nullptr;
1371
1372 if (iSub == KLMElementNumbers::c_BKLM) {
1373 // FIXED: Use constant instead of hardcoded value
1374 if (iL >= (BKLMElementNumbers::c_FirstRPCLayer - 1)) {
1375 hn = Form("h_timeF%d_S%d_L%d_P%d_C%d_tc", iF, iS, iL, iP, iC);
1376 ht = Form("Time distribution for RPC of Channel%d, %s, Layer%d, Sector%d, %s",
1377 iC, iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
1378 h_temp_tc = new TH1F(hn.Data(), ht.Data(), nBin, m_LowerTimeBoundaryRPC, m_UpperTimeBoundaryRPC);
1379 } else {
1380 hn = Form("h_timeF%d_S%d_L%d_P%d_C%d_tc", iF, iS, iL, iP, iC);
1381 ht = Form("time distribution for Scintillator of Channel%d, %s, Layer%d, Sector%d, %s",
1382 iC, iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
1383 h_temp_tc = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryScintillatorsBKLM,
1385 }
1386 } else {
1387 hn = Form("h_timeF%d_S%d_L%d_P%d_C%d_tc_end", iF, iS, iL, iP, iC);
1388 ht = Form("Time distribution for Scintillator of Channel%d, %s, Layer%d, Sector%d, %s (Endcap)",
1389 iC, iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
1390 h_temp_tc = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryScintillatorsEKLM,
1392 }
1393
1394 for (const Event& event : eventsChannel) {
1395 // Add ADC cut
1396 if (!passesADCCut(event, iSub, iL))
1397 continue;
1398
1399 double timeHit = event.time();
1400 if (m_useEventT0)
1401 timeHit = timeHit - event.t0;
1402 if (timeHit <= -400e3)
1403 continue;
1404 h_temp_tc->Fill(timeHit);
1405 }
1406
1407 h_temp_tc->Fit(fcn_gaus, "LESQ");
1408 double tmpMean_channel = fcn_gaus->GetParameter(1);
1409
1410 if (iSub == KLMElementNumbers::c_BKLM) {
1411 // FIXED: Use constant instead of hardcoded value
1412 if (iL >= (BKLMElementNumbers::c_FirstRPCLayer - 1)) {
1413 m_timeShift[channelId] = tmpMean_channel - tmpMean_rpc_global;
1414 } else {
1415 m_timeShift[channelId] = tmpMean_channel - tmpMean_scint_global;
1416 }
1417 } else {
1418 m_timeShift[channelId] = tmpMean_channel - tmpMean_scint_global_end;
1419 }
1420
1421 delete h_temp_tc;
1422 }
1423
1424 m_evts.clear();
1425 B2INFO("Batch processed and cleared: " << batch.first);
1426 }
1427
1428 delete h_time_scint_tc;
1429 delete h_time_scint_tc_end;
1430 delete h_time_rpc_tc;
1431 B2INFO("Effective Light m_timeShift obtained.");
1432
1433 // NOTE: fillTimeDistanceProfiles also needs batching - user will handle separately
1438
1439 B2INFO("Effective light speed fitting.");
1440
1441 // Fit the RPC profiles (for diagnostics), but use fixed values if configured
1442 m_ProfileRpcPhi->Fit("fcn_pol1", "EMQ");
1443 double fittedDelayRPCPhi = fcn_pol1->GetParameter(1);
1444 double e_slope_rpc_phi = fcn_pol1->GetParError(1);
1445
1446 m_ProfileRpcZ->Fit("fcn_pol1", "EMQ");
1447 double fittedDelayRPCZ = fcn_pol1->GetParameter(1);
1448 double e_slope_rpc_z = fcn_pol1->GetParError(1);
1449
1450 // Use fixed RPC delay if configured (per BELLE2-NOTE-TE-2021-015: c_eff = 0.5c)
1451 double delayRPCPhi, delayRPCZ;
1452 if (m_useFixedRPCDelay) {
1453 delayRPCPhi = m_fixedRPCDelay;
1454 delayRPCZ = m_fixedRPCDelay;
1455 B2INFO("Using fixed RPC propagation delay: " << m_fixedRPCDelay << " ns/cm (c_eff = 0.5c)"
1456 << LogVar("Fitted phi (not used)", fittedDelayRPCPhi)
1457 << LogVar("Fitted Z (not used)", fittedDelayRPCZ));
1458 } else {
1459 delayRPCPhi = fittedDelayRPCPhi;
1460 delayRPCZ = fittedDelayRPCZ;
1461 }
1462
1463 m_ProfileBKLMScintillatorPhi->Fit("fcn_pol1", "EMQ");
1464 double slope_scint_phi = fcn_pol1->GetParameter(1);
1465 double e_slope_scint_phi = fcn_pol1->GetParError(1);
1466
1467 m_ProfileBKLMScintillatorZ->Fit("fcn_pol1", "EMQ");
1468 double slope_scint_z = fcn_pol1->GetParameter(1);
1469 double e_slope_scint_z = fcn_pol1->GetParError(1);
1470
1471 m_ProfileEKLMScintillatorPlane1->Fit("fcn_pol1", "EMQ");
1472 double slope_scint_plane1_end = fcn_pol1->GetParameter(1);
1473 double e_slope_scint_plane1_end = fcn_pol1->GetParError(1);
1474
1475 m_ProfileEKLMScintillatorPlane2->Fit("fcn_pol1", "EMQ");
1476 double slope_scint_plane2_end = fcn_pol1->GetParameter(1);
1477 double e_slope_scint_plane2_end = fcn_pol1->GetParError(1);
1478
1479 TString logStr_phi, logStr_z;
1480 if (m_useFixedRPCDelay) {
1481 logStr_phi = Form("%.4f ns/cm (fixed)", delayRPCPhi);
1482 logStr_z = Form("%.4f ns/cm (fixed)", delayRPCZ);
1483 B2INFO("Delay in RPCs (using fixed value):"
1484 << LogVar("Used Value (phi readout)", logStr_phi.Data())
1485 << LogVar("Used Value (z readout)", logStr_z.Data()));
1486 } else {
1487 logStr_phi = Form("%.4f +/- %.4f ns/cm", delayRPCPhi, e_slope_rpc_phi);
1488 logStr_z = Form("%.4f +/- %.4f ns/cm", delayRPCZ, e_slope_rpc_z);
1489 B2INFO("Delay in RPCs:"
1490 << LogVar("Fitted Value (phi readout)", logStr_phi.Data())
1491 << LogVar("Fitted Value (z readout)", logStr_z.Data()));
1492 }
1493 logStr_phi = Form("%.4f +/- %.4f ns/cm", slope_scint_phi, e_slope_scint_phi);
1494 logStr_z = Form("%.4f +/- %.4f ns/cm", slope_scint_z, e_slope_scint_z);
1495 B2INFO("Delay in BKLM scintillators:"
1496 << LogVar("Fitted Value (phi readout) ", logStr_phi.Data())
1497 << LogVar("Fitted Value (z readout) ", logStr_z.Data()));
1498 logStr_phi = Form("%.4f +/- %.4f ns/cm", slope_scint_plane1_end,
1499 e_slope_scint_plane1_end);
1500 logStr_z = Form("%.4f +/- %.4f ns/cm", slope_scint_plane2_end,
1501 e_slope_scint_plane2_end);
1502 B2INFO("Delay in EKLM scintillators:"
1503 << LogVar("Fitted Value (plane1 readout) ", logStr_phi.Data())
1504 << LogVar("Fitted Value (plane2 readout) ", logStr_z.Data()));
1505
1506 logStr_z = Form("%.4f +/- %.4f ns/cm", delayBKLM, delayBKLMError);
1507 B2INFO("Delay in BKLM scintillators:"
1508 << LogVar("Fitted Value (2d fit) ", logStr_z.Data()));
1509 logStr_z = Form("%.4f +/- %.4f ns/cm", delayEKLM, delayEKLMError);
1510 B2INFO("Delay in EKLM scintillators:"
1511 << LogVar("Fitted Value (2d fit) ", logStr_z.Data()));
1512
1513 m_timeConstants->setDelay(delayEKLM, KLMTimeConstants::c_EKLM);
1514 m_timeConstants->setDelay(delayBKLM, KLMTimeConstants::c_BKLM);
1515 m_timeConstants->setDelay(delayRPCPhi, KLMTimeConstants::c_RPCPhi);
1516 m_timeConstants->setDelay(delayRPCZ, KLMTimeConstants::c_RPCZ);
1517
1518 /**********************************
1519 * THIRD LOOP (BATCHED)
1520 * Fill per-channel distributions and fit
1521 **********************************/
1522 B2INFO("Third loop: Time distribution filling (batched processing)...");
1523
1524 for (const auto& batch : batches) {
1525 B2INFO("Processing batch: " << batch.first);
1526 readCalibrationDataBatch(batch.second);
1527
1528 for (KLMChannelIndex klmChannel = m_klmChannels.begin(); klmChannel != m_klmChannels.end(); ++klmChannel) {
1529 channelId = klmChannel.getKLMChannelNumber();
1530
1531 if (!batch.second(klmChannel))
1532 continue;
1533
1534 if (m_cFlag[channelId] == ChannelCalibrationStatus::c_NotEnoughData)
1535 continue;
1536
1537 if (m_evts.find(channelId) == m_evts.end())
1538 continue;
1539
1540 eventsChannel = m_evts[channelId];
1541 int iSub = klmChannel.getSubdetector();
1542 int iF, iS, iL, iP, iC;
1543
1544 if (iSub == KLMElementNumbers::c_BKLM) {
1545 iF = klmChannel.getSection();
1546 iS = klmChannel.getSector() - 1;
1547 iL = klmChannel.getLayer() - 1;
1548 iP = klmChannel.getPlane();
1549 iC = klmChannel.getStrip() - 1;
1550 } else {
1551 iF = klmChannel.getSection() - 1;
1552 iS = klmChannel.getSector() - 1;
1553 iL = klmChannel.getLayer() - 1;
1554 iP = klmChannel.getPlane() - 1;
1555 iC = klmChannel.getStrip() - 1;
1556 }
1557
1558 // Create per-channel histogram
1559 TString hn, ht;
1560 TH1F* h_temp = nullptr;
1561
1562 if (iSub == KLMElementNumbers::c_BKLM) {
1563 // FIXED: Use constant instead of hardcoded value
1564 if (iL >= (BKLMElementNumbers::c_FirstRPCLayer - 1)) {
1565 hn = Form("h_timeF%d_S%d_L%d_P%d_C%d", iF, iS, iL, iP, iC);
1566 ht = Form("Time distribution for RPC of Channel%d, %s, Layer%d, Sector%d, %s",
1567 iC, iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
1568 h_temp = new TH1F(hn.Data(), ht.Data(), nBin, m_LowerTimeBoundaryRPC, m_UpperTimeBoundaryRPC);
1569 } else {
1570 hn = Form("h_timeF%d_S%d_L%d_P%d_C%d", iF, iS, iL, iP, iC);
1571 ht = Form("time distribution for Scintillator of Channel%d, %s, Layer%d, Sector%d, %s",
1572 iC, iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
1573 h_temp = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryScintillatorsBKLM,
1575 }
1576 } else {
1577 hn = Form("h_timeF%d_S%d_L%d_P%d_C%d_end", iF, iS, iL, iP, iC);
1578 ht = Form("Time distribution for Scintillator of Channel%d, %s, Layer%d, Sector%d, %s (Endcap)",
1579 iC, iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
1580 h_temp = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryScintillatorsEKLM,
1582 }
1583
1584 // Fill histogram
1585 for (const Event& event : eventsChannel) {
1586 // Add ADC cut
1587 if (!passesADCCut(event, iSub, iL))
1588 continue;
1589
1590 double timeHit = event.time();
1591 if (m_useEventT0)
1592 timeHit = timeHit - event.t0;
1593 if (timeHit <= -400e3)
1594 continue;
1595
1596 if (iSub == KLMElementNumbers::c_BKLM) {
1597 // FIXED: Use constant instead of hardcoded value
1598 if (iL >= (BKLMElementNumbers::c_FirstRPCLayer - 1)) {
1599 double propgationT;
1601 propgationT = event.dist * delayRPCZ;
1602 else
1603 propgationT = event.dist * delayRPCPhi;
1604 double time = timeHit - propgationT;
1605
1606 h_time_rpc->Fill(time);
1607 h_temp->Fill(time);
1608
1609 if (m_saveAllPlots) {
1610 h_timeF_rpc[iF]->Fill(time);
1611 h_timeFS_rpc[iF][iS]->Fill(time);
1612 h_timeFSL[iF][iS][iL]->Fill(time);
1613 h_timeFSLP[iF][iS][iL][iP]->Fill(time);
1614 h2_timeF_rpc[iF]->Fill(iS, time);
1615 h2_timeFS[iF][iS]->Fill(iL, time);
1616 h2_timeFSLP[iF][iS][iL][iP]->Fill(iC, time);
1617 }
1618 } else {
1619 double propgationT = event.dist * delayBKLM;
1620 double time = timeHit - propgationT;
1621
1622 h_time_scint->Fill(time);
1623 h_temp->Fill(time);
1624
1625 if (m_saveAllPlots) {
1626 h_timeF_scint[iF]->Fill(time);
1627 h_timeFS_scint[iF][iS]->Fill(time);
1628 h_timeFSL[iF][iS][iL]->Fill(time);
1629 h_timeFSLP[iF][iS][iL][iP]->Fill(time);
1630 h2_timeF_scint[iF]->Fill(iS, time);
1631 h2_timeFS[iF][iS]->Fill(iL, time);
1632 h2_timeFSLP[iF][iS][iL][iP]->Fill(iC, time);
1633 }
1634 }
1635 } else {
1636 double propgationT = event.dist * delayEKLM;
1637 double time = timeHit - propgationT;
1638
1639 h_time_scint_end->Fill(time);
1640 h_temp->Fill(time);
1641
1642 if (m_saveAllPlots) {
1643 h_timeF_scint_end[iF]->Fill(time);
1644 h_timeFS_scint_end[iF][iS]->Fill(time);
1645 h_timeFSL_end[iF][iS][iL]->Fill(time);
1646 h_timeFSLP_end[iF][iS][iL][iP]->Fill(time);
1647 h2_timeF_scint_end[iF]->Fill(iS, time);
1648 h2_timeFS_end[iF][iS]->Fill(iL, time);
1649 h2_timeFSLP_end[iF][iS][iL][iP]->Fill(iC, time);
1650 }
1651 }
1652 }
1653
1654 TFitResultPtr r = h_temp->Fit(fcn_gaus, "LESQ");
1655 if (int(r) == 0) {
1656 m_cFlag[channelId] = ChannelCalibrationStatus::c_SuccessfulCalibration;
1657 m_time_channel[channelId] = fcn_gaus->GetParameter(1);
1658 m_etime_channel[channelId] = fcn_gaus->GetParError(1);
1659 }
1660
1661 // Get the appropriate directory for this channel
1662 TDirectory* dir = (iSub == KLMElementNumbers::c_BKLM) ?
1663 m_channelHistDir_BKLM[iF][iS][iL][iP] :
1664 m_channelHistDir_EKLM[iF][iS][iL][iP];
1666 }
1667
1668 m_evts.clear();
1669 B2INFO("Batch processed and cleared: " << batch.first);
1670 }
1671
1672 B2INFO("Original filling done.");
1673
1674 // Fill TGraphs with extracted parameters
1675 int iChannel_rpc = 0;
1676 int iChannel = 0;
1677 int iChannel_end = 0;
1678 for (KLMChannelIndex klmChannel = m_klmChannels.begin(); klmChannel != m_klmChannels.end(); ++klmChannel) {
1679 channelId = klmChannel.getKLMChannelNumber();
1680 if (m_cFlag[channelId] != ChannelCalibrationStatus::c_SuccessfulCalibration)
1681 continue;
1682
1683 int iSub = klmChannel.getSubdetector();
1684 if (iSub == KLMElementNumbers::c_BKLM) {
1685 int iL = klmChannel.getLayer() - 1;
1686 // FIXED: Use constant instead of hardcoded value
1687 if (iL >= (BKLMElementNumbers::c_FirstRPCLayer - 1)) {
1688 gre_time_channel_rpc->SetPoint(iChannel_rpc, channelId, m_time_channel[channelId]);
1689 gre_time_channel_rpc->SetPointError(iChannel_rpc, 0., m_etime_channel[channelId]);
1690 iChannel_rpc++;
1691 } else {
1692 gre_time_channel_scint->SetPoint(iChannel, channelId, m_time_channel[channelId]);
1693 gre_time_channel_scint->SetPointError(iChannel, 0., m_etime_channel[channelId]);
1694 iChannel++;
1695 }
1696 } else {
1697 gre_time_channel_scint_end->SetPoint(iChannel_end, channelId, m_time_channel[channelId]);
1698 gre_time_channel_scint_end->SetPointError(iChannel_end, 0., m_etime_channel[channelId]);
1699 iChannel_end++;
1700 }
1701 }
1702
1703 gre_time_channel_scint->Fit("fcn_const", "EMQ");
1704 m_time_channelAvg_scint = fcn_const->GetParameter(0);
1705 m_etime_channelAvg_scint = fcn_const->GetParError(0);
1706
1707 gre_time_channel_scint_end->Fit("fcn_const", "EMQ");
1708 m_time_channelAvg_scint_end = fcn_const->GetParameter(0);
1709 m_etime_channelAvg_scint_end = fcn_const->GetParError(0);
1710
1711 gre_time_channel_rpc->Fit("fcn_const", "EMQ");
1712 m_time_channelAvg_rpc = fcn_const->GetParameter(0);
1713 m_etime_channelAvg_rpc = fcn_const->GetParError(0);
1714
1715 B2INFO("Channel's time distribution fitting done.");
1716 B2DEBUG(20, LogVar("Average time (RPC)", m_time_channelAvg_rpc)
1717 << LogVar("Average time (BKLM scintillators)", m_time_channelAvg_scint)
1718 << LogVar("Average time (EKLM scintillators)", m_time_channelAvg_scint_end));
1719
1720 B2INFO("Calibrated channel's time distribution filling begins.");
1721
1722 m_timeShift.clear();
1723 for (KLMChannelIndex klmChannel = m_klmChannels.begin(); klmChannel != m_klmChannels.end(); ++klmChannel) {
1724 channelId = klmChannel.getKLMChannelNumber();
1725 h_calibrated->Fill(m_cFlag[channelId]);
1726 if (m_time_channel.find(channelId) == m_time_channel.end())
1727 continue;
1728 double timeShift = m_time_channel[channelId];
1729 m_timeShift[channelId] = timeShift;
1730 m_timeCableDelay->setTimeDelay(channelId, m_timeShift[channelId]);
1731 }
1732
1733 for (KLMChannelIndex klmChannel = m_klmChannels.begin(); klmChannel != m_klmChannels.end(); ++klmChannel) {
1734 channelId = klmChannel.getKLMChannelNumber();
1735 if (m_timeShift.find(channelId) != m_timeShift.end())
1736 continue;
1737 m_timeShift[channelId] = esti_timeShift(klmChannel);
1738 m_timeCableDelay->setTimeDelay(channelId, m_timeShift[channelId]);
1739 B2DEBUG(20, "Uncalibrated Estimation " << LogVar("Channel", channelId) << LogVar("Estimated value", m_timeShift[channelId]));
1740 }
1741
1742 iChannel_rpc = 0;
1743 iChannel = 0;
1744 iChannel_end = 0;
1745 for (KLMChannelIndex klmChannel = m_klmChannels.begin(); klmChannel != m_klmChannels.end(); ++klmChannel) {
1746 channelId = klmChannel.getKLMChannelNumber();
1747 if (m_timeShift.find(channelId) == m_timeShift.end()) {
1748 B2ERROR("!!! Not All Channels Calibration Constant Set. Error Happened on " << LogVar("Channel", channelId));
1749 continue;
1750 }
1751 int iSub = klmChannel.getSubdetector();
1752 if (iSub == KLMElementNumbers::c_BKLM) {
1753 // FIXED: Use 0-indexed layer and constant
1754 int iL = klmChannel.getLayer() - 1;
1755 if (iL >= (BKLMElementNumbers::c_FirstRPCLayer - 1)) {
1756 gr_timeShift_channel_rpc->SetPoint(iChannel_rpc, channelId, m_timeShift[channelId]);
1757 iChannel_rpc++;
1758 } else {
1759 gr_timeShift_channel_scint->SetPoint(iChannel, channelId, m_timeShift[channelId]);
1760 iChannel++;
1761 }
1762 } else {
1763 gr_timeShift_channel_scint_end->SetPoint(iChannel_end, channelId, m_timeShift[channelId]);
1764 iChannel_end++;
1765 }
1766 }
1767
1768 // NOTE: This also needs batching
1773
1774 /**********************************
1775 * FOURTH LOOP (BATCHED)
1776 * Fill calibrated per-channel histograms
1777 **********************************/
1778 B2INFO("Fourth loop: Calibrated time distribution filling (batched processing)...");
1779
1780 for (const auto& batch : batches) {
1781 B2INFO("Processing batch: " << batch.first);
1782 readCalibrationDataBatch(batch.second);
1783
1784 for (KLMChannelIndex klmChannel = m_klmChannels.begin(); klmChannel != m_klmChannels.end(); ++klmChannel) {
1785 channelId = klmChannel.getKLMChannelNumber();
1786
1787 if (!batch.second(klmChannel))
1788 continue;
1789
1790 if (m_evts.find(channelId) == m_evts.end())
1791 continue;
1792
1793 eventsChannel = m_evts[channelId];
1794 int iSub = klmChannel.getSubdetector();
1795 int iF, iS, iL, iP, iC;
1796
1797 if (iSub == KLMElementNumbers::c_BKLM) {
1798 iF = klmChannel.getSection();
1799 iS = klmChannel.getSector() - 1;
1800 iL = klmChannel.getLayer() - 1;
1801 iP = klmChannel.getPlane();
1802 iC = klmChannel.getStrip() - 1;
1803 } else {
1804 iF = klmChannel.getSection() - 1;
1805 iS = klmChannel.getSector() - 1;
1806 iL = klmChannel.getLayer() - 1;
1807 iP = klmChannel.getPlane() - 1;
1808 iC = klmChannel.getStrip() - 1;
1809 }
1810
1811 TString hn, ht;
1812 TH1F* hc_temp = nullptr;
1813
1814 if (iSub == KLMElementNumbers::c_BKLM) {
1815 // FIXED: Use constant instead of hardcoded value
1816 if (iL >= (BKLMElementNumbers::c_FirstRPCLayer - 1)) {
1817 hn = Form("hc_timeF%d_S%d_L%d_P%d_C%d", iF, iS, iL, iP, iC);
1818 ht = Form("Calibrated time distribution for RPC of Channel%d, %s, Layer%d, Sector%d, %s",
1819 iC, iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
1820 hc_temp = new TH1F(hn.Data(), ht.Data(), nBin, m_LowerTimeBoundaryCalibratedRPC,
1822 } else {
1823 hn = Form("hc_timeF%d_S%d_L%d_P%d_C%d", iF, iS, iL, iP, iC);
1824 ht = Form("Calibrated time distribution for Scintillator of Channel%d, %s, Layer%d, Sector%d, %s",
1825 iC, iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
1826 hc_temp = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryCalibratedScintillatorsBKLM,
1828 }
1829 } else {
1830 hn = Form("hc_timeF%d_S%d_L%d_P%d_C%d_end", iF, iS, iL, iP, iC);
1831 ht = Form("Calibrated time distribution for Scintillator of Channel%d, %s, Layer%d, Sector%d, %s (Endcap)",
1832 iC, iPstring[iP].Data(), iL, iS, iFstring[iF].Data());
1833 hc_temp = new TH1F(hn.Data(), ht.Data(), nBin_scint, m_LowerTimeBoundaryCalibratedScintillatorsEKLM,
1835 }
1836
1837 for (const Event& event : eventsChannel) {
1838 // Add ADC cut
1839 if (!passesADCCut(event, iSub, iL))
1840 continue;
1841
1842 double timeHit = event.time();
1843 if (m_useEventT0)
1844 timeHit = timeHit - event.t0;
1845 if (timeHit <= -400e3)
1846 continue;
1847
1848 if (iSub == KLMElementNumbers::c_BKLM) {
1849 // FIXED: Use constant instead of hardcoded value
1850 if (iL >= (BKLMElementNumbers::c_FirstRPCLayer - 1)) {
1851 double propgationT;
1853 propgationT = event.dist * delayRPCZ;
1854 else
1855 propgationT = event.dist * delayRPCPhi;
1856 double time = timeHit - propgationT - m_timeShift[channelId];
1857
1858 hc_time_rpc->Fill(time);
1859 hc_temp->Fill(time);
1860
1861 if (m_saveAllPlots) {
1862 hc_timeF_rpc[iF]->Fill(time);
1863 hc_timeFS_rpc[iF][iS]->Fill(time);
1864 hc_timeFSL[iF][iS][iL]->Fill(time);
1865 hc_timeFSLP[iF][iS][iL][iP]->Fill(time);
1866 h2c_timeF_rpc[iF]->Fill(iS, time);
1867 h2c_timeFS[iF][iS]->Fill(iL, time);
1868 h2c_timeFSLP[iF][iS][iL][iP]->Fill(iC, time);
1869 }
1870 } else {
1871 double propgationT = event.dist * delayBKLM;
1872 double time = timeHit - propgationT - m_timeShift[channelId];
1873
1874 hc_time_scint->Fill(time);
1875 hc_temp->Fill(time);
1876
1877 if (m_saveAllPlots) {
1878 hc_timeF_scint[iF]->Fill(time);
1879 hc_timeFS_scint[iF][iS]->Fill(time);
1880 hc_timeFSL[iF][iS][iL]->Fill(time);
1881 hc_timeFSLP[iF][iS][iL][iP]->Fill(time);
1882 h2c_timeF_scint[iF]->Fill(iS, time);
1883 h2c_timeFS[iF][iS]->Fill(iL, time);
1884 h2c_timeFSLP[iF][iS][iL][iP]->Fill(iC, time);
1885 }
1886 }
1887 } else {
1888 double propgationT = event.dist * delayEKLM;
1889 double time = timeHit - propgationT - m_timeShift[channelId];
1890
1891 hc_time_scint_end->Fill(time);
1892 hc_temp->Fill(time);
1893
1894 if (m_saveAllPlots) {
1895 hc_timeF_scint_end[iF]->Fill(time);
1896 hc_timeFS_scint_end[iF][iS]->Fill(time);
1897 hc_timeFSL_end[iF][iS][iL]->Fill(time);
1898 hc_timeFSLP_end[iF][iS][iL][iP]->Fill(time);
1899 h2c_timeF_scint_end[iF]->Fill(iS, time);
1900 h2c_timeFS_end[iF][iS]->Fill(iL, time);
1901 h2c_timeFSLP_end[iF][iS][iL][iP]->Fill(iC, time);
1902 }
1903 }
1904 }
1905
1906 if (m_cFlag[channelId] == ChannelCalibrationStatus::c_NotEnoughData) {
1907 delete hc_temp;
1908 continue;
1909 }
1910
1911 TFitResultPtr rc = hc_temp->Fit(fcn_gaus, "LESQ");
1912 if (int(rc) == 0) {
1913 m_cFlag[channelId] = ChannelCalibrationStatus::c_SuccessfulCalibration;
1914 m_ctime_channel[channelId] = fcn_gaus->GetParameter(1);
1915 mc_etime_channel[channelId] = fcn_gaus->GetParError(1);
1916 }
1917
1918 // Get the appropriate directory for this channel
1919 TDirectory* dir = (iSub == KLMElementNumbers::c_BKLM) ?
1920 m_channelHistDir_BKLM[iF][iS][iL][iP] :
1921 m_channelHistDir_EKLM[iF][iS][iL][iP];
1922 writeThenDelete_(hc_temp, m_saveChannelHists, dir);
1923 }
1924
1925 m_evts.clear();
1926 B2INFO("Batch processed and cleared: " << batch.first);
1927 }
1928
1929 // Fill TGraphs with calibrated parameters
1930 int icChannel_rpc = 0;
1931 int icChannel = 0;
1932 int icChannel_end = 0;
1933 for (KLMChannelIndex klmChannel = m_klmChannels.begin(); klmChannel != m_klmChannels.end(); ++klmChannel) {
1934 channelId = klmChannel.getKLMChannelNumber();
1935 if (m_cFlag[channelId] != ChannelCalibrationStatus::c_SuccessfulCalibration)
1936 continue;
1937
1938 int iSub = klmChannel.getSubdetector();
1939 if (iSub == KLMElementNumbers::c_BKLM) {
1940 int iL = klmChannel.getLayer() - 1;
1941 // FIXED: Use constant instead of hardcoded value
1942 if (iL >= (BKLMElementNumbers::c_FirstRPCLayer - 1)) {
1943 gre_ctime_channel_rpc->SetPoint(icChannel_rpc, channelId, m_ctime_channel[channelId]);
1944 gre_ctime_channel_rpc->SetPointError(icChannel_rpc, 0., mc_etime_channel[channelId]);
1945 icChannel_rpc++;
1946 } else {
1947 gre_ctime_channel_scint->SetPoint(icChannel, channelId, m_ctime_channel[channelId]);
1948 gre_ctime_channel_scint->SetPointError(icChannel, 0., mc_etime_channel[channelId]);
1949 icChannel++;
1950 }
1951 } else {
1952 gre_ctime_channel_scint_end->SetPoint(icChannel_end, channelId, m_ctime_channel[channelId]);
1953 gre_ctime_channel_scint_end->SetPointError(icChannel_end, 0., mc_etime_channel[channelId]);
1954 icChannel_end++;
1955 }
1956 }
1957
1958 gre_ctime_channel_scint->Fit("fcn_const", "EMQ");
1959 m_ctime_channelAvg_scint = fcn_const->GetParameter(0);
1960 mc_etime_channelAvg_scint = fcn_const->GetParError(0);
1961
1962 gre_ctime_channel_scint_end->Fit("fcn_const", "EMQ");
1963 m_ctime_channelAvg_scint_end = fcn_const->GetParameter(0);
1964 mc_etime_channelAvg_scint_end = fcn_const->GetParError(0);
1965
1966 gre_ctime_channel_rpc->Fit("fcn_const", "EMQ");
1967 m_ctime_channelAvg_rpc = fcn_const->GetParameter(0);
1968 mc_etime_channelAvg_rpc = fcn_const->GetParError(0);
1969
1970 B2INFO("Channel's time distribution fitting done.");
1971 B2DEBUG(20, LogVar("Average calibrated time (RPC)", m_ctime_channelAvg_rpc)
1972 << LogVar("Average calibrated time (BKLM scintillators)", m_ctime_channelAvg_scint)
1973 << LogVar("Average calibrated time (EKLM scintillators)", m_ctime_channelAvg_scint_end));
1974
1975 B2INFO("Calibrated channel's time distribution filling begins.");
1976
1977 m_timeRes.clear();
1978 for (KLMChannelIndex klmChannel = m_klmChannels.begin(); klmChannel != m_klmChannels.end(); ++klmChannel) {
1979 channelId = klmChannel.getKLMChannelNumber();
1980 hc_calibrated->Fill(m_cFlag[channelId]);
1981 if (m_ctime_channel.find(channelId) == m_ctime_channel.end())
1982 continue;
1983 double timeRes = m_ctime_channel[channelId];
1984 m_timeRes[channelId] = timeRes;
1985 m_timeResolution->setTimeResolution(channelId, m_timeRes[channelId]);
1986 }
1987
1988 for (KLMChannelIndex klmChannel = m_klmChannels.begin(); klmChannel != m_klmChannels.end(); ++klmChannel) {
1989 channelId = klmChannel.getKLMChannelNumber();
1990 if (m_timeRes.find(channelId) != m_timeRes.end())
1991 continue;
1992 m_timeRes[channelId] = esti_timeRes(klmChannel);
1993 m_timeResolution->setTimeResolution(channelId, m_timeRes[channelId]);
1994 B2DEBUG(20, "Calibrated Estimation " << LogVar("Channel", channelId) << LogVar("Estimated value", m_timeRes[channelId]));
1995 }
1996
1997 icChannel_rpc = 0;
1998 icChannel = 0;
1999 icChannel_end = 0;
2000 for (KLMChannelIndex klmChannel = m_klmChannels.begin(); klmChannel != m_klmChannels.end(); ++klmChannel) {
2001 channelId = klmChannel.getKLMChannelNumber();
2002 if (m_timeRes.find(channelId) == m_timeRes.end()) {
2003 B2ERROR("!!! Not All Channels Calibration Constant Set. Error Happened on " << LogVar("Channel", channelId));
2004 continue;
2005 }
2006 int iSub = klmChannel.getSubdetector();
2007 if (iSub == KLMElementNumbers::c_BKLM) {
2008 // FIXED: Use 0-indexed layer and constant
2009 int iL = klmChannel.getLayer() - 1;
2010 if (iL >= (BKLMElementNumbers::c_FirstRPCLayer - 1)) {
2011 gr_timeRes_channel_rpc->SetPoint(icChannel_rpc, channelId, m_timeRes[channelId]);
2012 icChannel_rpc++;
2013 } else {
2014 gr_timeRes_channel_scint->SetPoint(icChannel, channelId, m_timeRes[channelId]);
2015 icChannel++;
2016 }
2017 } else {
2018 gr_timeRes_channel_scint_end->SetPoint(icChannel_end, channelId, m_timeRes[channelId]);
2019 icChannel_end++;
2020 }
2021 }
2022
2023 // ===================================================================
2024 // FIFTH PASS: Di-muon EventT0 analysis for hit resolution calibration
2025 // ===================================================================
2026 B2INFO("Fifth pass: Computing di-muon ΔT0 for EventT0 hit resolution calibration...");
2027
2028 // Data structure for per-track T0 accumulation
2029 struct TrackT0Info {
2030 int charge;
2031 int nHits_BKLM_Scint;
2032 int nHits_BKLM_RPC_Phi; // Split RPC by readout direction
2033 int nHits_BKLM_RPC_Z;
2034 int nHits_EKLM_Scint;
2035 double sumT0_BKLM_Scint;
2036 double sumT0_BKLM_RPC_Phi;
2037 double sumT0_BKLM_RPC_Z;
2038 double sumT0_EKLM_Scint;
2039
2040 TrackT0Info() : charge(0),
2041 nHits_BKLM_Scint(0),
2042 nHits_BKLM_RPC_Phi(0),
2043 nHits_BKLM_RPC_Z(0),
2044 nHits_EKLM_Scint(0),
2045 sumT0_BKLM_Scint(0.0),
2046 sumT0_BKLM_RPC_Phi(0.0),
2047 sumT0_BKLM_RPC_Z(0.0),
2048 sumT0_EKLM_Scint(0.0) {}
2049 };
2050
2051 // Map: (Run, Event) -> (nTrack -> TrackT0Info)
2052 std::map<std::pair<int, int>, std::map<int, TrackT0Info>> eventTrackMap;
2053
2054 // Process all data in batches to build event-track map
2055 for (const auto& batch : batches) {
2056 B2INFO("Processing batch for di-muon analysis: " << batch.first);
2057 readCalibrationDataBatch(batch.second);
2058
2059 for (const auto& channelPair : m_evts) {
2060 KLMChannelNumber chId = channelPair.first;
2061 const std::vector<Event>& chEvents = channelPair.second;
2062
2063 // Get channel geometry
2064 int subdetector, section, sector, layer, plane, strip;
2065 m_ElementNumbers->channelNumberToElementNumbers(
2066 chId, &subdetector, &section, &sector, &layer, &plane, &strip);
2067
2068 // Convert to 0-indexed immediately (consistent with loops 1-4)
2069 int iSub = subdetector;
2070 int iL = layer - 1;
2071
2072 for (const Event& event : chEvents) {
2073 // Apply ADC cut with 0-indexed layer
2074 if (!passesADCCut(event, iSub, iL))
2075 continue;
2076
2077 // Event and track identification
2078 std::pair<int, int> eventKey(event.Run, event.Events);
2079 int trackIdx = event.nTrack;
2080 int charge = event.Track_Charge;
2081
2082 // Compute calibrated time for this hit
2083 double timeHit = event.time() - m_timeShift[chId];
2084
2085 if (timeHit <= -400e3)
2086 continue;
2087
2088 // Apply propagation correction (using 0-indexed layer)
2089 double propT = 0.0;
2090 if (iSub == KLMElementNumbers::c_BKLM) {
2091 if (iL >= (BKLMElementNumbers::c_FirstRPCLayer - 1)) {
2092 // RPC
2093 if (plane == BKLMElementNumbers::c_ZPlane)
2094 propT = event.dist * delayRPCZ;
2095 else
2096 propT = event.dist * delayRPCPhi;
2097 } else {
2098 // Scintillator
2099 propT = event.dist * delayBKLM;
2100 }
2101 } else {
2102 // EKLM
2103 propT = event.dist * delayEKLM;
2104 }
2105
2106 double t0_estimate = timeHit - propT;
2107
2108 // Accumulate per-track T0
2109 TrackT0Info& trackInfo = eventTrackMap[eventKey][trackIdx];
2110 trackInfo.charge = charge;
2111
2112 if (iSub == KLMElementNumbers::c_BKLM) {
2113 if (iL >= (BKLMElementNumbers::c_FirstRPCLayer - 1)) {
2114 // RPC - split by readout direction
2115 if (plane == BKLMElementNumbers::c_ZPlane) {
2116 trackInfo.nHits_BKLM_RPC_Z++;
2117 trackInfo.sumT0_BKLM_RPC_Z += t0_estimate;
2118 } else {
2119 trackInfo.nHits_BKLM_RPC_Phi++;
2120 trackInfo.sumT0_BKLM_RPC_Phi += t0_estimate;
2121 }
2122 } else {
2123 // Scintillator
2124 trackInfo.nHits_BKLM_Scint++;
2125 trackInfo.sumT0_BKLM_Scint += t0_estimate;
2126 }
2127 } else {
2128 trackInfo.nHits_EKLM_Scint++;
2129 trackInfo.sumT0_EKLM_Scint += t0_estimate;
2130 }
2131 }
2132 }
2133
2134 m_evts.clear();
2135 }
2136
2137 B2INFO("Event-track map built. Processing events for EventT0 histograms...");
2138
2139 // Accumulators for variance calculation using the Gaussian MLE
2140 // Model: ΔT0_i ~ N(0, σ_hit^2 * v_i), v_i = 1/N⁺_i + 1/N⁻_i
2141 double sum_delta2_over_v_BKLM_Scint = 0.0;
2142 double sum_delta2_over_v_BKLM_RPC_Phi = 0.0;
2143 double sum_delta2_over_v_BKLM_RPC_Z = 0.0;
2144 double sum_delta2_over_v_EKLM_Scint = 0.0;
2145
2146 int nDimuon_BKLM_Scint = 0;
2147 int nDimuon_BKLM_RPC_Phi = 0;
2148 int nDimuon_BKLM_RPC_Z = 0;
2149 int nDimuon_EKLM_Scint = 0;
2150
2151 for (const auto& eventPair : eventTrackMap) {
2152 const auto& trackMap = eventPair.second;
2153
2154 // Check if exactly 2 tracks (di-muon candidate)
2155 if (trackMap.size() != 2)
2156 continue;
2157
2158 auto it1 = trackMap.begin();
2159 auto it2 = trackMap.begin();
2160 ++it2;
2161 const TrackT0Info& track1 = it1->second;
2162 const TrackT0Info& track2 = it2->second;
2163
2164 // Check opposite charges
2165 if (track1.charge * track2.charge >= 0)
2166 continue;
2167
2168 // Identify mu+ and mu-
2169 const TrackT0Info& muPlus = (track1.charge > 0) ? track1 : track2;
2170 const TrackT0Info& muMinus = (track1.charge > 0) ? track2 : track1;
2171
2172 // === BKLM Scintillator ===
2173 if (muPlus.nHits_BKLM_Scint > 0 && muMinus.nHits_BKLM_Scint > 0) {
2174 double t0_plus = muPlus.sumT0_BKLM_Scint / muPlus.nHits_BKLM_Scint;
2175 double t0_minus = muMinus.sumT0_BKLM_Scint / muMinus.nHits_BKLM_Scint;
2176 double deltaT0 = t0_plus - t0_minus;
2177
2178 // v = 1/N⁺ + 1/N⁻ for this event
2179 double v = 1.0 / muPlus.nHits_BKLM_Scint + 1.0 / muMinus.nHits_BKLM_Scint;
2180 int nTotal = muPlus.nHits_BKLM_Scint + muMinus.nHits_BKLM_Scint;
2181
2182 if (v <= 0.0)
2183 continue;
2184
2185 // Accumulate for σ_hit^2 = (1/N_evt) Σ [ ΔT0^2 / v ]
2186 sum_delta2_over_v_BKLM_Scint += (deltaT0 * deltaT0) / v;
2187 nDimuon_BKLM_Scint++;
2188
2189 // Histograms for monitoring
2190 h_eventT0_scint->Fill(t0_plus);
2191 h_eventT0_scint->Fill(t0_minus);
2192 hc_eventT0_scint->Fill(deltaT0);
2193
2194 // ==== NEW DIAGNOSTIC FILLS ====
2195 h_nHits_plus_scint->Fill(muPlus.nHits_BKLM_Scint);
2196 h_nHits_minus_scint->Fill(muMinus.nHits_BKLM_Scint);
2197 h2_deltaT0_vs_v_scint->Fill(v, deltaT0);
2198 prof_deltaT0_rms_vs_v_scint->Fill(v, deltaT0);
2199 h2_deltaT0_vs_nhits_scint->Fill(nTotal, deltaT0);
2200
2201 // Fill multiplicity-binned histograms
2202 if (nTotal < 5) {
2203 hc_eventT0_scint_lowN->Fill(deltaT0);
2204 } else if (nTotal < 15) {
2205 hc_eventT0_scint_midN->Fill(deltaT0);
2206 } else {
2207 hc_eventT0_scint_highN->Fill(deltaT0);
2208 }
2209 }
2210
2211 // === BKLM RPC Phi ===
2212 if (muPlus.nHits_BKLM_RPC_Phi > 0 && muMinus.nHits_BKLM_RPC_Phi > 0) {
2213 double t0_plus = muPlus.sumT0_BKLM_RPC_Phi / muPlus.nHits_BKLM_RPC_Phi;
2214 double t0_minus = muMinus.sumT0_BKLM_RPC_Phi / muMinus.nHits_BKLM_RPC_Phi;
2215 double deltaT0 = t0_plus - t0_minus;
2216
2217 double v = 1.0 / muPlus.nHits_BKLM_RPC_Phi + 1.0 / muMinus.nHits_BKLM_RPC_Phi;
2218 int nTotal = muPlus.nHits_BKLM_RPC_Phi + muMinus.nHits_BKLM_RPC_Phi;
2219
2220 if (v <= 0.0)
2221 continue;
2222
2223 sum_delta2_over_v_BKLM_RPC_Phi += (deltaT0 * deltaT0) / v;
2224 nDimuon_BKLM_RPC_Phi++;
2225
2226 h_eventT0_rpc->Fill(t0_plus);
2227 h_eventT0_rpc->Fill(t0_minus);
2228 hc_eventT0_rpc->Fill(deltaT0);
2229
2230 // Diagnostic fills
2231 h_nHits_plus_rpc->Fill(muPlus.nHits_BKLM_RPC_Phi);
2232 h_nHits_minus_rpc->Fill(muMinus.nHits_BKLM_RPC_Phi);
2233 h2_deltaT0_vs_v_rpc->Fill(v, deltaT0);
2234 prof_deltaT0_rms_vs_v_rpc->Fill(v, deltaT0);
2235 h2_deltaT0_vs_nhits_rpc->Fill(nTotal, deltaT0);
2236
2237 if (nTotal < 10) {
2238 hc_eventT0_rpc_lowN->Fill(deltaT0);
2239 } else if (nTotal < 30) {
2240 hc_eventT0_rpc_midN->Fill(deltaT0);
2241 } else {
2242 hc_eventT0_rpc_highN->Fill(deltaT0);
2243 }
2244 }
2245
2246 // === BKLM RPC Z ===
2247 if (muPlus.nHits_BKLM_RPC_Z > 0 && muMinus.nHits_BKLM_RPC_Z > 0) {
2248 double t0_plus = muPlus.sumT0_BKLM_RPC_Z / muPlus.nHits_BKLM_RPC_Z;
2249 double t0_minus = muMinus.sumT0_BKLM_RPC_Z / muMinus.nHits_BKLM_RPC_Z;
2250 double deltaT0 = t0_plus - t0_minus;
2251
2252 double v = 1.0 / muPlus.nHits_BKLM_RPC_Z + 1.0 / muMinus.nHits_BKLM_RPC_Z;
2253 int nTotal = muPlus.nHits_BKLM_RPC_Z + muMinus.nHits_BKLM_RPC_Z;
2254
2255 if (v <= 0.0)
2256 continue;
2257
2258 sum_delta2_over_v_BKLM_RPC_Z += (deltaT0 * deltaT0) / v;
2259 nDimuon_BKLM_RPC_Z++;
2260
2261 h_eventT0_rpc->Fill(t0_plus);
2262 h_eventT0_rpc->Fill(t0_minus);
2263 hc_eventT0_rpc->Fill(deltaT0);
2264
2265 // Diagnostic fills
2266 h_nHits_plus_rpc->Fill(muPlus.nHits_BKLM_RPC_Z);
2267 h_nHits_minus_rpc->Fill(muMinus.nHits_BKLM_RPC_Z);
2268 h2_deltaT0_vs_v_rpc->Fill(v, deltaT0);
2269 prof_deltaT0_rms_vs_v_rpc->Fill(v, deltaT0);
2270 h2_deltaT0_vs_nhits_rpc->Fill(nTotal, deltaT0);
2271
2272 if (nTotal < 10) {
2273 hc_eventT0_rpc_lowN->Fill(deltaT0);
2274 } else if (nTotal < 30) {
2275 hc_eventT0_rpc_midN->Fill(deltaT0);
2276 } else {
2277 hc_eventT0_rpc_highN->Fill(deltaT0);
2278 }
2279 }
2280
2281 // === EKLM Scintillator ===
2282 if (muPlus.nHits_EKLM_Scint > 0 && muMinus.nHits_EKLM_Scint > 0) {
2283 double t0_plus = muPlus.sumT0_EKLM_Scint / muPlus.nHits_EKLM_Scint;
2284 double t0_minus = muMinus.sumT0_EKLM_Scint / muMinus.nHits_EKLM_Scint;
2285 double deltaT0 = t0_plus - t0_minus;
2286
2287 double v = 1.0 / muPlus.nHits_EKLM_Scint + 1.0 / muMinus.nHits_EKLM_Scint;
2288 int nTotal = muPlus.nHits_EKLM_Scint + muMinus.nHits_EKLM_Scint;
2289
2290 if (v <= 0.0)
2291 continue;
2292
2293 sum_delta2_over_v_EKLM_Scint += (deltaT0 * deltaT0) / v;
2294 nDimuon_EKLM_Scint++;
2295
2296 h_eventT0_scint_end->Fill(t0_plus);
2297 h_eventT0_scint_end->Fill(t0_minus);
2298 hc_eventT0_scint_end->Fill(deltaT0);
2299
2300 // ==== NEW DIAGNOSTIC FILLS ====
2301 h_nHits_plus_scint_end->Fill(muPlus.nHits_EKLM_Scint);
2302 h_nHits_minus_scint_end->Fill(muMinus.nHits_EKLM_Scint);
2303 h2_deltaT0_vs_v_scint_end->Fill(v, deltaT0);
2304 prof_deltaT0_rms_vs_v_scint_end->Fill(v, deltaT0);
2305 h2_deltaT0_vs_nhits_scint_end->Fill(nTotal, deltaT0);
2306
2307 // Fill multiplicity-binned histograms
2308 if (nTotal < 5) {
2309 hc_eventT0_scint_end_lowN->Fill(deltaT0);
2310 } else if (nTotal < 15) {
2311 hc_eventT0_scint_end_midN->Fill(deltaT0);
2312 } else {
2313 hc_eventT0_scint_end_highN->Fill(deltaT0);
2314 }
2315 }
2316 }
2317
2318 B2INFO("Di-muon ΔT0 data collected."
2319 << LogVar("BKLM Scint di-muon events", nDimuon_BKLM_Scint)
2320 << LogVar("BKLM RPC Phi di-muon events", nDimuon_BKLM_RPC_Phi)
2321 << LogVar("BKLM RPC Z di-muon events", nDimuon_BKLM_RPC_Z)
2322 << LogVar("EKLM Scint di-muon events", nDimuon_EKLM_Scint));
2323
2324 // === Extract σ_hit using the Gaussian MLE ===
2325 // σ_hit^2 = (1 / N_evt) Σ_i [ ΔT0_i^2 / (1/N⁺_i + 1/N⁻_i) ]
2326
2327 float sigma_BKLM_Scint = 10.0f; // Default fallback
2328 float sigma_BKLM_Scint_err = 1.0f;
2329 if (nDimuon_BKLM_Scint > 0) {
2330 double sigma2 = sum_delta2_over_v_BKLM_Scint / static_cast<double>(nDimuon_BKLM_Scint);
2331 sigma_BKLM_Scint = static_cast<float>(std::sqrt(sigma2));
2332 // Uncertainty approximation (Gaussian statistics)
2333 sigma_BKLM_Scint_err = sigma_BKLM_Scint / std::sqrt(2.0 * nDimuon_BKLM_Scint);
2334 }
2335
2336 float sigma_RPC_Phi = 10.0f;
2337 float sigma_RPC_Phi_err = 1.0f;
2338 if (nDimuon_BKLM_RPC_Phi > 0) {
2339 double sigma2 = sum_delta2_over_v_BKLM_RPC_Phi / static_cast<double>(nDimuon_BKLM_RPC_Phi);
2340 sigma_RPC_Phi = static_cast<float>(std::sqrt(sigma2));
2341 sigma_RPC_Phi_err = sigma_RPC_Phi / std::sqrt(2.0 * nDimuon_BKLM_RPC_Phi);
2342 }
2343
2344 float sigma_RPC_Z = 10.0f;
2345 float sigma_RPC_Z_err = 1.0f;
2346 if (nDimuon_BKLM_RPC_Z > 0) {
2347 double sigma2 = sum_delta2_over_v_BKLM_RPC_Z / static_cast<double>(nDimuon_BKLM_RPC_Z);
2348 sigma_RPC_Z = static_cast<float>(std::sqrt(sigma2));
2349 sigma_RPC_Z_err = sigma_RPC_Z / std::sqrt(2.0 * nDimuon_BKLM_RPC_Z);
2350 }
2351
2352 // Compute combined RPC sigma (weighted average by number of events)
2353 float sigma_RPC = 10.0f;
2354 float sigma_RPC_err = 1.0f;
2355 int nDimuon_RPC_total = nDimuon_BKLM_RPC_Phi + nDimuon_BKLM_RPC_Z;
2356 if (nDimuon_RPC_total > 0) {
2357 // Weighted average by statistics
2358 double w_phi = static_cast<double>(nDimuon_BKLM_RPC_Phi) / nDimuon_RPC_total;
2359 double w_z = static_cast<double>(nDimuon_BKLM_RPC_Z) / nDimuon_RPC_total;
2360 sigma_RPC = w_phi * sigma_RPC_Phi + w_z * sigma_RPC_Z;
2361 // Propagate uncertainties
2362 sigma_RPC_err = std::sqrt(w_phi * w_phi * sigma_RPC_Phi_err * sigma_RPC_Phi_err +
2363 w_z * w_z * sigma_RPC_Z_err * sigma_RPC_Z_err);
2364 }
2365
2366 float sigma_EKLM_Scint = 10.0f;
2367 float sigma_EKLM_Scint_err = 1.0f;
2368 if (nDimuon_EKLM_Scint > 0) {
2369 double sigma2 = sum_delta2_over_v_EKLM_Scint / static_cast<double>(nDimuon_EKLM_Scint);
2370 sigma_EKLM_Scint = static_cast<float>(std::sqrt(sigma2));
2371 sigma_EKLM_Scint_err = sigma_EKLM_Scint / std::sqrt(2.0 * nDimuon_EKLM_Scint);
2372 }
2373
2374 B2INFO("Extracted per-hit resolutions using event-by-event weighting:"
2375 << LogVar("σ_BKLM_Scint [ns]", sigma_BKLM_Scint) << LogVar("±", sigma_BKLM_Scint_err)
2376 << LogVar("σ_RPC_Phi [ns]", sigma_RPC_Phi) << LogVar("±", sigma_RPC_Phi_err)
2377 << LogVar("σ_RPC_Z [ns]", sigma_RPC_Z) << LogVar("±", sigma_RPC_Z_err)
2378 << LogVar("σ_RPC_combined [ns]", sigma_RPC) << LogVar("±", sigma_RPC_err)
2379 << LogVar("σ_EKLM_Scint [ns]", sigma_EKLM_Scint) << LogVar("±", sigma_EKLM_Scint_err));
2380
2381 // === Store in payload ===
2382 m_eventT0HitResolution->setSigmaBKLMScint(sigma_BKLM_Scint, sigma_BKLM_Scint_err);
2383 m_eventT0HitResolution->setSigmaRPC(sigma_RPC, sigma_RPC_err); // Combined for backward compatibility
2384 m_eventT0HitResolution->setSigmaRPCPhi(sigma_RPC_Phi, sigma_RPC_Phi_err); // Direction-specific
2385 m_eventT0HitResolution->setSigmaRPCZ(sigma_RPC_Z, sigma_RPC_Z_err); // Direction-specific
2386 m_eventT0HitResolution->setSigmaEKLMScint(sigma_EKLM_Scint, sigma_EKLM_Scint_err);
2387
2388 B2INFO("EventT0 hit resolution calibration complete and stored in payload.");
2389
2390 // Clear temporary data
2391 eventTrackMap.clear();
2392
2393 delete fcn_const;
2394 m_evts.clear();
2395 m_timeShift.clear();
2396 m_timeRes.clear();
2397 m_cFlag.clear();
2398
2399 saveHist();
2400
2401 saveCalibration(m_timeCableDelay, "KLMTimeCableDelay");
2402 saveCalibration(m_timeConstants, "KLMTimeConstants");
2403 saveCalibration(m_timeResolution, "KLMTimeResolution");
2404 saveCalibration(m_eventT0HitResolution, "KLMEventT0HitResolution");
2405
2407}
2408
2410{
2411 m_outFile->cd();
2412 B2INFO("Save Histograms into Files.");
2413
2414 /* Save vital plots. */
2415 TDirectory* dir_monitor = m_outFile->mkdir("monitor_Hists", "", true);
2416 dir_monitor->cd();
2417 h_calibrated->SetDirectory(dir_monitor);
2418 hc_calibrated->SetDirectory(dir_monitor);
2419 h_diff->SetDirectory(dir_monitor);
2420
2421 m_outFile->cd();
2422 TDirectory* dir_eventT0 = m_outFile->mkdir("EventT0", "", true);
2423 dir_eventT0->cd();
2424
2425 // Original histograms
2426 h_eventT0_rpc->SetDirectory(dir_eventT0);
2427 h_eventT0_scint->SetDirectory(dir_eventT0);
2428 h_eventT0_scint_end->SetDirectory(dir_eventT0);
2429
2430 hc_eventT0_rpc->SetDirectory(dir_eventT0);
2431 hc_eventT0_scint->SetDirectory(dir_eventT0);
2432 hc_eventT0_scint_end->SetDirectory(dir_eventT0);
2433
2434 // ==== NEW DIAGNOSTIC PLOTS ====
2435
2436 // Hit multiplicity
2437 h_nHits_plus_rpc->SetDirectory(dir_eventT0);
2438 h_nHits_minus_rpc->SetDirectory(dir_eventT0);
2439 h_nHits_plus_scint->SetDirectory(dir_eventT0);
2440 h_nHits_minus_scint->SetDirectory(dir_eventT0);
2441 h_nHits_plus_scint_end->SetDirectory(dir_eventT0);
2442 h_nHits_minus_scint_end->SetDirectory(dir_eventT0);
2443
2444 // ΔT0 vs v
2445 h2_deltaT0_vs_v_rpc->SetDirectory(dir_eventT0);
2446 h2_deltaT0_vs_v_scint->SetDirectory(dir_eventT0);
2447 h2_deltaT0_vs_v_scint_end->SetDirectory(dir_eventT0);
2448
2449 // Profile plots
2450 prof_deltaT0_rms_vs_v_rpc->SetDirectory(dir_eventT0);
2451 prof_deltaT0_rms_vs_v_scint->SetDirectory(dir_eventT0);
2452 prof_deltaT0_rms_vs_v_scint_end->SetDirectory(dir_eventT0);
2453
2454 // ΔT0 vs total hits
2455 h2_deltaT0_vs_nhits_rpc->SetDirectory(dir_eventT0);
2456 h2_deltaT0_vs_nhits_scint->SetDirectory(dir_eventT0);
2457 h2_deltaT0_vs_nhits_scint_end->SetDirectory(dir_eventT0);
2458
2459 // Multiplicity-binned ΔT0
2460 hc_eventT0_rpc_lowN->SetDirectory(dir_eventT0);
2461 hc_eventT0_rpc_midN->SetDirectory(dir_eventT0);
2462 hc_eventT0_rpc_highN->SetDirectory(dir_eventT0);
2463 hc_eventT0_scint_lowN->SetDirectory(dir_eventT0);
2464 hc_eventT0_scint_midN->SetDirectory(dir_eventT0);
2465 hc_eventT0_scint_highN->SetDirectory(dir_eventT0);
2466 hc_eventT0_scint_end_lowN->SetDirectory(dir_eventT0);
2467 hc_eventT0_scint_end_midN->SetDirectory(dir_eventT0);
2468 hc_eventT0_scint_end_highN->SetDirectory(dir_eventT0);
2469
2470 m_outFile->cd();
2471 TDirectory* dir_effC = m_outFile->mkdir("effC_Hists", "", true);
2472 dir_effC->cd();
2473 m_ProfileRpcPhi->SetDirectory(dir_effC);
2474 m_ProfileRpcZ->SetDirectory(dir_effC);
2475 m_ProfileBKLMScintillatorPhi->SetDirectory(dir_effC);
2476 m_ProfileBKLMScintillatorZ->SetDirectory(dir_effC);
2477 m_ProfileEKLMScintillatorPlane1->SetDirectory(dir_effC);
2478 m_ProfileEKLMScintillatorPlane2->SetDirectory(dir_effC);
2479 m_Profile2RpcPhi->SetDirectory(dir_effC);
2480 m_Profile2RpcZ->SetDirectory(dir_effC);
2481 m_Profile2BKLMScintillatorPhi->SetDirectory(dir_effC);
2482 m_Profile2BKLMScintillatorZ->SetDirectory(dir_effC);
2483 m_Profile2EKLMScintillatorPlane1->SetDirectory(dir_effC);
2484 m_Profile2EKLMScintillatorPlane2->SetDirectory(dir_effC);
2485
2486 m_outFile->cd();
2487 TDirectory* dir_time = m_outFile->mkdir("time", "", true);
2488 dir_time->cd();
2489
2490 h_time_scint->SetDirectory(dir_time);
2491 hc_time_scint->SetDirectory(dir_time);
2492
2493 h_time_scint_end->SetDirectory(dir_time);
2494 hc_time_scint_end->SetDirectory(dir_time);
2495
2496 h_time_rpc->SetDirectory(dir_time);
2497 hc_time_rpc->SetDirectory(dir_time);
2498
2499 gre_time_channel_rpc->Write("gre_time_channel_rpc");
2500 gre_time_channel_scint->Write("gre_time_channel_scint");
2501 gre_time_channel_scint_end->Write("gre_time_channel_scint_end");
2502 gr_timeShift_channel_rpc->Write("gr_timeShift_channel_rpc");
2503 gr_timeShift_channel_scint->Write("gr_timeShift_channel_scint");
2504 gr_timeShift_channel_scint_end->Write("gr_timeShift_channel_scint_end");
2505 gre_ctime_channel_rpc->Write("gre_ctime_channel_rpc");
2506 gre_ctime_channel_scint->Write("gre_ctime_channel_scint");
2507 gre_ctime_channel_scint_end->Write("gre_ctime_channel_scint_end");
2508 gr_timeRes_channel_rpc->Write("gr_timeRes_channel_rpc");
2509 gr_timeRes_channel_scint->Write("gr_timeRes_channel_scint");
2510 gr_timeRes_channel_scint_end->Write("gr_timeRes_channel_scint_end");
2511
2512 B2INFO("Top file setup Done.");
2513
2514 /* Save debug plots (only if m_saveAllPlots is true). */
2515 if (!m_saveAllPlots) {
2516 B2INFO("Skipping debug histogram directory creation (m_saveAllPlots = false)");
2517 m_outFile->cd();
2518 m_outFile->Write();
2519 m_outFile->Close();
2520 B2INFO("File Write and Close. Done.");
2521 return;
2522 }
2523
2524 TDirectory* dir_time_F[2];
2525 TDirectory* dir_time_FS[2][8];
2526 TDirectory* dir_time_FSL[2][8][15];
2527 TDirectory* dir_time_FSLP[2][8][15][2];
2528 TDirectory* dir_time_F_end[2];
2529 TDirectory* dir_time_FS_end[2][4];
2530 TDirectory* dir_time_FSL_end[2][4][14];
2531 TDirectory* dir_time_FSLP_end[2][4][14][2];
2532 char dirname[50];
2533 B2INFO("Sub files declare Done.");
2534 for (int iF = 0; iF < 2; ++iF) {
2535 h_timeF_rpc[iF]->SetDirectory(dir_time);
2536 hc_timeF_rpc[iF]->SetDirectory(dir_time);
2537
2538 h2_timeF_rpc[iF]->SetDirectory(dir_time);
2539 h2c_timeF_rpc[iF]->SetDirectory(dir_time);
2540
2541 h_timeF_scint[iF]->SetDirectory(dir_time);
2542 hc_timeF_scint[iF]->SetDirectory(dir_time);
2543
2544 h2_timeF_scint[iF]->SetDirectory(dir_time);
2545 h2c_timeF_scint[iF]->SetDirectory(dir_time);
2546
2547 h_timeF_scint_end[iF]->SetDirectory(dir_time);
2548 hc_timeF_scint_end[iF]->SetDirectory(dir_time);
2549
2550 h2_timeF_scint_end[iF]->SetDirectory(dir_time);
2551 h2c_timeF_scint_end[iF]->SetDirectory(dir_time);
2552
2553 sprintf(dirname, "isForward_%d", iF);
2554 dir_time_F[iF] = dir_time->mkdir(dirname, "", true);
2555 dir_time_F[iF]->cd();
2556
2557 for (int iS = 0; iS < 8; ++iS) {
2558 h_timeFS_rpc[iF][iS]->SetDirectory(dir_time_F[iF]);
2559 hc_timeFS_rpc[iF][iS]->SetDirectory(dir_time_F[iF]);
2560
2561 h_timeFS_scint[iF][iS]->SetDirectory(dir_time_F[iF]);
2562 hc_timeFS_scint[iF][iS]->SetDirectory(dir_time_F[iF]);
2563
2564 h2_timeFS[iF][iS]->SetDirectory(dir_time_F[iF]);
2565 h2c_timeFS[iF][iS]->SetDirectory(dir_time_F[iF]);
2566
2567 sprintf(dirname, "Sector_%d", iS + 1);
2568 dir_time_FS[iF][iS] = dir_time_F[iF]->mkdir(dirname, "", true);
2569 dir_time_FS[iF][iS]->cd();
2570
2571 for (int iL = 0; iL < 15; ++iL) {
2572 h_timeFSL[iF][iS][iL]->SetDirectory(dir_time_FS[iF][iS]);
2573 hc_timeFSL[iF][iS][iL]->SetDirectory(dir_time_FS[iF][iS]);
2574
2575 sprintf(dirname, "Layer_%d", iL + 1);
2576 dir_time_FSL[iF][iS][iL] = dir_time_FS[iF][iS]->mkdir(dirname, "", true);
2577 dir_time_FSL[iF][iS][iL]->cd();
2578 for (int iP = 0; iP < 2; ++iP) {
2579 h_timeFSLP[iF][iS][iL][iP]->SetDirectory(dir_time_FSL[iF][iS][iL]);
2580 hc_timeFSLP[iF][iS][iL][iP]->SetDirectory(dir_time_FSL[iF][iS][iL]);
2581 h2_timeFSLP[iF][iS][iL][iP]->SetDirectory(dir_time_FSL[iF][iS][iL]);
2582 h2c_timeFSLP[iF][iS][iL][iP]->SetDirectory(dir_time_FSL[iF][iS][iL]);
2583
2584 sprintf(dirname, "Plane_%d", iP);
2585 dir_time_FSLP[iF][iS][iL][iP] = dir_time_FSL[iF][iS][iL]->mkdir(dirname, "", true);
2586 dir_time_FSLP[iF][iS][iL][iP]->cd();
2587
2588 }
2589 }
2590 }
2591
2592 sprintf(dirname, "isForward_%d_end", iF + 1);
2593 dir_time_F_end[iF] = dir_time->mkdir(dirname, "", true);
2594 dir_time_F_end[iF]->cd();
2595 int maxLayer = 12 + 2 * iF;
2596 for (int iS = 0; iS < 4; ++iS) {
2597 h_timeFS_scint_end[iF][iS]->SetDirectory(dir_time_F_end[iF]);
2598 hc_timeFS_scint_end[iF][iS]->SetDirectory(dir_time_F_end[iF]);
2599
2600 h2_timeFS_end[iF][iS]->SetDirectory(dir_time_F_end[iF]);
2601 h2c_timeFS_end[iF][iS]->SetDirectory(dir_time_F_end[iF]);
2602
2603 sprintf(dirname, "Sector_%d_end", iS + 1);
2604 dir_time_FS_end[iF][iS] = dir_time_F_end[iF]->mkdir(dirname, "", true);
2605 dir_time_FS_end[iF][iS]->cd();
2606 for (int iL = 0; iL < maxLayer; ++iL) {
2607 h_timeFSL_end[iF][iS][iL]->SetDirectory(dir_time_FS_end[iF][iS]);
2608 hc_timeFSL_end[iF][iS][iL]->SetDirectory(dir_time_FS_end[iF][iS]);
2609
2610 sprintf(dirname, "Layer_%d_end", iL + 1);
2611 dir_time_FSL_end[iF][iS][iL] = dir_time_FS_end[iF][iS]->mkdir(dirname, "", true);
2612 dir_time_FSL_end[iF][iS][iL]->cd();
2613 for (int iP = 0; iP < 2; ++iP) {
2614 h_timeFSLP_end[iF][iS][iL][iP]->SetDirectory(dir_time_FSL_end[iF][iS][iL]);
2615 hc_timeFSLP_end[iF][iS][iL][iP]->SetDirectory(dir_time_FSL_end[iF][iS][iL]);
2616 h2_timeFSLP_end[iF][iS][iL][iP]->SetDirectory(dir_time_FSL_end[iF][iS][iL]);
2617 h2c_timeFSLP_end[iF][iS][iL][iP]->SetDirectory(dir_time_FSL_end[iF][iS][iL]);
2618
2619 sprintf(dirname, "plane_%d_end", iP);
2620 dir_time_FSLP_end[iF][iS][iL][iP] = dir_time_FSL_end[iF][iS][iL]->mkdir(dirname, "", true);
2621 dir_time_FSLP_end[iF][iS][iL][iP]->cd();
2622
2623 }
2624 }
2625 }
2626 }
2627 m_outFile->cd();
2628 m_outFile->Write();
2629 m_outFile->Close();
2630 B2INFO("File Write and Close. Done.");
2631}
2632
2634{
2635 double tS = 0.0;
2636 int iSub = klmChannel.getSubdetector();
2637 int iF = klmChannel.getSection();
2638 int iS = klmChannel.getSector();
2639 int iL = klmChannel.getLayer();
2640 int iP = klmChannel.getPlane();
2641 int iC = klmChannel.getStrip();
2643 if (iSub == KLMElementNumbers::c_BKLM)
2644 totNStrips = BKLMElementNumbers::getNStrips(iF, iS, iL, iP);
2645 if (iC == 1) {
2646 KLMChannelIndex kCIndex_upper(iSub, iF, iS, iL, iP, iC + 1);
2647 tS = tS_upperStrip(kCIndex_upper).second;
2648 } else if (iC == totNStrips) {
2649 KLMChannelIndex kCIndex_lower(iSub, iF, iS, iL, iP, iC - 1);
2650 tS = tS_lowerStrip(kCIndex_lower).second;
2651 } else {
2652 KLMChannelIndex kCIndex_upper(iSub, iF, iS, iL, iP, iC + 1);
2653 KLMChannelIndex kCIndex_lower(iSub, iF, iS, iL, iP, iC - 1);
2654 std::pair<int, double> tS_upper = tS_upperStrip(kCIndex_upper);
2655 std::pair<int, double> tS_lower = tS_lowerStrip(kCIndex_lower);
2656 unsigned int td_upper = tS_upper.first - iC;
2657 unsigned int td_lower = iC - tS_lower.first;
2658 unsigned int td = tS_upper.first - tS_lower.first;
2659 tS = (double(td_upper) * tS_lower.second + double(td_lower) * tS_upper.second) / double(td);
2660 }
2661 return tS;
2662}
2663
2664std::pair<int, double> KLMTimeAlgorithm::tS_upperStrip(const KLMChannelIndex& klmChannel)
2665{
2666 std::pair<int, double> tS;
2667 int cId = klmChannel.getKLMChannelNumber();
2668 int iSub = klmChannel.getSubdetector();
2669 int iF = klmChannel.getSection();
2670 int iS = klmChannel.getSector();
2671 int iL = klmChannel.getLayer();
2672 int iP = klmChannel.getPlane();
2673 int iC = klmChannel.getStrip();
2675 if (iSub == KLMElementNumbers::c_BKLM)
2676 totNStrips = BKLMElementNumbers::getNStrips(iF, iS, iL, iP);
2677 if (m_timeShift.find(cId) != m_timeShift.end()) {
2678 tS.first = iC;
2679 tS.second = m_timeShift[cId];
2680 } else if (iC == totNStrips) {
2681 tS.first = iC;
2682 tS.second = 0.0;
2683 } else {
2684 KLMChannelIndex kCIndex(iSub, iF, iS, iL, iP, iC + 1);
2685 tS = tS_upperStrip(kCIndex);
2686 }
2687 return tS;
2688}
2689
2690std::pair<int, double> KLMTimeAlgorithm::tS_lowerStrip(const KLMChannelIndex& klmChannel)
2691{
2692 std::pair<int, double> tS;
2693 int cId = klmChannel.getKLMChannelNumber();
2694 int iC = klmChannel.getStrip();
2695 if (m_timeShift.find(cId) != m_timeShift.end()) {
2696 tS.first = iC;
2697 tS.second = m_timeShift[cId];
2698 } else if (iC == 1) {
2699 tS.first = iC;
2700 tS.second = 0.0;
2701 } else {
2702 int iSub = klmChannel.getSubdetector();
2703 int iF = klmChannel.getSection();
2704 int iS = klmChannel.getSector();
2705 int iL = klmChannel.getLayer();
2706 int iP = klmChannel.getPlane();
2707 KLMChannelIndex kCIndex(iSub, iF, iS, iL, iP, iC - 1);
2708 tS = tS_lowerStrip(kCIndex);
2709 }
2710 return tS;
2711}
2712
2714{
2715 double tR = 0.0;
2716 int iSub = klmChannel.getSubdetector();
2717 int iF = klmChannel.getSection();
2718 int iS = klmChannel.getSector();
2719 int iL = klmChannel.getLayer();
2720 int iP = klmChannel.getPlane();
2721 int iC = klmChannel.getStrip();
2723 if (iSub == KLMElementNumbers::c_BKLM)
2724 totNStrips = BKLMElementNumbers::getNStrips(iF, iS, iL, iP);
2725 if (iC == 1) {
2726 KLMChannelIndex kCIndex_upper(iSub, iF, iS, iL, iP, iC + 1);
2727 tR = tR_upperStrip(kCIndex_upper).second;
2728 } else if (iC == totNStrips) {
2729 KLMChannelIndex kCIndex_lower(iSub, iF, iS, iL, iP, iC - 1);
2730 tR = tR_lowerStrip(kCIndex_lower).second;
2731 } else {
2732 KLMChannelIndex kCIndex_upper(iSub, iF, iS, iL, iP, iC + 1);
2733 KLMChannelIndex kCIndex_lower(iSub, iF, iS, iL, iP, iC - 1);
2734 std::pair<int, double> tR_upper = tR_upperStrip(kCIndex_upper);
2735 std::pair<int, double> tR_lower = tR_lowerStrip(kCIndex_lower);
2736 unsigned int tr_upper = tR_upper.first - iC;
2737 unsigned int tr_lower = iC - tR_lower.first;
2738 unsigned int tr = tR_upper.first - tR_lower.first;
2739 tR = (double(tr_upper) * tR_lower.second + double(tr_lower) * tR_upper.second) / double(tr);
2740 }
2741 return tR;
2742}
2743
2744std::pair<int, double> KLMTimeAlgorithm::tR_upperStrip(const KLMChannelIndex& klmChannel)
2745{
2746 std::pair<int, double> tR;
2747 int cId = klmChannel.getKLMChannelNumber();
2748 int iSub = klmChannel.getSubdetector();
2749 int iF = klmChannel.getSection();
2750 int iS = klmChannel.getSector();
2751 int iL = klmChannel.getLayer();
2752 int iP = klmChannel.getPlane();
2753 int iC = klmChannel.getStrip();
2755 if (iSub == KLMElementNumbers::c_BKLM)
2756 totNStrips = BKLMElementNumbers::getNStrips(iF, iS, iL, iP);
2757 if (m_timeRes.find(cId) != m_timeRes.end()) {
2758 tR.first = iC;
2759 tR.second = m_timeRes[cId];
2760 } else if (iC == totNStrips) {
2761 tR.first = iC;
2762 tR.second = 0.0;
2763 } else {
2764 KLMChannelIndex kCIndex(iSub, iF, iS, iL, iP, iC + 1);
2765 tR = tR_upperStrip(kCIndex);
2766 }
2767 return tR;
2768}
2769
2770std::pair<int, double> KLMTimeAlgorithm::tR_lowerStrip(const KLMChannelIndex& klmChannel)
2771{
2772 std::pair<int, double> tR;
2773 int cId = klmChannel.getKLMChannelNumber();
2774 int iC = klmChannel.getStrip();
2775 if (m_timeRes.find(cId) != m_timeRes.end()) {
2776 tR.first = iC;
2777 tR.second = m_timeRes[cId];
2778 } else if (iC == 1) {
2779 tR.first = iC;
2780 tR.second = 0.0;
2781 } else {
2782 int iSub = klmChannel.getSubdetector();
2783 int iF = klmChannel.getSection();
2784 int iS = klmChannel.getSector();
2785 int iL = klmChannel.getLayer();
2786 int iP = klmChannel.getPlane();
2787 KLMChannelIndex kCIndex(iSub, iF, iS, iL, iP, iC - 1);
2788 tR = tR_lowerStrip(kCIndex);
2789 }
2790 return tR;
2791}
@ c_FirstRPCLayer
First RPC layer.
static int getNStrips(int section, int sector, int layer, int plane)
Get number of strips.
void saveCalibration(TClonesArray *data, const std::string &name)
Store DBArray payload with given name with default IOV.
const std::vector< Calibration::ExpRun > & getRunList() const
Get the list of runs for which calibration is called.
EResult
The result of calibration.
@ c_OK
Finished successfully =0 in Python.
@ c_NotEnoughData
Needs more data =2 in Python.
CalibrationAlgorithm(const std::string &collectorModuleName)
Constructor - sets the prefix for collected objects (won't be accesses until execute(....
Class for accessing objects in the database.
Definition DBObjPtr.h:21
Singleton class to cache database objects.
Definition DBStore.h:31
static DataStore & Instance()
Instance of singleton Store.
Definition DataStore.cc:53
void setInitializeActive(bool active)
Setter for m_initializeActive.
Definition DataStore.cc:93
static constexpr int getMaximalStripNumber()
Get maximal strip number.
static const GeometryData & Instance(enum DataSource dataSource=c_Database, const GearDir *gearDir=nullptr)
Instantiation.
KLM channel index.
int getSubdetector() const
Get subdetector.
int getLayer() const
Get layer.
int getSection() const
Get section.
int getPlane() const
Get plane.
int getStrip() const
Get strip.
int getSector() const
Get sector.
KLMChannelNumber getKLMChannelNumber() const
Get KLM channel number.
static const KLMElementNumbers & Instance()
Instantiation.
Class to store per-hit time resolution (sigma) for KLM EventT0, separated by detector type.
TProfile * m_Profile2EKLMScintillatorPlane2
For EKLM scintillator plane2.
TDirectory * m_channelHistDir_BKLM[2][8][15][2]
Directory structure for per-channel histograms (BKLM).
double mc_etime_channelAvg_rpc
Calibrated central value error of the global time distribution (BKLM RPC part).
bool m_applyChargeRestriction
Whether to apply ADC/charge restriction cuts for scintillators.
TH2F * h2c_timeF_scint_end[2]
EKLM part.
KLMTimeResolution * m_timeResolution
DBObject of time resolution.
TH1F * hc_eventT0_scint_end_highN
Corrected EventT0 for EKLM scintillator with high hit count.
TProfile * prof_deltaT0_rms_vs_v_scint_end
DeltaT0 RMS vs inverse hit count profile for EKLM scintillator.
TH1F * h_time_scint_tc_end
EKLM part.
TH1F * hc_eventT0_scint_midN
Corrected EventT0 for BKLM scintillator with medium hit count.
void createHistograms()
Create histograms.
TGraphErrors * gre_time_channel_scint
BKLM Scintillator.
TH1F * h_timeFSL[2][8][15]
BKLM part.
TH1F * hc_timeFSL_end[2][4][14]
EKLM part.
TH1F * h_timeFSLP_end[2][4][14][2]
EKLM part.
TGraph * gr_timeRes_channel_rpc
BKLM RPC.
TH1F * hc_timeFSLP_end[2][4][14][2]
EKLM part.
TH1F * h_timeFSLP[2][8][15][2]
BKLM part.
TH1F * hc_timeF_scint_end[2]
EKLM part.
std::map< KLMChannelNumber, double > m_timeShift
Shift values of each channel.
TH1F * h_time_scint
BKLM scintillator part.
double m_time_channelAvg_scint
Central value of the global time distribution (BKLM scintillator part).
TH1F * hc_timeFS_scint_end[2][4]
EKLM part.
double esti_timeRes(const KLMChannelIndex &klmChannel)
Estimate value of calibration constant for calibrated channels.
double m_UpperTimeBoundaryCalibratedRPC
Upper time boundary for RPC (calibrated data).
double m_ctime_channelAvg_rpc
Calibrated central value of the global time distribution (BKLM RPC part).
KLMTimeConstants * m_timeConstants
DBObject of time cost on some parts of the detector.
void setupDatabase()
Setup the database.
TProfile * prof_deltaT0_rms_vs_v_rpc
DeltaT0 RMS vs inverse hit count profile for RPC.
TH1F * h_eventT0_scint
EventT0 seen by BKLM scintillator hits.
TH1F * hc_timeFS_scint[2][8]
BKLM scintillator part.
std::map< KLMChannelNumber, double > m_time_channel
Time distribution central value of each channel.
TH1F * hc_eventT0_rpc_lowN
Corrected EventT0 for RPC with low hit count.
double m_ctime_channelAvg_scint_end
Calibrated central value of the global time distribution (EKLM scintillator part).
CalibrationAlgorithm::EResult readCalibrationData()
Read calibration data.
TH1F * hc_eventT0_scint_lowN
Corrected EventT0 for BKLM scintillator with low hit count.
TGraph * gr_timeShift_channel_scint_end
EKLM.
TGraph * gr_timeRes_channel_scint
BKLM scintillator.
TH2F * h2_deltaT0_vs_v_scint
DeltaT0 vs inverse hit count for BKLM scintillator.
TH1F * hc_timeF_scint[2]
BKLM scintillator part.
TH1F * h_timeFS_scint[2][8]
BKLM scintillator part.
bool m_saveChannelHists
Write per-channel temporary histograms (tc/raw/hc) in minimal mode.
double m_UpperTimeBoundaryScintillatorsBKLM
Upper time boundary for BKLM scintillators.
const KLMElementNumbers * m_ElementNumbers
Element numbers.
void writeThenDelete_(TH1 *h, bool write, TDirectory *dir=nullptr)
Optionally write a histogram, then delete it to free memory.
std::pair< int, double > tR_upperStrip(const KLMChannelIndex &klmChannel)
Tracing available channels with increasing strip number.
TH1F * hc_timeF_rpc[2]
BKLM RPC part.
TH2F * h2c_timeFS_end[2][4]
EKLM part.
const EKLM::GeometryData * m_EKLMGeometry
EKLM geometry data.
TGraphErrors * gre_ctime_channel_scint_end
EKLM.
TH1F * h_nHits_plus_scint_end
Number of EKLM scintillator hits per mu+ track.
TProfile * m_Profile2BKLMScintillatorPhi
For BKLM scintillator phi plane.
TH1F * hc_time_scint_end
EKLM part.
TH1F * hc_eventT0_scint
Corrected EventT0 for BKLM scintillator hits.
TGraphErrors * gre_time_channel_scint_end
EKLM.
TH2F * h2_timeFSLP[2][8][15][2]
BKLM part.
double m_UpperTimeBoundaryCalibratedScintillatorsEKLM
Upper time boundary for BKLM scintillators (calibrated data).
TGraph * gr_timeShift_channel_scint
BKLM scintillator.
double m_time_channelAvg_scint_end
Central value of the global time distribution (EKLM scintillator part).
TProfile * m_Profile2EKLMScintillatorPlane1
For EKLM scintillator plane1.
TH1F * hc_timeFS_rpc[2][8]
BKLM RPC part.
double m_UpperTimeBoundaryScintillatorsEKLM
Upper time boundary for BKLM scintillators.
void fillTimeDistanceProfiles(TProfile *profileRpcPhi, TProfile *profileRpcZ, TProfile *profileBKLMScintillatorPhi, TProfile *profileBKLMScintillatorZ, TProfile *profileEKLMScintillatorPlane1, TProfile *profileEKLMScintillatorPlane2, bool fill2dHistograms)
Fill profiles of time versus distance.
TFile * m_outFile
Output file.
double esti_timeShift(const KLMChannelIndex &klmChannel)
Estimate value of calibration constant for uncalibrated channels.
std::pair< int, double > tS_upperStrip(const KLMChannelIndex &klmChannel)
Tracing available channels with increasing strip number.
double m_LowerTimeBoundaryCalibratedScintillatorsEKLM
Lower time boundary for EKLM scintillators (calibrated data).
TH1F * hc_timeFSLP[2][8][15][2]
BKLM part.
TGraphErrors * gre_ctime_channel_rpc
BKLM RPC.
void saveHist()
Save histograms to file.
const bklm::GeometryPar * m_BKLMGeometry
BKLM geometry data.
bool m_saveAllPlots
Default minimal unless you set true in your header script.
TH2F * h2c_timeFSLP[2][8][15][2]
BKLM part.
double m_ctime_channelAvg_scint
Calibrated central value of the global time distribution (BKLM scintillator part).
~KLMTimeAlgorithm() override
Destructor.
TF1 * fcn_const
Const function.
double m_UpperTimeBoundaryCalibratedScintillatorsBKLM
Upper time boundary for BKLM scintillators (calibrated data).
TProfile * m_Profile2RpcZ
For BKLM RPC z plane.
TH1F * h_nHits_minus_rpc
Number of RPC hits per mu- track.
TH2F * h2_timeFSLP_end[2][4][14][2]
EKLM part.
TH1I * hc_calibrated
Calibration statistics for each channel.
TH1F * h_eventT0_rpc
EventT0 seen by RPC hits.
void timeDistance2dFit(const std::vector< std::pair< KLMChannelNumber, unsigned int > > &channels, double &delay, double &delayError)
Two-dimensional fit for individual channels.
TGraph * gr_timeRes_channel_scint_end
EKLM.
TH1I * h_calibrated
Calibration statistics for each channel.
TProfile * m_ProfileBKLMScintillatorZ
For BKLM scintillator z plane.
double m_LowerTimeBoundaryScintillatorsBKLM
Lower time boundary for BKLM scintillators.
TH1F * hc_eventT0_scint_end_midN
Corrected EventT0 for EKLM scintillator with medium hit count.
TH1F * h_time_rpc_tc
BKLM RPC part.
TH1F * h_time_scint_end
EKLM part.
TH2F * h2c_timeF_scint[2]
BKLM scintillator part.
TF1 * fcn_pol1
Pol1 function.
double m_etime_channelAvg_scint_end
Central value error of the global time distribution (EKLM scintillator part).
TH1F * hc_time_rpc
BKLM RPC part.
double mc_etime_channelAvg_scint
Calibrated central value error of the global time distribution (BKLM scintillator part).
TH2F * h2c_timeFSLP_end[2][4][14][2]
EKLM part.
double mc_etime_channelAvg_scint_end
Calibrated central value error of the global time distribution (EKLM scintillator part).
bool passesADCCut(const Event &event, int subdetector, int layer) const
Check if event passes ADC count cuts for quality selection.
TH2F * h2_timeF_scint_end[2]
EKLM part.
KLMEventT0HitResolution * m_eventT0HitResolution
DBObject of per-hit time resolution for EventT0.
TF1 * fcn_gaus
Gaussian function.
double m_LowerTimeBoundaryCalibratedScintillatorsBKLM
Lower time boundary for BKLM scintillators (calibrated data).
TH1F * h_timeF_rpc[2]
BKLM RPC part.
TProfile * m_ProfileBKLMScintillatorPhi
For BKLM scintillator phi plane.
TH1F * hc_time_scint
BKLM scintillator part.
TH2F * h2_timeFS[2][8]
BKLM part.
double m_fixedRPCDelay
Fixed propagation delay for RPCs (ns/cm).
double m_etime_channelAvg_scint
Central value error of the global time distribution (BKLM scintillator part).
TH1F * h_timeF_scint_end[2]
EKLM part.
TH1F * hc_eventT0_scint_end
Corrected EventT0 for EKLM scintillator hits.
TProfile * m_ProfileRpcPhi
For BKLM RPC phi plane.
TGraphErrors * gre_ctime_channel_scint
BKLM Scintillator.
TH2F * h2_deltaT0_vs_nhits_scint
DeltaT0 vs total hit count for BKLM scintillator.
TH2F * h2_deltaT0_vs_nhits_rpc
DeltaT0 vs total hit count for RPC.
TProfile * m_ProfileEKLMScintillatorPlane2
For EKLM scintillator plane2.
TH1F * h_time_rpc
BKLM RPC part.
TH1F * h_timeFSL_end[2][4][14]
EKLM part.
TProfile * m_Profile2RpcPhi
For BKLM RPC phi plane.
TH1F * h_timeF_scint[2]
BKLM scintillator part.
TH1F * hc_timeFSL[2][8][15]
BKLM part.
TProfile * m_Profile2BKLMScintillatorZ
For BKLM scintillator z plane.
TH2F * h2_deltaT0_vs_v_scint_end
DeltaT0 vs inverse hit count for EKLM scintillator.
TH1F * h_timeFS_rpc[2][8]
BKLM RPC part.
KLMChannelIndex m_klmChannels
KLM ChannelIndex object.
TGraph * gr_timeShift_channel_rpc
BKLM RPC.
std::map< KLMChannelNumber, double > m_timeRes
Resolution values of each channel.
TH1F * h_eventT0_scint_end
EventT0 seen by EKLM scintillator hits.
TH1F * h_diff
Distance between global and local position.
TH1F * hc_eventT0_rpc_highN
Corrected EventT0 for RPC with high hit count.
TH1F * h_nHits_plus_scint
Number of BKLM scintillator hits per mu+ track.
TH2F * h2_timeF_scint[2]
BKLM scintillator part.
TH1F * h_time_scint_tc
BKLM scintillator part.
double m_LowerTimeBoundaryRPC
Lower time boundary for RPC.
virtual EResult calibrate() override
Run algorithm on data.
std::map< KLMChannelNumber, double > m_ctime_channel
Calibrated time distribution central value of each channel.
double m_LowerTimeBoundaryCalibratedRPC
Lower time boundary for RPC (calibrated data).
TH2F * h2_deltaT0_vs_nhits_scint_end
DeltaT0 vs total hit count for EKLM scintillator.
bool m_useEventT0
Whether to use event T0 from CDC.
int m_MinimalDigitNumber
Minimal digit number (total).
TProfile * m_ProfileEKLMScintillatorPlane1
For EKLM scintillator plane1.
double m_UpperTimeBoundaryRPC
Upper time boundary for RPC.
TH2F * h2c_timeF_rpc[2]
BKLM RPC part.
TH1F * hc_eventT0_scint_highN
Corrected EventT0 for BKLM scintillator with high hit count.
TF1 * fcn_land
Landau function.
KLMTimeCableDelay * m_timeCableDelay
DBObject of the calibration constant of each channel due to cable decay.
TH2F * h2_deltaT0_vs_v_rpc
DeltaT0 vs inverse hit count for RPC.
std::pair< int, double > tS_lowerStrip(const KLMChannelIndex &klmChannel)
Tracing available channels with decreasing strip number.
TProfile * m_ProfileRpcZ
For BKLM RPC z plane.
bool m_useFixedRPCDelay
Whether to use fixed propagation delay for RPCs.
std::map< KLMChannelNumber, double > mc_etime_channel
Calibrated time distribution central value Error of each channel.
std::pair< int, double > tR_lowerStrip(const KLMChannelIndex &klmChannel)
Tracing available channels with decreasing strip number.
void readCalibrationDataBatch(std::function< bool(const KLMChannelIndex &)> channelFilter)
Load calibration data for a specific batch of channels.
TH1F * hc_eventT0_rpc_midN
Corrected EventT0 for RPC with medium hit count.
TH1F * h_nHits_minus_scint
Number of BKLM scintillator hits per mu- track.
ROOT::Math::MinimizerOptions m_minimizerOptions
Minimization options.
TProfile * prof_deltaT0_rms_vs_v_scint
DeltaT0 RMS vs inverse hit count profile for BKLM scintillator.
std::map< KLMChannelNumber, int > m_cFlag
Calibration flag if the channel has enough hits collected and fitted OK.
TGraphErrors * gre_time_channel_rpc
BKLM RPC.
TH2F * h2_timeFS_end[2][4]
EKLM part.
TH2F * h2_timeF_rpc[2]
BKLM RPC part.
TH1F * h_nHits_plus_rpc
Number of RPC hits per mu+ track.
std::map< KLMChannelNumber, std::vector< struct Event > > m_evts
Container of hit information.
TDirectory * m_channelHistDir_EKLM[2][4][14][2]
Directory structure for per-channel histograms (EKLM).
TH1F * hc_eventT0_rpc
Corrected EventT0 for RPC hits.
TH1F * h_nHits_minus_scint_end
Number of EKLM scintillator hits per mu- track.
TH1F * h_timeFS_scint_end[2][4]
EKLM part.
double m_time_channelAvg_rpc
Central value of the global time distribution (BKLM RPC part).
TH2F * h2c_timeFS[2][8]
BKLM part.
double m_etime_channelAvg_rpc
Central value error of the global time distribution (BKLM RPC part).
double m_LowerTimeBoundaryScintillatorsEKLM
Lower time boundary for EKLM scintillators.
void readCalibrationDataCounts(std::map< KLMChannelNumber, unsigned int > &eventCounts)
Count events per channel (lightweight scan without loading full data).
std::map< KLMChannelNumber, double > m_etime_channel
Time distribution central value Error of each channel.
int m_lower_limit_counts
Lower limit of hits collected for on single channel.
TH1F * hc_eventT0_scint_end_lowN
Corrected EventT0 for EKLM scintillator with low hit count.
void readCalibrationDataFor2DFit(const std::vector< std::pair< KLMChannelNumber, unsigned int > > &channelsBKLM, const std::vector< std::pair< KLMChannelNumber, unsigned int > > &channelsEKLM)
Load calibration data only for channels needed for 2D fit.
Class to store BKLM delay time coused by cable in the database.
Class to store KLM constants related to time.
@ c_BKLM
BKLM scintillator.
@ c_EKLM
EKLM scintillator.
Class to store KLM time resolution in the database.
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
Type-safe access to single objects in the data store.
Definition StoreObjPtr.h:96
bool isValid() const
Check whether the object was created.
bool construct(Args &&... params)
Construct an object of type T in this StoreObjPtr, using the provided constructor arguments.
static const double cm
Standard units with the value = 1.
Definition Unit.h:47
static GeometryPar * instance(void)
Static method to get a reference to the singleton GeometryPar instance.
Define the geometry of a BKLM module Each sector [octant] contains Modules.
Definition Module.h:76
Class to store variables with their name which were sent to the logging service.
std::shared_ptr< T > getObjectPtr(const std::string &name, const std::vector< Calibration::ExpRun > &requestedRuns)
Get calibration data object by name and list of runs, the Merge function will be called to generate t...
constexpr T square(const T &x)
Calculate the square of the input.
Definition MathHelpers.h:21
static DBStore & Instance()
Instance of a singleton DBStore.
Definition DBStore.cc:26
void updateEvent()
Updates all intra-run dependent objects.
Definition DBStore.cc:140
void update()
Updates all objects that are outside their interval of validity.
Definition DBStore.cc:77
double sqrt(double a)
sqrt for double
Definition beamHelpers.h:28
uint16_t KLMChannelNumber
Channel number.
Abstract base class for different kinds of events.