LArSoft  v10_06_00
Liquid Argon Software toolkit - https://larsoft.org/
trkf::TrackMomentumCalculator Class Reference

#include "TrackMomentumCalculator.h"

Classes

struct  Segments
 Struct to store segments. x, y and z are the 3D points of the segment nx, ny, nz forms the vector that point to the direction of most scattering L is the length of the segment, using steps_size. More...
 

Public Member Functions

 TrackMomentumCalculator (double minLength=100.0, double maxLength=1350.0, double steps_size=10., int angleMethod=1, int nsteps=6)
 Constructor. More...
 
double GetTrackMomentum (double trkrange, int pdg) const
 
double GetMomentumMultiScatterChi2 (art::Ptr< recob::Track > const &trk, const bool checkValidPoints=false, const int maxMomentum_MeV=7500, const double min_resolution=0, const double max_resolution=45)
 Calculate muon momentum (GeV) using multiple coulomb scattering. Chi2 minimization of the Highland formula. More...
 
double GetMomentumMultiScatterLLHD (art::Ptr< recob::Track > const &trk, const bool checkValidPoints=false, const int maxMomentum_MeV=7500, const double min_resolution=0.001, const double max_resolution=800, const bool check_valid_scattered=false, const double angle_correction=0.757)
 Calculate muon momentum (GeV) using multiple coulomb scattering by log likelihood. More...
 
double GetMuMultiScatterLLHD3 (art::Ptr< recob::Track > const &trk, bool dir)
 
TVector3 GetMultiScatterStartingPoint (art::Ptr< recob::Track > const &trk)
 

Private Types

enum  ScatterAngleMethods { kAnglezx = 1, kAnglezy, kAngleCombined }
 

Private Member Functions

bool plotRecoTracks_ (std::vector< double > const &xxx, std::vector< double > const &yyy, std::vector< double > const &zzz)
 
void compute_max_fluctuation_vector (const std::vector< double > segx, const std::vector< double > segy, const std::vector< double > segz, std::vector< double > &segnx, std::vector< double > &segny, std::vector< double > &segnz, std::vector< bool > &segn_isvalid, std::vector< double > &vx, std::vector< double > &vy, std::vector< double > &vz, bool check_valid_scattered)
 Computes the vector with most scattering inside a segment with size steps_size. More...
 
std::optional< SegmentsgetSegTracks_ (std::vector< double > const &xxx, std::vector< double > const &yyy, std::vector< double > const &zzz, double seg_size, bool check_valid_scattered=false)
 Split tracks into segments to calculate the scattered angle later. Check DOI 10.1088/1748-0221/12/10/P10010. More...
 
std::tuple< double, double, double > getDeltaThetaRMS_ (Segments const &segments, double thick) const
 Gets the scattered angle RMS for a all segments. More...
 
int getDeltaThetaij_ (std::vector< double > &ei, std::vector< double > &ej, std::vector< double > &th, std::vector< double > &ind, Segments const &segments, double thick, double const angle_correction) const
 Gets the scatterd angle for all the segments. More...
 
double my_g (double xx, double Q, double s) const
 chi square minizer using Minuit2, it will minize (xx-Q)/s More...
 
double my_mcs_llhd (std::vector< double > const &dEi, std::vector< double > const &dEj, std::vector< double > const &dthij, std::vector< double > const &ind, double x0, double x1) const
 Minimizer of log likelihood for scattered angle. More...
 
double find_angle (double vz, double vy) const
 Gets angle between two vy and vz. More...
 

Private Attributes

double seg_stop {-1.}
 
int n_seg {}
 
double x_seg [50000]
 
double y_seg [50000]
 
double z_seg [50000]
 
std::vector< double > steps
 
double minLength
 
double maxLength
 
double steps_size
 
double rad_length {14.0}
 
ScatterAngleMethods fMCSAngleMethod
 
int n_steps
 
TPolyLine3D * gr_reco_xyz {nullptr}
 
TGraph gr_reco_xy {}
 
TGraph gr_reco_yz {}
 
TGraph gr_reco_xz {}
 
TPolyLine3D * gr_seg_xyz {nullptr}
 
TGraph gr_seg_xy {}
 
TGraph gr_seg_yz {}
 
TGraph gr_seg_xz {}
 

Detailed Description

Definition at line 21 of file TrackMomentumCalculator.h.

Member Enumeration Documentation

Enumerator
kAnglezx 

