Belle II Software development
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
25using namespace std;
26using namespace ROOT::Math;
27
28namespace 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:589
const ParticleType & find(int pdg) const
Returns particle in set with given PDG code, or invalidParticle if not found.
Definition: Const.h:571
int getPDGCode() const
PDG code.
Definition: Const.h:473
static const ParticleSet chargedStableSet
set of charged stable particles
Definition: Const.h:618
EDetector
Enum for identifying the detector components (detector and subdetector).
Definition: Const.h:42
static const double speedOfLight
[cm/ns]
Definition: Const.h:695
static const ParticleType invalidParticle
Invalid particle, used internally.
Definition: Const.h:681
Store one Ext hit as a ROOT object.
Definition: ExtHit.h:31
int getPdgCode() const
Get PDG code of this extrapolation's hypothesis.
Definition: ExtHit.h:117
int getCopyID() const
Get detector-element ID of sensitive element within detector.
Definition: ExtHit.h:125
ROOT::Math::XYZVector getMomentum() const
Get momentum at this extrapolation hit.
Definition: ExtHit.h:151
ROOT::Math::XYZVector getPosition() const
Get position of this extrapolation hit.
Definition: ExtHit.h:144
double getTOF() const
Get time of flight from the point of closest approach near the origin to this hit.
Definition: ExtHit.h:136
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:27
const TOPNominalTDC & getNominalTDC() const
Returns nominal time-to-digit conversion parameters.
Definition: TOPGeometry.h:218
unsigned getNumModules() const
Returns number of modules.
Definition: TOPGeometry.h:136
@ 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 std::vector< BackgroundPDF > & getBackgroundPDFs()
Returns background PDF's of all modules.
static const YScanner * getYScanner(int moduleID)
Returns y-scanner of a given module.
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.
STL namespace.
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
TrackAngles()
Default constructor.
Definition: TOPTrack.h:55