16 #include <ecl/modules/eclChargedPID/ECLChargedPIDModule.h>
25 setDescription(
"The module implements charged particle identification using ECL-related observables. For each Track matched with a suitable ECLShower, likelihoods for each particle hypothesis are obtained from pdfs stored in a conditions database payload, and then get stored in an ECLPidLikelihood object. The dimensionality of the likelihood depends on how many variables are stored in the payload. The baseline method could be a simple univariate likelihood based on E/p PDFs, but it could be extended to include more ECL quantitites (e.g. shower shape variables, w/ proper decorrelation).");
27 setPropertyFlags(c_ParallelProcessingCertified);
29 addParam(
"applyClusterTimingSel",
30 m_applyClusterTimingSel,
31 "Set true if you want to apply a abs(clusterTiming)/clusterTimingError<1 cut on clusters. This cut is optimised to achieve 99% timing efficiency for true photons from the IP.",
50 if (!
m_pdfs) { B2FATAL(
"No ECL charged PID PDFs payload found in database!"); }
72 if (fitRes ==
nullptr)
continue;
73 const auto relShowers = track.getRelationsTo<
ECLShower>();
74 if (relShowers.size() == 0)
continue;
76 const double p = fitRes->getMomentum().Mag();
77 const double theta = fitRes->getMomentum().Theta();
78 const auto charge = fitRes->getChargeSign();
80 double shEnergy(0.0), maxEnergy(0.0);
82 const ECLShower* mostEnergeticShower =
nullptr;
84 for (
const auto& eclShower : relShowers) {
88 if (abs(eclShower.getTime()) > eclShower.getDeltaTime99())
continue;
92 if (shEnergy > maxEnergy) {
94 mostEnergeticShower = &eclShower;
99 double showerTheta = (mostEnergeticShower) ? mostEnergeticShower->
getTheta() : -999.0;
100 int showerReg = (mostEnergeticShower) ? mostEnergeticShower->
getDetectorRegion() : -1;
116 B2DEBUG(20,
"-------------------------------");
117 B2DEBUG(20,
"TRACK properties:");
118 B2DEBUG(20,
"p = " << p <<
" [GeV/c]");
119 B2DEBUG(30,
"theta = " << theta <<
" [rad]");
120 B2DEBUG(20,
"charge = " << charge);
121 B2DEBUG(20,
"-------------------------------");
122 B2DEBUG(20,
"SHOWER properties:");
123 B2DEBUG(20,
"showerTheta = " << showerTheta <<
" [rad], showerReg = " << showerReg);
125 B2DEBUG(30,
"varid: " <<
static_cast<unsigned int>(varid) <<
" = " << var);
127 B2DEBUG(20,
"-------------------------------");
135 if (mostEnergeticShower && showerReg && std::abs(charge)) {
143 unsigned int hypo_idx(-1);
146 hypo_idx = hypo.getIndex();
148 auto pdgId = hypo.getPDGCode();
150 B2DEBUG(20,
"\n\thypo[" << hypo_idx <<
"] = " << pdgId <<
", hypo[" << hypo_idx <<
"] * reco_charge = " << pdgId * charge);
153 auto varids =
m_pdfs->getVars(pdgId, charge, p, showerTheta);
156 std::vector<double> variables;
157 for (
const auto& varid : *varids) {
162 if (
m_pdfs->doVarsTransfo()) {
171 for (
unsigned int idx(0); idx < variables.size(); idx++) {
173 auto var = variables.at(idx);
174 auto varid = varids->at(idx);
176 const TF1* pdf =
m_pdfs->getPdf(pdgId, charge, p, showerTheta, varid);
181 B2DEBUG(30,
"\t\tL(" << pdgId * charge <<
") = " << prod
182 <<
" * pdf(varid: " <<
static_cast<unsigned int>(varid) <<
") = "
183 << prod <<
" * " << ipdfval
184 <<
" = " << prod * ipdfval);
194 B2DEBUG(20,
"\tL(" << pdgId * charge <<
") = " << pdfval);
196 likelihoods[hypo_idx] = (std::isnormal(pdfval) && pdfval > 0) ? log(pdfval) :
c_dummyLogL;
198 B2DEBUG(20,
"\tlog(L(" << pdgId * charge <<
")) = " << likelihoods[hypo_idx]);
204 track.addRelationTo(eclPidLikelihood);
214 double y, xmin, xmax;
215 pdf->GetRange(xmin, xmax);
217 if (x <= xmin) { y = pdf->Eval(xmin + 1e-9); }
218 else if (x >= xmax) { y = pdf->Eval(xmax - 1e-9); }
219 else { y = pdf->Eval(x); }
221 return (y) ? y : 1e-9;
225 std::vector<double>& variables)
228 unsigned int nvars = variables.size();
231 auto vts =
m_pdfs->getVTS(pdg, charge, p, theta);
234 B2DEBUG(30,
"\tclass path: " << vts->classPath);
235 B2DEBUG(30,
"\tgbin = " << vts->gbin <<
", (theta,p) = (" << vts->jth <<
"," << vts->ip <<
")");
236 B2DEBUG(30,
"\tnvars: " << nvars);
238 auto varids =
m_pdfs->getVars(pdg, charge, p, theta);
240 for (
unsigned int ivar(0); ivar < nvars; ivar++) {
241 unsigned int ndivs = vts->nDivisions[ivar];
242 B2DEBUG(30,
"\tvarid: " <<
static_cast<unsigned int>(varids->at(ivar)) <<
" = " << variables.at(ivar) <<
", nsteps = " << ndivs);
243 for (
unsigned int jdiv(0); jdiv < ndivs; jdiv++) {
244 auto ij =
linIndex(ivar, jdiv, vts->nDivisionsMax);
245 B2DEBUG(30,
"\t\tx[" << ivar <<
"][" << jdiv <<
"] = x[" << ij <<
"] = " << vts->x[ij]);
246 B2DEBUG(30,
"\t\tcumulDist[" << ivar <<
"][" << jdiv <<
"] = cumulDist[" << ij <<
"] = " << vts->cumulDist[ij]);
250 std::vector<double> vtransfo_gauss;
251 vtransfo_gauss.reserve(nvars);
254 for (
unsigned int ivar(0); ivar < nvars; ivar++) {
256 int ndivs = vts->nDivisions[ivar];
259 auto ij =
linIndex(ivar, jdiv, vts->nDivisionsMax);
260 while (variables.at(ivar) > vts->x[ij]) {
262 ij =
linIndex(ivar, jdiv, vts->nDivisionsMax);
265 if (jdiv < 0) { jdiv = 0; }
266 if (jdiv >= ndivs) { jdiv = ndivs - 1; }
268 if ((variables.at(ivar) > vts->x[ij] && jdiv != ndivs - 1) || jdiv == 0) {
273 auto ijnext =
linIndex(ivar, jnextdiv, vts->nDivisionsMax);
275 double dx = vts->x[ij] - vts->x[ijnext];
276 double dy = vts->cumulDist[ij] - vts->cumulDist[ijnext];
277 cumulant = vts->cumulDist[ij] + (variables.at(ivar) - vts->x[ijnext]) * dy / dx;
279 cumulant = std::min(cumulant, 1.0 - 10e-10);
280 cumulant = std::max(cumulant, 10e-10);
282 double maxErfInvArgRange = 0.99999999;
283 double arg = 2.0 * cumulant - 1.0;
285 arg = std::min(maxErfInvArgRange, arg);
286 arg = std::max(-maxErfInvArgRange, arg);
288 vtransfo_gauss.at(ivar) =
c_sqrt2 * TMath::ErfInverse(arg);
291 B2DEBUG(30,
"\tSHOWER properties (Gaussian-transformed):");
292 for (
unsigned int idx(0); idx < nvars; idx++) {
293 B2DEBUG(30,
"\tvarid: " <<
static_cast<unsigned int>(varids->at(idx)) <<
" = " << vtransfo_gauss.at(idx));
295 B2DEBUG(30,
"\t-------------------------------");
297 std::vector<double> vtransfo_decorr;
298 vtransfo_decorr.reserve(nvars);
300 for (
unsigned int i(0); i < nvars; i++) {
301 double vartransfo(0);
302 for (
unsigned int j(0); j < nvars; j++) {
304 vartransfo += vtransfo_gauss[j] * vts->covMatrix[ij];
306 vtransfo_decorr.push_back(vartransfo);
309 B2DEBUG(30,
"\tSHOWER properties (Decorrelation-transformed):");
310 for (
unsigned int idx(0); idx < nvars; idx++) {
311 B2DEBUG(30,
"\tvarid: " <<
static_cast<unsigned int>(varids->at(idx)) <<
" = " << vtransfo_decorr.at(idx));
313 B2DEBUG(30,
"\t-------------------------------");
316 for (
unsigned int i(0); i < nvars; i++) {
317 variables[i] = vtransfo_decorr.at(i);