Use scattered angle z-x (z is along the particle's direction)

kAnglezy 

Use scattered angle z-y.

kAngleCombined 

Use space angle: sqrt( zx^2 + zy^2 )/sqrt(2)

Definition at line 231 of file TrackMomentumCalculator.h.

231  {
232  kAnglezx = 1,
233  kAnglezy,
235  };
Use scattered angle z-x (z is along the particle&#39;s direction)
Use space angle: sqrt( zx^2 + zy^2 )/sqrt(2)

Constructor & Destructor Documentation

trkf::TrackMomentumCalculator::TrackMomentumCalculator ( double  minLength = 100.0,
double  maxLength = 1350.0,
double  steps_size = 10.,
int  angleMethod = 1,
int  nsteps = 6 
)

Constructor.

Parameters are relevant for Multiple Coulomb Scattering

Parameters
minLengthminimum length in cm of tracks (length here is based on the amout of segments)
maxLengthmaximum length in cm of tracks (length here is based on the amout of segments)
steps_sizesize in cm of each segment to compute scattering

Definition at line 302 of file TrackMomentumCalculator.cxx.

References fMCSAngleMethod, maxLength, n_steps, steps, and steps_size.

307  : minLength{min}
308  , maxLength{max}
309  , steps_size{stepsize}
310  , fMCSAngleMethod{static_cast<ScatterAngleMethods>(angleMethod)}
311  , n_steps{nsteps}
312  {
313  for (int i = 1; i <= n_steps; i++) {
314  steps.push_back(steps_size * i);
315  }
316  }

Member Function Documentation

void trkf::TrackMomentumCalculator::compute_max_fluctuation_vector ( const std::vector< double >  segx,
const std::vector< double >  segy,
const std::vector< double >  segz,
std::vector< double > &  segnx,
std::vector< double > &  segny,
std::vector< double > &  segnz,
std::vector< bool > &  segn_isvalid,
std::vector< double > &  vx,
std::vector< double > &  vy,
std::vector< double > &  vz,
bool  check_valid_scattered 
)
private

Computes the vector with most scattering inside a segment with size steps_size.

Parameters
segx,segy,segzsegments points
segnx,segny,segnzvector components to be filled
vectorused to control points to be used at segments

Definition at line 866 of file TrackMomentumCalculator.cxx.

References util::abs(), and n_seg.

Referenced by getSegTracks_().

877  {
878  auto const na = vx.size();
879 
880  double sumx = 0.0;
881  double sumy = 0.0;
882  double sumz = 0.0;
883 
884  bool isvalid = true;
885  // In case vx, vy, etc have 3 points, probably two are just "linear"
886  // interpolations. In this case, the angle of scattering will be zero.
887  if (check_valid_scattered && na <= 2) { isvalid = false; }
888 
889  // computes the average in x, y, z
890  for (std::size_t i = 0; i < na; ++i) {
891  sumx += vx.at(i);
892  sumy += vy.at(i);
893  sumz += vz.at(i);
894  }
895 
896  sumx /= na;
897  sumy /= na;
898  sumz /= na;
899 
900  std::vector<double> mx;
901  std::vector<double> my;
902  std::vector<double> mz;
903 
904  TMatrixDSym m(3);
905 
906  // Computes the Covariance matrix (Principal Component Analysis (PCA)
907  for (std::size_t i = 0; i < na; ++i) {
908  double const xxw1 = vx.at(i);
909  double const yyw1 = vy.at(i);
910  double const zzw1 = vz.at(i);
911 
912  mx.push_back(xxw1 - sumx);
913  my.push_back(yyw1 - sumy);
914  mz.push_back(zzw1 - sumz);
915 
916  double const xxw0 = mx.at(i);
917  double const yyw0 = my.at(i);
918  double const zzw0 = mz.at(i);
919 
920  m(0, 0) += xxw0 * xxw0 / na;
921  m(0, 1) += xxw0 * yyw0 / na;
922  m(0, 2) += xxw0 * zzw0 / na;
923 
924  m(1, 0) += yyw0 * xxw0 / na;
925  m(1, 1) += yyw0 * yyw0 / na;
926  m(1, 2) += yyw0 * zzw0 / na;
927 
928  m(2, 0) += zzw0 * xxw0 / na;
929  m(2, 1) += zzw0 * yyw0 / na;
930  m(2, 2) += zzw0 * zzw0 / na;
931  }
932 
933  TMatrixDSymEigen me(m);
934 
935  // retrieve eigenvalues and vectors
936  TVectorD eigenval = me.GetEigenValues();
937  TMatrixD eigenvec = me.GetEigenVectors();
938 
939  double max1 = -666.0;
940 
941  double ind1 = 0;
942 
943  // get maximum eingevalue
944  for (int i = 0; i < 3; ++i) {
945  double const p1 = eigenval(i);
946 
947  if (p1 > max1) {
948  max1 = p1;
949  ind1 = i;
950  }
951  }
952 
953  // set the `direction` vector that points to the maximum fluctuation
954  double ax = eigenvec(0, ind1);
955  double ay = eigenvec(1, ind1);
956  double az = eigenvec(2, ind1);
957 
958  if (n_seg > 1) {
959  // for x, y and z, check if the last point is bigger then the previous point.
960  // Ensures that the computed fluctation follows the trend of the track
961  if (segx.at(n_seg - 1) - segx.at(n_seg - 2) > 0)
962  ax = std::abs(ax);
963  else
964  ax = -1.0 * std::abs(ax);
965 
966  if (segy.at(n_seg - 1) - segy.at(n_seg - 2) > 0)
967  ay = std::abs(ay);
968  else
969  ay = -1.0 * std::abs(ay);
970 
971  if (segz.at(n_seg - 1) - segz.at(n_seg - 2) > 0)
972  az = std::abs(az);
973  else
974  az = -1.0 * std::abs(az);
975 
976  segnx.push_back(ax);
977  segny.push_back(ay);
978  segnz.push_back(az);
979  segn_isvalid.push_back(isvalid);
980  }
981 
982  // clear the vectors
983  vx.clear();
984  vy.clear();
985  vz.clear();
986  }
constexpr auto abs(T v)
Returns the absolute value of the argument.
double trkf::TrackMomentumCalculator::find_angle ( double  vz,
double  vy 
) const
private

Gets angle between two vy and vz.

Parameters
vz
vy
Returns
angle in mrad

Definition at line 1378 of file TrackMomentumCalculator.cxx.

References util::abs().

Referenced by getDeltaThetaij_(), and getDeltaThetaRMS_().

1379  {
1380  double thetayz = -999.0;
1381 
1382  if (vz > 0 && vy > 0) {
1383  double ratio = std::abs(vy / vz);
1384  thetayz = std::atan(ratio);
1385  }
1386 
1387  else if (vz < 0 && vy > 0) {
1388  double ratio = std::abs(vy / vz);
1389  thetayz = std::atan(ratio);
1390  thetayz = TMath::Pi() - thetayz;
1391  }
1392 
1393  else if (vz < 0 && vy < 0) {
1394  double ratio = std::abs(vy / vz);
1395  thetayz = std::atan(ratio);
1396  thetayz = thetayz + TMath::Pi();
1397  }
1398 
1399  else if (vz > 0 && vy < 0) {
1400  double ratio = std::abs(vy / vz);
1401  thetayz = std::atan(ratio);
1402  thetayz = 2.0 * TMath::Pi() - thetayz;
1403  }
1404 
1405  else if (vz == 0 && vy > 0) {
1406  thetayz = TMath::Pi() / 2.0;
1407  }
1408 
1409  else if (vz == 0 && vy < 0) {
1410  thetayz = 3.0 * TMath::Pi() / 2.0;
1411  }
1412  else if (vz > 0 && vy == 0) {
1413  thetayz = 0;
1414  }
1415  else if (vz < 0 && vy == 0) {
1416  thetayz = TMath::Pi();
1417  }
1418 
1419  if (thetayz > TMath::Pi()) { thetayz = thetayz - 2.0 * TMath::Pi(); }
1420 
1421  return 1000.0 * thetayz;
1422  }
constexpr auto abs(T v)
Returns the absolute value of the argument.
int trkf::TrackMomentumCalculator::getDeltaThetaij_ ( std::vector< double > &  ei,
std::vector< double > &  ej,
std::vector< double > &  th,
std::vector< double > &  ind,
Segments const &  segments,
double  thick,
double const  angle_correction 
) const
private

Gets the scatterd angle for all the segments.

Parameters
ei,ejwill be filled with energy lost at point i and j
thdelta theta to be filled
indselection of scattering plane
segments
thickis the steps_size
angle_correctionCorrection due to oversmoothing, applied for space angle only
Returns
sucess or failure

Definition at line 611 of file TrackMomentumCalculator.cxx.

References a1, a2, a3, util::abs(), find_angle(), fMCSAngleMethod, kAngleCombined, kAnglezx, kAnglezy, trkf::TrackMomentumCalculator::Segments::L, trkf::TrackMomentumCalculator::Segments::nx, trkf::TrackMomentumCalculator::Segments::ny, and trkf::TrackMomentumCalculator::Segments::nz.

Referenced by GetMomentumMultiScatterLLHD(), and GetMuMultiScatterLLHD3().

618  {
619  auto const& segnx = segments.nx;
620  auto const& segny = segments.ny;
621  auto const& segnz = segments.nz;
622  auto const& segL = segments.L;
623 
624  int const a1 = segnx.size();
625  int const a2 = segny.size();
626  int const a3 = segnz.size();
627 
628  if (a1 != a2 || a1 != a3) {
629  std::cout << " ( Get thij ) Error ! " << std::endl;
630  return -1.0;
631  }
632 
633  int tot = a1;
634 
635  for (int i = 0; i < tot - 1; i++) {
636  double const dx = segnx.at(i);
637  double const dy = segny.at(i);
638  double const dz = segnz.at(i);
639 
640  // Assumes z as propagation angle
641  TVector3 const vec_z{dx, dy, dz};
642  TVector3 vec_x;
643  TVector3 vec_y;
644 
645  double const switcher = basex.Dot(vec_z);
646  if (std::abs(switcher) <= 0.995) {
647  vec_y = vec_z.Cross(basex).Unit();
648  vec_x = vec_y.Cross(vec_z);
649  }
650  else {
651  // cout << " It switched ! Isn't this lovely !!! " << endl; //
652  vec_y = basez.Cross(vec_z).Unit();
653  vec_x = vec_y.Cross(vec_z);
654  }
655 
656  TVector3 const Rx{vec_x.Dot(basex), vec_x.Dot(basey), vec_x.Dot(basez)};
657  TVector3 const Ry{vec_y.Dot(basex), vec_y.Dot(basey), vec_y.Dot(basez)};
658  TVector3 const Rz{vec_z.Dot(basex), vec_z.Dot(basey), vec_z.Dot(basez)};
659 
660  double const here_dx = segnx.at(i + 1);
661  double const here_dy = segny.at(i + 1);
662  double const here_dz = segnz.at(i + 1);
663 
664  TVector3 const here_vec{here_dx, here_dy, here_dz};
665  TVector3 const rot_here{Rx.Dot(here_vec), Ry.Dot(here_vec), Rz.Dot(here_vec)};
666 
667  double const scx = rot_here.X();
668  double const scy = rot_here.Y();
669  double const scz = rot_here.Z();
670 
671  double const azy = find_angle(scz, scy);
672  double const azx = find_angle(scz, scx);
673 
674  constexpr double ULim = 10000.0; // Avoid huge (wrong) angles
675  constexpr double LLim = -10000.0;
676 
677  double const Li = segL.at(i);
678  double const Lj = segL.at(i + 1);
679 
680  if (azy <= ULim && azy >= LLim) { // safe scatter in the yz plane
681 
682  if (azx <= ULim && azx >= LLim) { // safe scatter in the za plane
683  ei.push_back(Li); // Energy deposited at i
684  ej.push_back(Lj); // Energy deposited at i+1
685  if (fMCSAngleMethod == kAnglezx) {
686  th.push_back(azx); // scattered angle z-x
687  }
688  else if (fMCSAngleMethod == kAnglezy) {
689  th.push_back(azy);
690  }
691  else if (fMCSAngleMethod == kAngleCombined) {
692  th.push_back(std::hypot(azx, azy) /
693  angle_correction); // space angle (applying correction)
694  }
695  }
696  }
697  }
698 
699  return 0;
700  }
constexpr auto abs(T v)
Returns the absolute value of the argument.
#define a2
#define a3
Use scattered angle z-x (z is along the particle&#39;s direction)
double find_angle(double vz, double vy) const
Gets angle between two vy and vz.
Use space angle: sqrt( zx^2 + zy^2 )/sqrt(2)
#define a1
std::tuple< double, double, double > trkf::TrackMomentumCalculator::getDeltaThetaRMS_ ( Segments const &  segments,
double  thick 
) const
private

Gets the scattered angle RMS for a all segments.

Parameters
segmentssegments computed
thickis the steps_size

TODO: Add better description of steps

Returns
tuple with mean value, rms and error of rms

Definition at line 1245 of file TrackMomentumCalculator.cxx.

References a1, a2, a3, find_angle(), fMCSAngleMethod, kAngleCombined, kAnglezx, kAnglezy, trkf::TrackMomentumCalculator::Segments::L, pmtana::mean(), trkf::TrackMomentumCalculator::Segments::nx, trkf::TrackMomentumCalculator::Segments::ny, and trkf::TrackMomentumCalculator::Segments::nz.

Referenced by GetMomentumMultiScatterChi2().

1248  {
1249  auto const& segnx = segments.nx;
1250  auto const& segny = segments.ny;
1251  auto const& segnz = segments.nz;
1252  auto const& segL = segments.L;
1253 
1254  int const a1 = segnx.size();
1255  int const a2 = segny.size();
1256  int const a3 = segnz.size();
1257 
1258  if (a1 != a2 || a1 != a3) {
1259  cout << " ( Get RMS ) Error ! " << endl;
1260  return std::make_tuple(0., 0., 0.);
1261  }
1262 
1263  int const tot = a1;
1264 
1265  std::vector<double> buf0;
1266 
1267  for (int i = 0; i < tot; i++) {
1268  double const dx = segnx.at(i);
1269  double const dy = segny.at(i);
1270  double const dz = segnz.at(i);
1271 
1272  TVector3 const vec_z{dx, dy, dz};
1273  TVector3 vec_x;
1274  TVector3 vec_y;
1275 
1276  double const switcher = basex.Dot(vec_z);
1277 
1278  if (switcher <= 0.995) {
1279  vec_y = vec_z.Cross(basex).Unit();
1280  vec_x = vec_y.Cross(vec_z);
1281  }
1282  else {
1283  // cout << " It switched ! Isn't this lovely !!! " << endl;
1284  vec_y = basez.Cross(vec_z).Unit();
1285  vec_x = vec_y.Cross(vec_z);
1286  }
1287 
1288  TVector3 const Rx{vec_x.Dot(basex), vec_x.Dot(basey), vec_x.Dot(basez)};
1289  TVector3 const Ry{vec_y.Dot(basex), vec_y.Dot(basey), vec_y.Dot(basez)};
1290  TVector3 const Rz{vec_z.Dot(basex), vec_z.Dot(basey), vec_z.Dot(basez)};
1291 
1292  double const refL = segL.at(i);
1293 
1294  for (int j = i; j < tot; j++) {
1295  double const L1 = segL.at(j);
1296 
1297  double const dz1 = L1 - refL;
1298 
1299  if (dz1 >= thick) {
1300  double const here_dx = segnx.at(j);
1301  double const here_dy = segny.at(j);
1302  double const here_dz = segnz.at(j);
1303 
1304  TVector3 const here_vec{here_dx, here_dy, here_dz};
1305  TVector3 const rot_here{Rx.Dot(here_vec), Ry.Dot(here_vec), Rz.Dot(here_vec)};
1306 
1307  double const scx = rot_here.X();
1308  double const scy = rot_here.Y();
1309  double const scz = rot_here.Z();
1310 
1311  double const azy = find_angle(scz, scy);
1312  double const azx = find_angle(scz, scx);
1313 
1314  constexpr double ULim = 10000.0; // Avoid huge (wrong) angles
1315  constexpr double LLim = -10000.0;
1316 
1317  if (azy <= ULim && azy >= LLim) { // safe scatter in the yz plane
1318 
1319  if (azx <= ULim && azx >= LLim) { // safe scatter in the za plane
1320  if (fMCSAngleMethod == kAnglezx) {
1321  buf0.push_back(azx); // scattered angle z-x
1322  }
1323  else if (fMCSAngleMethod == kAnglezy) {
1324  buf0.push_back(azy);
1325  }
1326  else if (fMCSAngleMethod == kAngleCombined) {
1327  buf0.push_back(std::hypot(azx, azy));
1328  }
1329  }
1330  }
1331  break; // of course !
1332  }
1333  }
1334  }
1335 
1336  int const nmeas = buf0.size();
1337  double nnn = 0.0;
1338 
1339  double mean = 0.0;
1340  double rms = 0.0;
1341  double rmse = 0.0;
1342 
1343  for (int i = 0; i < nmeas; i++) {
1344  mean += buf0.at(i);
1345  nnn++;
1346  }
1347 
1348  mean = mean / nnn;
1349 
1350  for (int i = 0; i < nmeas; i++)
1351  rms += ((buf0.at(i)) * (buf0.at(i)));
1352 
1353  rms = rms / (nnn);
1354  rms = std::sqrt(rms);
1355  rmse = rms / std::sqrt(2.0 * tot);
1356 
1357  double rms1 = rms;
1358 
1359  rms = 0.0;
1360 
1361  double ntot1 = 0.0;
1362  double const lev1 = 2.50;
1363 
1364  for (int i = 0; i < nmeas; i++) {
1365  double const amp = buf0.at(i);
1366  if (amp < (mean + lev1 * rms1) && amp > (mean - lev1 * rms1)) {
1367  ++ntot1;
1368  rms += amp * amp;
1369  }
1370  }
1371 
1372  rms = rms / (ntot1);
1373  rms = std::sqrt(rms);
1374  rmse = rms / std::sqrt(2.0 * ntot1);
1375  return std::make_tuple(mean, rms, rmse);
1376  }
#define a2
#define a3
Use scattered angle z-x (z is along the particle&#39;s direction)
double find_angle(double vz, double vy) const
Gets angle between two vy and vz.
Float_t thick
Definition: plot.C:23
Use space angle: sqrt( zx^2 + zy^2 )/sqrt(2)
double mean(const std::vector< short > &wf, size_t start, size_t nsample)
Definition: UtilFunc.cxx:13
#define a1
double trkf::TrackMomentumCalculator::GetMomentumMultiScatterChi2 ( art::Ptr< recob::Track > const &  trk,
const bool  checkValidPoints = false,
const int  maxMomentum_MeV = 7500,
const double  min_resolution = 0,
const double  max_resolution = 45 
)

Calculate muon momentum (GeV) using multiple coulomb scattering. Chi2 minimization of the Highland formula.

Parameters
trkthe muon track
checkValidPointsrather take into account only valid points or not
maxMomentum_MeVmaximum momentum in MeV for the minimization

TODO: Add better description of the steps done.

Returns
momentum in GeV

Definition at line 702 of file TrackMomentumCalculator.cxx.

References fMCSAngleMethod, getDeltaThetaRMS_(), getSegTracks_(), recob::Track::HasValidPoint(), kAngleCombined, recob::Track::Length(), recob::Track::LocationAtPoint(), maxLength, pmtana::mean(), n_steps, recob::Track::NumberTrajectoryPoints(), plotRecoTracks_(), steps, and steps_size.

Referenced by trkf::KalmanFilterFinalTrackFitter::setMomValue().

707  {
708  std::vector<double> recoX;
709  std::vector<double> recoY;
710  std::vector<double> recoZ;
711 
712  int n_points = trk->NumberTrajectoryPoints();
713 
714  for (int i = 0; i < n_points; i++) {
715  if (checkValidPoints && !trk->HasValidPoint(i)) continue;
716  auto const& pos = trk->LocationAtPoint(i);
717  recoX.push_back(pos.X());
718  recoY.push_back(pos.Y());
719  recoZ.push_back(pos.Z());
720  }
721 
722  if (recoX.size() < 2) return -1.0;
723 
724  if (!plotRecoTracks_(recoX, recoY, recoZ)) return -1.0;
725 
726  double const seg_size{steps_size};
727  auto const segments = getSegTracks_(recoX, recoY, recoZ, seg_size);
728  if (!segments.has_value()) return -1.0;
729 
730  auto const seg_steps = segments->x.size();
731  if (seg_steps < 2) return -1;
732 
733  double const recoSegmentLength = segments->L.at(seg_steps - 1);
734  if (recoSegmentLength < minLength || recoSegmentLength > maxLength) return -1;
735 
736  double ymax = -999.0;
737  double ymin = +999.0;
738 
739  std::vector<double> xmeas;
740  std::vector<double> ymeas;
741  std::vector<double> eymeas;
742  xmeas.reserve(n_steps);
743  ymeas.reserve(n_steps);
744  eymeas.reserve(n_steps);
745  for (int j = 0; j < n_steps; j++) {
746  double const trial = steps.at(j);
747  // computes the rms by groups of trial, if seg_size was chosen as 10, trials will be 10, 20, etc.. until 10 * n_steps
748  auto const [mean, rms, rmse] = getDeltaThetaRMS_(*segments, trial);
749 
750  if (std::isnan(mean) || std::isinf(mean)) {
751  mf::LogDebug("TrackMomentumCalculator") << "Returned mean is either nan or infinity.";
752  continue;
753  }
754  if (std::isnan(rms) || std::isinf(rms)) {
755  mf::LogDebug("TrackMomentumCalculator") << "Returned rms is either nan or infinity.";
756  continue;
757  }
758  if (std::isnan(rmse) || std::isinf(rmse)) {
759  mf::LogDebug("TrackMomentumCalculator") << "Returned rmse is either nan or infinity.";
760  continue;
761  }
762 
763  if (mean == -1 && rms == -1 && rmse == -1) continue;
764  xmeas.push_back(trial); // x values are different steps length, ex: 10, 20, 30 cm
765  ymeas.push_back(rms); // y values are the RMS of the scattered angle for each step defined
766  eymeas.push_back(
767  std::hypot(rmse, 0.05 * rms)); // <--- conservative syst. error to fix chi^{2} behaviour !!!
768 
769  if (ymin > rms) ymin = rms;
770  if (ymax < rms) ymax = rms;
771  }
772 
773  assert(xmeas.size() == ymeas.size());
774  assert(xmeas.size() == eymeas.size());
775  if (xmeas.empty()) { return -1.0; }
776 
777  TGraphErrors gr_meas{n_steps, xmeas.data(), ymeas.data(), nullptr, eymeas.data()};
778 
779  gr_meas.SetTitle("(#Delta#theta)_{rms} versus material thickness; Material "
780  "thickness in cm; (#Delta#theta)_{rms} in mrad");
781 
782  gr_meas.SetLineColor(kBlack);
783  gr_meas.SetMarkerColor(kBlack);
784  gr_meas.SetMarkerStyle(20);
785  gr_meas.SetMarkerSize(1.2);
786 
787  gr_meas.GetXaxis()->SetLimits(steps.at(0) - steps.at(0), steps.at(n_steps - 1) + steps.at(0));
788  gr_meas.SetMinimum(0.0);
789  gr_meas.SetMaximum(1.80 * ymax);
790 
791  double correction = 1.;
792  if (fMCSAngleMethod == kAngleCombined) { correction = std::sqrt(2.); }
793 
794  ROOT::Minuit2::Minuit2Minimizer mP{};
795  FcnWrapper const wrapper{std::move(xmeas), std::move(ymeas), std::move(eymeas), correction};
796  ROOT::Math::Functor FCA([&wrapper](double const* xs) { return wrapper.my_mcs_chi2(xs); }, 2);
797 
798  // Start point for resolution
799  double startpoint = 2;
800  if (startpoint < min_resolution) startpoint = (max_resolution - min_resolution) / 2.;
801  bool fixresolution = false;
802  double maxres = max_resolution;
803  if (max_resolution == 0 || max_resolution <= min_resolution) {
804  fixresolution = true;
805  startpoint = min_resolution;
806  maxres += 1;
807  }
808 
809  mP.SetFunction(FCA);
810  mP.SetLimitedVariable(0, "p_{MCS}", 1.0, 0.01, 0.001, maxMomentum_MeV / 1.e3);
811  mP.SetLimitedVariable(1, "#delta#theta", startpoint, startpoint / 2., min_resolution, maxres);
812  if (fixresolution) { mP.FixVariable(1); }
813  mP.SetMaxFunctionCalls(1.E9);
814  mP.SetMaxIterations(1.E9);
815  mP.SetTolerance(0.01);
816  mP.SetStrategy(2);
817  mP.SetErrorDef(1);
818 
819  bool const mstatus = mP.Minimize();
820 
821  mP.Hesse();
822 
823  const double* pars = mP.X();
824 
825  auto const recoL = trk->Length();
826  double const deltap = (recoL * kcal) / 2.0;
827 
828  double const p_mcs = pars[0] + deltap;
829 
830  return mstatus ? p_mcs : -1.0;
831  }
Point_t const & LocationAtPoint(size_t i) const
Access to track position at different points.
Definition: Track.h:160
bool HasValidPoint(size_t i) const
Various functions related to the presence and the number of (valid) points.
Definition: Track.h:145
size_t NumberTrajectoryPoints() const
Various functions related to the presence and the number of (valid) points.
Definition: Track.h:136
std::optional< Segments > getSegTracks_(std::vector< double > const &xxx, std::vector< double > const &yyy, std::vector< double > const &zzz, double seg_size, bool check_valid_scattered=false)
Split tracks into segments to calculate the scattered angle later. Check DOI 10.1088/1748-0221/12/10/...
double Length(size_t p=0) const
Access to various track properties.
Definition: Track.h:207
bool plotRecoTracks_(std::vector< double > const &xxx, std::vector< double > const &yyy, std::vector< double > const &zzz)
std::tuple< double, double, double > getDeltaThetaRMS_(Segments const &segments, double thick) const
Gets the scattered angle RMS for a all segments.
Use space angle: sqrt( zx^2 + zy^2 )/sqrt(2)
double mean(const std::vector< short > &wf, size_t start, size_t nsample)
Definition: UtilFunc.cxx:13
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
double trkf::TrackMomentumCalculator::GetMomentumMultiScatterLLHD ( art::Ptr< recob::Track > const &  trk,
const bool  checkValidPoints = false,
const int  maxMomentum_MeV = 7500,
const double  min_resolution = 0.001,
const double  max_resolution = 800,
const bool  check_valid_scattered = false,
const double  angle_correction = 0.757 
)

Calculate muon momentum (GeV) using multiple coulomb scattering by log likelihood.

Parameters
trkthe muon track
checkValidPointsrather take into account only valid points or not
maxMomentum_MeVmaximum momentum in MeV for the minimization
MomentumStep_MeVenergy steps for minimization
max_resolutionmaximum angular resolution for fit. Setting to zero will cause the fit only over momentum and fixed resolution of 2 mrad
check_valid_scatteredset to true will check if scatter angles are valid. Angles are invalid if there is only two points in one segment.
angle_correctionCorrection for space angle due to possible oversmoothing. The value (0.757) was set based on studies with MC. Change this value through the fhcl file

TODO: Add better description of the steps done

Returns
momentum in GeV

Definition at line 445 of file TrackMomentumCalculator.cxx.

References fMCSAngleMethod, getDeltaThetaij_(), getSegTracks_(), GetTrackMomentum(), recob::Track::HasValidPoint(), kAngleCombined, recob::Track::Length(), recob::Track::LocationAtPoint(), maxLength, recob::Track::NumberTrajectoryPoints(), plotRecoTracks_(), and steps_size.

452  {
453 
454  std::vector<double> recoX;
455  std::vector<double> recoY;
456  std::vector<double> recoZ;
457 
458  int n_points = trk->NumberTrajectoryPoints();
459 
460  for (int i = 0; i < n_points; i++) {
461  if (checkValidPoints && !trk->HasValidPoint(i)) continue;
462  auto const& pos = trk->LocationAtPoint(i);
463  recoX.push_back(pos.X());
464  recoY.push_back(pos.Y());
465  recoZ.push_back(pos.Z());
466  }
467 
468  if (recoX.size() < 2) return -1.0;
469 
470  if (!plotRecoTracks_(recoX, recoY, recoZ)) return -1.0;
471 
472  double const seg_size{steps_size};
473 
474  auto const segments = getSegTracks_(recoX, recoY, recoZ, seg_size, check_valid_scattered);
475  if (!segments.has_value()) return -1.0;
476 
477  auto const seg_steps = segments->x.size();
478  if (seg_steps < 2) return -1;
479 
480  double const recoSegmentLength = segments->L.at(seg_steps - 1);
481  if (recoSegmentLength < minLength || recoSegmentLength > maxLength) return -1;
482 
483  std::vector<double> dEi;
484  std::vector<double> dEj;
485  std::vector<double> dthij;
486  std::vector<double> ind;
487  std::vector<bool> dthij_valid = segments->nvalid;
488  if (getDeltaThetaij_(dEi, dEj, dthij, ind, *segments, seg_size, angle_correction) != 0)
489  return -1;
490 
491  auto const ndEi = dEi.size();
492  if (ndEi < 1) return -1;
493 
494  double correction = 1.;
495  if (fMCSAngleMethod == kAngleCombined) { correction = std::sqrt(2.); }
496 
497  // Gets energy evaluated by range
498  auto recoL = trk->Length();
499  double const minP = this->GetTrackMomentum(recoL, 13);
500 
501  ROOT::Minuit2::Minuit2Minimizer mP{};
502  FcnWrapperLLHD const wrapper{std::move(dEi),
503  std::move(dEj),
504  std::move(dthij),
505  std::move(ind),
506  std::move(dthij_valid),
507  seg_size,
508  correction};
509  ROOT::Math::Functor FCA([&wrapper](double const* xs) { return wrapper.my_mcs_llhd(xs); }, 2);
510 
511  mP.SetFunction(FCA);
512 
513  // Start point for resolution
514  // If max_resolution is zero, startpoint is equal min_resolution
515  double startpoint = 2;
516  if (startpoint < min_resolution)
517  startpoint = (max_resolution - min_resolution) / 2.; // prevent wrong values
518  bool fixresolution = false;
519  double maxres = max_resolution;
520  if (max_resolution == 0 || max_resolution <= min_resolution) {
521  fixresolution = true;
522  startpoint = min_resolution;
523  maxres += 1;
524  }
525 
526  // Starting energy as double of the energy by range
527  // Assumes that the smallet possible energy is given by 60% with CSDA
528  // Step as 10 %
529  mP.SetLimitedVariable(0, "p_{MCS}", minP * 2, minP * 0.1, minP * 0.6, maxMomentum_MeV / 1.e3);
530  mP.SetLimitedVariable(1, "#delta#theta", startpoint, startpoint / 2., min_resolution, maxres);
531  if (fixresolution) { mP.FixVariable(1); }
532  mP.SetMaxFunctionCalls(1.E9);
533  mP.SetMaxIterations(1.E9);
534  mP.SetTolerance(0.01);
535  mP.SetStrategy(2);
536  mP.SetErrorDef(1);
537 
538  bool const mstatus = mP.Minimize();
539 
540  mP.Hesse();
541 
542  const double* pars = mP.X();
543 
544  double const p_mcs = pars[0];
545 
546  return mstatus ? p_mcs : -1.0;
547  }
Point_t const & LocationAtPoint(size_t i) const
Access to track position at different points.
Definition: Track.h:160
bool HasValidPoint(size_t i) const
Various functions related to the presence and the number of (valid) points.
Definition: Track.h:145
size_t NumberTrajectoryPoints() const
Various functions related to the presence and the number of (valid) points.
Definition: Track.h:136
std::optional< Segments > getSegTracks_(std::vector< double > const &xxx, std::vector< double > const &yyy, std::vector< double > const &zzz, double seg_size, bool check_valid_scattered=false)
Split tracks into segments to calculate the scattered angle later. Check DOI 10.1088/1748-0221/12/10/...
int getDeltaThetaij_(std::vector< double > &ei, std::vector< double > &ej, std::vector< double > &th, std::vector< double > &ind, Segments const &segments, double thick, double const angle_correction) const
Gets the scatterd angle for all the segments.
double Length(size_t p=0) const
Access to various track properties.
Definition: Track.h:207
bool plotRecoTracks_(std::vector< double > const &xxx, std::vector< double > const &yyy, std::vector< double > const &zzz)
Use space angle: sqrt( zx^2 + zy^2 )/sqrt(2)
double GetTrackMomentum(double trkrange, int pdg) const
TVector3 trkf::TrackMomentumCalculator::GetMultiScatterStartingPoint ( art::Ptr< recob::Track > const &  trk)

Definition at line 549 of file TrackMomentumCalculator.cxx.

References GetMuMultiScatterLLHD3(), recob::Track::LocationAtPoint(), and recob::Track::NumberTrajectoryPoints().

550  {
551  double const LLHDp = GetMuMultiScatterLLHD3(trk, true);
552  double const LLHDm = GetMuMultiScatterLLHD3(trk, false);
553 
554  if (LLHDp != -1 && LLHDm != -1 && LLHDp > LLHDm) {
555  int const n_points = trk->NumberTrajectoryPoints();
556  return trk->LocationAtPoint<TVector3>(n_points - 1);
557  }
558  else {
559  return trk->LocationAtPoint<TVector3>(0);
560  }
561 
562  // Should never get here
563  return TVector3{};
564  }
Point_t const & LocationAtPoint(size_t i) const
Access to track position at different points.
Definition: Track.h:160
size_t NumberTrajectoryPoints() const
Various functions related to the presence and the number of (valid) points.
Definition: Track.h:136
double GetMuMultiScatterLLHD3(art::Ptr< recob::Track > const &trk, bool dir)
double trkf::TrackMomentumCalculator::GetMuMultiScatterLLHD3 ( art::Ptr< recob::Track > const &  trk,
bool  dir 
)

Definition at line 566 of file TrackMomentumCalculator.cxx.

References getDeltaThetaij_(), getSegTracks_(), recob::Track::Length(), recob::Track::LocationAtPoint(), maxLength, my_mcs_llhd(), recob::Track::NumberTrajectoryPoints(), and plotRecoTracks_().

Referenced by GetMultiScatterStartingPoint().

568  {
569  std::vector<double> recoX;
570  std::vector<double> recoY;
571  std::vector<double> recoZ;
572 
573  int const n_points = trk->NumberTrajectoryPoints();
574  for (int i = 0; i < n_points; ++i) {
575  auto const index = dir ? i : n_points - 1 - i;
576  auto const& pos = trk->LocationAtPoint(index);
577  recoX.push_back(pos.X());
578  recoY.push_back(pos.Y());
579  recoZ.push_back(pos.Z());
580  }
581 
582  if (recoX.size() < 2) return -1.0;
583 
584  if (!plotRecoTracks_(recoX, recoY, recoZ)) return -1.0;
585 
586  constexpr double seg_size{5.0};
587  auto const segments = getSegTracks_(recoX, recoY, recoZ, seg_size);
588  if (!segments.has_value()) return -1.0;
589 
590  auto const seg_steps = segments->x.size();
591  if (seg_steps < 2) return -1;
592 
593  double const recoSegmentLength = segments->L.at(seg_steps - 1);
594  if (recoSegmentLength < 15.0 || recoSegmentLength > maxLength) return -1;
595 
596  std::vector<double> dEi;
597  std::vector<double> dEj;
598  std::vector<double> dthij;
599  std::vector<double> ind;
600  double angle_correction = 1; // never tested in this function
601  if (getDeltaThetaij_(dEi, dEj, dthij, ind, *segments, seg_size, angle_correction) != 0)
602  return -1;
603 
604  auto const recoL = trk->Length();
605  double const p_range = recoL * kcal;
606  double const logL = my_mcs_llhd(dEi, dEj, dthij, ind, p_range, 5.65);
607 
608  return logL;
609  }
Point_t const & LocationAtPoint(size_t i) const
Access to track position at different points.
Definition: Track.h:160
size_t NumberTrajectoryPoints() const
Various functions related to the presence and the number of (valid) points.
Definition: Track.h:136
std::optional< Segments > getSegTracks_(std::vector< double > const &xxx, std::vector< double > const &yyy, std::vector< double > const &zzz, double seg_size, bool check_valid_scattered=false)
Split tracks into segments to calculate the scattered angle later. Check DOI 10.1088/1748-0221/12/10/...
int getDeltaThetaij_(std::vector< double > &ei, std::vector< double > &ej, std::vector< double > &th, std::vector< double > &ind, Segments const &segments, double thick, double const angle_correction) const
Gets the scatterd angle for all the segments.
double Length(size_t p=0) const
Access to various track properties.
Definition: Track.h:207
double my_mcs_llhd(std::vector< double > const &dEi, std::vector< double > const &dEj, std::vector< double > const &dthij, std::vector< double > const &ind, double x0, double x1) const
Minimizer of log likelihood for scattered angle.
bool plotRecoTracks_(std::vector< double > const &xxx, std::vector< double > const &yyy, std::vector< double > const &zzz)
TDirectory * dir
Definition: macro.C:5
std::optional< TrackMomentumCalculator::Segments > trkf::TrackMomentumCalculator::getSegTracks_ ( std::vector< double > const &  xxx,
std::vector< double > const &  yyy,
std::vector< double > const &  zzz,
double  seg_size,
bool  check_valid_scattered = false 
)
private

Split tracks into segments to calculate the scattered angle later. Check DOI 10.1088/1748-0221/12/10/P10010.

Parameters
xxx3D reconstructed points x-axis
yyy3D reconstructed points y-axiy
zzz3D reconstructed points z-axiz
seg_sizeSegments size defined in class constructor
check_valid_scatteredset to true will check if scatter angles are valid. Angles are invalid if there is only two points in one segment. Set true only for LLHD! TODO: Add better description of steps
Returns
Segments

Definition at line 994 of file TrackMomentumCalculator.cxx.

References a1, a2, a3, compute_max_fluctuation_vector(), gr_seg_xy, gr_seg_xyz, gr_seg_xz, gr_seg_yz, n_seg, seg_stop, x1, x2, x_seg, y1, y2, y_seg, and z_seg.

Referenced by GetMomentumMultiScatterChi2(), GetMomentumMultiScatterLLHD(), and GetMuMultiScatterLLHD3().

1000  {
1001  double stag = 0.0;
1002 
1003  int a1 = xxx.size();
1004  int a2 = yyy.size();
1005  int a3 = zzz.size();
1006 
1007  if ((a1 != a2) || (a1 != a3) || (a2 != a3)) {
1008  cout << " ( Digitize reco tacks ) Error ! " << endl;
1009  return std::nullopt;
1010  }
1011 
1012  int const stopper = seg_stop / seg_size;
1013 
1014  // values to be filled and returned
1015  std::vector<double> segx, segnx;
1016  std::vector<double> segy, segny;
1017  std::vector<double> segz, segnz;
1018  std::vector<bool> segn_isvalid;
1019  std::vector<double> segL;
1020 
1021  n_seg = 0;
1022 
1023  double x0{};
1024  double y0{};
1025  double z0{};
1026 
1027  double x00 = xxx.at(0);
1028  double y00 = yyy.at(0);
1029  double z00 = zzz.at(0);
1030 
1031  int indC = 0;
1032 
1033  // These vectors will keep the points inside reach segments
1034  // They are cleared inside the function `compute_max_fluctuation_vector`
1035  // each time it finishes with a segment
1036  std::vector<double> vx;
1037  std::vector<double> vy;
1038  std::vector<double> vz;
1039 
1040  for (int i = 0; i < a1; i++) {
1041  x0 = xxx.at(i);
1042  y0 = yyy.at(i);
1043  z0 = zzz.at(i);
1044 
1045  double const RR0 = std::hypot(x00 - x0, y00 - y0, z00 - z0);
1046 
1047  if (RR0 >= stag) { // stag is aways set to zero, this is always true
1048 
1049  segx.push_back(x0);
1050  segy.push_back(y0);
1051  segz.push_back(z0);
1052 
1053  segL.push_back(0);
1054 
1055  // TGraph
1056  x_seg[n_seg] = x0;
1057  y_seg[n_seg] = y0;
1058  z_seg[n_seg] = z0;
1059 
1060  n_seg++;
1061 
1062  vx.push_back(x0);
1063  vy.push_back(y0);
1064  vz.push_back(z0);
1065 
1066  indC = i + 1;
1067 
1068  break;
1069  }
1070  }
1071 
1072  for (int i = indC; i < a1 - 1; i++) { // starting at second point (i=1) if stag set to zero
1073  // current point
1074  double const x1 = xxx.at(i);
1075  double const y1 = yyy.at(i);
1076  double const z1 = zzz.at(i);
1077 
1078  // distante from previous point
1079  double const dr1 = std::hypot(x1 - x0, y1 - y0, z1 - z0);
1080 
1081  // next point
1082  double const x2 = xxx.at(i + 1);
1083  double const y2 = yyy.at(i + 1);
1084  double const z2 = zzz.at(i + 1);
1085 
1086  // distant of next point to previous point
1087  double const dr2 = std::hypot(x2 - x0, y2 - y0, z2 - z0);
1088 
1089  if (dr1 < seg_size) {
1090  vx.push_back(x1);
1091  vy.push_back(y1);
1092  vz.push_back(z1);
1093  }
1094 
1095  /* If current point is inside segment length w.r.t. the first point of
1096  * the segment (x0,y0,z0), but the next point is outsize: create a new
1097  * point in between (x1,y1,z1) and (x2,y2,z2) in which will be exacly at
1098  * the segment length (w.r.t. to the first point) This is done using the
1099  * cosines law for a given factor `t` times dr (x2-x1, ...), and so:
1100  *
1101  * (ds)^2 = (dr1)^2 + (t*dr)^2 + 2*dot_product(dr1, t*dr)
1102  * Using cos(180-theta) = -cos(theta))
1103  *
1104  * Solve for `t` the second degree equation: t^2 + beta*t + gamma = 0
1105  */
1106  if (dr1 <= seg_size && dr2 > seg_size) {
1107  double const dx = x2 - x1;
1108  double const dy = y2 - y1;
1109  double const dz = z2 - z1;
1110  double const dr = std::hypot(dx, dy, dz);
1111 
1112  if (dr == 0) {
1113  cout << " ( Zero ) Error ! " << endl;
1114  return std::nullopt;
1115  }
1116 
1117  double const beta = 2.0 * ((x1 - x0) * dx + (y1 - y0) * dy + (z1 - z0) * dz) / (dr * dr);
1118 
1119  double const gamma = (dr1 * dr1 - seg_size * seg_size) / (dr * dr);
1120  double const delta = beta * beta - 4.0 * gamma;
1121 
1122  if (delta < 0.0) {
1123  cout << " ( Discriminant ) Error ! " << endl;
1124  return std::nullopt;
1125  }
1126 
1127  // solves for t
1128  double const lysi1 = (-beta + std::sqrt(delta)) / 2.0;
1129  double const t = lysi1;
1130 
1131  // find next points in that will exactly at the segment length from x0
1132  double const xp = x1 + t * dx;
1133  double const yp = y1 + t * dy;
1134  double const zp = z1 + t * dz;
1135 
1136  // Add points to be returned
1137  segx.push_back(xp);
1138  segy.push_back(yp);
1139  segz.push_back(zp);
1140 
1141  segL.push_back(n_seg * seg_size);
1142 
1143  // for TGraph
1144  x_seg[n_seg] = xp;
1145  y_seg[n_seg] = yp;
1146  z_seg[n_seg] = zp;
1147 
1148  n_seg++;
1149 
1150  // This are the new `x0` points (for next segment)
1151  x0 = xp;
1152  y0 = yp;
1153  z0 = zp;
1154 
1155  // Add points to segment
1156  vx.push_back(x0);
1157  vy.push_back(y0);
1158  vz.push_back(z0);
1159 
1160  if (n_seg <= 1) // This should never happen
1161  return std::nullopt;
1162 
1163  // Now, compute the deviation in `segx, ...` of the segment
1164  // vx, vy, vz are used and cleared afterwards
1166  segx, segy, segz, segnx, segny, segnz, segn_isvalid, vx, vy, vz, check_valid_scattered);
1167 
1168  // Starting over
1169  vx.push_back(x0);
1170  vy.push_back(y0);
1171  vz.push_back(z0);
1172  }
1173  else if (dr1 > seg_size) { // in this case, just interpolate until reach `seg_size`
1174 
1175  // Rolling `i` back for the next iteration.
1176  // Because the current point does not belong to this segment
1177  i = (i - 1);
1178 
1179  double const dx = x1 - x0;
1180  double const dy = y1 - y0;
1181  double const dz = z1 - z0;
1182  double const dr = std::hypot(dx, dy, dz);
1183 
1184  if (dr == 0) {
1185  cout << " ( Zero ) Error ! " << endl;
1186  return std::nullopt;
1187  }
1188 
1189  // computes the point by simple interpolation
1190  double const t = seg_size / dr;
1191  double const xp = x0 + t * dx;
1192  double const yp = y0 + t * dy;
1193  double const zp = z0 + t * dz;
1194 
1195  segx.push_back(xp);
1196  segy.push_back(yp);
1197  segz.push_back(zp);
1198  segL.push_back(1.0 * n_seg * 1.0 * seg_size + stag);
1199 
1200  // for TGraph
1201  x_seg[n_seg] = xp;
1202  y_seg[n_seg] = yp;
1203  z_seg[n_seg] = zp;
1204 
1205  n_seg++;
1206 
1207  x0 = xp;
1208  y0 = yp;
1209  z0 = zp;
1210 
1211  vx.push_back(x0);
1212  vy.push_back(y0);
1213  vz.push_back(z0);
1214 
1215  if (n_seg <= 1) // This should never happen
1216  return std::nullopt;
1217 
1218  // Now, compute the deviation in `segx, ...` of the segment
1219  // vx, vy, vz are used and cleared afterwards
1221  segx, segy, segz, segnx, segny, segnz, segn_isvalid, vx, vy, vz, check_valid_scattered);
1222 
1223  // vectors are cleared in previous step
1224  vx.push_back(x0);
1225  vy.push_back(y0);
1226  vz.push_back(z0);
1227  }
1228 
1229  if (n_seg >= (stopper + 1.0) && seg_stop != -1) break;
1230  }
1231 
1232  delete gr_seg_xyz;
1233  gr_seg_xyz = new TPolyLine3D{n_seg, z_seg, x_seg, y_seg};
1234  gr_seg_yz = TGraph{n_seg, z_seg, y_seg};
1235  gr_seg_xz = TGraph{n_seg, z_seg, x_seg};
1236  gr_seg_xy = TGraph{n_seg, x_seg, y_seg};
1237 
1238  return std::make_optional<Segments>(
1239  Segments{segx, segnx, segy, segny, segz, segnz, segL, segn_isvalid});
1240  }
Float_t y1[n_points_granero]
Definition: compare.C:5
Float_t x1[n_points_granero]
Definition: compare.C:5
Float_t y2[n_points_geant4]
Definition: compare.C:26
#define a2
#define a3
void compute_max_fluctuation_vector(const std::vector< double > segx, const std::vector< double > segy, const std::vector< double > segz, std::vector< double > &segnx, std::vector< double > &segny, std::vector< double > &segnz, std::vector< bool > &segn_isvalid, std::vector< double > &vx, std::vector< double > &vy, std::vector< double > &vz, bool check_valid_scattered)
Computes the vector with most scattering inside a segment with size steps_size.
Float_t x2[n_points_geant4]
Definition: compare.C:26
#define a1
double trkf::TrackMomentumCalculator::GetTrackMomentum ( double  trkrange,
int  pdg 
) const

Definition at line 318 of file TrackMomentumCalculator.cxx.

References util::abs(), and E.

Referenced by trkmkr::KalmanFilterFitTrackMaker::getMomentum(), GetMomentumMultiScatterLLHD(), trkf::KalmanFilterTrajectoryFitter::setMomValue(), and trkf::KalmanFilterFinalTrackFitter::setMomValue().

319  {
320  /* Muon range-momentum tables from CSDA (Argon density = 1.4 g/cm^3)
321  website:
322  http://pdg.lbl.gov/2012/AtomicNuclearProperties/MUON_ELOSS_TABLES/muonloss_289.pdf
323 
324  CSDA table values:
325  double Range_grampercm[30] = {9.833E-1, 1.786E0, 3.321E0,
326  6.598E0, 1.058E1, 3.084E1, 4.250E1, 6.732E1, 1.063E2, 1.725E2,
327  2.385E2, 4.934E2, 6.163E2, 8.552E2, 1.202E3, 1.758E3, 2.297E3,
328  4.359E3, 5.354E3, 7.298E3, 1.013E4, 1.469E4, 1.910E4, 3.558E4,
329  4.326E4, 5.768E4, 7.734E4, 1.060E5, 1.307E5}; double KE_MeV[30] = {10, 14,
330  20, 30, 40, 80, 100, 140, 200, 300, 400, 800, 1000, 1400, 2000, 3000,
331  4000, 8000, 10000, 14000, 20000, 30000, 40000, 80000, 100000, 140000,
332  200000, 300000, 400000};
333 
334  Functions below are obtained by fitting polynomial fits to KE_MeV vs
335  Range (cm) graph. A better fit was obtained by splitting the graph into
336  two: Below range<=200cm,a polynomial of power 4 was a good fit; above
337  200cm, a polynomial of power 6 was a good fit
338 
339  Fit errors for future purposes:
340  Below 200cm, Forpoly4 fit: p0 err=1.38533;p1 err=0.209626; p2
341  err=0.00650077; p3 err=6.42207E-5; p4 err=1.94893E-7; Above 200cm,
342  Forpoly6 fit: p0 err=5.24743;p1 err=0.0176229; p2 err=1.6263E-5; p3
343  err=5.9155E-9; p4 err=9.71709E-13; p5 err=7.22381E-17;p6
344  err=1.9709E-21;*/
345 
347  //*********For muon, the calculations are valid up to 1.91E4 cm range
348  //corresponding to a Muon KE of 40 GeV**********//
350 
351  /*Proton range-momentum tables from CSDA (Argon density = 1.4 g/cm^3):
352  website: https://physics.nist.gov/PhysRefData/Star/Text/PSTAR.html
353 
354  CSDA values:
355  double KE_MeV_P_Nist[31]={10, 15, 20, 30, 40, 80, 100, 150, 200, 250, 300,
356  350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000,
357  1500, 2000, 2500, 3000, 4000, 5000};
358 
359  double Range_gpercm_P_Nist[31]={1.887E-1,3.823E-1, 6.335E-1, 1.296,
360  2.159, 7.375, 1.092E1, 2.215E1, 3.627E1, 5.282E1, 7.144E1,
361  9.184E1, 1.138E2, 1.370E2, 1.614E2, 1.869E2, 2.132E2, 2.403E2,
362  2.681E2, 2.965E2, 3.254E2, 3.548E2, 3.846E2, 4.148E2, 4.454E2,
363  7.626E2, 1.090E3, 1.418E3, 1.745E3, 2.391E3, 3.022E3};
364 
365  Functions below are obtained by fitting power and polynomial fits to
366  KE_MeV vs Range (cm) graph. A better fit was obtained by splitting the
367  graph into two: Below range<=80cm,a a*(x^b) was a good fit; above 80cm, a
368  polynomial of power 6 was a good fit
369 
370  Fit errors for future purposes:
371  For power function fit: a=0.388873; and b=0.00347075
372  Forpoly6 fit: p0 err=3.49729;p1 err=0.0487859; p2 err=0.000225834; p3
373  err=4.45542E-7; p4 err=4.16428E-10; p5 err=1.81679E-13;p6
374  err=2.96958E-17;*/
375 
377  //*********For proton, the calculations are valid up to 3.022E3 cm range
378  //corresponding to a Muon KE of 5 GeV**********//
380 
381  /* Pion range-momentum extracted from Bethe-Bloch equation. The
382  computation are all one using
383  https://github.com/sungbinoh/PDSPTreeAnalyzer.git (last commit 4a3d1d2)
384 
385  The computation is done with the spline of the Range_grampercm and
386  KE_MeV_Pion.*/
387 
389  //*********For pion, the calculations are valid only when there is no
390  //inelastic scattering present. So this method should be used
391  //carefully.**********//
393 
394  if (trkrange < 0 || std::isnan(trkrange)) {
395  mf::LogError("TrackMomentumCalculator") << "Invalid track range " << trkrange << " return -1";
396  return -1.;
397  }
398 
399  double KE, Momentum, M;
400  constexpr double Muon_M = m_muon * 1e3, Proton_M = 938.272, Pion_M = 139.57039;
401 
402  if (abs(pdg) == 13) {
403  M = Muon_M;
404  KE = KEvsR_spline3.Eval(trkrange);
405  }
406  else if (abs(pdg) == 2212) {
407  M = Proton_M;
408  if (trkrange > 0 && trkrange <= 80)
409  KE = 29.9317 * std::pow(trkrange, 0.586304);
410  else if (trkrange > 80 && trkrange <= 3.022E3)
411  KE = 149.904 + (3.34146 * trkrange) + (-0.00318856 * trkrange * trkrange) +
412  (4.34587E-6 * trkrange * trkrange * trkrange) +
413  (-3.18146E-9 * trkrange * trkrange * trkrange * trkrange) +
414  (1.17854E-12 * trkrange * trkrange * trkrange * trkrange * trkrange) +
415  (-1.71763E-16 * trkrange * trkrange * trkrange * trkrange * trkrange * trkrange);
416  else
417  KE = -999;
418  }
419  else if (abs(pdg) == 211) {
420  M = Pion_M;
421  KE = KEvsRPi_spline3.Eval(trkrange);
422  }
423  else
424  KE = -999;
425 
426  if (KE < 0)
427  Momentum = -999;
428  else
429  Momentum = std::sqrt((KE * KE) + (2 * M * KE));
430 
431  Momentum = Momentum / 1000;
432 
433  return Momentum;
434  }
constexpr auto abs(T v)
Returns the absolute value of the argument.
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
Float_t E
Definition: plot.C:20
double trkf::TrackMomentumCalculator::my_g ( double  xx,
double  Q,
double  s 
) const
private

chi square minizer using Minuit2, it will minize (xx-Q)/s

Parameters
xx
Q
s
Returns
Momentum in GeV

Definition at line 1424 of file TrackMomentumCalculator.cxx.

Referenced by my_mcs_llhd().

1425  {
1426  if (s == 0.) {
1427  cout << " Error : The code tries to divide by zero ! " << endl;
1428  return 0.;
1429  }
1430 
1431  double const arg = (xx - Q) / s;
1432  double const result = -0.5 * std::log(2.0 * TMath::Pi()) - std::log(s) - 0.5 * arg * arg;
1433 
1434  if (std::isnan(result) || std::isinf(result)) {
1435  cout << " Is nan ! my_g ! " << -std::log(s) << ", " << s << endl;
1436  }
1437 
1438  return result;
1439  }
Double_t xx
Definition: macro.C:12
double trkf::TrackMomentumCalculator::my_mcs_llhd ( std::vector< double > const &  dEi,
std::vector< double > const &  dEj,
std::vector< double > const &  dthij,
std::vector< double > const &  ind,
double  x0,
double  x1 
) const
private

Minimizer of log likelihood for scattered angle.

Parameters
dEienergy at step i
dEjenergy at step j
dthijscattered angle between points i and j
indselection of scattering plane
x0momentum to be fitted
x1resolution to be fitted

TODO: Add better description of steps

Returns
momentum in GeV

Definition at line 1441 of file TrackMomentumCalculator.cxx.

References util::abs(), my_g(), rad_length, steps_size, and x1.

Referenced by GetMuMultiScatterLLHD3().

1447  {
1448  double p = x0;
1449  double theta0x = x1;
1450 
1451  double result = 0.0;
1452  double nnn1 = dEi.size(); // number of segments of energy
1453 
1454  double red_length = (steps_size) / rad_length;
1455  double addth = 0;
1456 
1457  for (int i = 0; i < nnn1; i++) {
1458  double Ei = p - dEi.at(i); // Estimated energy at point i
1459  double Ej = p - dEj.at(i); // Estimated enery at point j
1460 
1461  // If the momentum p choosen allows that the muon stopped inside, add 1 rad to the change in scatter angle (as the particle stops)
1462  if (Ei > 0 && Ej < 0) addth = 3.14 * 1000.0;
1463 
1464  Ei = std::abs(Ei);
1465  Ej = std::abs(Ej);
1466 
1467  // Highland formula
1468  // Parameters given at Particle Data Group https://pdg.lbl.gov/2023/web/viewer.html?file=../reviews/rpp2022-rev-passage-particles-matter.pdf
1469  double tH0 =
1470  (13.6 / std::sqrt(Ei * Ej)) * (1.0 + 0.038 * std::log(red_length)) * std::sqrt(red_length);
1471 
1472  double rms = -1.0;
1473 
1474  if (ind.at(i) == 1) {
1475  // Computes the rms of angle
1476  rms = std::hypot(tH0, theta0x);
1477 
1478  double const DT = dthij.at(i) + addth;
1479  double const prob = my_g(DT, 0.0, rms); // Computes log likelihood
1480 
1481  result = result - 2.0 * prob; // Adds for each segment
1482  }
1483  }
1484 
1485  if (std::isnan(result) || std::isinf(result)) {
1486  std::cout << " Is nan ! my_mcs_llhd ( 1 ) ! " << std::endl;
1487  }
1488  return result;
1489  }
double my_g(double xx, double Q, double s) const
chi square minizer using Minuit2, it will minize (xx-Q)/s
Float_t x1[n_points_granero]
Definition: compare.C:5
constexpr auto abs(T v)
Returns the absolute value of the argument.
bool trkf::TrackMomentumCalculator::plotRecoTracks_ ( std::vector< double > const &  xxx,
std::vector< double > const &  yyy,
std::vector< double > const &  zzz 
)
private

Definition at line 833 of file TrackMomentumCalculator.cxx.

References gr_reco_xy, gr_reco_xyz, gr_reco_xz, gr_reco_yz, and n.

Referenced by GetMomentumMultiScatterChi2(), GetMomentumMultiScatterLLHD(), and GetMuMultiScatterLLHD3().

836  {
837  auto const n = xxx.size();
838  auto const y_size = yyy.size();
839  auto const z_size = zzz.size();
840 
841  if (n != y_size || n != z_size) {
842  cout << " ( Get reco tacks ) Error ! " << endl;
843  return false;
844  }
845 
846  // Here, we perform a const-cast to double* because, sadly,
847  // TPolyLine3D requires a pointer to a non-const object. We will
848  // trust that ROOT does not mess around with the underlying data.
849  auto xs = const_cast<double*>(xxx.data());
850  auto ys = const_cast<double*>(yyy.data());
851  auto zs = const_cast<double*>(zzz.data());
852 
853  auto const narrowed_size = static_cast<int>(n); // ROOT requires a signed integral type
854  delete gr_reco_xyz;
855  gr_reco_xyz = new TPolyLine3D{narrowed_size, zs, xs, ys};
856  gr_reco_yz = TGraph{narrowed_size, zzz.data(), yyy.data()};
857  gr_reco_xz = TGraph{narrowed_size, zzz.data(), xxx.data()};
858  gr_reco_xy = TGraph{narrowed_size, xxx.data(), yyy.data()};
859 
860  return true;
861  }
Char_t n[5]

Member Data Documentation

ScatterAngleMethods trkf::TrackMomentumCalculator::fMCSAngleMethod
private
TGraph trkf::TrackMomentumCalculator::gr_reco_xy {}
private

Definition at line 251 of file TrackMomentumCalculator.h.

Referenced by plotRecoTracks_().

TPolyLine3D* trkf::TrackMomentumCalculator::gr_reco_xyz {nullptr}
private

Definition at line 250 of file TrackMomentumCalculator.h.

Referenced by plotRecoTracks_().

TGraph trkf::TrackMomentumCalculator::gr_reco_xz {}
private

Definition at line 253 of file TrackMomentumCalculator.h.

Referenced by plotRecoTracks_().

TGraph trkf::TrackMomentumCalculator::gr_reco_yz {}
private

Definition at line 252 of file TrackMomentumCalculator.h.

Referenced by plotRecoTracks_().

TGraph trkf::TrackMomentumCalculator::gr_seg_xy {}
private

Definition at line 256 of file TrackMomentumCalculator.h.

Referenced by getSegTracks_().

TPolyLine3D* trkf::TrackMomentumCalculator::gr_seg_xyz {nullptr}
private

Definition at line 255 of file TrackMomentumCalculator.h.

Referenced by getSegTracks_().

TGraph trkf::TrackMomentumCalculator::gr_seg_xz {}
private

Definition at line 258 of file TrackMomentumCalculator.h.

Referenced by getSegTracks_().

TGraph trkf::TrackMomentumCalculator::gr_seg_yz {}
private

Definition at line 257 of file TrackMomentumCalculator.h.

Referenced by getSegTracks_().

double trkf::TrackMomentumCalculator::maxLength
private
double trkf::TrackMomentumCalculator::minLength
private

Definition at line 226 of file TrackMomentumCalculator.h.

int trkf::TrackMomentumCalculator::n_seg {}
private

Definition at line 208 of file TrackMomentumCalculator.h.

Referenced by compute_max_fluctuation_vector(), and getSegTracks_().

int trkf::TrackMomentumCalculator::n_steps
private
double trkf::TrackMomentumCalculator::rad_length {14.0}
private

Definition at line 229 of file TrackMomentumCalculator.h.

Referenced by my_mcs_llhd().

double trkf::TrackMomentumCalculator::seg_stop {-1.}
private

Definition at line 207 of file TrackMomentumCalculator.h.

Referenced by getSegTracks_().

std::vector<double> trkf::TrackMomentumCalculator::steps
private
double trkf::TrackMomentumCalculator::steps_size
private
double trkf::TrackMomentumCalculator::x_seg[50000]
private

Definition at line 210 of file TrackMomentumCalculator.h.

Referenced by getSegTracks_().

double trkf::TrackMomentumCalculator::y_seg[50000]
private

Definition at line 211 of file TrackMomentumCalculator.h.

Referenced by getSegTracks_().

double trkf::TrackMomentumCalculator::z_seg[50000]
private

Definition at line 212 of file TrackMomentumCalculator.h.

Referenced by getSegTracks_().


The documentation for this class was generated from the following files: