16#include "FairLogger.h"
19#include "TFitResult.h"
20#include "TFitResultPtr.h"
21#include "TGraphErrors.h"
46 using DPair = std::array<Double_t, 2>;
53 constexpr bool WithinBounds(
const double val,
const double lower_bound,
const double upper_bound)
55 return (val >= lower_bound && val <= upper_bound);
71 , fFit(
"CosmicTracker:fFit",
"pol1")
76 fDistances.push_back(fDistances.back() + BarSize_Z);
78 fTrack.Interactions.reserve(256);
84 fBarIDs.push_back(barID);
89 const auto zPosition = fDistances[plane] + 0.5 *
BarSize_Z;
93 const auto barPoint = fYZ.GetN();
109 const auto barPoint = fXZ.GetN();
126 LOG(debug) <<
"CosmicTracker::Fit : Number of Points: X-Z: " << fXZ.GetN() <<
" Y-Z: " << fYZ.GetN();
130 LOG(debug) <<
"CosmicTracker::Fit : Not enough Points to make reasonable fit.";
137 LOG(debug) <<
"CosmicTracker::Fit : Not enough Points to make reasonable fit after "
138 "horizontal filtering.";
145 LOG(debug) <<
"CosmicTracker::Fit : Not enough Points to make reasonable fit after vertical "
153 TVector3& direction = fTrack.Direction;
154 TVector3& entryPoint = fTrack.EntryPoint;
155 TVector3& invDirection = fTrack.InvDirection;
157 const auto yFit = fit(fYZ);
160 LOG(debug) <<
"CosmicTracker::Fit : Could not get a reasonable vertical fit.";
164 if (fabs(yFit[0]) < 0.1)
166 LOG(debug) <<
"CosmicTracker::Fit : Y-Slope too small. Better reject this Track.";
170 const auto xFit = fit(fXZ);
173 LOG(debug) <<
"CosmicTracker::Fit : Could not get a reasonable horizontal fit.";
177 direction[0] = xFit[0];
178 entryPoint[0] = xFit[1];
180 direction[1] = yFit[0];
181 entryPoint[1] = yFit[1];
186 if (direction[1] > 0)
190 entryPoint[2] = fDistances.back() +
BarSize_Z;
191 entryPoint[0] += direction[0] * entryPoint[2];
192 entryPoint[1] += direction[1] * entryPoint[2];
194 for (
int i = 0; i < 3; ++i)
195 direction[i] *= -1.0;
199 const auto scale =
CLight / direction.Mag();
200 for (
int i = 0; i < 3; ++i)
202 direction[i] *= scale;
203 invDirection[i] = 1.0 / direction[i];
207 const auto flightTimeEntry = getCrossPointTime(entryPoint - direction * 2 *
TimeEps,
212 { fDistances[0], fDistances.back() +
BarSize_Z });
214 if (isnan(flightTimeEntry))
217 entryPoint += direction * (flightTimeEntry -
TimeEps);
219 LOG(debug) <<
"X: " << entryPoint[0] <<
" + t * " << direction[0];
220 LOG(debug) <<
"Y: " << entryPoint[1] <<
" + t * " << direction[1];
221 LOG(debug) <<
"Z: " << entryPoint[2] <<
" + t * " << direction[2];
223 fillInteractions(fTrack);
224 if (fTrack.Interactions.size() < 3)
226 fTrack.Interactions.clear();
227 fTrack.TotalTrackLength = 0.;
230 LOG(debug) <<
"Interactions: " << fTrack.Interactions.size();
235 void CosmicTracker::filter(TGraphErrors& graph)
const
237 std::array<Int_t, 256> remove;
240 auto nPoints = graph.GetN();
241 auto x = graph.GetX();
242 auto y = graph.GetY();
246 for (
auto p = 0; p < nPoints; ++p)
248 Bool_t foundClose =
false;
249 for (
auto op = 0; op < nPoints; ++op)
253 const auto dist2 =
Sqr(x[p] - x[op]) +
Sqr(y[p] - y[op]);
264 if (++nRemove == remove.size())
272 LOG(debug) <<
" Removed : " << nRemove;
277 const auto totalPoints = nPoints - nRemove;
278 for (
auto p = remove[0]; p < totalPoints; ++p)
280 if (offset < nRemove && p + offset == remove[offset])
287 x[p] = x[p + offset];
288 y[p] = y[p + offset];
291 graph.Set(totalPoints);
296 nPoints = graph.GetN();
297 const auto linReg = linearRegression(x, y, nPoints);
298 const auto factor = 1. / (
Sqr(linReg[1]) + 1.);
302 for (
auto p = nPoints - 1; p >= 0; --p)
304 const auto dist2 =
Sqr(linReg[1] * x[p] - y[p] + linReg[0]) * factor;
318 graph.RemovePoint(p);
334 fTrack.Interactions.clear();
335 fTrack.TotalTrackLength = 0.;
336 fTrack.Stopped =
false;
341 std::array<Double_t, 2> CosmicTracker::fit(TGraphErrors& graph)
343 const auto linReg = linearRegression(graph.GetX(), graph.GetY(), graph.GetN());
344 if (!isfinite(linReg[0]))
347 fFit.SetParameter(0, linReg[0]);
348 fFit.SetParameter(1, linReg[1]);
350 TFitResultPtr resultptr = graph.Fit(&fFit,
"NQS");
352 const auto slope = fFit.GetParameter(1);
353 const auto yIntercept = fFit.GetParameter(0);
355 auto redchi2 = resultptr->Chi2() / resultptr->Ndf();
361 return { slope, yIntercept };
364 Double_t CosmicTracker::getCrossPointTime(
const TVector3& point,
365 const TVector3& direction,
366 const TVector3& invDirection,
367 const DPair& xBounds,
368 const DPair& yBounds,
369 const DPair& zBounds)
const
371 const auto invert = (
WithinBounds(point, xBounds, yBounds, zBounds) ? -1. : 1.);
375 if (invert * invDirection[0] > 0)
377 crossPoint[0] = xBounds[0];
381 crossPoint[0] = xBounds[1];
384 if (invert * invDirection[1] > 0)
386 crossPoint[1] = yBounds[0];
390 crossPoint[1] = yBounds[1];
393 if (invert * invDirection[2] > 0)
395 crossPoint[2] = zBounds[0];
399 crossPoint[2] = zBounds[1];
402 auto wasHit = kFALSE;
404 for (
int i = 0; i < 3; ++i)
406 const auto flightTime = (crossPoint[i] - point[i]) * invDirection[i];
407 if (flightTime > 0. &&
408 WithinBounds(point + direction * (flightTime + invert *
TimeEps), xBounds, yBounds, zBounds))
416 DPair CosmicTracker::linearRegression(
const Double_t* x,
const Double_t* y,
const Int_t points)
const
418 const auto invPoints = 1. / points;
419 const auto invRedPoints = 1. / (points - 1);
420 const auto xMean = invPoints * std::accumulate(x, x + points, 0.);
421 const auto yMean = std::accumulate(y, y + points, 0.) / points;
422 const auto xVar = invRedPoints * std::accumulate(x,
425 [xMean](
const Double_t acc,
const Double_t val)
426 {
return acc +
Sqr(val - xMean); });
431 return {
Inf, xMean };
433 const auto yVar = invRedPoints * std::accumulate(y,
436 [yMean](
const Double_t acc,
const Double_t val)
437 {
return acc +
Sqr(val - yMean); });
440 for (
auto p = 0; p < points; ++p)
441 xyVar += (x[p] - xMean) * (y[p] - yMean);
442 xyVar *= invRedPoints;
444 const auto slope = (yVar - xVar + std::sqrt(
Sqr(yVar - xVar) + 4 *
Sqr(xyVar))) / (2 * xyVar);
445 const auto yIntercept = yMean - slope * xMean;
450 return { yIntercept, slope };
453 void CosmicTracker::fillInteractions(R3BNeulandCosmicTrack& track)
const
455 auto nMissedHits = 0;
456 auto lastValidSize = 0;
457 auto missedEnergy = 0.;
459 std::array<Int_t, 3> barDirections;
460 for (
auto i = 0; i < 3; ++i)
462 barDirections[i] = (track.
Direction[i] > 0. ? 1 : -1);
466 Int_t currentPlane = 0, currentBar;
469 while (currentPlane < fDistances.size() - 1 &&
486 const auto crossTime =
490 { -0.5 * BarLength, 0.5 * BarLength },
491 { -0.5 * BarLength, 0.5 * BarLength },
492 { fDistances[currentPlane], fDistances[currentPlane] + BarSize_Z });
494 if (isnan(crossTime))
502 auto planeChanged = kTRUE;
503 DPair xBorder, yBorder;
507 LOG(debug) <<
"Entry Plane: " << currentPlane <<
" at " << currentPoint.X() <<
" " << currentPoint.Y()
508 <<
" " << currentPoint.Z();
533 currentBar += barDirections[1];
539 currentBar += barDirections[0];
544 const auto crossTime =
545 getCrossPointTime(currentPoint,
550 { fDistances[currentPlane], fDistances[currentPlane] + BarSize_Z });
552 if (isnan(crossTime))
555 const auto barID = currentBar + currentPlane *
BarsPerPlane;
556 const auto trackLength = crossTime *
CLight;
563 currentPoint.X() + crossTime * track.
Direction.X(),
573 currentPoint.Y() + crossTime * track.
Direction.Y(),
578 if (std::find(fBarIDs.begin(), fBarIDs.end(), barID) != fBarIDs.end())
588 if (missedEnergy > 10. || (missedEnergy > 7. && nMissedHits > 1))
590 if (lastValidSize == 0)
608 { fDistances[0], fDistances.back() +
BarSize_Z }))
610 LOG(debug) <<
"Left NeuLAND at Plane " << currentPlane <<
" with " << currentPoint.X() <<
" "
611 << currentPoint.Y() <<
" " << currentPoint.Z();
620 currentPlane += barDirections[2];
627 getCrossPointTime(currentPoint,
630 { -0.5 * BarLength, 0.5 * BarLength },
631 { -0.5 * BarLength, 0.5 * BarLength },
632 { fDistances[currentPlane], fDistances[currentPlane] + BarSize_Z });
std::array< Double_t, 2 > DPair
void AddPoint(const Int_t barID, const Double_t pos=NaN)
const R3BNeulandCosmicTrack & GetTrack()
std::array< Double_t, 2 > DPair
constexpr bool WithinBounds(const double val, const double lower_bound, const double upper_bound)
constexpr auto MaxDistance
Simulation of NeuLAND Bar/Paddle.
constexpr auto BarsPerPlane
constexpr auto ModuleID2PlaneID(int moduleID) -> int
constexpr auto BarUncertainty_Z
constexpr auto MIPStoppingPower
constexpr auto BarSize_XY
constexpr auto BarUncertainty_XY
constexpr auto IsPlaneIDHorizontal(int plane_id) -> bool
constexpr auto MaxNumberOfPlanes
constexpr T Sqr(const T val)
Double_t TotalTrackLength
std::vector< Interaction > Interactions