11 #include <reconstruction/modules/VXDDedxPID/VXDDedxPIDModule.h>
12 #include <reconstruction/modules/VXDDedxPID/HelixHelper.h>
14 #include <framework/gearbox/Const.h>
16 #include <vxd/geometry/GeoCache.h>
18 #include <genfit/MaterialEffects.h>
34 setPropertyFlags(c_ParallelProcessingCertified);
37 setDescription(
"Extract dE/dx and corresponding log-likelihood from fitted tracks and hits in the SVD and PXD.");
40 addParam(
"useIndividualHits", m_useIndividualHits,
41 "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(
"onlyPrimaryParticles", m_onlyPrimaryParticles,
"Only save data for primary particles (as determined by MC truth)",
false);
44 addParam(
"usePXD", m_usePXD,
"Use PXDClusters for dE/dx calculation",
false);
45 addParam(
"useSVD", m_useSVD,
"Use SVDClusters for dE/dx calculation",
true);
46 addParam(
"trackDistanceThreshold", m_trackDistanceThreshhold,
47 "Use a faster helix parametrisation, with corrections as soon as the approximation is more than ... cm off.",
double(4.0));
48 addParam(
"enableDebugOutput", m_enableDebugOutput,
"Option to write out debugging information to DedxTracks (DataStore objects).",
50 addParam(
"ignoreMissingParticles", m_ignoreMissingParticles,
"Ignore particles for which no PDFs are found",
false);
61 if (!m_DBDedxPDFs) B2FATAL(
"No VXD Dedx PDFS available");
62 int nBinsXPXD, nBinsYPXD;
63 double xMinPXD, xMaxPXD, yMinPXD, yMaxPXD;
64 nBinsXPXD = nBinsYPXD = -1;
65 xMinPXD = xMaxPXD = yMinPXD = yMaxPXD = 0.0;
67 int nBinsXSVD, nBinsYSVD;
68 double xMinSVD, xMaxSVD, yMinSVD, yMaxSVD;
69 nBinsXSVD = nBinsYSVD = -1;
70 xMinSVD = xMaxSVD = yMinSVD = yMaxSVD = 0.0;
72 for (
unsigned int iPart = 0; iPart < 6; iPart++) {
74 const TH2F* svd_pdf = m_DBDedxPDFs->getSVDPDF(iPart, !m_useIndividualHits);
75 const TH2F* pxd_pdf = m_DBDedxPDFs->getPXDPDF(iPart, !m_useIndividualHits);
77 if (pxd_pdf->GetEntries() == 0 || svd_pdf->GetEntries() == 0) {
78 if (m_ignoreMissingParticles)
80 B2FATAL(
"Couldn't find PDF for PDG " << pdgCode);
84 const double epsFactor = 1e-5;
85 if (nBinsXPXD == -1 and nBinsYPXD == -1) {
86 nBinsXPXD = pxd_pdf->GetNbinsX();
87 nBinsYPXD = pxd_pdf->GetNbinsY();
88 xMinPXD = pxd_pdf->GetXaxis()->GetXmin();
89 xMaxPXD = pxd_pdf->GetXaxis()->GetXmax();
90 yMinPXD = pxd_pdf->GetYaxis()->GetXmin();
91 yMaxPXD = pxd_pdf->GetYaxis()->GetXmax();
92 }
else if (nBinsXPXD != pxd_pdf->GetNbinsX()
93 or nBinsYPXD != pxd_pdf->GetNbinsY()
94 or fabs(xMinPXD - pxd_pdf->GetXaxis()->GetXmin()) > epsFactor * xMaxPXD
95 or fabs(xMaxPXD - pxd_pdf->GetXaxis()->GetXmax()) > epsFactor * xMaxPXD
96 or fabs(yMinPXD - pxd_pdf->GetYaxis()->GetXmin()) > epsFactor * yMaxPXD
97 or fabs(yMaxPXD - pxd_pdf->GetYaxis()->GetXmax()) > epsFactor * yMaxPXD) {
98 B2FATAL(
"PDF for PDG " << pdgCode <<
", PXD has binning/dimensions differing from previous PDF.");
102 if (nBinsXSVD == -1 and nBinsYSVD == -1) {
103 nBinsXSVD = svd_pdf->GetNbinsX();
104 nBinsYSVD = svd_pdf->GetNbinsY();
105 xMinSVD = svd_pdf->GetXaxis()->GetXmin();
106 xMaxSVD = svd_pdf->GetXaxis()->GetXmax();
107 yMinSVD = svd_pdf->GetYaxis()->GetXmin();
108 yMaxSVD = svd_pdf->GetYaxis()->GetXmax();
109 }
else if (nBinsXSVD != svd_pdf->GetNbinsX()
110 or nBinsYSVD != svd_pdf->GetNbinsY()
111 or fabs(xMinSVD - svd_pdf->GetXaxis()->GetXmin()) > epsFactor * xMaxSVD
112 or fabs(xMaxSVD - svd_pdf->GetXaxis()->GetXmax()) > epsFactor * xMaxSVD
113 or fabs(yMinSVD - svd_pdf->GetYaxis()->GetXmin()) > epsFactor * yMaxSVD
114 or fabs(yMaxSVD - svd_pdf->GetYaxis()->GetXmax()) > epsFactor * yMaxSVD) {
115 B2FATAL(
"PDF for PDG " << pdgCode <<
", PXD has binning/dimensions differing from previous PDF.");
124 m_tracks.isRequired();
125 m_recoTracks.isRequired();
128 m_mcparticles.isOptional();
129 m_tracks.optionalRelationTo(m_mcparticles);
132 m_svdClusters.isRequired();
134 m_svdClusters.isOptional();
136 m_pxdClusters.isRequired();
138 m_pxdClusters.isOptional();
141 if (m_enableDebugOutput) {
142 m_dedxTracks.registerInDataStore();
143 m_tracks.registerRelationTo(m_dedxTracks);
147 m_dedxLikelihoods.registerInDataStore();
148 m_tracks.registerRelationTo(m_dedxLikelihoods);
150 m_DBDedxPDFs.addCallback([
this]() {checkPDFs();});
157 if (!genfit::MaterialEffects::getInstance()->isInitialized()) {
158 B2FATAL(
"Need to have SetupGenfitExtrapolationModule in path before this one.");
173 const int numMCParticles = m_mcparticles.getEntries();
181 for (
const auto& track : m_tracks) {
184 std::shared_ptr<VXDDedxTrack> dedxTrack = std::make_shared<VXDDedxTrack>();
192 B2WARNING(
"No related fit for track ...");
196 if ((m_enableDebugOutput or m_onlyPrimaryParticles) and numMCParticles != 0) {
208 dedxTrack->
m_motherPDG = mother ? mother->getPDG() : 0;
210 const TVector3 trueMomentum = mcpart->
getMomentum();
211 dedxTrack->
m_pTrue = trueMomentum.Mag();
216 const TVector3& trackPos = fitResult->
getPosition();
217 const TVector3& trackMom = fitResult->
getMomentum();
218 dedxTrack->
m_p = trackMom.Mag();
225 B2WARNING(
"No related track for this fit...");
232 B2ERROR(
"GFTrack is pruned, please run VXDDedxPID only on unpruned tracks! Skipping this track.");
240 const std::vector<PXDCluster*>& pxdClusters = recoTrack->
getPXDHitList();
241 saveSiHits(dedxTrack.get(), helixAtOrigin, pxdClusters);
245 const std::vector<SVDCluster*>& svdClusters = recoTrack->
getSVDHitList();
246 saveSiHits(dedxTrack.get(), helixAtOrigin, svdClusters);
249 if (dedxTrack->
dedx.empty()) {
250 B2DEBUG(50,
"Found track with no hits, ignoring.");
255 if (!m_useIndividualHits) {
256 for (
int detector = 0; detector <= c_SVD; detector++) {
257 if (!detectorEnabled(
static_cast<Detector
>(detector)))
265 if (m_enableDebugOutput) {
267 const int numDedx = dedxTrack->
dedx.size();
274 VXDDedxTrack* newVXDDedxTrack = m_dedxTracks.appendNew(*dedxTrack);
275 track.addRelationTo(newVXDDedxTrack);
280 track.addRelationTo(likelihoodObj);
288 B2DEBUG(50,
"VXDDedxPIDModule exiting after processing " << m_trackID <<
289 " tracks in " << m_eventID + 1 <<
" events.");
293 const std::vector<double>& dedx)
const
296 std::vector<double> sortedDedx = dedx;
297 std::sort(sortedDedx.begin(), sortedDedx.end());
299 double truncatedMeanTmp = 0.0;
300 double meanTmp = 0.0;
301 double sumOfSquares = 0.0;
302 const int numDedx = sortedDedx.size();
305 for (
int i = 0; i < numDedx; i++) {
306 meanTmp += sortedDedx[i];
312 for (
int i = 0; i < numDedx - 2; i++) {
313 truncatedMeanTmp += sortedDedx[i];
314 sumOfSquares += sortedDedx[i] * sortedDedx[i];
316 if (numDedx - 2 != 0) {
317 truncatedMeanTmp /= numDedx - 2;
321 *truncatedMean = truncatedMeanTmp;
323 if (numDedx - 2 > 1) {
324 *truncatedMeanErr = sqrt(sumOfSquares /
double(numDedx - 2) - truncatedMeanTmp * truncatedMeanTmp) / double(
327 *truncatedMeanErr = 0;
336 const TVector3 localPos(hit->getU(), hit->getV(), 0.0);
337 const TVector3& globalPos = sensor.pointToGlobal(localPos);
340 const TVector3& sensorNormal = sensor.vectorToGlobal(TVector3(0.0, 0.0, 1.0));
341 const double angle = sensorNormal.Angle(localMomentum);
344 return TMath::Min(sensor.getWidth(), sensor.getThickness() / fabs(cos(angle)));
354 if (hit->isUCluster()) {
355 const float u = hit->getPosition();
356 a = sensor.pointToGlobal(TVector3(sensor.getBackwardWidth() / sensor.getWidth(0) * u, -0.5 * sensor.getLength(), 0.0));
357 b = sensor.pointToGlobal(TVector3(sensor.getForwardWidth() / sensor.getWidth(0) * u, +0.5 * sensor.getLength(), 0.0));
359 const float v = hit->getPosition();
360 a = sensor.pointToGlobal(TVector3(-0.5 * sensor.getWidth(v), v, 0.0));
361 b = sensor.pointToGlobal(TVector3(+0.5 * sensor.getWidth(v), v, 0.0));
364 const TVector3& localMomentum = helix->
momentum(pathLength);
366 const TVector3& sensorNormal = sensor.vectorToGlobal(TVector3(0.0, 0.0, 1.0));
367 const double angle = sensorNormal.Angle(localMomentum);
369 return TMath::Min(sensor.getWidth(), sensor.getThickness() / fabs(cos(angle)));
374 const std::vector<HitClass*>& hits)
const
376 const int numHits = hits.size();
383 const int currentDetector = geo.
get(hits.front()->getSensorID()).
getType();
385 assert(currentDetector <= 1);
387 std::vector<double> siliconDedx;
388 siliconDedx.reserve(numHits);
391 for (
int i = 0; i < numHits; i++) {
392 const HitClass* hit = hits[i];
394 B2ERROR(
"Added hit is a null pointer!");
397 const VxdID& currentSensor = hit->getSensorID();
399 if (m_enableDebugOutput) {
401 assert(layer >= -6 && layer < 0);
406 const double totalDistance = getTraversedLength(hit, &helix);
407 const float charge = hit->getCharge();
408 const float dedx = charge / totalDistance;
410 B2WARNING(
"dE/dx is " << dedx <<
" in layer " << layer);
411 }
else if (i == 0 or prevSensor != currentSensor) {
412 prevSensor = currentSensor;
414 siliconDedx.push_back(dedx);
415 track->m_dedxAvg[currentDetector] += dedx;
416 track->addDedx(layer, totalDistance, dedx);
417 if (m_useIndividualHits) {
418 if (currentDetector == 0) savePXDLogLikelihood(track->m_vxdLogl, track->m_p, dedx);
419 else if (currentDetector == 1) saveSVDLogLikelihood(track->m_vxdLogl, track->m_p, dedx);
423 if (m_enableDebugOutput) {
424 track->addHit(currentSensor, layer, charge, totalDistance, dedx);
429 if (!m_useIndividualHits or m_enableDebugOutput) {
430 calculateMeans(&(track->m_dedxAvg[currentDetector]),
431 &(track->m_dedxAvgTruncated[currentDetector]),
432 &(track->m_dedxAvgTruncatedErr[currentDetector]),
440 const TH2F* pdf = m_DBDedxPDFs->getPXDPDF(0, !m_useIndividualHits);
441 const Int_t binX = pdf->GetXaxis()->FindFixBin(p);
442 const Int_t binY = pdf->GetYaxis()->FindFixBin(dedx);
445 pdf = m_DBDedxPDFs->getPXDPDF(iPart, !m_useIndividualHits);
446 if (pdf->GetEntries() == 0)
448 double probability = 0.0;
451 if (binX < 1 or binX > pdf->GetNbinsX()
452 or binY < 1 or binY > pdf->GetNbinsY()) {
453 probability = pdf->GetBinContent(binX, binY);
458 probability =
const_cast<TH2F*
>(pdf)->Interpolate(p, dedx);
461 if (probability != probability)
462 B2ERROR(
"probability NAN for a track with p=" << p <<
" and dedx=" << dedx);
465 if (probability == 0.0)
466 probability = m_useIndividualHits ? (1e-5) : (1e-3);
468 logl[iPart] += log(probability);
475 const TH2F* pdf = m_DBDedxPDFs->getSVDPDF(0, !m_useIndividualHits);
476 const Int_t binX = pdf->GetXaxis()->FindFixBin(p);
477 const Int_t binY = pdf->GetYaxis()->FindFixBin(dedx);
480 pdf = m_DBDedxPDFs->getSVDPDF(iPart, !m_useIndividualHits);
481 if (pdf->GetEntries() == 0)
483 double probability = 0.0;
486 if (binX < 1 or binX > pdf->GetNbinsX()
487 or binY < 1 or binY > pdf->GetNbinsY()) {
488 probability = pdf->GetBinContent(binX, binY);
493 probability =
const_cast<TH2F*
>(pdf)->Interpolate(p, dedx);
496 if (probability != probability)
497 B2ERROR(
"probability NAN for a track with p=" << p <<
" and dedx=" << dedx);
500 if (probability == 0.0)
501 probability = m_useIndividualHits ? (1e-5) : (1e-3);
503 logl[iPart] += log(probability);