Belle II Software development
TOPValidationAlgorithm.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#include <top/calibration/TOPValidationAlgorithm.h>
10#include <top/utilities/Chi2MinimumFinder1D.h>
11#include <top/dbobjects/TOPCalPrecision.h>
12
13#include <TFile.h>
14#include <TH1F.h>
15#include <TH1D.h>
16#include <TH2F.h>
17#include <TProfile.h>
18
19#include <string>
20#include <vector>
21#include <map>
22#include <set>
23#include <cmath>
24
25using namespace std;
26
27namespace Belle2 {
32 namespace TOP {
33
35 CalibrationAlgorithm("TOPValidationCollector")
36 {
37 setDescription("Calibration algorithm for automatic validation of the calibration");
38 }
39
40
42 {
43 // open output root file
44
45 auto* file = TFile::Open("TOPCalValidation.root", "recreate");
46
47 // write-out the histograms that are ready
48
49 B2INFO("TOPValidationAlgorithm: get basic histograms");
50
51 double scaleFactor = 1; // scaling factor for module and common T0 uncertainties
52 auto h1 = getObjectPtr<TH1F>("moduleT0_pulls");
53 if (h1) {
54 if (h1->GetEntries() > 1) scaleFactor = h1->GetRMS();
55 h1->Write();
56 }
57
58 std::vector<string> slotNames;
59 for (unsigned slot = 1; slot <= c_numModules; slot++) {
60 string slotName = "slot";
61 if (slot < 10) slotName += "0";
62 slotName += to_string(slot);
63 slotNames.push_back(slotName);
64 }
65
66 for (unsigned slot = 0; slot < c_numModules; slot++) {
67 string name = "hits_" + slotNames[slot];
68 auto h = getObjectPtr<TH2F>(name);
69 if (h) h->Write();
70 }
71
72 // channelT0 residuals: determine Chi2 minima and save the results into histograms
73
74 B2INFO("TOPValidationAlgorithm: determine channel T0 residuals");
75
76 auto* h_profile = new TProfile("calPrecision", "calibration precision; slot; residuals [ns]", 16, 0.5, 16.5, -1, 1, "S");
77 for (unsigned slot = 0; slot < c_numModules; slot++) {
78 string name = "chi2_" + slotNames[slot];
79 auto h = getObjectPtr<TH2F>(name);
80 if (not h) continue;
81
82 int nx = h->GetNbinsX();
83 string nameOut = "channelT0_" + slotNames[slot];
84 string title = "ChannelT0, " + slotNames[slot] + "; channel; residuals [ns]";
85 auto* h0 = new TH1F(nameOut.c_str(), title.c_str(), nx, 0, nx);
86
87 for (int ibin = 1; ibin <= nx; ibin++) {
88 Chi2MinimumFinder1D finder(std::shared_ptr<TH1D>(h->ProjectionY("py", ibin, ibin)));
89 const auto& minimum = finder.getMinimum();
90 if (not minimum.valid) continue;
91 h0->SetBinContent(ibin, minimum.position);
92 h0->SetBinError(ibin, minimum.error);
93 h_profile->Fill(slot + 1, minimum.position);
94 }
95 }
96 auto* calPrecision = new TOPCalPrecision();
97 calPrecision->set(h_profile);
98 saveCalibration(calPrecision);
99
100 // moduleT0, commonT0 and others: get input tree and set branch addresses
101
102 B2INFO("TOPValidationAlgorithm: get input tree");
103
104 auto inputTree = getObjectPtr<TTree>("tree");
105 if (not inputTree) {
106 B2ERROR("TOPValidationAlgorithm: input tree not found");
107 file->Write();
108 file->Close();
109 return c_Failure;
110 }
111 inputTree->SetBranchAddress("expNo", &m_treeEntry.expNo);
112 inputTree->SetBranchAddress("runNo", &m_treeEntry.runNo);
113 inputTree->SetBranchAddress("numTracks", &m_treeEntry.numTracks);
114 inputTree->SetBranchAddress("commonT0", &m_treeEntry.commonT0);
115 inputTree->SetBranchAddress("commonT0Err", &m_treeEntry.commonT0Err);
116 inputTree->SetBranchAddress("moduleT0", &m_treeEntry.moduleT0);
117 inputTree->SetBranchAddress("moduleT0Err", &m_treeEntry.moduleT0Err);
118 inputTree->SetBranchAddress("numTBCalibrated", &m_treeEntry.numTBCalibrated);
119 inputTree->SetBranchAddress("numT0Calibrated", &m_treeEntry.numT0Calibrated);
120 inputTree->SetBranchAddress("numActive", &m_treeEntry.numActive);
121 inputTree->SetBranchAddress("numActiveCalibrated", &m_treeEntry.numActiveCalibrated);
122 inputTree->SetBranchAddress("thrEffi", &m_treeEntry.thrEffi);
123 inputTree->SetBranchAddress("asicShifts", &m_treeEntry.asicShifts);
124 inputTree->SetBranchAddress("svdOffset", &m_treeEntry.svdOffset);
125 inputTree->SetBranchAddress("svdSigma", &m_treeEntry.svdSigma);
126 inputTree->SetBranchAddress("cdcOffset", &m_treeEntry.cdcOffset);
127 inputTree->SetBranchAddress("cdcSigma", &m_treeEntry.cdcSigma);
128 inputTree->SetBranchAddress("fillPatternOffset", &m_treeEntry.fillPatternOffset);
129 inputTree->SetBranchAddress("fillPatternFraction", &m_treeEntry.fillPatternFraction);
130
131 // sort input tree entries according to exp/run
132
133 B2INFO("TOPValidationAlgorithm: sort input tree entries");
134
135 std::multimap<int, ValidationTreeStruct> sortedEntries;
136 std::set<int> sortedRuns;
137 for (int iev = 0; iev < inputTree->GetEntries(); iev++) {
138 inputTree->GetEntry(iev);
139 int expRun = (m_treeEntry.expNo << 16) + m_treeEntry.runNo;
140 sortedEntries.emplace(expRun, m_treeEntry);
141 sortedRuns.insert(expRun);
142 }
143
144 // merge input entries of the same exp/run and rescale the errors
145
146 B2INFO("TOPValidationAlgorithm: merge input tree entries");
147
148 std::vector<ValidationTreeStruct> mergedEntries;
149 for (auto expRun : sortedRuns) {
150 ValidationTreeStruct mergedEntry;
151 const auto range = sortedEntries.equal_range(expRun);
152 for (auto it = range.first; it != range.second; ++it) {
153 mergedEntry.merge(it->second);
154 }
155 mergedEntry.rescaleErrors(scaleFactor);
156 mergedEntries.push_back(mergedEntry);
157 }
158
159 // make histograms vs. run index
160
161 int nx = mergedEntries.size();
162 if (nx == 0) {
163 B2ERROR("TOPValidationAlgorithm: input tree is empty");
164 file->Write();
165 file->Close();
166 return c_Failure;
167 }
168
169 file->cd();
170
171 std::set<int> sortedExps;
172 for (auto& entry : mergedEntries) sortedExps.insert(entry.expNo);
173 std::string titleIndex = "Experiment";
174 if (sortedExps.size() > 1) titleIndex += "s";
175 for (auto expNo : sortedExps) titleIndex += " " + to_string(expNo) + ",";
176 titleIndex.pop_back();
177 auto* h_index = new TH1F("runIndex", (titleIndex + "; run index; run number").c_str(), nx, 0, nx);
178 for (int i = 0; i < nx; i++) {
179 h_index->SetBinContent(i + 1, mergedEntries[i].runNo);
180 }
181
182 auto* h_numTracks = new TH1F("numTracks", "Number of tracks; run index; number of tracks", nx, 0, nx);
183 for (int i = 0; i < nx; i++) {
184 h_numTracks->SetBinContent(i + 1, mergedEntries[i].numTracks);
185 }
186
187 auto* h_numMerged = new TH1F("numMerged", "Number of merged entries; run index; number of merged", nx, 0, nx);
188 for (int i = 0; i < nx; i++) {
189 h_numMerged->SetBinContent(i + 1, mergedEntries[i].numMerged);
190 }
191
192 auto* h_commonT0 = new TH1F("commonT0", "commonT0; run index; residuals [ns]", nx, 0, nx);
193 for (int i = 0; i < nx; i++) {
194 h_commonT0->SetBinContent(i + 1, mergedEntries[i].commonT0);
195 h_commonT0->SetBinError(i + 1, mergedEntries[i].commonT0Err);
196 }
197
198 for (unsigned slot = 0; slot < c_numModules; slot++) {
199 string name = "moduleT0_" + slotNames[slot];
200 string title = "moduleT0, " + slotNames[slot] + "; run index; residuals [ns]";
201 auto* h = new TH1F(name.c_str(), title.c_str(), nx, 0, nx);
202 for (int i = 0; i < nx; i++) {
203 h->SetBinContent(i + 1, mergedEntries[i].moduleT0[slot]);
204 h->SetBinError(i + 1, mergedEntries[i].moduleT0Err[slot]);
205 }
206 }
207
208 for (unsigned slot = 0; slot < c_numModules; slot++) {
209 string name = "numTBCalibrated_" + slotNames[slot];
210 string title = "Time base calibrated, " + slotNames[slot] + "; run index; fraction";
211 auto* h = new TH1F(name.c_str(), title.c_str(), nx, 0, nx);
212 for (int i = 0; i < nx; i++) {
213 h->SetBinContent(i + 1, mergedEntries[i].numTBCalibrated[slot] / 512.0);
214 }
215 }
216
217 for (unsigned slot = 0; slot < c_numModules; slot++) {
218 string name = "numT0Calibrated_" + slotNames[slot];
219 string title = "channel T0 calibrated, " + slotNames[slot] + "; run index; fraction";
220 auto* h = new TH1F(name.c_str(), title.c_str(), nx, 0, nx);
221 for (int i = 0; i < nx; i++) {
222 h->SetBinContent(i + 1, mergedEntries[i].numT0Calibrated[slot] / 512.0);
223 }
224 }
225
226 for (unsigned slot = 0; slot < c_numModules; slot++) {
227 string name = "numActive_" + slotNames[slot];
228 string title = "Active, " + slotNames[slot] + "; run index; fraction";
229 auto* h = new TH1F(name.c_str(), title.c_str(), nx, 0, nx);
230 for (int i = 0; i < nx; i++) {
231 h->SetBinContent(i + 1, mergedEntries[i].numActive[slot] / 512.0);
232 }
233 }
234
235 for (unsigned slot = 0; slot < c_numModules; slot++) {
236 string name = "numActiveCalibrated_" + slotNames[slot];
237 string title = "Active and calibrated, " + slotNames[slot] + "; run index; fraction";
238 auto* h = new TH1F(name.c_str(), title.c_str(), nx, 0, nx);
239 for (int i = 0; i < nx; i++) {
240 h->SetBinContent(i + 1, mergedEntries[i].numActiveCalibrated[slot] / 512.0);
241 }
242 }
243
244 for (unsigned slot = 0; slot < c_numModules; slot++) {
245 string name = "thrEffi_" + slotNames[slot];
246 string title = "Threshold efficiency, " + slotNames[slot] + "; run index; efficiency";
247 auto* h = new TH1F(name.c_str(), title.c_str(), nx, 0, nx);
248 for (int i = 0; i < nx; i++) {
249 h->SetBinContent(i + 1, mergedEntries[i].thrEffi[slot]);
250 }
251 }
252
253 for (unsigned carrier = 0; carrier < 4; carrier++) {
254 string name = "asicShifts_" + to_string(carrier);
255 string title = "BS13d, carrier " + to_string(carrier) + "; run index; shift [ns]";
256 auto* h = new TH1F(name.c_str(), title.c_str(), nx, 0, nx);
257 for (int i = 0; i < nx; i++) {
258 auto y = mergedEntries[i].asicShifts[carrier];
259 if (isnan(y)) {
260 h->SetBinError(i + 1, 0);
261 } else {
262 h->SetBinContent(i + 1, y);
263 h->SetBinError(i + 1, 0.001);
264 }
265 }
266 }
267
268 auto* h_svdOffset = new TH1F("svdOffset", "Event T0 offset w.r.t TOP; run index; offset [ns]", nx, 0, nx);
269 auto* h_svdSigma = new TH1F("svdSigma", "Event T0 resolution; run index; sigma [ns]", nx, 0, nx);
270 for (int i = 0; i < nx; i++) {
271 h_svdOffset->SetBinContent(i + 1, mergedEntries[i].svdOffset);
272 h_svdOffset->SetBinError(i + 1, mergedEntries[i].svdSigma / 1000);
273 h_svdSigma->SetBinContent(i + 1, mergedEntries[i].svdSigma);
274 h_svdSigma->SetBinError(i + 1, 0.001);
275 }
276
277 auto* h_cdcOffset = new TH1F("cdcOffset", "Event T0 offset w.r.t TOP; run index; offset [ns]", nx, 0, nx);
278 auto* h_cdcSigma = new TH1F("cdcSigma", "Event T0 resolution; run index; sigma [ns]", nx, 0, nx);
279 for (int i = 0; i < nx; i++) {
280 h_cdcOffset->SetBinContent(i + 1, mergedEntries[i].cdcOffset);
281 h_cdcOffset->SetBinError(i + 1, mergedEntries[i].cdcSigma / 1000);
282 h_cdcSigma->SetBinContent(i + 1, mergedEntries[i].cdcSigma);
283 h_cdcSigma->SetBinError(i + 1, 0.001);
284 }
285
286 auto* h_fillPatternOffset = new TH1F("fillPatternOffset", "Fill pattern offset; run index; offset [RF clk]", nx, 0, nx);
287 auto* h_fillPatternFract = new TH1F("fillPatternFract",
288 "Fraction of buckets matched with filled ones; run index; fraction", nx, 0, nx);
289 for (int i = 0; i < nx; i++) {
290 if (isnan(mergedEntries[i].fillPatternOffset)) {
291 h_fillPatternOffset->SetBinError(i + 1, 0);
292 } else {
293 h_fillPatternOffset->SetBinContent(i + 1, mergedEntries[i].fillPatternOffset);
294 h_fillPatternOffset->SetBinError(i + 1, 0.01);
295 }
296 h_fillPatternFract->SetBinContent(i + 1, mergedEntries[i].fillPatternFraction);
297 }
298
299 // write-out the results
300
301 B2INFO("TOPValidationAlgorithm: write the results");
302
303 file->Write();
304 file->Close();
305
306 return c_OK;
307 }
308
309 } // end namespace TOP
311} // end namespace Belle2
void saveCalibration(TClonesArray *data, const std::string &name)
Store DBArray payload with given name with default IOV.
void setDescription(const std::string &description)
Set algorithm description (in constructor)
EResult
The result of calibration.
@ c_OK
Finished successfully =0 in Python.
CalibrationAlgorithm(const std::string &collectorModuleName)
Constructor - sets the prefix for collected objects (won't be accesses until execute(....
Time calibration precisions (per module)
Minimum finder using tabulated chi^2 values in one dimension.
virtual EResult calibrate() final
algorithm implementation
ValidationTreeStruct m_treeEntry
input tree entry
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...
Abstract base class for different kinds of events.
STL namespace.
Calibration validation tree structure.
void rescaleErrors(double scaleFactor)
Rescale errors.
void merge(const ValidationTreeStruct &other)
Merge two structures.