All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
TOFUtils.cc
Go to the documentation of this file.
1 #include "TOFUtils.h"
2 
3 #include <cmath>
4 #include <algorithm>
5 #include <limits>
6 
7 #include "marlin/VerbosityLevels.h"
8 #include "marlinutil/CalorimeterHitType.h"
9 #include "HelixClass.h"
10 #include "DD4hep/Detector.h"
11 #include "DD4hep/DD4hepUnits.h"
12 #include "DDRec/DetectorData.h"
13 #include "CLHEP/Random/Randomize.h"
14 #include "CLHEP/Units/PhysicalConstants.h"
15 #include "TGraphErrors.h"
16 #include "TF1.h"
17 #include "MarlinTrk/MarlinTrkUtils.h"
18 #include "UTIL/LCRelationNavigator.h"
19 #include "UTIL/ILDConf.h"
20 #include "IMPL/TrackImpl.h"
21 
22 using std::vector;
23 using std::numeric_limits;
24 using std::pair;
25 using EVENT::TrackerHit;
26 using EVENT::Track;
27 using EVENT::Cluster;
28 using EVENT::CalorimeterHit;
29 using EVENT::TrackState;
30 using dd4hep::Detector;
31 using dd4hep::DetElement;
33 using dd4hep::rec::FixedPadSizeTPCData;
34 using MarlinTrk::IMarlinTrack;
35 using MarlinTrk::IMarlinTrkSystem;
36 using UTIL::LCRelationNavigator;
37 using UTIL::ILDDetID;
38 using IMPL::TrackImpl;
39 using IMPL::TrackStateImpl;
40 using CLHEP::RandGauss;
41 
42 bool TOFUtils::sortByRho(EVENT::TrackerHit* a, EVENT::TrackerHit* b){
43  Vector3D posA( a->getPosition() );
44  Vector3D posB( b->getPosition() );
45  return posA.rho() < posB.rho();
46 }
47 
48 
49 IMPL::TrackStateImpl TOFUtils::getTrackStateAtHit(MarlinTrk::IMarlinTrack* marlinTrk, EVENT::TrackerHit* hit){
50  TrackStateImpl ts;
51  double chi2Dummy;
52  int ndfDummy;
53  marlinTrk->getTrackState(hit, ts, chi2Dummy, ndfDummy);
54  return ts;
55 }
56 
57 
58 dd4hep::rec::Vector3D TOFUtils::getHelixMomAtTrackState(const EVENT::TrackState& ts, double bField){
59  double phi = ts.getPhi();
60  double d0 = ts.getD0();
61  double z0 = ts.getZ0();
62  double omega = ts.getOmega();
63  double tanL = ts.getTanLambda();
64 
65  HelixClass helix;
66  helix.Initialize_Canonical(phi, d0, z0, omega, tanL, bField);
67  return helix.getMomentum();
68 }
69 
70 
71 double TOFUtils::getHelixArcLength(const EVENT::TrackState& ts1, const EVENT::TrackState& ts2){
72  double omega = ts1.getOmega();
73  double z1 = ts1.getReferencePoint()[2] + ts1.getZ0();
74  double z2 = ts2.getReferencePoint()[2] + ts2.getZ0();
75  double dPhi = std::abs( ts2.getPhi() - ts1.getPhi() );
76  if (dPhi > M_PI) dPhi = 2*M_PI - dPhi;
77 
78  return std::sqrt( std::pow(dPhi/omega, 2) + std::pow(z2-z1, 2) );
79 }
80 
81 
82 double TOFUtils::getHelixLengthAlongZ(const EVENT::TrackState& ts1, const EVENT::TrackState& ts2){
83  double tanL = ts1.getTanLambda();
84  double z1 = ts1.getReferencePoint()[2] + ts1.getZ0();
85  double z2 = ts2.getReferencePoint()[2] + ts2.getZ0();
86 
87  return std::abs( (z2-z1)/tanL ) * std::sqrt( 1.+tanL*tanL );
88 }
89 
90 double TOFUtils::getHelixNRevolutions(const EVENT::TrackState& ts1, const EVENT::TrackState& ts2){
91  double omega = ts1.getOmega();
92  double tanL = ts1.getTanLambda();
93  double z1 = ts1.getReferencePoint()[2] + ts1.getZ0();
94  double z2 = ts2.getReferencePoint()[2] + ts2.getZ0();
95 
96  // helix length projected on xy
97  double circHelix = std::abs( (z2-z1)/tanL );
98  double circFull = 2*M_PI/std::abs(omega);
99 
100  return circHelix/circFull;
101 }
102 
103 
105  auto& detector = Detector::getInstance();
106  DetElement tpcDet = detector.detector("TPC");
107  FixedPadSizeTPCData* tpc = tpcDet.extension <FixedPadSizeTPCData>();
108  return tpc->rMaxReadout/dd4hep::mm;
109 }
110 
111 
112 EVENT::TrackerHit* TOFUtils::getSETHit(EVENT::Track* track, double tpcOuterR){
113  vector<TrackerHit*> hits = track->getTrackerHits();
114  TrackerHit* lastHit = hits.back();
115  Vector3D pos (lastHit->getPosition());
116 
117  if ( pos.rho() > tpcOuterR ) return lastHit;
118  return nullptr;
119 }
120 
121 
122 std::vector<EVENT::CalorimeterHit*> TOFUtils::selectFrankEcalHits( EVENT::Cluster* cluster, EVENT::Track* track, int maxEcalLayer, double bField ){
123  const TrackState* tsEcal = track->getTrackState(TrackState::AtCalorimeter);
124  Vector3D trackPosAtEcal ( tsEcal->getReferencePoint() );
125  Vector3D trackMomAtEcal = TOFUtils::getHelixMomAtTrackState(*tsEcal, bField);
126 
127  vector<CalorimeterHit*> selectedHits(maxEcalLayer, nullptr);
128  vector<double> minDistances(maxEcalLayer, numeric_limits<double>::max());
129 
130  for ( auto hit : cluster->getCalorimeterHits() ){
131  CHT hitType( hit->getType() );
132  bool isECALHit = ( hitType.caloID() == CHT::ecal );
133  int layer = hitType.layer();
134  if ( (!isECALHit) || ( layer >= maxEcalLayer) ) continue;
135 
136  Vector3D hitPos( hit->getPosition() );
137  double dToLine = (hitPos - trackPosAtEcal).cross(trackMomAtEcal.unit()).r();
138  if ( dToLine < minDistances[layer] ){
139  minDistances[layer] = dToLine;
140  selectedHits[layer] = hit;
141  }
142  }
143  selectedHits.erase( std::remove_if( selectedHits.begin(), selectedHits.end(), [](CalorimeterHit* h) { return h == nullptr; } ), selectedHits.end() );
144 
145  return selectedHits;
146 }
147 
148 
149 std::vector<EVENT::Track*> TOFUtils::getSubTracks(EVENT::Track* track){
150  vector<Track*> subTracks;
151  subTracks.push_back(track);
152 
153  int nSubTracks = track->getTracks().size();
154  if (nSubTracks <= 1) return subTracks;
155 
156  int nTPCHits = track->getSubdetectorHitNumbers()[(ILDDetID::TPC)*2-1];
157  int nSubTrack0Hits = track->getTracks()[0]->getTrackerHits().size();
158  int nSubTrack1Hits = track->getTracks()[1]->getTrackerHits().size();
159 
160  //OPTIMIZE: this is not reliable, but I don't see any other way at the moment.
161  //Read documentation in the header file for details.
162  int startIdx;
163  if( std::abs(nTPCHits - nSubTrack0Hits) <= 1 ) startIdx = 1;
164  else if ( std::abs(nTPCHits - nSubTrack1Hits) <= 1 ) startIdx = 2;
165  else{
166  //FIXME: This happens very rarily (0.01%) for unknown reasons, so we just, skip adding subTracks...
167  streamlog_out(WARNING)<<"Can't understand which subTrack is responsible for the first TPC hits! Skip adding subTracks."<<std::endl;
168  return subTracks;
169  }
170  for(int j=startIdx; j < nSubTracks; ++j) subTracks.push_back( track->getTracks()[j] );
171  return subTracks;
172 }
173 
174 
175 std::vector<IMPL::TrackStateImpl> TOFUtils::getTrackStatesPerHit(std::vector<EVENT::Track*> tracks, MarlinTrk::IMarlinTrkSystem* trkSystem, bool extrapolateToEcal, double bField){
176  vector<TrackStateImpl> trackStatesPerHit;
177  int nTracks = tracks.size();
178  for(int i=0; i<nTracks; ++i){
179  Track* track = tracks[i];
180  vector <TrackerHit*> hits = track->getTrackerHits();
181  std::sort(hits.begin(), hits.end(), sortByRho);
182 
183  // setup initial dummy covariance matrix
184  vector<float> covMatrix(15);
185  // initialize variances
186  covMatrix[0] = 1e+06; //sigma_d0^2
187  covMatrix[2] = 100.; //sigma_phi0^2
188  covMatrix[5] = 0.00001; //sigma_omega^2
189  covMatrix[9] = 1e+06; //sigma_z0^2
190  covMatrix[14] = 100.; //sigma_tanl^2
191  double maxChi2PerHit = 100.;
192  std::unique_ptr<IMarlinTrack> marlinTrk( trkSystem->createTrack() );
193  TrackImpl refittedTrack;
194 
195  //Need to initialize trackState at last hit
196  TrackStateImpl preFit = *track->getTrackState(TrackState::AtLastHit);
197  preFit.setCovMatrix( covMatrix );
198  int errorFit = MarlinTrk::createFinalisedLCIOTrack(marlinTrk.get(), hits, &refittedTrack, IMarlinTrack::backward, &preFit, bField, maxChi2PerHit);
199  //if fit fails, try also fit forward
200  if (errorFit != 0){
201  streamlog_out(DEBUG8)<<"Fit backward fails! Trying to fit forward for "<<i+1<<" subTrack in this PFO!"<<std::endl;
202 
203  marlinTrk.reset( trkSystem->createTrack() );
204  errorFit = MarlinTrk::createFinalisedLCIOTrack(marlinTrk.get(), hits, &refittedTrack, IMarlinTrack::forward, &preFit, bField, maxChi2PerHit);
205  }
206  if (errorFit != 0){
207  streamlog_out(WARNING)<<"Fit fails in both directions. Skipping "<<i+1<<" subTrack in this PFO!"<<std::endl;
208  continue;
209  }
210  //here hits are sorted by rho=(x^2+y^2) in the fit direction. forward - increasing rho, backward - decreasing rho
211  vector< pair<TrackerHit*, double> > hitsInFit;
212  marlinTrk->getHitsInFit(hitsInFit);
213 
214  //Find which way to loop over the array of hits. We need to loop in the direction of the track.
215  bool loopForward = true;
216  double zFirst = std::abs( hitsInFit.front().first->getPosition()[2] );
217  double zLast = std::abs( hitsInFit.back().first->getPosition()[2] );
218 
219  // OPTIMIZE: 10 mm is just a round number. With very small z difference it is more robust to use rho, to be sure z difference is not caused by tpc Z resolution or multiple scattering
220  if ( std::abs(zLast - zFirst) > 10. ){
221  if ( zLast < zFirst ) loopForward = false;
222  streamlog_out(DEBUG8)<<"Using Z to define loop direction over subTrack hits."<<std::endl;
223  streamlog_out(DEBUG8)<<"subTrack "<<i+1<<" zFirst: "<<hitsInFit.front().first->getPosition()[2]<<" zLast: "<<hitsInFit.back().first->getPosition()[2]<<" loop forward: "<<loopForward<<std::endl;
224  }
225  else{
226  double rhoFirst = std::hypot( hitsInFit.front().first->getPosition()[0], hitsInFit.front().first->getPosition()[1] );
227  double rhoLast = std::hypot( hitsInFit.back().first->getPosition()[0], hitsInFit.back().first->getPosition()[1] );
228  if ( rhoLast < rhoFirst ) loopForward = false;
229  streamlog_out(DEBUG8)<<"Track is very perpendicular (dz < 10 mm). Using rho to define loop direction over subTrack hits."<<std::endl;
230  streamlog_out(DEBUG8)<<"subTrack "<<i+1<<" zFirst: "<<hitsInFit.front().first->getPosition()[2]<<" zLast: "<<hitsInFit.back().first->getPosition()[2]<<std::endl;
231  streamlog_out(DEBUG8)<<"subTrack "<<i+1<<" rhoFirst: "<<rhoFirst<<" rhoLast: "<<rhoLast<<" loop forward: "<<loopForward<<std::endl;
232  }
233 
234  int nHitsInFit = hitsInFit.size();
235  // if first successfully fitted subTrack add IP track state
236  if ( trackStatesPerHit.empty() ) trackStatesPerHit.push_back(*(static_cast<const TrackStateImpl*> (refittedTrack.getTrackState(TrackState::AtIP)) ));
237 
238  // NOTE: although we use z to understand track direction, hits are still sorted by rho
239  if (loopForward){
240  for( int j=0; j<nHitsInFit; ++j ){
241  TrackStateImpl ts = getTrackStateAtHit(marlinTrk.get(), hitsInFit[j].first);
242  trackStatesPerHit.push_back(ts);
243  }
244  }
245  else{
246  for( int j=nHitsInFit-1; j>=0; --j ){
247  TrackStateImpl ts = getTrackStateAtHit(marlinTrk.get(), hitsInFit[j].first);
248  trackStatesPerHit.push_back(ts);
249  }
250  }
251 
252  if (i == nTracks - 1){
253  // SET hit is not present in hitsInFit as it is composite hit from strips
254  // Add ts at the SET hit manualy which fitter returns with reffited track
255  // If LastHit != SET hit, then we duplicate previous track state at last TPC hit
256  // isn't pretty, but shouldn't affect the track length
257  trackStatesPerHit.push_back( *(static_cast<const TrackStateImpl*> (refittedTrack.getTrackState(TrackState::AtLastHit)) ) );
258  if (extrapolateToEcal) trackStatesPerHit.push_back( *(static_cast<const TrackStateImpl*> (refittedTrack.getTrackState(TrackState::AtCalorimeter) ) ) );
259  }
260  }
261  // one can maybe use hits of refittedTrack, but they include also hits that had failed in the fit
262  // code would look cleaner, but using hits that are failed in fit probably would have worse performance..
263  // needs to be checked.
264  return trackStatesPerHit;
265 }
266 
267 
268 double TOFUtils::getTofClosest( EVENT::Cluster* cluster, EVENT::Track* track, double timeResolution){
269  const TrackState* tsEcal = track->getTrackState(TrackState::AtCalorimeter);
270  Vector3D trackPosAtEcal ( tsEcal->getReferencePoint() );
271 
272  double hitTime = numeric_limits<double>::max();
273  double closestDistance = numeric_limits<double>::max();
274  for( auto hit : cluster->getCalorimeterHits() ){
275  CHT hitType( hit->getType() );
276  bool isECALHit = ( hitType.caloID() == CHT::ecal );
277  if (! isECALHit) continue;
278 
279  Vector3D hitPos( hit->getPosition() );
280  double dToTrack = (hitPos - trackPosAtEcal).r();
281  if( dToTrack < closestDistance ){
282  closestDistance = dToTrack;
283  hitTime = hit->getTime();
284  }
285  }
286 
287  if ( hitTime == numeric_limits<double>::max() ) return 0.;
288  return RandGauss::shoot(hitTime, timeResolution) - closestDistance/CLHEP::c_light;
289 }
290 
291 
292 double TOFUtils::getTofFrankAvg( std::vector<EVENT::CalorimeterHit*> selectedHits, EVENT::Track* track, double timeResolution){
293  const TrackState* tsEcal = track->getTrackState(TrackState::AtCalorimeter);
294  Vector3D trackPosAtEcal ( tsEcal->getReferencePoint() );
295 
296  int nHits = selectedHits.size();
297  if (nHits == 0) return 0.;
298 
299  double tof = 0.;
300  for ( auto hit : selectedHits ){
301  Vector3D hitPos( hit->getPosition() );
302  double dToTrack = (hitPos - trackPosAtEcal).r();
303  tof += RandGauss::shoot(hit->getTime(), timeResolution) - dToTrack/CLHEP::c_light;
304  }
305  return tof/nHits;
306 }
307 
308 
309 double TOFUtils::getTofFrankFit( std::vector<EVENT::CalorimeterHit*> selectedHits, EVENT::Track* track, double timeResolution){
310  const TrackState* tsEcal = track->getTrackState(TrackState::AtCalorimeter);
311  Vector3D trackPosAtEcal ( tsEcal->getReferencePoint() );
312 
313  int nHits = selectedHits.size();
314  if (nHits == 0) return 0.;
315  else if (nHits == 1){
316  //we can't fit 1 point, but lets return something reasonable
317  Vector3D hitPos( selectedHits[0]->getPosition() );
318  double dToTrack = (hitPos - trackPosAtEcal).r();
319  return RandGauss::shoot(selectedHits[0]->getTime(), timeResolution) - dToTrack/CLHEP::c_light;
320  }
321 
322  vector <double> x, y;
323  for ( auto hit : selectedHits ){
324  Vector3D hitPos( hit->getPosition() );
325  double dToTrack = (hitPos - trackPosAtEcal).r();
326  x.push_back(dToTrack);
327  double time = RandGauss::shoot(hit->getTime(), timeResolution);
328  y.push_back(time);
329  }
330 
331  TGraph gr(nHits, x.data(), y.data());
332  gr.Fit("pol1", "Q");
333  return gr.GetFunction("pol1")->GetParameter(0);
334 }
static const float mm
double getHelixLengthAlongZ(const EVENT::TrackState &ts1, const EVENT::TrackState &ts2)
Get track length.
Definition: TOFUtils.cc:82
double getTofFrankAvg(std::vector< EVENT::CalorimeterHit * > selectedHits, EVENT::Track *track, double timeResolution)
Get the time-of-flight using average of the Frank ECal hits.
Definition: TOFUtils.cc:292
double getTofClosest(EVENT::Cluster *cluster, EVENT::Track *track, double timeResolution)
Get the time-of-flight using the closest ECal hit.
Definition: TOFUtils.cc:268
double getHelixNRevolutions(const EVENT::TrackState &ts1, const EVENT::TrackState &ts2)
Get number of helix revolutions.
Definition: TOFUtils.cc:90
CLHEP::Hep3Vector Vector3D
EVENT::TrackerHit * getSETHit(EVENT::Track *track, double tpcOuterR)
Returns SET hit.
Definition: TOFUtils.cc:112
double getTPCOuterR()
Returns TPC outer radius from the DD4hep detector geometry.
Definition: TOFUtils.cc:104
Real hypot(const Real &a, const Real &b)
std::vector< IMPL::TrackStateImpl > getTrackStatesPerHit(std::vector< EVENT::Track * > tracks, MarlinTrk::IMarlinTrkSystem *trkSystem, bool extrapolateToEcal, double bField)
Get list of track states.
Definition: TOFUtils.cc:175
static const float e
double getTofFrankFit(std::vector< EVENT::CalorimeterHit * > selectedHits, EVENT::Track *track, double timeResolution)
Get the time-of-flight using fit of the Frank ECal hits.
Definition: TOFUtils.cc:309
std::vector< EVENT::CalorimeterHit * > selectFrankEcalHits(EVENT::Cluster *cluster, EVENT::Track *track, int maxEcalLayer, double bField)
Get a subset of the cluster calorimeter hits.
Definition: TOFUtils.cc:122
double getHelixArcLength(const EVENT::TrackState &ts1, const EVENT::TrackState &ts2)
Get track length.
Definition: TOFUtils.cc:71
std::vector< EVENT::Track * > getSubTracks(EVENT::Track *track)
Get all subtracks of the Track.
Definition: TOFUtils.cc:149
bool sortByRho(EVENT::TrackerHit *a, EVENT::TrackerHit *b)
Comparator function by radius for tracker hits.
Definition: TOFUtils.cc:42
IMPL::TrackStateImpl getTrackStateAtHit(MarlinTrk::IMarlinTrack *marlinTrk, EVENT::TrackerHit *hit)
Get track state at tracker hit.
Definition: TOFUtils.cc:49
dd4hep::rec::Vector3D getHelixMomAtTrackState(const EVENT::TrackState &ts, double bField)
Get track momentum at the track state.
Definition: TOFUtils.cc:58