Belle II Software prerelease-11-00-00a
SVDdEdxCalibrationAlgorithm.h
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#pragma once
10
11#include <calibration/CalibrationAlgorithm.h>
12
13#include <TH2F.h>
14#include <TF1.h>
15#include <TList.h>
16#include <TTree.h>
17#include <TProfile.h>
18#include <TDatabasePDG.h>
19
20namespace Belle2 {
29 public:
33
35
39
40 virtual ~SVDdEdxCalibrationAlgorithm() override {}
41
45 void setMonitoringPlots(bool value = false) { m_isMakePlots = value; }
46
50 void setNumDEdxBins(const int& value) { m_numDEdxBins = value; }
51
55 void setNumPBins(const int& value) { m_numPBins = value; }
56
60 void setNumBGBins(const int& value) { m_numBGBins = value; }
61
65 void setDEdxCutoff(const double& value) { m_dedxCutoff = value; }
66
70 void setMinEvtsPerTree(const double& value) { m_MinEvtsPerTree = value; }
71
75 void setCustomProfile(bool value = true) { m_CustomProfile = value; }
76
80 void setFixUnstableFitParameter(bool value = true) { m_FixUnstableFitParameter = value; }
81
86
91
92 protected:
96 virtual EResult calibrate() override;
97
98 private:
100 TTree* LambdaMassFit(std::shared_ptr<TTree> preselTree);
101 std::unique_ptr<TList> LambdaHistogramming(TTree* inputTree);
102 TTree* DstarMassFit(std::shared_ptr<TTree> preselTree);
103 std::unique_ptr<TList> DstarHistogramming(TTree* inputTree);
104 std::unique_ptr<TList> GammaHistogramming(std::shared_ptr<TTree> preselTree);
105 std::unique_ptr<TList> GenerateNewHistograms(std::shared_ptr<TTree> ttreeLambda, std::shared_ptr<TTree> ttreeDstar,
106 std::shared_ptr<TTree> ttreeGamma, std::shared_ptr<TTree>
107 ttreeGeneric);
108 int m_numDEdxBins = 100;
109 int m_numPBins = 69;
110 int m_numBGBins = 69;
111 double m_dedxCutoff = 5.e6;
112 double m_dedxMaxPossible = 7.e6;
114 100;
116 5e6;
119 0;
121 0;
123 1;
124
125 const double m_ElectronPDGMass = TDatabasePDG::Instance()->GetParticle(11)->Mass();
126 const double m_MuonPDGMass = TDatabasePDG::Instance()->GetParticle(13)->Mass();
127 const double m_PionPDGMass = TDatabasePDG::Instance()->GetParticle(211)->Mass();
128 const double m_KaonPDGMass = TDatabasePDG::Instance()->GetParticle(321)->Mass();
129 const double m_ProtonPDGMass = TDatabasePDG::Instance()->GetParticle(2212)->Mass();
130 const double m_DeuteronPDGMass = TDatabasePDG::Instance()->GetParticle(1000010020)->Mass();
131
135 std::vector<double> CreatePBinningScheme()
136 {
137 std::vector<double> pbins;
138 pbins.reserve(m_numPBins + 1);
139 pbins.push_back(0.0);
140 pbins.push_back(0.05);
141
142 for (int iBin = 2; iBin <= m_numPBins; iBin++) {
143 if (iBin <= 19)
144 pbins.push_back(0.025 + 0.025 * iBin);
145 else if (iBin <= 59)
146 pbins.push_back(pbins.at(19) + 0.05 * (iBin - 19));
147 else
148 pbins.push_back(pbins.at(59) + 0.3 * (iBin - 59));
149 }
150
151 return pbins;
152 }
153
158 TH2F* Normalise2DHisto(TH2F* HistoToNormalise)
159 {
160 for (int pbin = 0; pbin <= m_numPBins + 1; pbin++) {
161 for (int dedxbin = 0; dedxbin <= m_numDEdxBins + 1; dedxbin++) {
162 // get rid of the bins with negative weights
163 if (HistoToNormalise->GetBinContent(pbin, dedxbin) <= 1) {
164 HistoToNormalise->SetBinContent(pbin, dedxbin, 0);
165 };
166 }
167 // create a projection (1D histogram) in a given momentum bin
168
169 TH1D* MomentumSlice = static_cast<TH1D*>(HistoToNormalise->ProjectionY("slice_tr", pbin, pbin));
170 // normalise, but ignore the cases with empty histograms
171 if (MomentumSlice->Integral(0, m_numDEdxBins + 1) > 0) {
172 MomentumSlice->Scale(1. / MomentumSlice->Integral(0, m_numDEdxBins + 1));
173 }
174 // fill back the 2D histogram with the result
175 for (int dedxbin = 0; dedxbin <= m_numDEdxBins + 1; dedxbin++) {
176 HistoToNormalise->SetBinContent(pbin, dedxbin, MomentumSlice->GetBinContent(dedxbin));
177 HistoToNormalise->SetBinError(pbin, dedxbin, MomentumSlice->GetBinError(dedxbin));
178 }
179 }
180 return HistoToNormalise;
181 }
182
186 TH2F* PrepareNewHistogram(TH2F* DataHistogram, TString NewName, TF1* betagamma_function, TF1* ResolutionFunctionOriginal,
187 double bias_correction)
188 {
189 TF1* ResolutionFunction = static_cast<TF1*>(ResolutionFunctionOriginal->Clone(Form("%sClone",
190 ResolutionFunctionOriginal->GetName()))); // to avoid modifying the resolution function
191 ResolutionFunction->SetRange(0, m_dedxMaxPossible); // allow the function to take values outside the histogram range
192 TH2F* DataHistogramNew = static_cast<TH2F*>(DataHistogram->Clone(NewName));
193
194 DataHistogramNew->Reset();
195
196 for (int pbin = 1; pbin <= m_numPBins + 1; pbin++) {
197 double mean_dEdx_value = betagamma_function->Eval(DataHistogramNew->GetXaxis()->GetBinCenter(pbin));
198 ResolutionFunction->FixParameter(1, mean_dEdx_value + bias_correction);
199
200 // create a projection (1D histogram) in a given momentum bin
201 TH1D* MomentumSlice = static_cast<TH1D*>(DataHistogramNew->ProjectionY("slice", pbin, pbin));
202
203 // fill manually (instead of FillRandom) to also preserve events in the overflow bin
204 // this is needed for the correct normalisation
205 for (int iEvent = 0; iEvent < m_NToGenerate; iEvent++) {
206 MomentumSlice->Fill(ResolutionFunction->GetRandom());
207 }
208
209 // get rid of the empty bins: set their bin content to 0.5 (i.e. smaller than 1 event)
210 // this is to allow for a well-defined log-likelihood calculation
211 for (int dedxbin = 0; dedxbin <= m_numDEdxBins + 1; dedxbin++) {
212 if (MomentumSlice->GetBinContent(dedxbin) < 1) {
213 MomentumSlice->SetBinContent(dedxbin, 0.5);
214 };
215 }
216
217 // normalise each momentum slice to unity, but ignore the cases with empty histograms
218 if (MomentumSlice->Integral(0, m_numDEdxBins + 1) > 0) {
219 MomentumSlice->Scale(1. / MomentumSlice->Integral(0, m_numDEdxBins + 1));
220 }
221 // fill back the 2D histo with the result
222 for (int dedxbin = 0; dedxbin <= m_numDEdxBins + 1; dedxbin++) {
223 DataHistogramNew->SetBinContent(pbin, dedxbin, MomentumSlice->GetBinContent(dedxbin));
224 DataHistogramNew->SetBinError(pbin, dedxbin, MomentumSlice->GetBinError(dedxbin));
225 }
226 }
227
228 return DataHistogramNew;
229
230 }
231
235 TH1D* PrepareProfile(TH2F* DataHistogram, TString NewName)
236 {
237// define our resolution function: Crystal Ball. Parameter [1] is the mean and [2] is the relative width.
238 TF1* ResolutionFunction = new TF1("ResolutionFunction", "[0]*ROOT::Math::crystalball_function(x,[4],[3],[2]*[1],[1])", 100e3,
239 7000e3);
240
241
242 ResolutionFunction->SetNpx(1000);
243
244 ResolutionFunction->SetParameters(1000, 6.e5, 0.1, 1, 1);
245 ResolutionFunction->SetParLimits(0, 0, 1.e6);
246 ResolutionFunction->SetParLimits(1, 3.e5, 7.e6);
247 ResolutionFunction->SetParLimits(2, 0, 10);
248 ResolutionFunction->SetParLimits(3, 0.01, 100);
249 ResolutionFunction->SetParLimits(4, 0.01, 100);
250
251 ResolutionFunction->SetRange(0, m_dedxMaxPossible); // allow the function to take values outside the histogram range
252
253 TH1D* DataHistogramNew = static_cast<TH1D*>(DataHistogram->ProfileX()->ProjectionX());
254 TH1D* DataHistogramClone = static_cast<TH1D*>(DataHistogramNew->Clone(Form("%sClone",
255 DataHistogramNew->GetName()))); // preserve the original profile for uncertainty cross-checks
256 DataHistogramNew->SetName(NewName);
257 DataHistogramNew->SetTitle(NewName);
258 DataHistogramNew->Reset();
259
260 for (int pbin = 1; pbin <= m_numBGBins; pbin++) {
261 // create a projection (1D histogram) in a given momentum bin
262 TH1D* MomentumSlice = static_cast<TH1D*>(DataHistogram->ProjectionY("slice", pbin, pbin));
263
264 if (MomentumSlice->Integral() < 1) continue;
265// guesstimate the starting fit values
266 ResolutionFunction->SetParameter(1, MomentumSlice->GetMean());
267 ResolutionFunction->SetParameter(2, MomentumSlice->GetStdDev() / MomentumSlice->GetMean());
268 ResolutionFunction->SetRange(MomentumSlice->GetMean() * 0.2, MomentumSlice->GetMean() * 1.75);
269// fit each slice to extract the mean
270 MomentumSlice->Fit(ResolutionFunction, "RQI");
271
272 double stat_error = DataHistogramClone->GetBinError(pbin);
273// fill back the 1D histo with the result
274 double bincontent = ResolutionFunction->GetParameter(1);
275 double binerror = ResolutionFunction->GetParError(1);
276
277 binerror = std::max(binerror, stat_error);
278
279 DataHistogramNew->SetBinContent(pbin, bincontent);
280 DataHistogramNew->SetBinError(pbin, binerror);
281 }
282
283 return DataHistogramNew;
284
285 }
286
287 };
288
289} // namespace Belle2
EResult
The result of calibration.
CalibrationAlgorithm(const std::string &collectorModuleName)
Constructor - sets the prefix for collected objects (won't be accesses until execute(....
void setMinEvtsPerTree(const double &value)
set the upper edge of the dEdx binning for the payloads
int m_numPBins
the number of momentum bins for the payloads
virtual ~SVDdEdxCalibrationAlgorithm() override
Destructor.
const double m_MuonPDGMass
PDG mass for the muon.
const double m_ElectronPDGMass
PDG mass for the electron.
void setNumDEdxBins(const int &value)
set the number of dEdx bins for the payloads
bool m_FixUnstableFitParameter
In the dEdx:betagamma fit, there is one free parameter that makes fit convergence poor.
const double m_DeuteronPDGMass
PDG mass for the deuteron.
void setFixUnstableFitParameter(bool value=true)
In the dEdx:betagamma fit, there is one free parameter that makes fit convergence poor.
std::vector< double > CreatePBinningScheme()
build the binning scheme for the momentum
TH2F * Normalise2DHisto(TH2F *HistoToNormalise)
Normalise a given dEdx:momentum histogram in each momentum bin, so that sum of entries in each moment...
bool m_UseProtonBGFunctionForEverything
Assume that the dEdx:betagamma trend is the same for all hadrons; use the proton trend as representat...
int m_numBGBins
the number of beta*gamma bins for the profile and fitting
void setDEdxCutoff(const double &value)
set the upper edge of the dEdx binning for the payloads
std::unique_ptr< TList > DstarHistogramming(TTree *inputTree)
produce histograms for K/pi
double m_dedxMaxPossible
the approximate max possible value of dEdx
bool m_isMakePlots
produce plots for monitoring
int m_MinEvtsPerTree
number of events in TTree below which we don't try to fit
TH1D * PrepareProfile(TH2F *DataHistogram, TString NewName)
Reimplement the Profile histogram calculation for a 2D histogram.
int m_numDEdxBins
the number of dEdx bins for the payloads
TTree * LambdaMassFit(std::shared_ptr< TTree > preselTree)
Mass fit for Lambda->ppi.
std::unique_ptr< TList > LambdaHistogramming(TTree *inputTree)
produce histograms for protons
const double m_KaonPDGMass
PDG mass for the charged kaon.
int m_NToGenerate
the number of events to be generated in each momentum bin in the new payloads.
TH2F * PrepareNewHistogram(TH2F *DataHistogram, TString NewName, TF1 *betagamma_function, TF1 *ResolutionFunctionOriginal, double bias_correction)
Generate a new dEdx:momentum histogram from a function that encodes dEdx:momentum trend and a functio...
std::unique_ptr< TList > GammaHistogramming(std::shared_ptr< TTree > preselTree)
produce histograms for e
void setNumBGBins(const int &value)
set the number of beta*gamma bins for the fits
TTree * DstarMassFit(std::shared_ptr< TTree > preselTree)
Mass fit for D*->Dpi.
void setCustomProfile(bool value=true)
reimplement the profile histogram calculation
bool m_UsePionBGFunctionForEverything
Assume that the dEdx:betagamma trend is the same for all hadrons; use the pion trend as representativ...
void setNumPBins(const int &value)
set the number of momentum bins for the payloads
std::unique_ptr< TList > GenerateNewHistograms(std::shared_ptr< TTree > ttreeLambda, std::shared_ptr< TTree > ttreeDstar, std::shared_ptr< TTree > ttreeGamma, std::shared_ptr< TTree > ttreeGeneric)
generate high-statistics histograms
virtual EResult calibrate() override
run algorithm on data
bool m_CustomProfile
reimplement profile histogram calculation instead of the ROOT implementation?
void setUsePionBGFunctionForEverything(bool value=false)
use the pion beta*gamma function for other hadrons
double m_dedxCutoff
the upper edge of the dEdx binning for the payloads
void setMonitoringPlots(bool value=false)
function to enable plotting
const double m_ProtonPDGMass
PDG mass for the proton.
void setUseProtonBGFunctionForEverything(bool value=false)
use the proton beta*gamma function for other hadrons
const double m_PionPDGMass
PDG mass for the charged pion.
Abstract base class for different kinds of events.