9 #include <top/modules/collectors/TOPValidationCollectorModule.h>
10 #include <top/geometry/TOPGeometryPar.h>
11 #include <top/reconstruction_cpp/TOPTrack.h>
12 #include <top/reconstruction_cpp/PDFConstructor.h>
13 #include <top/reconstruction_cpp/TOPRecoManager.h>
16 #include <framework/gearbox/Const.h>
17 #include <framework/logging/Logger.h>
18 #include <framework/dataobjects/EventMetaData.h>
51 setDescription(
"A collector for automatic validation of TOP calibration");
52 setPropertyFlags(c_ParallelProcessingCertified);
55 addParam(
"numBins", m_numBins,
"number of bins of the search region", 100);
56 addParam(
"timeRange", m_timeRange,
57 "time range in which to search for the minimum [ns]", 10.0);
58 addParam(
"sigmaSmear", m_sigmaSmear,
59 "sigma in [ns] for additional smearing of PDF", 0.0);
60 addParam(
"sample", m_sample,
61 "sample type: one of dimuon or bhabha", std::string(
"dimuon"));
62 addParam(
"deltaEcms", m_deltaEcms,
63 "c.m.s energy window (half size) if sample is dimuon or bhabha", 0.1);
64 addParam(
"dr", m_dr,
"cut on POCA in r", 2.0);
65 addParam(
"dz", m_dz,
"cut on POCA in abs(z)", 4.0);
66 addParam(
"minZ", m_minZ,
67 "minimal local z of extrapolated hit", -130.0);
68 addParam(
"maxZ", m_maxZ,
69 "maximal local z of extrapolated hit", 130.0);
70 addParam(
"pdfOption", m_pdfOption,
71 "PDF option, one of 'rough', 'fine', 'optimal'", std::string(
"rough"));
76 void TOPValidationCollectorModule::prepare()
80 m_digits.isRequired();
81 m_tracks.isRequired();
82 m_extHits.isRequired();
83 m_recBunch.isRequired();
87 if (m_pdfOption ==
"rough") {
88 m_PDFOption = PDFConstructor::c_Rough;
89 }
else if (m_pdfOption ==
"fine") {
90 m_PDFOption = PDFConstructor::c_Fine;
91 }
else if (m_pdfOption ==
"optimal") {
92 m_PDFOption = PDFConstructor::c_Optimal;
94 B2ERROR(
"Unknown PDF option '" << m_pdfOption <<
"'");
99 if (m_sample ==
"dimuon" or m_sample ==
"bhabha") {
101 m_selector.setDeltaEcms(m_deltaEcms);
102 m_selector.setCutOnPOCA(m_dr, m_dz);
103 m_selector.setCutOnLocalZ(m_minZ, m_maxZ);
105 B2ERROR(
"Invalid sample type '" << m_sample <<
"'");
110 double tmin = -m_timeRange / 2;
111 double tmax = m_timeRange / 2;
112 for (
int set = 0; set < c_numSets; set++) {
113 for (
int slot = 1; slot <= c_numModules; slot++) {
120 for (
int slot = 1; slot <= c_numModules; slot++) {
121 string slotName = to_string(slot);
122 if (slot < 10) slotName.insert(0,
"0");
123 string name =
"chi2_slot" + slotName;
124 string title =
"Chi2 scan, slot" + slotName +
"; channel; t0 [ns]";
125 auto h =
new TH2F(name.c_str(), title.c_str(), c_numChannels, 0, c_numChannels, m_numBins, tmin, tmax);
126 registerObject<TH2F>(name, h);
127 m_namesChi.push_back(name);
130 for (
int slot = 1; slot <= c_numModules; slot++) {
131 string slotName = to_string(slot);
132 if (slot < 10) slotName.insert(0,
"0");
133 string name =
"hits_slot" + slotName;
134 string title =
"Photon hits, slot" + slotName +
"; channel; time [ns]";
135 auto h =
new TH2F(name.c_str(), title.c_str(), c_numChannels, 0, c_numChannels, 100, 0., 20.);
136 registerObject<TH2F>(name, h);
137 m_namesHit.push_back(name);
140 auto h =
new TH1F(
"moduleT0_pulls",
"Module T0 pulls; pulls", 200, -15.0, 15.0);
141 registerObject<TH1F>(
"moduleT0_pulls", h);
143 auto tree =
new TTree(
"tree",
"TOP calibration validation tree");
144 tree->Branch(
"expNo", &m_treeEntry.expNo,
"expNo/I");
145 tree->Branch(
"runNo", &m_treeEntry.runNo,
"runNo/I");
146 tree->Branch(
"numTracks", &m_treeEntry.numTracks,
"numTracks/I");
147 tree->Branch(
"commonT0", &m_treeEntry.commonT0,
"commonT0/F");
148 tree->Branch(
"commonT0Err", &m_treeEntry.commonT0Err,
"commonT0Err/F");
149 tree->Branch(
"moduleT0", &m_treeEntry.moduleT0,
"moduleT0[16]/F");
150 tree->Branch(
"moduleT0Err", &m_treeEntry.moduleT0Err,
"moduleT0Err[16]/F");
151 tree->Branch(
"numTBCalibrated", &m_treeEntry.numTBCalibrated,
"numTBCalibrated[16]/I");
152 tree->Branch(
"numT0Calibrated", &m_treeEntry.numT0Calibrated,
"numT0Calibrated[16]/I");
153 tree->Branch(
"numActive", &m_treeEntry.numActive,
"numActive[16]/I");
154 tree->Branch(
"numActiveCalibrated", &m_treeEntry.numActiveCalibrated,
"numActiveCalibrated[16]/I");
155 tree->Branch(
"thrEffi", &m_treeEntry.thrEffi,
"thrEffi[16]/F");
156 tree->Branch(
"asicShifts", &m_treeEntry.asicShifts,
"asicShifts[4]/F");
157 registerObject<TTree>(
"tree", tree);
161 void TOPValidationCollectorModule::startRun()
167 m_treeEntry.expNo = evtMetaData->getExperiment();
168 m_treeEntry.runNo = evtMetaData->getRun();
172 for (
auto& finders : m_finders) {
173 for (
auto& finder : finders) finder.clear();
178 const auto& fe_mapper = TOPGeometryPar::Instance()->getFrontEndMapper();
179 for (
unsigned module = 0; module < c_numModules; module++) {
180 auto& numTBCalibrated = m_treeEntry.numTBCalibrated[module];
181 auto& numT0Calibrated = m_treeEntry.numT0Calibrated[module];
182 auto& numActive = m_treeEntry.numActive[module];
183 auto& numActiveCalibrated = m_treeEntry.numActiveCalibrated[module];
184 auto& thrEffi = m_treeEntry.thrEffi[module];
185 int slot = module + 1;
186 for (
unsigned channel = 0; channel < c_numChannels; channel++) {
187 bool tbCalibrated =
false;
188 const auto* fe = fe_mapper.getMap(slot, channel / 128);
190 tbCalibrated = m_timebase->isAvailable(fe->getScrodID(), channel);
192 B2ERROR(
"No front-end map found");
194 bool t0Calibrated = m_channelT0->isCalibrated(slot, channel);
195 bool active = m_channelMask->isActive(slot, channel);
196 if (tbCalibrated) numTBCalibrated++;
197 if (t0Calibrated) numT0Calibrated++;
198 if (active) numActive++;
199 if (tbCalibrated and t0Calibrated and active) {
200 numActiveCalibrated++;
201 thrEffi += m_thresholdEff->getThrEff(slot, channel);
204 if (numActiveCalibrated > 0) thrEffi /= numActiveCalibrated;
207 for (
unsigned carrier = 0; carrier < 4; carrier++) {
208 unsigned asic = (3 * 4 + carrier) * 4;
209 m_treeEntry.asicShifts[carrier] = m_asicShift->isCalibrated(13, asic) ? m_asicShift->getT0(13, asic) :
210 std::numeric_limits<float>::quiet_NaN();
216 void TOPValidationCollectorModule::collect()
220 if (not m_recBunch.isValid())
return;
221 if (not m_recBunch->isReconstructed())
return;
223 TOPRecoManager::setDefaultTimeWindow();
224 const auto& chMapper = TOPGeometryPar::Instance()->getChannelMapper();
228 for (
const auto& track : m_tracks) {
232 if (not trk.
isValid())
continue;
234 if (not m_selector.isSelected(trk))
continue;
237 PDFConstructor pdfConstructor(trk, m_selector.getChargedStable(), m_PDFOption);
238 if (not pdfConstructor.
isValid())
continue;
242 if (module >= m_namesChi.size())
continue;
243 auto h = getObjectPtr<TH2F>(m_namesChi[module]);
244 int set = gRandom->Integer(c_numSets);
245 auto& finder = m_finders[set][module];
246 for (
int ibin = 0; ibin < h->GetNbinsY(); ibin++) {
247 double t0 = h->GetYaxis()->GetBinCenter(ibin + 1);
248 const auto& pixelLogLs = pdfConstructor.
getPixelLogLs(t0, m_sigmaSmear);
249 for (
unsigned channel = 0; channel < c_numChannels; channel++) {
250 int pix = chMapper.getPixelID(channel) - 1;
251 double chi = h->GetBinContent(channel + 1, ibin + 1);
252 chi += -2 * pixelLogLs[pix].logL;
253 h->SetBinContent(channel + 1, ibin + 1, chi);
256 for (
auto& LL : pixelLogLs) logL += LL.logL;
257 finder.add(ibin, -2 * logL);
259 m_treeEntry.numTracks++;
261 auto h1 = getObjectPtr<TH2F>(m_namesHit[module]);
262 for (
const auto& digit : m_digits) {
263 if (digit.getHitQuality() != TOPDigit::c_Good)
continue;
264 if (digit.getModuleID() != trk.
getModuleID())
continue;
265 h1->Fill(digit.getChannel(), digit.getTime());
271 void TOPValidationCollectorModule::closeRun()
276 for (
int module = 0; module < c_numModules; module++) {
277 std::vector<double> pos, err;
278 for (
int set = 0; set < c_numSets; set++) {
279 const auto& minimum = m_finders[set][module].getMinimum();
281 pos.push_back(minimum.position);
282 err.push_back(minimum.error);
285 auto h_pulls = getObjectPtr<TH1F>(
"moduleT0_pulls");
286 for (
unsigned i = 0; i < pos.size(); i++) {
287 for (
unsigned j = i + 1; j < pos.size(); j++) {
288 double pull = (pos[i] - pos[j]) / sqrt(err[i] * err[i] + err[j] * err[j]);
296 for (
int module = 0; module < c_numModules; module++) {
297 auto& finder = m_finders[0][module];
298 for (
int set = 1; set < c_numSets; set++) {
299 finder.add(m_finders[set][module]);
301 const auto& minimum = finder.getMinimum();
303 m_treeEntry.moduleT0[module] = minimum.position;
304 m_treeEntry.moduleT0Err[module] = minimum.error;
310 auto& finder = m_finders[0][0];
311 for (
int module = 1; module < c_numModules; module++) {
312 finder.add(m_finders[0][module]);
314 const auto& minimum = finder.getMinimum();
316 m_treeEntry.commonT0 = minimum.position;
317 m_treeEntry.commonT0Err = minimum.error;
322 auto tree = getObjectPtr<TTree>(
"tree");
Type-safe access to single objects in the data store.
Collector for automatic validation of calibration with dimuon events.
Minimum finder using tabulated chi^2 values in one dimension.
PDF construction and log likelihood determination for a given track and particle hypothesis.
bool isValid() const
Checks the object status.
const std::vector< LogL > & getPixelLogLs(double t0, double sigt=0) const
Returns extended log likelihoods in pixels for PDF shifted in time.
Reconstructed track at TOP.
bool isValid() const
Checks if track is successfully constructed.
int getModuleID() const
Returns slot ID.
Utility for the track selection - used in various calibration modules.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Abstract base class for different kinds of events.