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