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>
32 setPropertyFlags(c_ParallelProcessingCertified);
35 setDescription(
"Extract dE/dx and corresponding log-likelihood from fitted tracks and hits in the SVD and PXD.");
38 addParam(
"useIndividualHits", m_useIndividualHits,
39 "Include PDF value for each hit in likelihood. If false, the truncated mean of dedx values for the detectors will be used.",
false);
41 addParam(
"onlyPrimaryParticles", m_onlyPrimaryParticles,
"Only save data for primary particles (as determined by MC truth)",
false);
42 addParam(
"usePXD", m_usePXD,
"Use PXDClusters for dE/dx calculation",
false);
43 addParam(
"useSVD", m_useSVD,
"Use SVDClusters for dE/dx calculation",
true);
44 addParam(
"trackDistanceThreshold", m_trackDistanceThreshhold,
45 "Use a faster helix parametrisation, with corrections as soon as the approximation is more than ... cm off.",
double(4.0));
46 addParam(
"enableDebugOutput", m_enableDebugOutput,
"Option to write out debugging information to DedxTracks (DataStore objects).",
48 addParam(
"ignoreMissingParticles", m_ignoreMissingParticles,
"Ignore particles for which no PDFs are found",
false);
59 if (!m_DBDedxPDFs) B2FATAL(
"No VXD Dedx PDFS available");
60 int nBinsXPXD, nBinsYPXD;
61 double xMinPXD, xMaxPXD, yMinPXD, yMaxPXD;
62 nBinsXPXD = nBinsYPXD = -1;
63 xMinPXD = xMaxPXD = yMinPXD = yMaxPXD = 0.0;
65 int nBinsXSVD, nBinsYSVD;
66 double xMinSVD, xMaxSVD, yMinSVD, yMaxSVD;
67 nBinsXSVD = nBinsYSVD = -1;
68 xMinSVD = xMaxSVD = yMinSVD = yMaxSVD = 0.0;
70 for (
unsigned int iPart = 0; iPart < 6; iPart++) {
72 const TH2F* svd_pdf = m_DBDedxPDFs->getSVDPDF(iPart, !m_useIndividualHits);
73 const TH2F* pxd_pdf = m_DBDedxPDFs->getPXDPDF(iPart, !m_useIndividualHits);
75 if (pxd_pdf->GetEntries() == 0 || svd_pdf->GetEntries() == 0) {
76 if (m_ignoreMissingParticles)
78 B2FATAL(
"Couldn't find PDF for PDG " << pdgCode);
82 const double epsFactor = 1e-5;
83 if (nBinsXPXD == -1 and nBinsYPXD == -1) {
84 nBinsXPXD = pxd_pdf->GetNbinsX();
85 nBinsYPXD = pxd_pdf->GetNbinsY();
86 xMinPXD = pxd_pdf->GetXaxis()->GetXmin();
87 xMaxPXD = pxd_pdf->GetXaxis()->GetXmax();
88 yMinPXD = pxd_pdf->GetYaxis()->GetXmin();
89 yMaxPXD = pxd_pdf->GetYaxis()->GetXmax();
90 }
else if (nBinsXPXD != pxd_pdf->GetNbinsX()
91 or nBinsYPXD != pxd_pdf->GetNbinsY()
92 or fabs(xMinPXD - pxd_pdf->GetXaxis()->GetXmin()) > epsFactor * xMaxPXD
93 or fabs(xMaxPXD - pxd_pdf->GetXaxis()->GetXmax()) > epsFactor * xMaxPXD
94 or fabs(yMinPXD - pxd_pdf->GetYaxis()->GetXmin()) > epsFactor * yMaxPXD
95 or fabs(yMaxPXD - pxd_pdf->GetYaxis()->GetXmax()) > epsFactor * yMaxPXD) {
96 B2FATAL(
"PDF for PDG " << pdgCode <<
", PXD has binning/dimensions differing from previous PDF.");
100 if (nBinsXSVD == -1 and nBinsYSVD == -1) {
101 nBinsXSVD = svd_pdf->GetNbinsX();
102 nBinsYSVD = svd_pdf->GetNbinsY();
103 xMinSVD = svd_pdf->GetXaxis()->GetXmin();
104 xMaxSVD = svd_pdf->GetXaxis()->GetXmax();
105 yMinSVD = svd_pdf->GetYaxis()->GetXmin();
106 yMaxSVD = svd_pdf->GetYaxis()->GetXmax();
107 }
else if (nBinsXSVD != svd_pdf->GetNbinsX()
108 or nBinsYSVD != svd_pdf->GetNbinsY()
109 or fabs(xMinSVD - svd_pdf->GetXaxis()->GetXmin()) > epsFactor * xMaxSVD
110 or fabs(xMaxSVD - svd_pdf->GetXaxis()->GetXmax()) > epsFactor * xMaxSVD
111 or fabs(yMinSVD - svd_pdf->GetYaxis()->GetXmin()) > epsFactor * yMaxSVD
112 or fabs(yMaxSVD - svd_pdf->GetYaxis()->GetXmax()) > epsFactor * yMaxSVD) {
113 B2FATAL(
"PDF for PDG " << pdgCode <<
", PXD has binning/dimensions differing from previous PDF.");
122 m_tracks.isRequired();
123 m_recoTracks.isRequired();
126 m_mcparticles.isOptional();
127 m_tracks.optionalRelationTo(m_mcparticles);
130 m_svdClusters.isRequired();
132 m_svdClusters.isOptional();
134 m_pxdClusters.isRequired();
136 m_pxdClusters.isOptional();
139 if (m_enableDebugOutput) {
140 m_dedxTracks.registerInDataStore();
141 m_tracks.registerRelationTo(m_dedxTracks);
145 m_dedxLikelihoods.registerInDataStore();
146 m_tracks.registerRelationTo(m_dedxLikelihoods);
148 m_DBDedxPDFs.addCallback([
this]() {checkPDFs();});
155 if (!genfit::MaterialEffects::getInstance()->isInitialized()) {
156 B2FATAL(
"Need to have SetupGenfitExtrapolationModule in path before this one.");
171 const int numMCParticles = m_mcparticles.getEntries();
179 for (
const auto& track : m_tracks) {
182 std::shared_ptr<VXDDedxTrack> dedxTrack = std::make_shared<VXDDedxTrack>();
183 dedxTrack->m_eventID = m_eventID;
184 dedxTrack->m_trackID = m_trackID;
190 B2WARNING(
"No related fit for track ...");
194 if ((m_enableDebugOutput or m_onlyPrimaryParticles) and numMCParticles != 0) {
206 dedxTrack->m_motherPDG = mother ? mother->getPDG() : 0;
208 const TVector3 trueMomentum = mcpart->
getMomentum();
209 dedxTrack->m_pTrue = trueMomentum.Mag();
214 const TVector3& trackPos = fitResult->
getPosition();
215 const TVector3& trackMom = fitResult->
getMomentum();
216 dedxTrack->m_p = trackMom.Mag();
217 dedxTrack->m_cosTheta = trackMom.CosTheta();
223 B2WARNING(
"No related track for this fit...");
230 B2ERROR(
"GFTrack is pruned, please run VXDDedxPID only on unpruned tracks! Skipping this track.");
235 const HelixHelper helixAtOrigin(trackPos, trackMom, dedxTrack->m_charge);
238 const std::vector<PXDCluster*>& pxdClusters = recoTrack->
getPXDHitList();
239 saveSiHits(dedxTrack.get(), helixAtOrigin, pxdClusters);
243 const std::vector<SVDCluster*>& svdClusters = recoTrack->
getSVDHitList();
244 saveSiHits(dedxTrack.get(), helixAtOrigin, svdClusters);
247 if (dedxTrack->dedx.empty()) {
248 B2DEBUG(50,
"Found track with no hits, ignoring.");
253 if (!m_useIndividualHits) {
254 for (
int detector = 0; detector <= c_SVD; detector++) {
255 if (!detectorEnabled(
static_cast<Detector
>(detector)))
258 if (detector == 0) savePXDLogLikelihood(dedxTrack->m_vxdLogl, dedxTrack->m_p, dedxTrack->m_dedxAvgTruncated[detector]);
259 else if (detector == 1) saveSVDLogLikelihood(dedxTrack->m_vxdLogl, dedxTrack->m_p, dedxTrack->m_dedxAvgTruncated[detector]);
263 if (m_enableDebugOutput) {
265 const int numDedx = dedxTrack->dedx.size();
266 dedxTrack->m_nHits = numDedx;
269 dedxTrack->m_nHitsUsed = numDedx - 2;
272 VXDDedxTrack* newVXDDedxTrack = m_dedxTracks.appendNew(*dedxTrack);
273 track.addRelationTo(newVXDDedxTrack);
277 VXDDedxLikelihood* likelihoodObj = m_dedxLikelihoods.appendNew(dedxTrack->m_vxdLogl);
278 track.addRelationTo(likelihoodObj);
286 B2DEBUG(50,
"VXDDedxPIDModule exiting after processing " << m_trackID <<
287 " tracks in " << m_eventID + 1 <<
" events.");
291 const std::vector<double>& dedx)
const
294 std::vector<double> sortedDedx = dedx;
295 std::sort(sortedDedx.begin(), sortedDedx.end());
297 double truncatedMeanTmp = 0.0;
298 double meanTmp = 0.0;
299 double sumOfSquares = 0.0;
300 const int numDedx = sortedDedx.size();
303 for (
int i = 0; i < numDedx; i++) {
304 meanTmp += sortedDedx[i];
310 for (
int i = 0; i < numDedx - 2; i++) {
311 truncatedMeanTmp += sortedDedx[i];
312 sumOfSquares += sortedDedx[i] * sortedDedx[i];
314 if (numDedx - 2 != 0) {
315 truncatedMeanTmp /= numDedx - 2;
319 *truncatedMean = truncatedMeanTmp;
321 if (numDedx - 2 > 1) {
322 *truncatedMeanErr = sqrt(sumOfSquares /
double(numDedx - 2) - truncatedMeanTmp * truncatedMeanTmp) / double(
325 *truncatedMeanErr = 0;
334 const TVector3 localPos(hit->getU(), hit->getV(), 0.0);
335 const TVector3& globalPos = sensor.pointToGlobal(localPos);
338 const TVector3& sensorNormal = sensor.vectorToGlobal(TVector3(0.0, 0.0, 1.0));
339 const double angle = sensorNormal.Angle(localMomentum);
342 return TMath::Min(sensor.getWidth(), sensor.getThickness() / fabs(cos(angle)));
352 if (hit->isUCluster()) {
353 const float u = hit->getPosition();
354 a = sensor.pointToGlobal(TVector3(sensor.getBackwardWidth() / sensor.getWidth(0) * u, -0.5 * sensor.getLength(), 0.0));
355 b = sensor.pointToGlobal(TVector3(sensor.getForwardWidth() / sensor.getWidth(0) * u, +0.5 * sensor.getLength(), 0.0));
357 const float v = hit->getPosition();
358 a = sensor.pointToGlobal(TVector3(-0.5 * sensor.getWidth(v), v, 0.0));
359 b = sensor.pointToGlobal(TVector3(+0.5 * sensor.getWidth(v), v, 0.0));
362 const TVector3& localMomentum = helix->
momentum(pathLength);
364 const TVector3& sensorNormal = sensor.vectorToGlobal(TVector3(0.0, 0.0, 1.0));
365 const double angle = sensorNormal.Angle(localMomentum);
367 return TMath::Min(sensor.getWidth(), sensor.getThickness() / fabs(cos(angle)));
372 const std::vector<HitClass*>& hits)
const
374 const int numHits = hits.size();
381 const int currentDetector = geo.
get(hits.front()->getSensorID()).
getType();
383 assert(currentDetector <= 1);
385 std::vector<double> siliconDedx;
386 siliconDedx.reserve(numHits);
389 for (
int i = 0; i < numHits; i++) {
390 const HitClass* hit = hits[i];
392 B2ERROR(
"Added hit is a null pointer!");
395 const VxdID& currentSensor = hit->getSensorID();
397 if (m_enableDebugOutput) {
399 assert(layer >= -6 && layer < 0);
404 const double totalDistance = getTraversedLength(hit, &helix);
405 const float charge = hit->getCharge();
406 const float dedx = charge / totalDistance;
408 B2WARNING(
"dE/dx is " << dedx <<
" in layer " << layer);
409 }
else if (i == 0 or prevSensor != currentSensor) {
410 prevSensor = currentSensor;
412 siliconDedx.push_back(dedx);
413 track->m_dedxAvg[currentDetector] += dedx;
414 track->addDedx(layer, totalDistance, dedx);
415 if (m_useIndividualHits) {
416 if (currentDetector == 0) savePXDLogLikelihood(track->m_vxdLogl, track->m_p, dedx);
417 else if (currentDetector == 1) saveSVDLogLikelihood(track->m_vxdLogl, track->m_p, dedx);
421 if (m_enableDebugOutput) {
422 track->addHit(currentSensor, layer, charge, totalDistance, dedx);
427 if (!m_useIndividualHits or m_enableDebugOutput) {
428 calculateMeans(&(track->m_dedxAvg[currentDetector]),
429 &(track->m_dedxAvgTruncated[currentDetector]),
430 &(track->m_dedxAvgTruncatedErr[currentDetector]),
438 const TH2F* pdf = m_DBDedxPDFs->getPXDPDF(0, !m_useIndividualHits);
439 const Int_t binX = pdf->GetXaxis()->FindFixBin(p);
440 const Int_t binY = pdf->GetYaxis()->FindFixBin(dedx);
443 pdf = m_DBDedxPDFs->getPXDPDF(iPart, !m_useIndividualHits);
444 if (pdf->GetEntries() == 0)
446 double probability = 0.0;
449 if (binX < 1 or binX > pdf->GetNbinsX()
450 or binY < 1 or binY > pdf->GetNbinsY()) {
451 probability = pdf->GetBinContent(binX, binY);
456 probability =
const_cast<TH2F*
>(pdf)->Interpolate(p, dedx);
459 if (probability != probability)
460 B2ERROR(
"probability NAN for a track with p=" << p <<
" and dedx=" << dedx);
463 if (probability == 0.0)
464 probability = m_useIndividualHits ? (1e-5) : (1e-3);
466 logl[iPart] += log(probability);
473 const TH2F* pdf = m_DBDedxPDFs->getSVDPDF(0, !m_useIndividualHits);
474 const Int_t binX = pdf->GetXaxis()->FindFixBin(p);
475 const Int_t binY = pdf->GetYaxis()->FindFixBin(dedx);
478 pdf = m_DBDedxPDFs->getSVDPDF(iPart, !m_useIndividualHits);
479 if (pdf->GetEntries() == 0)
481 double probability = 0.0;
484 if (binX < 1 or binX > pdf->GetNbinsX()
485 or binY < 1 or binY > pdf->GetNbinsY()) {
486 probability = pdf->GetBinContent(binX, binY);
491 probability =
const_cast<TH2F*
>(pdf)->Interpolate(p, dedx);
494 if (probability != probability)
495 B2ERROR(
"probability NAN for a track with p=" << p <<
" and dedx=" << dedx);
498 if (probability == 0.0)
499 probability = m_useIndividualHits ? (1e-5) : (1e-3);
501 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.
TVector3 momentum(double s=0) const
momentum of the particle, at the helix point corresponding to a flown path length s (from poca).
double pathLengthToPoint(const TVector3 &p) const
returns the path length (along the helix) to the helix point closest to p.
double pathLengthToLine(const TVector3 &a, const TVector3 &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.
TVector3 getMomentum() const
Return momentum.
int m_pdg
PDG-Code of the particle.
int getPDG() const
Return PDG code of particle.
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.
Values of the result of a track fit with a given particle hypothesis.
short getChargeSign() const
Return track charge (1 or -1).
TVector3 getMomentum() const
Getter for vector of momentum at closest approach of track in r/phi projection.
TVector3 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).
Extract dE/dx from fitted tracks.
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'.
virtual void initialize() override
Initialize the module.
virtual void event() override
This method is called for each event.
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.
virtual ~VXDDedxPIDModule()
Destructor.
static double getTraversedLength(const PXDCluster *hit, const HelixHelper *helix)
returns traversed length through active medium of given PXDCluster.
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'.
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?
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
MCParticle * getMother() const
Returns a pointer to the mother particle.
Abstract base class for different kinds of events.