7 #include "art/Framework/Services/Registry/ServiceHandle.h"
9 #include "TMatrixDSym.h"
10 #include "TMatrixDSymEigen.h"
14 using namespace recob::tracking;
20 vector<size_t> breakpoints;
21 vector<float> segradlengths;
22 vector<float> cumseglens;
23 breakTrajInSegments(traj, breakpoints, segradlengths, cumseglens);
31 for (
unsigned int p = 0;
p<segradlengths.size();
p++) {
32 linearRegression(traj, breakpoints[
p], breakpoints[p+1], pcdir1);
34 if (segradlengths[
p]<-100. || segradlengths[
p-1]<-100.) {
35 dtheta.push_back(-999.);
37 const double cosval = pcdir0.X()*pcdir1.X()+pcdir0.Y()*pcdir1.Y()+pcdir0.Z()*pcdir1.Z();
40 double dt = 1000.*acos(cosval);
49 vector<float> cumLenFwd;
50 vector<float> cumLenBwd;
51 for (
unsigned int i = 0; i<cumseglens.size()-2; i++) {
52 cumLenFwd.push_back(cumseglens[i]);
53 cumLenBwd.push_back(cumseglens.back()-cumseglens[i+2]);
56 const ScanResult fwdResult = doLikelihoodScan(dtheta, segradlengths, cumLenFwd,
true , pid, detAngResol);
57 const ScanResult bwdResult = doLikelihoodScan(dtheta, segradlengths, cumLenBwd,
false, pid, detAngResol);
60 fwdResult.p,fwdResult.pUnc,fwdResult.logL,
61 bwdResult.p,bwdResult.pUnc,bwdResult.logL,
62 segradlengths,dtheta);
65 void TrajectoryMCSFitter::breakTrajInSegments(
const recob::TrackTrajectory& traj, vector<size_t>& breakpoints, vector<float>& segradlengths, vector<float>& cumseglens)
const {
67 art::ServiceHandle<geo::Geometry const> geom;
68 auto const* _SCE = (applySCEcorr_ ? lar::providerFrom<spacecharge::SpaceChargeService>() : NULL);
70 const double trajlen = traj.
Length();
71 const double thisSegLen = (trajlen>(segLen_*minNSegs_) ? segLen_ : trajlen/
double(minNSegs_) );
74 constexpr
double lar_radl_inv = 1./14.0;
75 cumseglens.push_back(0.);
79 breakpoints.push_back(nextValid);
82 const double Position[3] = {pos0.X(), pos0.Y(), pos0.Z()};
83 geo::TPCID tpcid = geom->FindTPCAtPosition(Position);
87 pos0_offset = _SCE->GetCalPosOffsets(p0, tpcid.
TPC);
89 pos0.SetX(pos0.X() - pos0_offset.X());
90 pos0.SetY(pos0.Y() + pos0_offset.Y());
91 pos0.SetZ(pos0.Z() + pos0_offset.Z());
100 const double Position[3] = {pos1.X(), pos1.Y(), pos1.Z()};
101 geo::TPCID tpcid = geom->FindTPCAtPosition(Position);
105 pos1_offset = _SCE->GetCalPosOffsets(
p1, tpcid.
TPC);
107 pos1.SetX(pos1.X() - pos1_offset.X());
108 pos1.SetY(pos1.Y() + pos1_offset.Y());
109 pos1.SetZ(pos1.Z() + pos1_offset.Z());
112 auto step = (pos1-pos0).R();
113 thislen += dir0.Dot(pos1-pos0);
127 if (thislen>=(thisSegLen-segLenTolerance_)) {
128 breakpoints.push_back(nextValid);
129 if (npoints>=minHitsPerSegment_) segradlengths.push_back(thislen*lar_radl_inv);
130 else segradlengths.push_back(-999.);
131 cumseglens.push_back(totlen);
140 segradlengths.push_back(thislen*lar_radl_inv);
141 cumseglens.push_back(cumseglens.back()+thislen);
146 const TrajectoryMCSFitter::ScanResult TrajectoryMCSFitter::doLikelihoodScan(std::vector<float>& dtheta, std::vector<float>& seg_nradlengths, std::vector<float>& cumLen,
147 bool fwdFit,
int pid,
float pmin,
float pmax,
float pstep,
float detAngResol)
const {
149 float best_logL = std::numeric_limits<float>::max();
151 std::vector<float> vlogL;
152 for (
float p_test = pmin; p_test <= pmax; p_test+=pstep) {
153 float logL = mcsLikelihood(p_test, detAngResol, dtheta, seg_nradlengths, cumLen, fwdFit, pid);
154 if (logL < best_logL) {
157 best_idx = vlogL.size();
159 vlogL.push_back(logL);
165 for (
int j=best_idx-1;j>=0;j--) {
166 float dLL = vlogL[j]-vlogL[best_idx];
168 lunc = (best_idx-j)*pstep;
175 if (best_idx<
int(vlogL.size()-1)) {
176 for (
unsigned int j=best_idx+1;j<vlogL.size();j++) {
177 float dLL = vlogL[j]-vlogL[best_idx];
179 runc = (j-best_idx)*pstep;
184 return ScanResult(best_p, std::max(lunc,runc), best_logL);
187 const TrajectoryMCSFitter::ScanResult TrajectoryMCSFitter::doLikelihoodScan(std::vector<float>& dtheta, std::vector<float>& seg_nradlengths, std::vector<float>& cumLen,
188 bool fwdFit,
int pid,
float detAngResol)
const {
191 const ScanResult& coarseRes = doLikelihoodScan(dtheta, seg_nradlengths, cumLen, fwdFit, pid, pMin_, pMax_, pStepCoarse_, detAngResol);
193 float pmax = std::min(coarseRes.p+fineScanWindow_,pMax_);
194 float pmin = std::max(coarseRes.p-fineScanWindow_,pMin_);
195 if (coarseRes.pUnc < (std::numeric_limits<float>::max()-1.)) {
196 pmax = std::min(coarseRes.p+2*coarseRes.pUnc,pMax_);
197 pmin = std::max(coarseRes.p-2*coarseRes.pUnc,pMin_);
201 const ScanResult& refineRes = doLikelihoodScan(dtheta, seg_nradlengths, cumLen, fwdFit, pid, pmin, pmax, pStep_, detAngResol);
206 void TrajectoryMCSFitter::linearRegression(
const recob::TrackTrajectory& traj,
const size_t firstPoint,
const size_t lastPoint,
Vector_t& pcdir)
const {
208 art::ServiceHandle<geo::Geometry const> geom;
209 auto const* _SCE = (applySCEcorr_ ? lar::providerFrom<spacecharge::SpaceChargeService>() : NULL);
213 size_t nextValid = firstPoint;
216 while (nextValid<lastPoint) {
219 const double Position[3] = {tempP.X(), tempP.Y(), tempP.Z()};
220 geo::TPCID tpcid = geom->FindTPCAtPosition(Position);
224 tempP_offset = _SCE->GetCalPosOffsets(ptemp, tpcid.
TPC);
226 tempP.SetX(tempP.X() - tempP_offset.X());
227 tempP.SetY(tempP.Y() + tempP_offset.Y());
228 tempP.SetZ(tempP.Z() + tempP_offset.Z());
230 middlePointCalc.
add(tempP);
236 const double norm = 1./double(npoints);
241 nextValid = firstPoint;
242 while (nextValid<lastPoint) {
245 const double Position[3] = {
p.X(),
p.Y(),
p.Z()};
246 geo::TPCID tpcid = geom->FindTPCAtPosition(Position);
250 p_offset = _SCE->GetCalPosOffsets(point, tpcid.
TPC);
252 p.SetX(
p.X() - p_offset.X());
253 p.SetY(
p.Y() + p_offset.Y());
254 p.SetZ(
p.Z() + p_offset.Z());
256 const double xxw0 =
p.X()-avgpos.X();
257 const double yyw0 =
p.Y()-avgpos.Y();
258 const double zzw0 =
p.Z()-avgpos.Z();
259 m(0, 0) += xxw0*xxw0*
norm;
260 m(0, 1) += xxw0*yyw0*
norm;
261 m(0, 2) += xxw0*zzw0*
norm;
262 m(1, 0) += yyw0*xxw0*
norm;
263 m(1, 1) += yyw0*yyw0*
norm;
264 m(1, 2) += yyw0*zzw0*
norm;
265 m(2, 0) += zzw0*xxw0*
norm;
266 m(2, 1) += zzw0*yyw0*
norm;
267 m(2, 2) += zzw0*zzw0*
norm;
271 const TMatrixDSymEigen me(
m);
272 const auto& eigenval = me.GetEigenValues();
273 const auto& eigenvec = me.GetEigenVectors();
276 double maxeval = eigenval(0);
277 for (
int i=1; i<3; ++i) {
278 if (eigenval(i)>maxeval) {
280 maxeval = eigenval(i);
284 pcdir =
Vector_t(eigenvec(0, maxevalidx),eigenvec(1, maxevalidx),eigenvec(2, maxevalidx));
289 double TrajectoryMCSFitter::mcsLikelihood(
double p,
double theta0x, std::vector<float>& dthetaij, std::vector<float>& seg_nradl, std::vector<float>& cumLen,
bool fwd,
int pid)
const {
291 const int beg = (fwd ? 0 : (dthetaij.size()-1));
292 const int end = (fwd ? dthetaij.size() : -1);
293 const int incr = (fwd ? +1 : -1);
297 const double m =
mass(pid);
298 const double m2 = m*
m;
299 const double Etot = sqrt(p*p + m2);
302 double const fixedterm = 0.5 * std::log( 2.0 * M_PI );
304 for (
int i = beg; i !=
end; i+=incr ) {
310 const double Eij = GetE(Etot,cumLen[i],m);
314 result = std::numeric_limits<double>::max();
317 const double pij = sqrt(Eij2 - m2);
318 const double beta = sqrt( 1. - ((m2)/(pij*pij + m2)) );
319 constexpr
double HighlandSecondTerm = 0.038;
320 const double tH0 = ( HighlandFirstTerm(pij) / (pij*beta) ) * ( 1.0 + HighlandSecondTerm * std::log( seg_nradl[i] ) ) * sqrt( seg_nradl[i] );
321 const double rms = sqrt( 2.0*( tH0 * tH0 + theta0x * theta0x ) );
323 std::cout <<
" Error : RMS cannot be zero ! " << std::endl;
324 return std::numeric_limits<double>::max();
326 const double arg = dthetaij[i]/rms;
327 result += ( std::log( rms ) + 0.5 * arg * arg + fixedterm);
332 double TrajectoryMCSFitter::energyLossLandau(
const double mass2,
const double e2,
const double x)
const {
336 if (x<=0.)
return 0.;
337 constexpr
double Iinv2 = 1./(188.E-6*188.E-6);
338 constexpr
double matConst = 1.4*18./40.;
339 constexpr
double me = 0.511;
340 constexpr
double kappa = 0.307075;
341 constexpr
double j = 0.200;
343 const double beta2 = (e2-mass2)/e2;
344 const double gamma2 = 1./(1.0 - beta2);
345 const double epsilon = 0.5*kappa*x*matConst/beta2;
347 return 0.001*epsilon*( log(2.*me*beta2*gamma2*epsilon*Iinv2) + j - beta2 );
350 double TrajectoryMCSFitter::energyLossBetheBloch(
const double mass,
const double e2)
const {
352 constexpr
double Iinv = 1./188.E-6;
353 constexpr
double matConst = 1.4*18./40.;
354 constexpr
double me = 0.511;
355 constexpr
double kappa = 0.307075;
357 const double beta2 = (e2-mass*
mass)/e2;
358 const double gamma2 = 1./(1.0 - beta2);
359 const double massRatio = me/
mass;
360 const double argument = (2.*me*gamma2*beta2*Iinv) * std::sqrt(1+2*std::sqrt(gamma2)*massRatio + massRatio*massRatio);
362 double dedx = kappa*matConst/beta2;
364 if (mass==0.0)
return(0.0);
365 if (argument <=
exp(beta2)) {
368 dedx *= (log(argument)-beta2)*1.
E-3;
369 if (dedx<0.) dedx = 0.;
374 double TrajectoryMCSFitter::GetE(
const double initial_E,
const double length_travelled,
const double m)
const {
378 constexpr
double kcal = 0.002105;
379 return (initial_E - kcal*length_travelled);
383 const double step_size = length_travelled / nElossSteps_;
385 double current_E = initial_E;
386 const double m2 = m*
m;
388 for (
auto i = 0; i < nElossSteps_; ++i) {
390 double dedx = energyLossBetheBloch(m,current_E);
391 current_E -= (dedx * step_size);
394 current_E -= energyLossLandau(m2,current_E*current_E,step_size);
396 if ( current_E <= m ) {
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Utilities related to art service access.
process_name opflash particleana ie x
T DirectionAtPoint(unsigned int p) const
Direction at point p. Use e.g. as:
recob::tracking::Vector_t Vector_t
Helper class to compute the middle point in a point set.
size_t LastValidPoint() const
Returns the index of the last valid point in the trajectory.
bool isValid
Whether this ID points to a valid element.
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
void add(Point const &p)
Accumulates a point.
double Length(size_t startAt=0) const
Returns the approximate length of the trajectory.
A trajectory in space reconstructed from hits.
T LocationAtPoint(unsigned int p) const
Position at point p. Use e.g. as:
auto end(FixedBins< T, C > const &) noexcept
Utilities to extend the interface of geometry vectors.
The data type to uniquely identify a TPC.
auto norm(Vector const &v)
Return norm of the specified vector.
Class storing the result of the Maximum Likelihood fit of Multiple Coulomb Scattering angles between ...
geo::Point_t middlePoint() const
size_t FirstValidPoint() const
Returns the index of the first valid point in the trajectory.
static constexpr size_t InvalidIndex
Value returned on failed index queries.
size_t NextValidPoint(size_t index) const
Returns the index of the next valid point in the trajectory.
TPCID_t TPC
Index of the TPC within its cryostat.
Vector_t StartDirection() const
Returns the direction of the trajectory at the first point.
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
recob::tracking::Vector_t Vector_t
physics associatedGroupsWithLeft p1
art framework interface to geometry description
BEGIN_PROLOG could also be cout