10#include <ecl/modules/eclChargedPID/ECLChargedPIDModule.h>
26 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 quantities (e.g. shower shape variables, w/ proper decorrelation).");
32 "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.",
51 if (!
m_pdfs) { B2FATAL(
"No ECL charged PID PDFs payload found in database!"); }
73 if (fitRes ==
nullptr)
continue;
74 const auto relShowers = track.getRelationsTo<
ECLShower>();
75 if (relShowers.size() == 0)
continue;
77 const double p = fitRes->getMomentum().R();
78 const double theta = fitRes->getMomentum().Theta();
79 const auto charge = fitRes->getChargeSign();
81 double shEnergy(0.0), maxEnergy(0.0);
83 const ECLShower* mostEnergeticShower =
nullptr;
85 for (
const auto& eclShower : relShowers) {
89 if (std::abs(eclShower.getTime()) > eclShower.getDeltaTime99())
continue;
93 if (shEnergy > maxEnergy) {
95 mostEnergeticShower = &eclShower;
100 double showerTheta = (mostEnergeticShower) ? mostEnergeticShower->
getTheta() : -999.0;
101 int showerReg = (mostEnergeticShower) ? mostEnergeticShower->
getDetectorRegion() : -1;
117 B2DEBUG(20,
"-------------------------------");
118 B2DEBUG(20,
"TRACK properties:");
119 B2DEBUG(20,
"p = " << p <<
" [GeV/c]");
120 B2DEBUG(30,
"theta = " << theta <<
" [rad]");
121 B2DEBUG(20,
"charge = " << charge);
122 B2DEBUG(20,
"-------------------------------");
123 B2DEBUG(20,
"SHOWER properties:");
124 B2DEBUG(20,
"showerTheta = " << showerTheta <<
" [rad], showerReg = " << showerReg);
126 B2DEBUG(30,
"varid: " <<
static_cast<unsigned int>(varid) <<
" = " << var);
128 B2DEBUG(20,
"-------------------------------");
136 if (mostEnergeticShower && showerReg && std::abs(charge)) {
146 unsigned int 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);
253 for (
unsigned int ivar(0); ivar < nvars; ivar++) {
255 int ndivs = vts->nDivisions[ivar];
258 auto ij =
linIndex(ivar, jdiv, vts->nDivisionsMax);
259 while (variables.at(ivar) > vts->x[ij]) {
261 ij =
linIndex(ivar, jdiv, vts->nDivisionsMax);
264 if (jdiv < 0) { jdiv = 0; }
265 if (jdiv >= ndivs) { jdiv = ndivs - 1; }
267 if ((variables.at(ivar) > vts->x[ij] && jdiv != ndivs - 1) || jdiv == 0) {
272 auto ijnext =
linIndex(ivar, jnextdiv, vts->nDivisionsMax);
274 double dx = vts->x[ij] - vts->x[ijnext];
275 double dy = vts->cumulDist[ij] - vts->cumulDist[ijnext];
276 double cumulant = vts->cumulDist[ij] + (variables.at(ivar) - vts->x[ijnext]) * dy / dx;
278 cumulant = std::min(cumulant, 1.0 - 10e-10);
279 cumulant = std::max(cumulant, 10e-10);
281 double maxErfInvArgRange = 0.99999999;
282 double arg = 2.0 * cumulant - 1.0;
284 arg = std::min(maxErfInvArgRange, arg);
285 arg = std::max(-maxErfInvArgRange, arg);
287 vtransfo_gauss.at(ivar) =
c_sqrt2 * TMath::ErfInverse(arg);
290 B2DEBUG(30,
"\tSHOWER properties (Gaussian-transformed):");
291 for (
unsigned int idx(0); idx < nvars; idx++) {
292 B2DEBUG(30,
"\tvarid: " <<
static_cast<unsigned int>(varids->at(idx)) <<
" = " << vtransfo_gauss.at(idx));
294 B2DEBUG(30,
"\t-------------------------------");
296 std::vector<double> vtransfo_decorr;
297 vtransfo_decorr.reserve(nvars);
299 for (
unsigned int i(0); i < nvars; i++) {
300 double vartransfo(0);
301 for (
unsigned int j(0); j < nvars; j++) {
303 vartransfo += vtransfo_gauss[j] * vts->covMatrix[ij];
305 vtransfo_decorr.push_back(vartransfo);
308 B2DEBUG(30,
"\tSHOWER properties (Decorrelation-transformed):");
309 for (
unsigned int idx(0); idx < nvars; idx++) {
310 B2DEBUG(30,
"\tvarid: " <<
static_cast<unsigned int>(varids->at(idx)) <<
" = " << vtransfo_decorr.at(idx));
312 B2DEBUG(30,
"\t-------------------------------");
315 for (
unsigned int i(0); i < nvars; i++) {
316 variables[i] = vtransfo_decorr.at(i);
static const unsigned int c_SetSize
Number of elements (for use in array bounds etc.)
static const ParticleSet chargedStableSet
set of charged stable particles
static const ChargedStable pion
charged pion particle
virtual ~ECLChargedPIDModule()
Destructor, use to clean up anything you created in the constructor.
virtual void initialize() override
Use this to initialize resources or memory your module needs.
DBObjPtr< ECLChargedPidPDFs > m_pdfs
Interface to get the DB payload for ECL charged PID PDFs.
virtual void event() override
Called once for each event.
virtual void endRun() override
Called once when a run ends.
virtual void terminate() override
Clean up anything you created in initialize().
double getPdfVal(const double &x, const TF1 *pdf)
Extract the PDF value for a given variable from the TF1 object.
static constexpr double c_sqrt2
Definition of sqrt(2)
ECLChargedPIDModule()
Constructor, for setting module description and parameters.
int linIndex(int i, int j, int m)
Get the index corresponding to element i,j in a linearised n*m array.
StoreObjPtr< EventMetaData > m_eventMetaData
The event information.
static constexpr double c_dummyLogL
Dummy value of Log Likelihood for a particle hypothesis.
void transfoGaussDecorr(const unsigned int pdg, const int charge, const double &p, const double &theta, std::vector< double > &variables)
Transform input variables according to:
void checkPdfsDB()
Check the PDFs payload for consistency every time they change in the database.
virtual void beginRun() override
Called once before a new run begins.
std::unordered_map< ECLChargedPidPDFs::InputVar, double > m_variables
Map to contain ECL shower observables.
StoreArray< Track > m_tracks
Array of Track objects.
bool m_applyClusterTimingSel
Apply cluster timing selection.
StoreArray< ECLPidLikelihood > m_eclPidLikelihoods
Array of ECLPidLikelihood objects.
@ c_DeltaL
DeltaL (track depth)
@ c_Z40
Zernike moment 40.
@ c_E
Energy of maxE shower.
@ c_Z51
Zernike moment 51.
@ c_LAT
Lateral shower shape.
Class to store ECL Showers.
double getAbsZernikeMoment(unsigned int n, unsigned int m) const
Get absolute value of Zernike Moment nm.
double getPulseShapeDiscriminationMVA() const
Get shower hadron intensity.
double getLateralEnergy() const
Get Lateral Energy in Shower.
double getE1oE9() const
Get energy ratio E1oE9.
double getEnergy() const
Get Energy.
double getE9oE21() const
Get energy ratio E9oE21.
int getDetectorRegion() const
Return detector region: 0: below acceptance, 1: FWD, 2: BRL, 3: BWD, 11: FWDGAP, 13: BWDGAP.
@ c_nPhotons
CR is split into n photons (N1)
double getTrkDepth() const
path on track extrapolation to POCA to average cluster direction
double getZernikeMVA() const
Get Zernike MVA.
double getTheta() const
Get Theta.
void setDescription(const std::string &description)
Sets the description of the module.
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Values of the result of a track fit with a given particle hypothesis.
void addParam(const std::string &name, T ¶mVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Abstract base class for different kinds of events.