@@ -96,15 +96,19 @@ namespace {
9696
9797 class TrackSegments {
9898 public:
99- TrackSegments () = default ;
99+ TrackSegments () {
100+ sigmaTofs_.reserve (30 ); // observed upper limit on nSegments
101+ };
100102
101- inline uint32_t addSegment (float tPath, float tMom2) {
103+ inline uint32_t addSegment (float tPath, float tMom2, float sigmaMom ) {
102104 segmentPathOvc_.emplace_back (tPath * c_inv);
103105 segmentMom2_.emplace_back (tMom2);
106+ segmentSigmaMom_.emplace_back (sigmaMom);
104107 nSegment_++;
105108
106109 LogTrace (" TrackExtenderWithMTD" ) << " addSegment # " << nSegment_ << " s = " << tPath
107- << " p = " << std::sqrt (tMom2);
110+ << " p = " << std::sqrt (tMom2) << " sigma_p = " << sigmaMom
111+ << " sigma_p/p = " << sigmaMom / std::sqrt (tMom2) * 100 << " %" ;
108112
109113 return nSegment_;
110114 }
@@ -118,11 +122,49 @@ namespace {
118122
119123 LogTrace (" TrackExtenderWithMTD" ) << " TOF Segment # " << iSeg + 1 << " p = " << std::sqrt (segmentMom2_[iSeg])
120124 << " tof = " << tof;
125+
126+ #ifdef EDM_ML_DEBUG
127+ float sigma_tof = segmentPathOvc_[iSeg] * segmentSigmaMom_[iSeg] /
128+ (segmentMom2_[iSeg] * sqrt (segmentMom2_[iSeg] + 1 / mass_inv2) * mass_inv2);
129+
130+ LogTrace (" TrackExtenderWithMTD" ) << " TOF Segment # " << iSeg + 1 << std::fixed << std::setw (6 )
131+ << " tof segment = " << segmentPathOvc_[iSeg] / beta << std::scientific
132+ << " +/- " << sigma_tof << std::fixed
133+ << " (rel. err. = " << sigma_tof / (segmentPathOvc_[iSeg] / beta) * 100
134+ << " %)" ;
135+ #endif
121136 }
122137
123138 return tof;
124139 }
125140
141+ inline float computeSigmaTof (float mass_inv2) {
142+ float sigmatof = 0 .;
143+
144+ // remove previously calculated sigmaTofs
145+ sigmaTofs_.clear ();
146+
147+ // compute sigma(tof) on each segment first by propagating sigma(p)
148+ // also add diagonal terms to sigmatof
149+ float sigma = 0 .;
150+ for (uint32_t iSeg = 0 ; iSeg < nSegment_; iSeg++) {
151+ sigma = segmentPathOvc_[iSeg] * segmentSigmaMom_[iSeg] /
152+ (segmentMom2_[iSeg] * sqrt (segmentMom2_[iSeg] + 1 / mass_inv2) * mass_inv2);
153+ sigmaTofs_.push_back (sigma);
154+
155+ sigmatof += sigma * sigma;
156+ }
157+
158+ // compute sigma on sum of tofs assuming full correlation between segments
159+ for (uint32_t iSeg = 0 ; iSeg < nSegment_; iSeg++) {
160+ for (uint32_t jSeg = iSeg + 1 ; jSeg < nSegment_; jSeg++) {
161+ sigmatof += 2 * sigmaTofs_[iSeg] * sigmaTofs_[jSeg];
162+ }
163+ }
164+
165+ return sqrt (sigmatof);
166+ }
167+
126168 inline uint32_t size () const { return nSegment_; }
127169
128170 inline uint32_t removeFirstSegment () {
@@ -144,6 +186,9 @@ namespace {
144186 uint32_t nSegment_ = 0 ;
145187 std::vector<float > segmentPathOvc_;
146188 std::vector<float > segmentMom2_;
189+ std::vector<float > segmentSigmaMom_;
190+
191+ std::vector<float > sigmaTofs_;
147192 };
148193
149194 struct TrackTofPidInfo {
@@ -164,21 +209,25 @@ namespace {
164209 float gammasq_pi;
165210 float beta_pi;
166211 float dt_pi;
212+ float sigma_dt_pi;
167213
168214 float gammasq_k;
169215 float beta_k;
170216 float dt_k;
217+ float sigma_dt_k;
171218
172219 float gammasq_p;
173220 float beta_p;
174221 float dt_p;
222+ float sigma_dt_p;
175223
176224 float prob_pi;
177225 float prob_k;
178226 float prob_p;
179227 };
180228
181229 enum class TofCalc { kCost = 1 , kSegm = 2 , kMixd = 3 };
230+ enum class SigmaTofCalc { kCost = 1 , kSegm = 2 };
182231
183232 const TrackTofPidInfo computeTrackTofPidInfo (float magp2,
184233 float length,
@@ -188,7 +237,8 @@ namespace {
188237 float t_vtx,
189238 float t_vtx_err,
190239 bool addPIDError = true ,
191- TofCalc choice = TofCalc::kCost ) {
240+ TofCalc choice = TofCalc::kCost ,
241+ SigmaTofCalc sigma_choice = SigmaTofCalc::kCost ) {
192242 constexpr float m_pi = 0 .13957018f ;
193243 constexpr float m_pi_inv2 = 1 .0f / m_pi / m_pi;
194244 constexpr float m_k = 0 .493677f ;
@@ -218,17 +268,36 @@ namespace {
218268 return res;
219269 };
220270
271+ auto sigmadeltat = [&](const float mass_inv2) {
272+ float res (1 .f );
273+ switch (sigma_choice) {
274+ case SigmaTofCalc::kCost :
275+ // sigma(t) = sigma(p) * |dt/dp| = sigma(p) * DeltaL/c * m^2 / (p^2 * E)
276+ res = tofpid.pathlength * c_inv * trs.segmentSigmaMom_ [trs.nSegment_ - 1 ] /
277+ (magp2 * sqrt (magp2 + 1 / mass_inv2) * mass_inv2);
278+ break ;
279+ case SigmaTofCalc::kSegm :
280+ res = trs.computeSigmaTof (mass_inv2);
281+ break ;
282+ }
283+
284+ return res;
285+ };
286+
221287 tofpid.gammasq_pi = 1 .f + magp2 * m_pi_inv2;
222288 tofpid.beta_pi = std::sqrt (1 .f - 1 .f / tofpid.gammasq_pi );
223289 tofpid.dt_pi = deltat (m_pi_inv2, tofpid.beta_pi );
290+ tofpid.sigma_dt_pi = sigmadeltat (m_pi_inv2);
224291
225292 tofpid.gammasq_k = 1 .f + magp2 * m_k_inv2;
226293 tofpid.beta_k = std::sqrt (1 .f - 1 .f / tofpid.gammasq_k );
227294 tofpid.dt_k = deltat (m_k_inv2, tofpid.beta_k );
295+ tofpid.sigma_dt_k = sigmadeltat (m_k_inv2);
228296
229297 tofpid.gammasq_p = 1 .f + magp2 * m_p_inv2;
230298 tofpid.beta_p = std::sqrt (1 .f - 1 .f / tofpid.gammasq_p );
231299 tofpid.dt_p = deltat (m_p_inv2, tofpid.beta_p );
300+ tofpid.sigma_dt_p = sigmadeltat (m_p_inv2);
232301
233302 tofpid.dt = tofpid.tmtd - tofpid.dt_pi - t_vtx; // assume by default the pi hypothesis
234303 tofpid.dterror = sqrt (tofpid.tmtderror * tofpid.tmtderror + t_vtx_err * t_vtx_err);
@@ -323,7 +392,13 @@ namespace {
323392 validpropagation = false ;
324393 }
325394 pathlength1 += layerpathlength;
326- trs.addSegment (layerpathlength, (it + 1 )->updatedState ().globalMomentum ().mag2 ());
395+
396+ // sigma(p) from curvilinear error (on q/p)
397+ float sigma_p = sqrt ((it + 1 )->updatedState ().curvilinearError ().matrix ()(0 , 0 )) *
398+ (it + 1 )->updatedState ().globalMomentum ().mag2 ();
399+
400+ trs.addSegment (layerpathlength, (it + 1 )->updatedState ().globalMomentum ().mag2 (), sigma_p);
401+
327402 LogTrace (" TrackExtenderWithMTD" ) << " TSOS " << std::fixed << std::setw (4 ) << trs.size () << " R_i " << std::fixed
328403 << std::setw (14 ) << it->updatedState ().globalPosition ().perp () << " z_i "
329404 << std::fixed << std::setw (14 ) << it->updatedState ().globalPosition ().z ()
@@ -345,12 +420,19 @@ namespace {
345420 validpropagation = false ;
346421 }
347422 pathlength = pathlength1 + pathlength2;
348- trs.addSegment (pathlength2, tscblPCA.momentum ().mag2 ());
423+
424+ float sigma_p = sqrt (tscblPCA.curvilinearError ().matrix ()(0 , 0 )) * tscblPCA.momentum ().mag2 ();
425+
426+ trs.addSegment (pathlength2, tscblPCA.momentum ().mag2 (), sigma_p);
427+
349428 LogTrace (" TrackExtenderWithMTD" ) << " TSOS " << std::fixed << std::setw (4 ) << trs.size () << " R_e " << std::fixed
350429 << std::setw (14 ) << tscblPCA.position ().perp () << " z_e " << std::fixed
351430 << std::setw (14 ) << tscblPCA.position ().z () << " p " << std::fixed << std::setw (14 )
352431 << tscblPCA.momentum ().mag () << " dp " << std::fixed << std::setw (14 )
353- << tscblPCA.momentum ().mag () - oldp;
432+ << tscblPCA.momentum ().mag () - oldp << " sigma_p = " << std::fixed << std::setw (14 )
433+ << sigma_p << " sigma_p/p = " << std::fixed << std::setw (14 )
434+ << sigma_p / tscblPCA.momentum ().mag () * 100 << " %" ;
435+
354436 return validpropagation;
355437 }
356438
@@ -459,7 +541,10 @@ class TrackExtenderWithMTDT : public edm::stream::EDProducer<> {
459541 float & sigmatmtdOut,
460542 float & tofpi,
461543 float & tofk,
462- float & tofp) const ;
544+ float & tofp,
545+ float & sigmatofpi,
546+ float & sigmatofk,
547+ float & sigmatofp) const ;
463548 reco::TrackExtra buildTrackExtra (const Trajectory& trajectory) const ;
464549
465550 string dumpLayer (const DetLayer* layer) const ;
@@ -481,6 +566,9 @@ class TrackExtenderWithMTDT : public edm::stream::EDProducer<> {
481566 edm::EDPutToken tofpiOrigTrkToken_;
482567 edm::EDPutToken tofkOrigTrkToken_;
483568 edm::EDPutToken tofpOrigTrkToken_;
569+ edm::EDPutToken sigmatofpiOrigTrkToken_;
570+ edm::EDPutToken sigmatofkOrigTrkToken_;
571+ edm::EDPutToken sigmatofpOrigTrkToken_;
484572 edm::EDPutToken assocOrigTrkToken_;
485573
486574 edm::EDGetTokenT<InputCollection> tracksToken_;
@@ -569,6 +657,9 @@ TrackExtenderWithMTDT<TrackCollection>::TrackExtenderWithMTDT(const ParameterSet
569657 tofpiOrigTrkToken_ = produces<edm::ValueMap<float >>(" generalTrackTofPi" );
570658 tofkOrigTrkToken_ = produces<edm::ValueMap<float >>(" generalTrackTofK" );
571659 tofpOrigTrkToken_ = produces<edm::ValueMap<float >>(" generalTrackTofP" );
660+ sigmatofpiOrigTrkToken_ = produces<edm::ValueMap<float >>(" generalTrackSigmaTofPi" );
661+ sigmatofkOrigTrkToken_ = produces<edm::ValueMap<float >>(" generalTrackSigmaTofK" );
662+ sigmatofpOrigTrkToken_ = produces<edm::ValueMap<float >>(" generalTrackSigmaTofP" );
572663 assocOrigTrkToken_ = produces<edm::ValueMap<int >>(" generalTrackassoc" );
573664
574665 builderToken_ = esConsumes<TransientTrackBuilder, TransientTrackRecord>(edm::ESInputTag (" " , transientTrackBuilder_));
@@ -683,6 +774,9 @@ void TrackExtenderWithMTDT<TrackCollection>::produce(edm::Event& ev, const edm::
683774 std::vector<float > tofpiOrigTrkRaw;
684775 std::vector<float > tofkOrigTrkRaw;
685776 std::vector<float > tofpOrigTrkRaw;
777+ std::vector<float > sigmatofpiOrigTrkRaw;
778+ std::vector<float > sigmatofkOrigTrkRaw;
779+ std::vector<float > sigmatofpOrigTrkRaw;
686780 std::vector<int > assocOrigTrkRaw;
687781
688782 auto const tracksH = ev.getHandle (tracksToken_);
@@ -727,6 +821,9 @@ void TrackExtenderWithMTDT<TrackCollection>::produce(edm::Event& ev, const edm::
727821
728822 LogTrace (" TrackExtenderWithMTD" ) << " TrackExtenderWithMTD: extrapolating track " << itrack
729823 << " p/pT = " << track->p () << " " << track->pt () << " eta = " << track->eta ();
824+ LogTrace (" TrackExtenderWithMTD" ) << " TrackExtenderWithMTD: sigma_p = "
825+ << sqrt (track->covariance ()(0 , 0 )) * track->p2 ()
826+ << " sigma_p/p = " << sqrt (track->covariance ()(0 , 0 )) * track->p () * 100 << " %" ;
730827
731828 float trackVtxTime = 0 .f ;
732829 if (useVertex_) {
@@ -803,12 +900,14 @@ void TrackExtenderWithMTDT<TrackCollection>::produce(edm::Event& ev, const edm::
803900 const auto & trajwithmtd =
804901 mtdthits.empty () ? std::vector<Trajectory>(1 , trajs) : theTransformer->transform (ttrack, thits);
805902 float pMap = 0 .f , betaMap = 0 .f , t0Map = 0 .f , sigmat0Map = -1 .f , pathLengthMap = -1 .f , tmtdMap = 0 .f ,
806- sigmatmtdMap = -1 .f , tofpiMap = 0 .f , tofkMap = 0 .f , tofpMap = 0 .f ;
903+ sigmatmtdMap = -1 .f , tofpiMap = 0 .f , tofkMap = 0 .f , tofpMap = 0 .f , sigmatofpiMap = -1 .f , sigmatofkMap = -1 .f ,
904+ sigmatofpMap = -1 .f ;
807905 int iMap = -1 ;
808906
809907 for (const auto & trj : trajwithmtd) {
810908 const auto & thetrj = (updateTraj_ ? trj : trajs);
811- float pathLength = 0 .f , tmtd = 0 .f , sigmatmtd = -1 .f , tofpi = 0 .f , tofk = 0 .f , tofp = 0 .f ;
909+ float pathLength = 0 .f , tmtd = 0 .f , sigmatmtd = -1 .f , tofpi = 0 .f , tofk = 0 .f , tofp = 0 .f , sigmatofpi = -1 .f ,
910+ sigmatofk = -1 .f , sigmatofp = -1 .f ;
812911 LogTrace (" TrackExtenderWithMTD" ) << " TrackExtenderWithMTD: refit track " << itrack << " p/pT = " << track->p ()
813912 << " " << track->pt () << " eta = " << track->eta ();
814913 reco::Track result = buildTrack (track,
@@ -823,7 +922,10 @@ void TrackExtenderWithMTDT<TrackCollection>::produce(edm::Event& ev, const edm::
823922 sigmatmtd,
824923 tofpi,
825924 tofk,
826- tofp);
925+ tofp,
926+ sigmatofpi,
927+ sigmatofk,
928+ sigmatofp);
827929 if (result.ndof () >= 0 ) {
828930 // / setup the track extras
829931 reco::TrackExtra::TrajParams trajParams;
@@ -856,6 +958,9 @@ void TrackExtenderWithMTDT<TrackCollection>::produce(edm::Event& ev, const edm::
856958 tofpiMap = tofpi;
857959 tofkMap = tofk;
858960 tofpMap = tofp;
961+ sigmatofpiMap = sigmatofpi;
962+ sigmatofkMap = sigmatofk;
963+ sigmatofpMap = sigmatofp;
859964 reco::TrackExtraRef extraRef (extrasRefProd, extras->size () - 1 );
860965 backtrack.setExtra ((updateExtra_ ? extraRef : track->extra ()));
861966 for (unsigned ihit = hitsstart; ihit < hitsend; ++ihit) {
@@ -865,7 +970,12 @@ void TrackExtenderWithMTDT<TrackCollection>::produce(edm::Event& ev, const edm::
865970 npixEndcap.push_back (backtrack.hitPattern ().numberOfValidPixelEndcapHits ());
866971 LogTrace (" TrackExtenderWithMTD" ) << " TrackExtenderWithMTD: tmtd " << tmtdMap << " +/- " << sigmatmtdMap
867972 << " t0 " << t0Map << " +/- " << sigmat0Map << " tof pi/K/p " << tofpiMap
868- << " " << tofkMap << " " << tofpMap;
973+ << " +/-" << fmt::format (" {:0.2g}" , sigmatofpiMap) << " ("
974+ << fmt::format (" {:0.2g}" , sigmatofpiMap / tofpiMap * 100 ) << " %) " << tofkMap
975+ << " +/-" << fmt::format (" {:0.2g}" , sigmatofkMap) << " ("
976+ << fmt::format (" {:0.2g}" , sigmatofkMap / tofkMap * 100 ) << " %) " << tofpMap
977+ << " +/-" << fmt::format (" {:0.2g}" , sigmatofpMap) << " ("
978+ << fmt::format (" {:0.2g}" , sigmatofpMap / tofpMap * 100 ) << " %) " ;
869979 } else {
870980 LogTrace (" TrackExtenderWithMTD" ) << " Error in the MTD track refitting. This should not happen" ;
871981 }
@@ -881,6 +991,9 @@ void TrackExtenderWithMTDT<TrackCollection>::produce(edm::Event& ev, const edm::
881991 tofpiOrigTrkRaw.push_back (tofpiMap);
882992 tofkOrigTrkRaw.push_back (tofkMap);
883993 tofpOrigTrkRaw.push_back (tofpMap);
994+ sigmatofpiOrigTrkRaw.push_back (sigmatofpiMap);
995+ sigmatofkOrigTrkRaw.push_back (sigmatofkMap);
996+ sigmatofpOrigTrkRaw.push_back (sigmatofpMap);
884997 assocOrigTrkRaw.push_back (iMap);
885998
886999 if (iMap == -1 ) {
@@ -915,6 +1028,9 @@ void TrackExtenderWithMTDT<TrackCollection>::produce(edm::Event& ev, const edm::
9151028 fillValueMap (ev, tracksH, tofpiOrigTrkRaw, tofpiOrigTrkToken_);
9161029 fillValueMap (ev, tracksH, tofkOrigTrkRaw, tofkOrigTrkToken_);
9171030 fillValueMap (ev, tracksH, tofpOrigTrkRaw, tofpOrigTrkToken_);
1031+ fillValueMap (ev, tracksH, sigmatofpiOrigTrkRaw, sigmatofpiOrigTrkToken_);
1032+ fillValueMap (ev, tracksH, sigmatofkOrigTrkRaw, sigmatofkOrigTrkToken_);
1033+ fillValueMap (ev, tracksH, sigmatofpOrigTrkRaw, sigmatofpOrigTrkToken_);
9181034 fillValueMap (ev, tracksH, assocOrigTrkRaw, assocOrigTrkToken_);
9191035}
9201036
@@ -1176,7 +1292,10 @@ reco::Track TrackExtenderWithMTDT<TrackCollection>::buildTrack(const reco::Track
11761292 float & sigmatmtdOut,
11771293 float & tofpi,
11781294 float & tofk,
1179- float & tofp) const {
1295+ float & tofp,
1296+ float & sigmatofpi,
1297+ float & sigmatofk,
1298+ float & sigmatofp) const {
11801299 TrajectoryStateClosestToBeamLine tscbl;
11811300 bool tsbcl_status = getTrajectoryStateClosestToBeamLine (traj, bs, thePropagator, tscbl);
11821301
@@ -1307,8 +1426,9 @@ reco::Track TrackExtenderWithMTDT<TrackCollection>::buildTrack(const reco::Track
13071426
13081427 if (validmtd && validpropagation) {
13091428 // here add the PID uncertainty for later use in the 1st step of 4D vtx reconstruction
1310- TrackTofPidInfo tofInfo =
1311- computeTrackTofPidInfo (p.mag2 (), pathlength, trs, thit, thiterror, 0 .f , 0 .f , true , TofCalc::kSegm );
1429+ TrackTofPidInfo tofInfo = computeTrackTofPidInfo (
1430+ p.mag2 (), pathlength, trs, thit, thiterror, 0 .f , 0 .f , true , TofCalc::kSegm , SigmaTofCalc::kCost );
1431+
13121432 pathLengthOut = pathlength; // set path length if we've got a timing hit
13131433 tmtdOut = thit;
13141434 sigmatmtdOut = thiterror;
@@ -1319,6 +1439,9 @@ reco::Track TrackExtenderWithMTDT<TrackCollection>::buildTrack(const reco::Track
13191439 tofpi = tofInfo.dt_pi ;
13201440 tofk = tofInfo.dt_k ;
13211441 tofp = tofInfo.dt_p ;
1442+ sigmatofpi = tofInfo.sigma_dt_pi ;
1443+ sigmatofk = tofInfo.sigma_dt_k ;
1444+ sigmatofp = tofInfo.sigma_dt_p ;
13221445 }
13231446 }
13241447
@@ -1426,4 +1549,4 @@ string TrackExtenderWithMTDT<TrackCollection>::dumpLayer(const DetLayer* layer)
14261549#include " DataFormats/GsfTrackReco/interface/GsfTrackFwd.h"
14271550typedef TrackExtenderWithMTDT<reco::TrackCollection> TrackExtenderWithMTD;
14281551
1429- DEFINE_FWK_MODULE (TrackExtenderWithMTD);
1552+ DEFINE_FWK_MODULE (TrackExtenderWithMTD);
0 commit comments