Belle II Software  release-06-02-00
TOPTrack.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <top/reconstruction_cpp/TOPTrack.h>
10 #include <top/reconstruction_cpp/TOPRecoManager.h>
11 #include <top/geometry/TOPGeometryPar.h>
12 #include <framework/geometry/BFieldManager.h>
13 #include <framework/logging/Logger.h>
14 #include <mdst/dataobjects/Track.h>
15 #include <mdst/dataobjects/TrackFitResult.h>
16 #include <mdst/dataobjects/HitPatternCDC.h>
17 #include <tracking/dataobjects/ExtHit.h>
18 #include <top/dataobjects/TOPBarHit.h>
19 #include <top/dataobjects/TOPDigit.h>
20 #include <framework/datastore/StoreArray.h>
21 #include <cmath>
22 #include <vector>
23 #include <algorithm>
24 
25 namespace Belle2 {
30  namespace TOP {
31 
32  TOPTrack::TrackAngles::TrackAngles(const TVector3& dir):
33  cosTh(dir.Z()), sinTh(sqrt(1 - cosTh * cosTh)), cosFi(dir.X() / sinTh), sinFi(dir.Y() / sinTh)
34  {}
35 
36 
37  TOPTrack::TOPTrack(const Track& track, const std::string& digitsName, const Const::ChargedStable& chargedStable)
38  {
39  // find extrapolated track hit at TOP
40 
41  Const::EDetector myDetID = Const::EDetector::TOP;
42  const auto* geo = TOPGeometryPar::Instance()->getGeometry();
43  int numModules = geo->getNumModules();
44  int pdgCode = abs(chargedStable.getPDGCode());
45 
46  RelationVector<ExtHit> extHits = track.getRelationsWith<ExtHit>();
47  double tmin = 1e10; // some large time
48  for (const auto& extHit : extHits) {
49  if (abs(extHit.getPdgCode()) != pdgCode) continue;
50  if (extHit.getDetectorID() != myDetID) continue;
51  if (extHit.getCopyID() < 1 or extHit.getCopyID() > numModules) continue;
52  if (extHit.getTOF() < tmin) {
53  tmin = extHit.getTOF();
54  m_extHit = &extHit;
55  }
56  }
57  if (not m_extHit) return;
58 
59  // set the object
60 
61  set(track, digitsName, chargedStable);
62  }
63 
64 
65  TOPTrack::TOPTrack(const ExtHit* extHit, const std::string& digitsName)
66  {
67  if (not extHit) return;
68  m_extHit = extHit;
69 
70  const auto* track = extHit->getRelated<Track>();
71  if (not track) {
72  B2ERROR("TOPTrack: no related Track found for valid ExtHit");
73  return;
74  }
75 
76  auto chargedStable = Const::chargedStableSet.find(abs(extHit->getPdgCode()));
77  if (chargedStable == Const::invalidParticle) {
78  B2ERROR("TOPTrack: extrapolation hypothesis of ExtHit is not ChargedStable");
79  return;
80  }
81 
82  // set the object
83 
84  set(*track, digitsName, chargedStable);
85  }
86 
87 
88  void TOPTrack::set(const Track& track, const std::string& digitsName, const Const::ChargedStable& chargedStable)
89  {
90  // require fitResult
91 
92  const auto* fitResult = track.getTrackFitResultWithClosestMass(chargedStable);
93  if (not fitResult) {
94  B2ERROR("TOPTrack: no TrackFitResult available for PDGCode = " << chargedStable.getPDGCode());
95  return;
96  }
97  m_pT = fitResult->getTransverseMomentum();
98 
99  // require hits in CDC
100 
101  if (fitResult->getHitPatternCDC().getNHits() == 0) return;
102 
103  // set pointers
104 
105  m_track = &track;
106  m_mcParticle = track.getRelated<MCParticle>();
107  if (m_mcParticle) {
108  const auto barHits = m_mcParticle->getRelationsWith<TOPBarHit>();
109  for (const auto& barHit : barHits) {
110  if (barHit.getModuleID() == m_extHit->getCopyID()) m_barHit = &barHit;
111  }
112  }
113 
114  // set track parameters and helix
115 
117  m_momentum = m_extHit->getMomentum().Mag();
118  m_charge = fitResult->getChargeSign();
119  m_TOFLength = m_extHit->getTOF() * Const::speedOfLight * getBeta(chargedStable);
120  m_valid = setHelix(m_alignment->getRotation(m_moduleID), m_alignment->getTranslation(m_moduleID));
121  if (not m_valid) return;
122 
123  // selection of photon hits belonging to this track
124 
125  unsigned numHitsOtherSlots = 0;
126  StoreArray<TOPDigit> digits(digitsName);
127  for (const auto& digit : digits) {
128  if (digit.getHitQuality() != TOPDigit::c_Good) continue;
129  if (digit.getModuleID() == m_moduleID) {
130  m_selectedHits.push_back(SelectedHit(digit.getPixelID(), digit.getTime(), digit.getTimeError()));
131  } else {
132  numHitsOtherSlots++;
133  }
134  }
135 
136  // background rate estimation (TODO to be improved ...)
137 
138  const auto* geo = TOPGeometryPar::Instance()->getGeometry();
139  const auto& tdc = geo->getNominalTDC();
140  double timeWindow = m_feSetting->getReadoutWindows() * tdc.getSyncTimeBase() / TOPNominalTDC::c_syncWindows;
141 
142  const auto& backgroundPDFs = TOPRecoManager::getBackgroundPDFs();
143  unsigned k = m_moduleID - 1;
144  double effi = (k < backgroundPDFs.size()) ? backgroundPDFs[k].getEfficiency() : 0;
145  double effiSum = 0;
146  for (const auto& bkg : backgroundPDFs) effiSum += bkg.getEfficiency();
147  m_bkgRate = (effiSum > effi) ? numHitsOtherSlots * effi / (effiSum - effi) / timeWindow : 0;
148 
149  // selected photon hits mapped to pixel columns
150 
151  const auto* yScanner = TOPRecoManager::getYScanner(m_moduleID);
152  if (not yScanner) {
153  B2ERROR("TOPTrack: YScanner for given module not found (must be a bug!)" << LogVar("slot", m_moduleID));
154  m_valid = false;
155  return;
156  }
157  unsigned numCols = yScanner->getPixelPositions().getNumPixelColumns();
158  for (const auto& hit : m_selectedHits) {
159  unsigned col = (hit.pixelID - 1) % numCols;
160  m_columnHits.emplace(col, &hit);
161  }
162 
163  m_valid = effi > 0; // no sense to provide PID for the track if the module is fully inefficient
164  }
165 
166 
167  bool TOPTrack::setHelix(const TRotation& rotation, const TVector3& translation)
168  {
169  m_emissionPoints.clear();
170 
171  // helix in module nominal frame (z-axis still parallel to magnetic field)
172 
173  const auto* geo = TOPGeometryPar::Instance()->getGeometry();
174  const auto& module = geo->getModule(m_moduleID);
175  auto globalPosition = m_extHit->getPosition();
176  auto position = module.pointGlobalToNominal(globalPosition);
177  auto momentum = module.momentumGlobalToNominal(m_extHit->getMomentum());
178  double Bz = BFieldManager::getField(globalPosition).Z();
179  m_helix.set(position, momentum, m_charge, Bz);
180  m_helix.setTransformation(rotation, translation);
181 
182  // geometry data
183 
184  const RaytracerBase::BarSegment bar(module);
185  const RaytracerBase::Mirror mirror(module);
186 
187  // bar surfaces in module nominal frame
188 
189  std::vector<TVector3> points;
190  std::vector<TVector3> normals;
191  points.push_back(rotation * TVector3(0, -bar.B / 2, 0) + translation); // lower
192  normals.push_back(rotation * TVector3(0, -1, 0));
193 
194  points.push_back(rotation * TVector3(0, bar.B / 2, 0) + translation); // upper
195  normals.push_back(rotation * TVector3(0, 1, 0));
196 
197  points.push_back(rotation * TVector3(-bar.A / 2, 0, 0) + translation); // left side
198  normals.push_back(rotation * TVector3(-1, 0, 0));
199 
200  points.push_back(rotation * TVector3(bar.A / 2, 0, 0) + translation); // right side
201  normals.push_back(rotation * TVector3(1, 0, 0));
202 
203  // intersection with quartz bar
204 
205  std::vector<double> lengths; // w.r.t extHit position
206  std::vector<TVector3> positions; // in module local frame
207  for (size_t i = 0; i < 2; i++) {
208  double t = m_helix.getDistanceToPlane(points[i], normals[i]);
209  if (isnan(t)) return false;
210  auto r = m_helix.getPosition(t);
211  if (abs(r.X()) > bar.A / 2) {
212  auto k = (r.X() > 0) ? 3 : 2;
213  t = m_helix.getDistanceToPlane(points[k], normals[k]);
214  if (isnan(t)) return false;
215  r = m_helix.getPosition(t);
216  if (r.Z() >= bar.zL and abs(r.Y()) > bar.B / 2) return false;
217  }
218  lengths.push_back(t);
219  positions.push_back(r);
220  }
221 
222  // crossing prism?
223 
224  if (positions[0].Z() < bar.zL or positions[1].Z() < bar.zL) {
225  const RaytracerBase::Prism prism(module);
226  bool ok = xsecPrism(lengths, positions, prism, rotation, translation);
227  if (not ok) return false;
228  }
229 
230  // crossing mirror surface?
231 
232  std::vector<bool> outOfBar;
233  TVector3 rc(mirror.xc, mirror.yc, mirror.zc);
234  double Rsq = mirror.R * mirror.R;
235  for (const auto& r : positions) {
236  outOfBar.push_back((r - rc).Mag2() > Rsq);
237  }
238  if (outOfBar[0] and outOfBar[1]) return false;
239 
240  if (outOfBar[0] or outOfBar[1]) { // track crosses mirror surface, where?
241  if (outOfBar[0]) std::reverse(lengths.begin(), lengths.end());
242  double t1 = lengths[0];
243  double t2 = lengths[1];
244  for (int i = 0; i < 20; i++) {
245  double t = (t1 + t2) / 2;
246  auto r = m_helix.getPosition(t);
247  if ((r - rc).Mag2() > Rsq) {
248  t2 = t;
249  } else {
250  t1 = t;
251  }
252  }
253  lengths[1] = (t1 + t2) / 2;
254  }
255 
256  // set track length in quartz and full length from IP to the average emission point
257 
258  m_length = abs(lengths[1] - lengths[0]);
259  double length = (lengths[0] + lengths[1]) / 2;
260  m_trackLength = m_TOFLength + length;
261 
262  // finally move reference position to average emission point
263 
265 
266  return m_length > bar.B / 2; // require minimal track lenght inside quartz (more than half of bar thickness)
267  }
268 
269 
270  bool TOPTrack::xsecPrism(std::vector<double>& lengths, std::vector<TVector3>& positions,
271  const RaytracerBase::Prism& prism, const TRotation& rotation,
272  const TVector3& translation)
273  {
274  std::vector<TVector3> points;
275  std::vector<TVector3> normals;
276 
277  points.push_back(rotation * TVector3(0, prism.yDown, 0) + translation); // lower-most surface
278  normals.push_back(rotation * TVector3(0, -1, 0));
279 
280  points.push_back(rotation * TVector3(0, prism.yUp, 0) + translation); // upper surface
281  normals.push_back(rotation * TVector3(0, 1, 0));
282 
283  points.push_back(rotation * TVector3(-prism.A / 2, 0, 0) + translation); // left-side surface
284  normals.push_back(rotation * TVector3(-1, 0, 0));
285 
286  points.push_back(rotation * TVector3(prism.A / 2, 0, 0) + translation); // right-side surface
287  normals.push_back(rotation * TVector3(1, 0, 0));
288 
289  for (size_t i = 0; i < 2; i++) {
290  if (positions[i].Z() < prism.zR) {
291  double t = m_helix.getDistanceToPlane(points[i], normals[i]);
292  if (isnan(t)) return false;
293  auto r = m_helix.getPosition(t);
294  if (i == 0 and r.Z() > prism.zFlat) { // intersection with slanted surface -> find it using bisection
295  auto point = rotation * TVector3(0, -prism.B / 2, 0) + translation;
296  double t1 = m_helix.getDistanceToPlane(point, normals[0]);
297  if (isnan(t1)) return false;
298  double t2 = t;
299  for (int iter = 0; iter < 20; iter++) {
300  t = (t1 + t2) / 2;
301  r = m_helix.getPosition(t);
302  double ySlanted = prism.yDown + prism.slope * (r.Z() - prism.zFlat);
303  if (r.Y() < ySlanted) t2 = t;
304  else t1 = t;
305  }
306  t = (t1 + t2) / 2;
307  }
308  if (abs(r.X()) > prism.A / 2) { // intersection on the side surface
309  auto k = (r.X() > 0) ? 3 : 2;
310  t = m_helix.getDistanceToPlane(points[k], normals[k]);
311  if (isnan(t)) return false;
312  r = m_helix.getPosition(t);
313  if (r.Z() < prism.zR) { // yes, it's on the prism side
314  if (r.Y() > prism.yUp or r.Y() < prism.yDown) return false;
315  double ySlanted = prism.yDown + prism.slope * (r.Z() - prism.zFlat);
316  if (r.Y() < ySlanted) return false;
317  } else { // no, it's on the prism entrance but outside the bar exit window -> find it using bisection
318  double t1 = lengths[i];
319  double t2 = t;
320  for (int iter = 0; iter < 20; iter++) {
321  t = (t1 + t2) / 2;
322  r = m_helix.getPosition(t);
323  if (r.Z() < prism.zR) t1 = t;
324  else t2 = t;
325  }
326  t = (t1 + t2) / 2;
327  }
328  }
329  lengths[i] = t;
330  positions[i] = m_helix.getPosition(t);
331  }
332  }
333 
334  if (positions[0].Z() < prism.zL and positions[1].Z() < prism.zL) return false;
335 
336  if (positions[0].Z() < prism.zL or positions[1].Z() < prism.zL) { // intersection is on exit window
337  int i0 = (positions[0].Z() < prism.zL) ? 0 : 1;
338  double t1 = lengths[i0];
339  double t2 = lengths[(i0 + 1) % 2];
340  for (int iter = 0; iter < 20; iter++) {
341  double t = (t1 + t2) / 2;
342  auto r = m_helix.getPosition(t);
343  if (r.Z() < prism.zL) t1 = t;
344  else t2 = t;
345  }
346  double t = (t1 + t2) / 2;
347  lengths[i0] = t;
348  positions[i0] = m_helix.getPosition(t);
349  }
350 
351  return true;
352  }
353 
354 
356  {
357  if (m_emissionPoints.size() > 1000) m_emissionPoints.clear(); // prevent blow-up
358 
359  auto& emissionPoint = m_emissionPoints[dL];
360  if (not emissionPoint.isSet) {
361  emissionPoint.position = m_helix.getPosition(dL);
362  emissionPoint.trackAngles = TrackAngles(m_helix.getDirection(dL));
363  emissionPoint.isSet = true;
364  }
365  return emissionPoint;
366  }
367 
368  bool TOPTrack::isScanRequired(unsigned col, double time, double wid) const
369  {
370  const auto& tts = TOPGeometryPar::Instance()->getGeometry()->getTTS(0); // PMT independent TTS should be fine here
371  const auto& range = m_columnHits.equal_range(col);
372  for (auto it = range.first; it != range.second; ++it) {
373  const auto hit = it->second;
374  for (const auto& gaus : tts.getTTS()) {
375  double sigsq = wid + pow(gaus.sigma, 2) + pow(hit->timeErr, 2);
376  double x = pow(hit->time - time - gaus.position, 2) / sigsq;
377  if (x < 10) return true;
378  }
379  }
380 
381  return false;
382  }
383 
384 
385  } // end top namespace
387 } // end Belle2 namespace
388 
Provides a type-safe way to pass members of the chargedStableSet set.
Definition: Const.h:470
const ParticleType & find(int pdg) const
Returns particle in set with given PDG code, or invalidParticle if not found.
Definition: Const.h:452
int getPDGCode() const
PDG code.
Definition: Const.h:354
static const ParticleSet chargedStableSet
set of charged stable particles
Definition: Const.h:499
EDetector
Enum for identifying the detector components (detector and subdetector).
Definition: Const.h:42
static const double speedOfLight
[cm/ns]
Definition: Const.h:575
static const ParticleType invalidParticle
Invalid particle, used internally.
Definition: Const.h:561
Store one Ext hit as a ROOT object.
Definition: ExtHit.h:30
int getPdgCode() const
Get PDG code of this extrapolation's hypothesis.
Definition: ExtHit.h:116
TVector3 getMomentum() const
Get momentum at this extrapolation hit.
Definition: ExtHit.h:147
int getCopyID() const
Get detector-element ID of sensitive element within detector.
Definition: ExtHit.h:124
TVector3 getPosition() const
Get position of this extrapolation hit.
Definition: ExtHit.h:143
double getTOF() const
Get time of flight from the point of closest approach near the origin to this hit.
Definition: ExtHit.h:135
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:32
Class for type safe access to objects that are referred to in relations.
T * getRelated(const std::string &name="", const std::string &namedRelation="") const
Get the object to or from which this object has a relation.
RelationVector< T > getRelationsWith(const std::string &name="", const std::string &namedRelation="") const
Get the relations between this object and another store array.
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
Class to store track parameters of incoming MC particles relation to MCParticle filled in top/simulat...
Definition: TOPBarHit.h:26
unsigned getNumModules() const
Returns number of modules.
Definition: TOPGeometry.h:136
const TOPNominalTDC & getNominalTDC() const
Returns nominal time-to-digit conversion parameters.
Definition: TOPGeometry.h:218
@ c_syncWindows
number of windows corresponding to syncTimeBase
Definition: TOPNominalTDC.h:29
TVector3 getDirection(double length) const
Returns particle direction at given length.
Definition: HelixSwimmer.cc:79
TVector3 getPosition(double length) const
Returns particle position at given length.
Definition: HelixSwimmer.cc:67
void set(const TVector3 &position, const TVector3 &momentum, double charge, double Bz)
Sets the helix.
Definition: HelixSwimmer.cc:24
void moveReferencePosition(double length)
Moves reference position along helix by length.
Definition: HelixSwimmer.cc:55
double getDistanceToPlane(const TVector3 &point, const TVector3 &normal) const
Returns the distance along helix to the nearest intersection with a plane nearly parallel to z axis.
Definition: HelixSwimmer.cc:92
void setTransformation(const TRotation &rotation, const TVector3 &translation)
Sets transformation from the frame in which helix is constructed to module local frame.
Definition: HelixSwimmer.cc:49
const TOPGeometry * getGeometry() const
Returns pointer to geometry object using basf2 units.
static TOPGeometryPar * Instance()
Static method to obtain the pointer to its instance.
static const YScanner * getYScanner(int moduleID)
Returns y-scanner of a given module.
static const std::vector< BackgroundPDF > & getBackgroundPDFs()
Returns background PDF's of all modules.
bool setHelix(const TRotation &rotation, const TVector3 &translation)
Sets helix (helix is given in nominal frame)
Definition: TOPTrack.cc:167
double m_bkgRate
estimated background hit rate
Definition: TOPTrack.h:311
DBObjPtr< TOPFrontEndSetting > m_feSetting
front-end settings
Definition: TOPTrack.h:302
DBObjPtr< TOPCalModuleAlignment > m_alignment
module alignment constants
Definition: TOPTrack.h:301
bool isScanRequired(unsigned col, double time, double wid) const
Checks if scan method of YScanner is needed to construct PDF for a given pixel column.
Definition: TOPTrack.cc:368
const TOPTrack::AssumedEmission & getEmissionPoint(double dL=0) const
Returns assumed photon emission position and track direction.
Definition: TOPTrack.cc:355
std::unordered_multimap< unsigned, const SelectedHit * > m_columnHits
selected hits mapped to pixel columns
Definition: TOPTrack.h:312
TOPTrack()
Default constructor.
Definition: TOPTrack.h:103
int m_moduleID
slot ID
Definition: TOPTrack.h:293
double m_momentum
track momentum magnitude at TOP
Definition: TOPTrack.h:294
std::map< double, TOPTrack::AssumedEmission > m_emissionPoints
assumed emission points in module local frame
Definition: TOPTrack.h:315
bool m_valid
true for properly defined track
Definition: TOPTrack.h:308
double m_pT
transverse momentum at POCA
Definition: TOPTrack.h:295
double m_trackLength
trajectory length from IP to average photon emission point
Definition: TOPTrack.h:298
double m_charge
track charge in units of elementary charge
Definition: TOPTrack.h:296
std::vector< SelectedHit > m_selectedHits
selected photon hits from TOPDigits belonging to this slot ID
Definition: TOPTrack.h:310
const MCParticle * m_mcParticle
MC particle.
Definition: TOPTrack.h:306
bool xsecPrism(std::vector< double > &lengths, std::vector< TVector3 > &positions, const RaytracerBase::Prism &prism, const TRotation &rotation, const TVector3 &translation)
Calculates intersection of trajectory with prism.
Definition: TOPTrack.cc:270
TOP::HelixSwimmer m_helix
trajectory helix in nominal slot frame
Definition: TOPTrack.h:300
double m_length
trajectory length within quartz
Definition: TOPTrack.h:299
void set(const Track &track, const std::string &digitsName, const Const::ChargedStable &chargedStable)
Sets the object (called by constructors)
Definition: TOPTrack.cc:88
const ExtHit * m_extHit
extrapolated hit
Definition: TOPTrack.h:305
const Track * m_track
mdst track
Definition: TOPTrack.h:304
double getBeta(const Const::ChargedStable &particle, double overrideMass=0) const
Returns particle beta.
Definition: TOPTrack.h:320
double m_TOFLength
trajectory length corresponding to TOF of extrapolated hit
Definition: TOPTrack.h:297
const TOPBarHit * m_barHit
bar hit
Definition: TOPTrack.h:307
Class that bundles various TrackFitResults.
Definition: Track.h:25
Class to store variables with their name which were sent to the logging service.
static void getField(const double *pos, double *field)
return the magnetic field at a given position.
const TOPNominalTTS & getTTS(unsigned type) const
Returns time transition spread of a given PMT type.
Definition: TOPGeometry.cc:50
Abstract base class for different kinds of events.
bar segment data in module local frame.
Definition: RaytracerBase.h:49
double A
width (dimension in x)
Definition: RaytracerBase.h:50
double B
thickness (dimension in y)
Definition: RaytracerBase.h:51
spherical mirror data in module local frame.
Definition: RaytracerBase.h:79
double yc
center of curvature in y
Definition: RaytracerBase.h:81
double xc
center of curvature in x
Definition: RaytracerBase.h:80
double zc
center of curvature in z
Definition: RaytracerBase.h:82
prism data in module local frame.
double A
width (dimension in x)
double yDown
minimal y of exit window
double slope
slope of slanted surface (dy/dz)
double yUp
maximal y of exit window
double zFlat
z where flat continues to slanted surface
double zR
maximal z, i.e position of prism-bar joint
double B
thickness at bar (dimension in y)
assumed photon emission point in local frame
Definition: TOPTrack.h:75
selected photon hit from TOPDigits
Definition: TOPTrack.h:84
Sine and cosine of track polar and azimuthal angles at assumed photon emission.
Definition: TOPTrack.h:47
TrackAngles()
Default constructor.
Definition: TOPTrack.h:56