9 #include <reconstruction/modules/VXDDedxPID/VXDDedxPIDModule.h>
10 #include <reconstruction/modules/VXDDedxPID/HelixHelper.h>
12 #include <framework/gearbox/Const.h>
14 #include <vxd/geometry/GeoCache.h>
16 #include <genfit/MaterialEffects.h>
18 #include <Math/VectorUtil.h>
36 setDescription(
"Extract dE/dx and corresponding log-likelihood from fitted tracks and hits in the SVD and PXD.");
40 "Include PDF value for each hit in likelihood. If false, the truncated mean of dedx values for the detectors will be used.",
false);
43 addParam(
"usePXD",
m_usePXD,
"Use PXDClusters for dE/dx calculation",
false);
46 "Use a faster helix parametrisation, with corrections as soon as the approximation is more than ... cm off.",
double(4.0));
58 if (!
m_DBDedxPDFs) B2FATAL(
"No VXD Dedx PDFS available");
59 int nBinsXPXD, nBinsYPXD;
60 double xMinPXD, xMaxPXD, yMinPXD, yMaxPXD;
61 nBinsXPXD = nBinsYPXD = -1;
62 xMinPXD = xMaxPXD = yMinPXD = yMaxPXD = 0.0;
64 int nBinsXSVD, nBinsYSVD;
65 double xMinSVD, xMaxSVD, yMinSVD, yMaxSVD;
66 nBinsXSVD = nBinsYSVD = -1;
67 xMinSVD = xMaxSVD = yMinSVD = yMaxSVD = 0.0;
69 for (
unsigned int iPart = 0; iPart < 6; iPart++) {
74 if (pxd_pdf->GetEntries() == 0 || svd_pdf->GetEntries() == 0) {
77 B2FATAL(
"Couldn't find PDF for PDG " << pdgCode);
81 const double epsFactor = 1e-5;
82 if (nBinsXPXD == -1 and nBinsYPXD == -1) {
83 nBinsXPXD = pxd_pdf->GetNbinsX();
84 nBinsYPXD = pxd_pdf->GetNbinsY();
85 xMinPXD = pxd_pdf->GetXaxis()->GetXmin();
86 xMaxPXD = pxd_pdf->GetXaxis()->GetXmax();
87 yMinPXD = pxd_pdf->GetYaxis()->GetXmin();
88 yMaxPXD = pxd_pdf->GetYaxis()->GetXmax();
89 }
else if (nBinsXPXD != pxd_pdf->GetNbinsX()
90 or nBinsYPXD != pxd_pdf->GetNbinsY()
91 or fabs(xMinPXD - pxd_pdf->GetXaxis()->GetXmin()) > epsFactor * xMaxPXD
92 or fabs(xMaxPXD - pxd_pdf->GetXaxis()->GetXmax()) > epsFactor * xMaxPXD
93 or fabs(yMinPXD - pxd_pdf->GetYaxis()->GetXmin()) > epsFactor * yMaxPXD
94 or fabs(yMaxPXD - pxd_pdf->GetYaxis()->GetXmax()) > epsFactor * yMaxPXD) {
95 B2FATAL(
"PDF for PDG " << pdgCode <<
", PXD has binning/dimensions differing from previous PDF.");
99 if (nBinsXSVD == -1 and nBinsYSVD == -1) {
100 nBinsXSVD = svd_pdf->GetNbinsX();
101 nBinsYSVD = svd_pdf->GetNbinsY();
102 xMinSVD = svd_pdf->GetXaxis()->GetXmin();
103 xMaxSVD = svd_pdf->GetXaxis()->GetXmax();
104 yMinSVD = svd_pdf->GetYaxis()->GetXmin();
105 yMaxSVD = svd_pdf->GetYaxis()->GetXmax();
106 }
else if (nBinsXSVD != svd_pdf->GetNbinsX()
107 or nBinsYSVD != svd_pdf->GetNbinsY()
108 or fabs(xMinSVD - svd_pdf->GetXaxis()->GetXmin()) > epsFactor * xMaxSVD
109 or fabs(xMaxSVD - svd_pdf->GetXaxis()->GetXmax()) > epsFactor * xMaxSVD
110 or fabs(yMinSVD - svd_pdf->GetYaxis()->GetXmin()) > epsFactor * yMaxSVD
111 or fabs(yMaxSVD - svd_pdf->GetYaxis()->GetXmax()) > epsFactor * yMaxSVD) {
112 B2FATAL(
"PDF for PDG " << pdgCode <<
", PXD has binning/dimensions differing from previous PDF.");
152 if (!genfit::MaterialEffects::getInstance()->isInitialized()) {
153 B2FATAL(
"Need to have SetupGenfitExtrapolationModule in path before this one.");
176 for (
const auto& track :
m_tracks) {
179 std::shared_ptr<VXDDedxTrack> dedxTrack = std::make_shared<VXDDedxTrack>();
187 B2WARNING(
"No related fit for track ...");
191 if (numMCParticles != 0) {
203 dedxTrack->m_motherPDG = mother ? mother->getPDG() : 0;
205 const ROOT::Math::XYZVector trueMomentum = mcpart->
getMomentum();
206 dedxTrack->m_pTrue = trueMomentum.R();
211 const ROOT::Math::XYZVector& trackPos = fitResult->
getPosition();
212 const ROOT::Math::XYZVector& trackMom = fitResult->
getMomentum();
213 dedxTrack->m_p = trackMom.R();
214 dedxTrack->m_cosTheta = cos(trackMom.Theta());
220 B2WARNING(
"No related track for this fit...");
227 B2ERROR(
"GFTrack is pruned, please run VXDDedxPID only on unpruned tracks! Skipping this track.");
232 const HelixHelper helixAtOrigin(trackPos, trackMom, dedxTrack->m_charge);
235 const std::vector<PXDCluster*>& pxdClusters = recoTrack->
getPXDHitList();
236 saveSiHits(dedxTrack.get(), helixAtOrigin, pxdClusters);
240 const std::vector<SVDCluster*>& svdClusters = recoTrack->
getSVDHitList();
241 saveSiHits(dedxTrack.get(), helixAtOrigin, svdClusters);
244 if (dedxTrack->dedx.empty()) {
245 B2DEBUG(50,
"Found track with no hits, ignoring.");
251 for (
int detector = 0; detector <= c_SVD; detector++) {
255 if (detector == 0)
savePXDLogLikelihood(dedxTrack->m_vxdLogl, dedxTrack->m_p, dedxTrack->m_dedxAvgTruncated[detector]);
256 else if (detector == 1)
saveSVDLogLikelihood(dedxTrack->m_vxdLogl, dedxTrack->m_p, dedxTrack->m_dedxAvgTruncated[detector]);
261 const int numDedx = dedxTrack->dedx.size();
262 dedxTrack->m_nHits = numDedx;
264 dedxTrack->m_nHitsUsed = numDedx - 2;
268 track.addRelationTo(newVXDDedxTrack);
272 track.addRelationTo(likelihoodObj);
280 B2DEBUG(50,
"VXDDedxPIDModule exiting after processing " <<
m_trackID <<
281 " tracks in " <<
m_eventID + 1 <<
" events.");
285 const std::vector<double>& dedx)
const
288 std::vector<double> sortedDedx = dedx;
289 std::sort(sortedDedx.begin(), sortedDedx.end());
291 double truncatedMeanTmp = 0.0;
292 double meanTmp = 0.0;
293 double sumOfSquares = 0.0;
294 const int numDedx = sortedDedx.size();
297 for (
int i = 0; i < numDedx; i++) {
298 meanTmp += sortedDedx[i];
304 for (
int i = 0; i < numDedx - 2; i++) {
305 truncatedMeanTmp += sortedDedx[i];
306 sumOfSquares += sortedDedx[i] * sortedDedx[i];
308 if (numDedx - 2 != 0) {
309 truncatedMeanTmp /= numDedx - 2;
313 *truncatedMean = truncatedMeanTmp;
315 if (numDedx - 2 > 1) {
316 *truncatedMeanErr =
sqrt(sumOfSquares /
double(numDedx - 2) - truncatedMeanTmp * truncatedMeanTmp) / double(
319 *truncatedMeanErr = 0;
328 const ROOT::Math::XYZVector localPos(hit->getU(), hit->getV(), 0.0);
329 const ROOT::Math::XYZVector& globalPos = sensor.pointToGlobal(localPos);
332 const ROOT::Math::XYZVector& sensorNormal = sensor.vectorToGlobal(ROOT::Math::XYZVector(0.0, 0.0, 1.0));
333 const double angle = ROOT::Math::VectorUtil::Angle(sensorNormal, localMomentum);
336 return TMath::Min(sensor.getWidth(), sensor.getThickness() / fabs(cos(angle)));
345 ROOT::Math::XYZVector a, b;
346 if (hit->isUCluster()) {
347 const float u = hit->getPosition();
348 a = sensor.pointToGlobal(ROOT::Math::XYZVector(sensor.getBackwardWidth() / sensor.getWidth(0) * u, -0.5 * sensor.getLength(), 0.0));
349 b = sensor.pointToGlobal(ROOT::Math::XYZVector(sensor.getForwardWidth() / sensor.getWidth(0) * u, +0.5 * sensor.getLength(), 0.0));
351 const float v = hit->getPosition();
352 a = sensor.pointToGlobal(ROOT::Math::XYZVector(-0.5 * sensor.getWidth(v), v, 0.0));
353 b = sensor.pointToGlobal(ROOT::Math::XYZVector(+0.5 * sensor.getWidth(v), v, 0.0));
355 const double pathLength = helix->
pathLengthToLine(ROOT::Math::XYZVector(a), ROOT::Math::XYZVector(b));
356 const ROOT::Math::XYZVector& localMomentum = helix->
momentum(pathLength);
358 const ROOT::Math::XYZVector& sensorNormal = sensor.vectorToGlobal(ROOT::Math::XYZVector(0.0, 0.0, 1.0));
359 const double angle = ROOT::Math::VectorUtil::Angle(sensorNormal, localMomentum);
361 return TMath::Min(sensor.getWidth(), sensor.getThickness() / fabs(cos(angle)));
366 const std::vector<HitClass*>& hits)
const
368 const int numHits = hits.size();
375 const int currentDetector = geo.
get(hits.front()->getSensorID()).
getType();
377 assert(currentDetector <= 1);
379 std::vector<double> siliconDedx;
380 siliconDedx.reserve(numHits);
383 for (
int i = 0; i < numHits; i++) {
384 const HitClass* hit = hits[i];
386 B2ERROR(
"Added hit is a null pointer!");
389 const VxdID& currentSensor = hit->getSensorID();
391 assert(layer >= -6 && layer < 0);
396 const float charge = hit->getCharge();
397 const float dedx = charge / totalDistance;
399 B2WARNING(
"dE/dx is " << dedx <<
" in layer " << layer);
400 }
else if (i == 0 or prevSensor != currentSensor) {
401 prevSensor = currentSensor;
403 siliconDedx.push_back(dedx);
404 track->m_dedxAvg[currentDetector] += dedx;
405 track->addDedx(layer, totalDistance, dedx);
412 track->addHit(currentSensor, layer, charge, totalDistance, dedx);
417 &(track->m_dedxAvgTruncated[currentDetector]),
418 &(track->m_dedxAvgTruncatedErr[currentDetector]),
426 const Int_t binX = pdf->GetXaxis()->FindFixBin(p);
427 const Int_t binY = pdf->GetYaxis()->FindFixBin(dedx);
431 if (pdf->GetEntries() == 0)
433 double probability = 0.0;
436 if (binX < 1 or binX > pdf->GetNbinsX()
437 or binY < 1 or binY > pdf->GetNbinsY()) {
438 probability = pdf->GetBinContent(binX, binY);
443 probability =
const_cast<TH2F*
>(pdf)->Interpolate(p, dedx);
446 if (probability != probability)
447 B2ERROR(
"probability NAN for a track with p=" << p <<
" and dedx=" << dedx);
450 if (probability == 0.0)
453 logl[iPart] += log(probability);
461 const Int_t binX = pdf->GetXaxis()->FindFixBin(p);
462 const Int_t binY = pdf->GetYaxis()->FindFixBin(dedx);
466 if (pdf->GetEntries() == 0)
468 double probability = 0.0;
471 if (binX < 1 or binX > pdf->GetNbinsX()
472 or binY < 1 or binY > pdf->GetNbinsY()) {
473 probability = pdf->GetBinContent(binX, binY);
478 probability =
const_cast<TH2F*
>(pdf)->Interpolate(p, dedx);
481 if (probability != probability)
482 B2ERROR(
"probability NAN for a track with p=" << p <<
" and dedx=" << dedx);
485 if (probability == 0.0)
488 logl[iPart] += log(probability);
static const unsigned int c_SetSize
Number of elements (for use in array bounds etc.)
const ParticleType & at(unsigned int index) const
Return particle at given index, or end() if out of range.
int getPDGCode() const
PDG code.
static const ParticleSet chargedStableSet
set of charged stable particles
static const ChargedStable pion
charged pion particle
Helper class representing a helical track.
double pathLengthToPoint(const ROOT::Math::XYZVector &p) const
returns the path length (along the helix) to the helix point closest to p.
ROOT::Math::XYZVector momentum(double s=0) const
momentum of the particle, at the helix point corresponding to a flown path length s (from poca).
double pathLengthToLine(const ROOT::Math::XYZVector &a, const ROOT::Math::XYZVector &b) const
returns the path length (along the helix) to the helix point closest to the line going through points...
A Class to store the Monte Carlo particle information.
@ c_PrimaryParticle
bit 0: Particle is primary particle.
bool hasStatus(unsigned short int bitmask) const
Return if specific status bit is set.
int m_pdg
PDG-Code of the particle.
int getPDG() const
Return PDG code of particle.
ROOT::Math::XYZVector getMomentum() const
Return momentum.
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...
The PXD Cluster class This class stores all information about reconstructed PXD clusters The position...
This is the Reconstruction Event-Data Model Track.
const genfit::FitStatus * getTrackFitStatus(const genfit::AbsTrackRep *representation=nullptr) const
Return the track fit status for the given representation or for the cardinal one. You are not allowed...
std::vector< Belle2::RecoTrack::UsedSVDHit * > getSVDHitList() const
Return an unsorted list of svd hits.
std::vector< Belle2::RecoTrack::UsedPXDHit * > getPXDHitList() const
Return an unsorted list of pxd hits.
The SVD Cluster class This class stores all information about reconstructed SVD clusters.
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
bool isOptional(const std::string &name="")
Tell the DataStore about an optional input.
int getEntries() const
Get the number of objects in the array.
Values of the result of a track fit with a given particle hypothesis.
short getChargeSign() const
Return track charge (1 or -1).
ROOT::Math::XYZVector getMomentum() const
Getter for vector of momentum at closest approach of track in r/phi projection.
ROOT::Math::XYZVector getPosition() const
Getter for vector of position at closest approach of track in r/phi projection.
Container for likelihoods obtained by the VXD dE/dx PID (VXDDedxPIDModule).
void saveSVDLogLikelihood(double(&logl)[Const::ChargedStable::c_SetSize], double p, float dedx) const
for all particles in the SVD, save log-likelihood values into 'logl'.
int m_trackID
counter for tracks in this event
virtual void initialize() override
Initialize the module.
StoreArray< SVDCluster > m_svdClusters
Optional array of SVDClusters.
bool m_usePXD
use PXD hits for likelihood
virtual void event() override
This method is called for each event.
StoreArray< MCParticle > m_mcparticles
Optional array of MCParticles.
StoreArray< VXDDedxLikelihood > m_dedxLikelihoods
Output array of VXDDedxLikelihoods.
void checkPDFs()
Check the pdfs for consistency everytime they change in the database.
virtual void terminate() override
End of the event processing.
void saveSiHits(VXDDedxTrack *track, const HelixHelper &helix, const std::vector< HitClass * > &hits) const
save energy loss and hit information from SVD/PXDHits to track
void calculateMeans(double *mean, double *truncatedMean, double *truncatedMeanErr, const std::vector< double > &dedx) const
Save arithmetic and truncated mean for the 'dedx' values.
StoreArray< VXDDedxTrack > m_dedxTracks
Output array of VXDDedxTracks.
virtual ~VXDDedxPIDModule()
Destructor.
int m_eventID
counter for events
bool m_useSVD
use SVD hits for likelihood
bool detectorEnabled(Dedx::Detector d) const
should info from this detector be included in likelihood?
bool m_ignoreMissingParticles
Ignore particles for which no PDFs are found.
StoreArray< Track > m_tracks
Required array of Tracks.
bool m_onlyPrimaryParticles
Only save data for primary particles (as determined by MC truth)
StoreArray< PXDCluster > m_pxdClusters
Optional array of PXDClusters.
static double getTraversedLength(const PXDCluster *hit, const HelixHelper *helix)
returns traversed length through active medium of given PXDCluster.
StoreArray< RecoTrack > m_recoTracks
Required array of input RecoTracks.
bool m_useIndividualHits
Include PDF value for each hit in likelihood.
VXDDedxPIDModule()
Default constructor.
double m_trackDistanceThreshhold
Use a faster helix parametrisation, with corrections as soon as the approximation is more than ....
void savePXDLogLikelihood(double(&logl)[Const::ChargedStable::c_SetSize], double p, float dedx) const
for all particles in the PXD, save log-likelihood values into 'logl'.
DBObjPtr< DedxPDFs > m_DBDedxPDFs
DB object for dedx:momentum PDFs.
Debug output for VXDDedxPID module.
Class to faciliate easy access to sensor information of the VXD like coordinate transformations or pi...
static GeoCache & getInstance()
Return a reference to the singleton instance.
static const SensorInfoBase & get(Belle2::VxdID id)
Return a reference to the SensorInfo of a given SensorID.
Base class to provide Sensor Information for PXD and SVD.
SensorType getType() const
Return the Type of the Sensor.
Class to uniquely identify a any structure of the PXD and SVD.
baseType getLayerNumber() const
Get the layer id.
bool isTrackPruned() const
Has the track been pruned after the fit?
REG_MODULE(arichBtest)
Register the Module.
void addParam(const std::string &name, T ¶mVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
double sqrt(double a)
sqrt for double
MCParticle * getMother() const
Returns a pointer to the mother particle.
Abstract base class for different kinds of events.