10#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 quantities (e.g. shower shape variables, w/ proper decorrelation).");
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().R();
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)) {
145 unsigned int hypo_idx = hypo.getIndex();
147 auto pdgId = hypo.getPDGCode();
149 B2DEBUG(20,
"\n\thypo[" << hypo_idx <<
"] = " << pdgId <<
", hypo[" << hypo_idx <<
"] * reco_charge = " << pdgId * charge);
152 auto varids =
m_pdfs->getVars(pdgId, charge, p, showerTheta);
155 std::vector<double> variables;
156 for (
const auto& varid : *varids) {
161 if (
m_pdfs->doVarsTransfo()) {
170 for (
unsigned int idx(0); idx < variables.size(); idx++) {
172 auto var = variables.at(idx);
173 auto varid = varids->at(idx);
175 const TF1* pdf =
m_pdfs->getPdf(pdgId, charge, p, showerTheta, varid);
180 B2DEBUG(30,
"\t\tL(" << pdgId * charge <<
") = " << prod
181 <<
" * pdf(varid: " <<
static_cast<unsigned int>(varid) <<
") = "
182 << prod <<
" * " << ipdfval
183 <<
" = " << prod * ipdfval);
193 B2DEBUG(20,
"\tL(" << pdgId * charge <<
") = " << pdfval);
195 likelihoods[hypo_idx] = (std::isnormal(pdfval) && pdfval > 0) ? log(pdfval) :
c_dummyLogL;
197 B2DEBUG(20,
"\tlog(L(" << pdgId * charge <<
")) = " << likelihoods[hypo_idx]);
203 track.addRelationTo(eclPidLikelihood);
213 double y, xmin, xmax;
214 pdf->GetRange(xmin, xmax);
216 if (x <= xmin) { y = pdf->Eval(xmin + 1e-9); }
217 else if (x >= xmax) { y = pdf->Eval(xmax - 1e-9); }
218 else { y = pdf->Eval(x); }
220 return (y) ? y : 1e-9;
224 std::vector<double>& variables)
227 unsigned int nvars = variables.size();
230 auto vts =
m_pdfs->getVTS(pdg, charge, p, theta);
233 B2DEBUG(30,
"\tclass path: " << vts->classPath);
234 B2DEBUG(30,
"\tgbin = " << vts->gbin <<
", (theta,p) = (" << vts->jth <<
"," << vts->ip <<
")");
235 B2DEBUG(30,
"\tnvars: " << nvars);
237 auto varids =
m_pdfs->getVars(pdg, charge, p, theta);
239 for (
unsigned int ivar(0); ivar < nvars; ivar++) {
240 unsigned int ndivs = vts->nDivisions[ivar];
241 B2DEBUG(30,
"\tvarid: " <<
static_cast<unsigned int>(varids->at(ivar)) <<
" = " << variables.at(ivar) <<
", nsteps = " << ndivs);
242 for (
unsigned int jdiv(0); jdiv < ndivs; jdiv++) {
243 auto ij =
linIndex(ivar, jdiv, vts->nDivisionsMax);
244 B2DEBUG(30,
"\t\tx[" << ivar <<
"][" << jdiv <<
"] = x[" << ij <<
"] = " << vts->x[ij]);
245 B2DEBUG(30,
"\t\tcumulDist[" << ivar <<
"][" << jdiv <<
"] = cumulDist[" << ij <<
"] = " << vts->cumulDist[ij]);
249 std::vector<double> vtransfo_gauss;
250 vtransfo_gauss.reserve(nvars);
252 for (
unsigned int ivar(0); ivar < nvars; ivar++) {
254 int ndivs = vts->nDivisions[ivar];
257 auto ij =
linIndex(ivar, jdiv, vts->nDivisionsMax);
258 while (variables.at(ivar) > vts->x[ij]) {
260 ij =
linIndex(ivar, jdiv, vts->nDivisionsMax);
263 if (jdiv < 0) { jdiv = 0; }
264 if (jdiv >= ndivs) { jdiv = ndivs - 1; }
266 if ((variables.at(ivar) > vts->x[ij] && jdiv != ndivs - 1) || jdiv == 0) {
271 auto ijnext =
linIndex(ivar, jnextdiv, vts->nDivisionsMax);
273 double dx = vts->x[ij] - vts->x[ijnext];
274 double dy = vts->cumulDist[ij] - vts->cumulDist[ijnext];
275 double cumulant = vts->cumulDist[ij] + (variables.at(ivar) - vts->x[ijnext]) * dy / dx;
277 cumulant = std::min(cumulant, 1.0 - 10e-10);
278 cumulant = std::max(cumulant, 10e-10);
280 double maxErfInvArgRange = 0.99999999;
281 double arg = 2.0 * cumulant - 1.0;
283 arg = std::min(maxErfInvArgRange, arg);
284 arg = std::max(-maxErfInvArgRange, arg);
286 vtransfo_gauss.at(ivar) =
c_sqrt2 * TMath::ErfInverse(arg);
289 B2DEBUG(30,
"\tSHOWER properties (Gaussian-transformed):");
290 for (
unsigned int idx(0); idx < nvars; idx++) {
291 B2DEBUG(30,
"\tvarid: " <<
static_cast<unsigned int>(varids->at(idx)) <<
" = " << vtransfo_gauss.at(idx));
293 B2DEBUG(30,
"\t-------------------------------");
295 std::vector<double> vtransfo_decorr;
296 vtransfo_decorr.reserve(nvars);
298 for (
unsigned int i(0); i < nvars; i++) {
299 double vartransfo(0);
300 for (
unsigned int j(0); j < nvars; j++) {
302 vartransfo += vtransfo_gauss[j] * vts->covMatrix[ij];
304 vtransfo_decorr.push_back(vartransfo);
307 B2DEBUG(30,
"\tSHOWER properties (Decorrelation-transformed):");
308 for (
unsigned int idx(0); idx < nvars; idx++) {
309 B2DEBUG(30,
"\tvarid: " <<
static_cast<unsigned int>(varids->at(idx)) <<
" = " << vtransfo_decorr.at(idx));
311 B2DEBUG(30,
"\t-------------------------------");
314 for (
unsigned int i(0); i < nvars; i++) {
315 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.