88 if (not
m_hits.isValid()) {
91 B2WARNING(
"StoreArray 'CDCDedxHits' does not exist, returning. Probably running on old cdst.");
93 B2WARNING(
"StoreArray 'CDCDedxHits' does not exist, returning. ...message will be suppressed now.");
111 double runGain = isData ?
m_DBRunGain->getRunGain() : 1.0;
120 B2ERROR(
"Scale factor from DB is zero! Will be set to one");
125 for (
const auto& track :
m_tracks) {
127 const auto* fitResult = track.getTrackFitResultWithClosestMass(
Const::pion);
129 B2WARNING(
"No related fit for track, skip it.");
134 const auto hits = track.getRelationsTo<
CDCDedxHit>();
135 if (hits.size() == 0)
continue;
138 const auto& trackMom = fitResult->getMomentum();
139 double theta = trackMom.Theta();
140 double cosTheta = std::cos(theta);
141 double sinTheta = std::sin(theta);
144 double cosCor = isData ?
m_DBCosineCor->getMean(cosTheta) : 1.0;
145 bool isEdge = std::abs(cosTheta + 0.860) < 0.010 or std::abs(cosTheta - 0.955) <= 0.005;
146 double cosEdgeCor = (isData and isEdge) ?
m_DBCosEdgeCor->getMean(cosTheta) : 1.0;
149 const auto* mcParticle = isData ? nullptr : track.getRelated<
MCParticle>();
154 dedxTrack->m_track = track.getArrayIndex();
155 dedxTrack->m_charge = fitResult->getChargeSign();
156 dedxTrack->m_cosTheta = cosTheta;
157 dedxTrack->m_p = trackMom.R();
159 dedxTrack->m_injring =
m_TTDInfo->isHER();
160 dedxTrack->m_injtime =
m_TTDInfo->getTimeSinceLastInjectionInMicroSeconds();
163 dedxTrack->m_pdg = mcParticle->getPDG();
164 dedxTrack->m_mcmass = mcParticle->getMass();
165 const auto* mother = mcParticle->getMother();
166 dedxTrack->m_motherPDG = mother ? mother->getPDG() : 0;
167 const auto& trueMom = mcParticle->getMomentum();
168 dedxTrack->m_pTrue = trueMom.R();
169 dedxTrack->m_cosThetaTrue = std::cos(trueMom.Theta());
171 dedxTrack->m_scale = scale;
172 dedxTrack->m_cosCor = cosCor;
173 dedxTrack->m_cosEdgeCor = cosEdgeCor;
174 dedxTrack->m_runGain = runGain;
175 dedxTrack->m_timeGain = timeGain;
176 dedxTrack->m_timeReso = timeReso;
182 std::map<int, DEDX> dedxWires;
183 for (
const auto& hit : hits) {
185 const auto& wireID = hit.getWireID();
186 int layer = wireID.getILayer();
187 int superlayer = wireID.getISuperLayer();
188 int currentLayer = (superlayer == 0) ? layer : (8 + (superlayer - 1) * 6 + layer);
190 lastLayer = currentLayer;
193 if (pCDC == 0) pCDC = hit.getPOCAMomentum().R();
196 double innerRadius = cdcgeo.innerRadiusWireLayer()[currentLayer];
197 double outerRadius = cdcgeo.outerRadiusWireLayer()[currentLayer];
198 const ROOT::Math::XYZVector& wirePosF = cdcgeo.wireForwardPosition(wireID, CDCGeometryPar::c_Aligned);
199 double wireRadius = wirePosF.Rho();
200 int nWires = cdcgeo.nWiresInLayer(currentLayer);
201 double topHeight = outerRadius - wireRadius;
202 double bottomHeight = wireRadius - innerRadius;
203 double topHalfWidth = M_PI * outerRadius / nWires;
204 double bottomHalfWidth = M_PI * innerRadius / nWires;
207 DedxPoint(bottomHalfWidth, -bottomHeight),
208 DedxPoint(-bottomHalfWidth, -bottomHeight));
211 double doca = hit.getSignedDOCAXY();
212 double entAng = hit.getEntranceAngle();
213 double celldx = cell.
dx(doca, entAng) / sinTheta;
214 if (not cell.
isValid())
continue;
217 int wire = wireID.getIWire();
218 int iwire = (superlayer == 0) ? 160 * layer + wire :
m_nLayerWires[superlayer - 1] + (160 + 32 * (superlayer - 1)) * layer + wire;
219 double wiregain = isData ?
m_DBWireGains->getWireGain(iwire) : 1.0;
222 double cellHalfWidth = M_PI * wireRadius / nWires;
223 double cellHeight = topHeight + bottomHeight;
224 double cellR = 2 * cellHalfWidth / cellHeight;
225 double tana = std::max(std::min(std::tan(entAng), 1e10), -1e10);
226 double docaRS = doca * std::sqrt((1 + cellR * cellR * tana * tana) / (1 + tana * tana));
227 double normDocaRS = docaRS / cellHalfWidth;
228 double entAngRS = std::atan(tana / cellR);
231 double onedcor = isData ?
m_DB1DCell->getMean(currentLayer, entAngRS) : 1.0;
232 double twodcor = isData ?
m_DB2DCell->getMean(currentLayer, normDocaRS, entAngRS) : 1.0;
235 double correction = runGain * cosCor * cosEdgeCor * timeGain * wiregain * twodcor * onedcor;
238 double adcCount = isData ?
m_DBNonlADC->getCorrectedADC(hit.getADCCount(), currentLayer) : hit.getADCCount();
239 double adcCalibrated = correction != 0 ? adcCount / scale / correction : 0;
242 if (correction != 0) dedxWires[iwire].add(hit, iwire, currentLayer, celldx, adcCalibrated);
246 dedxTrack->m_pCDC = pCDC;
247 const auto& pocaMom = hit.getPOCAMomentum();
248 double pocaPhi = pocaMom.Phi();
249 double pocaTheta = pocaMom.Theta();
250 double pocaZ = hit.getPOCAOnWire().Z();
251 double hitCharge = adcTranslator.
getCharge(adcCount, wireID,
false, pocaZ, pocaPhi);
252 double driftDRealistic = tdcTranslator.
getDriftLength(hit.getTDCCount(), wireID, 0,
true, pocaZ, pocaPhi, pocaTheta);
253 double driftDRealisticRes = tdcTranslator.
getDriftLengthResolution(driftDRealistic, wireID,
true, pocaZ, pocaPhi, pocaTheta);
254 double cellDedx = adcCalibrated / celldx;
256 dedxTrack->addHit(wire, iwire, currentLayer, doca, docaRS, entAng, entAngRS,
257 adcCount, hit.getADCCount(), hitCharge, celldx * sinTheta, cellDedx, cellHeight, cellHalfWidth,
258 hit.getTDCCount(), driftDRealistic, driftDRealisticRes, wiregain, twodcor, onedcor,
259 hit.getFoundByTrackFinder(), hit.getWeightPionHypo(), hit.getWeightKaonHypo(), hit.getWeightProtonHypo());
265 std::map<int, DEDX> dedxLayers;
266 for (
const auto& dedxWire : dedxWires) {
267 const auto& dedx = dedxWire.second;
268 dedxLayers[dedx.cLayer].add(dedx);
272 std::vector<double> dedxValues;
273 for (
const auto& dedxLayer : dedxLayers) {
274 const auto& dedx = dedxLayer.second;
275 if (dedx.dx > 0 and dedx.dE > 0) {
276 dedxValues.push_back(dedx.dE / dedx.dx);
278 if (dedxTrack) dedxTrack->addDedx(dedx.nhits, dedx.cWire, dedx.cLayer, dedx.dx, dedxValues.back());
281 if (dedxValues.empty())
continue;
284 std::sort(dedxValues.begin(), dedxValues.end());
288 for (
auto x : dedxValues) mean += x;
289 mean /= dedxValues.size();
292 int lowEdgeTrunc = int(dedxValues.size() *
m_removeLowest + 0.51);
293 int highEdgeTrunc = int(dedxValues.size() * (1 -
m_removeHighest) + 0.51);
294 double truncatedMean = 0;
295 double sumOfSquares = 0;
297 for (
int i = lowEdgeTrunc; i < highEdgeTrunc; i++) {
298 double x = dedxValues[i];
300 sumOfSquares += x * x;
304 truncatedMean /= numValues;
306 truncatedMean = mean;
307 numValues = dedxValues.size();
309 double truncatedError = numValues > 1 ? std::sqrt(sumOfSquares / numValues - truncatedMean * truncatedMean) / (numValues - 1) : 0;
312 double correctedMean = isData ?
m_DBHadronCor->getCorrectedMean(truncatedMean, cosTheta) : truncatedMean;
316 double mass = mcParticle->getMass();
319 double mcSigma =
m_DBSigmaPars->getSigma(mcMean, numValues, cosTheta, timeReso);
320 correctedMean = gRandom->Gaus(mcMean, mcSigma);
321 while (correctedMean < 0) correctedMean = gRandom->Gaus(mcMean, mcSigma);
323 if (dedxTrack) dedxTrack->m_simDedx = correctedMean;
330 double betagamma = pCDC / chargedStable.getMass();
331 double predictedMean =
m_DBMeanPars->getMean(betagamma);
332 double predictedSigma =
m_DBSigmaPars->getSigma(predictedMean, numValues, cosTheta, timeReso);
333 if (predictedSigma <= 0) B2ERROR(
"Predicted sigma is not positive for PDG = " << chargedStable.getPDGCode());
334 double chi = (correctedMean - predictedMean) / predictedSigma;
335 int index = chargedStable.getIndex();
336 cdcLogL[index] = -0.5 * chi * chi;
339 dedxTrack->m_predmean[index] = predictedMean;
340 dedxTrack->m_predres[index] = predictedSigma;
341 dedxTrack->m_cdcChi[index] = chi;
342 dedxTrack->m_cdcLogl[index] = cdcLogL[index];
348 track.addRelationTo(likelihoods);
352 double fullLength = 0;
353 for (
const auto& dedxLayer : dedxLayers) fullLength += dedxLayer.second.dx;
354 dedxTrack->m_length = fullLength;
355 dedxTrack->m_dedxAvg = mean;
356 dedxTrack->m_dedxAvgTruncatedNoSat = truncatedMean;
357 dedxTrack->m_dedxAvgTruncatedErr = truncatedError;
358 dedxTrack->m_dedxAvgTruncated = correctedMean;
359 dedxTrack->m_lNHitsUsed = numValues;
360 track.addRelationTo(dedxTrack);