LDMX Software
TrackingUtils.h
1#ifndef TRACKUTILS_H_
2#define TRACKUTILS_H_
3
4// TODO:: MAKE A CXX!!
5
6// Recoil back layers numbering scheme for module
7
8// +Y /\ 4 3 2 1 0
9// |
10// |
11// -Y \/ 9 8 7 6 5
12// -X <---- ----> +X
13
14// ModN (x, y, z)
15// 0 (96, 40, z2)
16// 1 (48, 40, z1)
17// 2 (0, 40, z2)
18// 3 (-48, 40, z1)
19// 4 (-96, 40, z2)
20
21// 5 (96, -40, z2)
22// 6 (48, -40, z1)
23// 7 (0, -40, z2)
24// 8 (-48, -40, z1)
25// 9 (-96, -40, z2)
26
27// ---< SimCore >---//
29#include "Tracking/Sim/LdmxSpacePoint.h"
30
31// --- Tracking ---//
32#include "Tracking/Event/Track.h"
33
34// --- < ACTS > --- //
35#include "Acts/Definitions/Algebra.hpp"
36#include "Acts/Definitions/PdgParticle.hpp"
37#include "Acts/Definitions/TrackParametrization.hpp"
38#include "Acts/Definitions/Units.hpp"
39#include "Acts/EventData/TrackParameters.hpp"
40#include "Acts/Surfaces/PerigeeSurface.hpp"
41#include "Acts/Surfaces/PlaneSurface.hpp"
42#include "Tracking/Event/Measurement.h"
43#include "Tracking/Sim/IndexSourceLink.h"
44
45namespace tracking {
46namespace sim {
47namespace utils {
48
49/*
50 It looks like the recoil is subdetector ID 4 and tagger is subdetector ID 1
51https://github.com/LDMX-Software/ldmx-sw/blob/0476ccc407e068560518e0614aa83b6eda22e186/DetDescr/include/DetDescr/DetectorID.h#L11-L24
52So you could bit shift and mask to get these numbers
53https://github.com/LDMX-Software/ldmx-sw/blob/0476ccc407e068560518e0614aa83b6eda22e186/DetDescr/include/DetDescr/DetectorID.h#L38-L39
54(sim_tracker_hit.getID() >> 26)&0x3f
55or if you are in ldmx-sw, it is easier, more robust, and just as performant to
56wrap the ID in the helper class and use its accessors sd =
57TrackerID(sim_tracker_hit.getID()).subdet(); if (sd ==
58SubdetectorID::SD_TRACKER_RECOIL) {
59 // hit in recoil
60} else if (sd == SubdetectorID::SD_TRACKER_TAGGER) {
61 // hit in tagger
62} else {
63 // this should never happen since the TrackerID constructor checks for
64mal-formed IDs
65}
66*/
67
68// This method returns the sensor ID
69inline int getSensorID(const ldmx::SimTrackerHit& hit) {
70 bool debug = false;
71
72 int vol = 2;
73
74 // TODO!! FIX THIS HARDCODE!
75 if (hit.getPosition()[2] > 0) vol = 3;
76
77 unsigned int sensorId = 0;
78 unsigned int layerId = 0;
79
80 // tagger numbering scheme for surfaces mapping
81 // Layers from 1 to 14 => transform to 0->13
82 if (vol == 2) {
83 sensorId = (hit.getLayerID() + 1) % 2; // 0,1,0,1 ...
84
85 // v12
86 // layerId = (hit.getLayerID() + 1) / 2; //1,2,3,4,5,6,7
87 // v14
88 layerId = 7 - ((hit.getLayerID() - 1) / 2);
89 }
90
91 // recoil numbering scheme for surfaces mapping
92 if (vol == 3) {
93 // For axial-stereo modules use the same numbering scheme as the tagger
94 if (hit.getLayerID() < 9) {
95 sensorId = (hit.getLayerID() + 1) % 2;
96 layerId = (hit.getLayerID() + 1) / 2;
97 }
98
99 // For the axial only modules
100 else {
101 sensorId = hit.getModuleID();
102 layerId = (hit.getLayerID() + 2) / 2; // 9->11 /2 = 5 10->12 / 2 = 6
103 }
104 }
105
106 // vol * 1000 + ly * 100 + sensor
107 unsigned int index = vol * 1000 + layerId * 100 + sensorId;
108
109 if (debug) {
110 std::cout << "LdmxSpacePointConverter::Check index::" << vol << "--"
111 << layerId << "--" << sensorId << "==>" << index << std::endl;
112 std::cout << vol << "===" << hit.getLayerID() << "===" << hit.getModuleID()
113 << std::endl;
114 }
115
116 return index;
117}
118
119// This method converts a SimHit in a LdmxSpacePoint for the Acts seeder.
120// (1) Rotate the coordinates into acts::seedFinder coordinates defined by
121// B-Field along z axis [Z_ldmx -> X_acts, X_ldmx->Y_acts, Y_ldmx->Z_acts] (2)
122// Saves the error information. At the moment the errors are fixed. They should
123// be obtained from the digitized hits.
124
125// TODO::Move to shared pointers?!
126// TODO::Pass to instances?
127// Vol==2 for tagger, Vol==3 for recoil
128
129inline ldmx::LdmxSpacePoint* convertSimHitToLdmxSpacePoint(
130 const ldmx::SimTrackerHit& hit, unsigned int vol = 2, double sigma_u = 0.05,
131 double sigma_v = 1.) {
132 unsigned int index = getSensorID(hit);
133
134 // Rotate position
135 float ldmxsp_x = hit.getPosition()[2];
136 float ldmxsp_y = hit.getPosition()[0];
137 float ldmxsp_z = hit.getPosition()[1];
138
139 return new ldmx::LdmxSpacePoint(ldmxsp_x, ldmxsp_y, ldmxsp_z, hit.getTime(),
140 index, hit.getEdep(), sigma_u * sigma_u,
141 sigma_v * sigma_v, hit.getID());
142}
143
144// BoundSymMatrix doesn't exist in v36 .. use BoundSquareMatrix
145// have to change this everywhere .. I think using BoundSysMatrix was defined
146// exactly the same as BoundSquareMatrix is now in ACTs
147inline void flatCov(Acts::BoundSquareMatrix cov, std::vector<double>& v_cov) {
148 v_cov.clear();
149 v_cov.reserve(cov.rows() * (cov.rows() + 1) / 2);
150 for (int i = 0; i < cov.rows(); i++)
151 for (int j = i; j < cov.cols(); j++) v_cov.push_back(cov(i, j));
152}
153
154inline Acts::BoundSquareMatrix unpackCov(const std::vector<double>& v_cov) {
155 Acts::BoundSquareMatrix cov;
156 int e{0};
157 for (int i = 0; i < cov.rows(); i++)
158 for (int j = i; j < cov.cols(); j++) {
159 cov(i, j) = v_cov.at(e);
160 cov(j, i) = cov(i, j);
161 e++;
162 }
163
164 return cov;
165}
166
167// Rotate to ACTS frame
168// z->x, x->y, y->z
169
170//(0 0 1) x = z
171//(1 0 0) y = x
172//(0 1 0) z = y
173
174inline Acts::Vector3 Ldmx2Acts(Acts::Vector3 ldmx_v) {
175 // TODO::Move it to a static member
176 Acts::SquareMatrix3 acts_rot;
177 acts_rot << 0., 0., 1., 1., 0., 0., 0., 1, 0.;
178
179 return acts_rot * ldmx_v;
180}
181
182// Transform position, momentum and charge to free parameters
183
184inline Acts::FreeVector toFreeParameters(Acts::Vector3 pos, Acts::Vector3 mom,
185 Acts::ActsScalar q) {
186 Acts::FreeVector free_params;
187 Acts::ActsScalar p = mom.norm() * Acts::UnitConstants::MeV;
188
189 free_params[Acts::eFreePos0] = pos(Acts::ePos0) * Acts::UnitConstants::mm;
190 free_params[Acts::eFreePos1] = pos(Acts::ePos1) * Acts::UnitConstants::mm;
191 free_params[Acts::eFreePos2] = pos(Acts::ePos2) * Acts::UnitConstants::mm;
192 free_params[Acts::eFreeTime] = 0.;
193 free_params[Acts::eFreeDir0] = mom(0) / mom.norm();
194 free_params[Acts::eFreeDir1] = mom(1) / mom.norm();
195 free_params[Acts::eFreeDir2] = mom(2) / mom.norm();
196 free_params[Acts::eFreeQOverP] =
197 (q != Acts::ActsScalar(0)) ? (q / p) : 0.; // 1. / p instead?
198
199 return free_params;
200}
201
202// Pack the acts track parameters into something that is serializable for the
203// event bus
204
205inline std::vector<double> convertActsToLdmxPars(Acts::BoundVector acts_par) {
206 std::vector<double> v_ldmx(
207 acts_par.data(), acts_par.data() + acts_par.rows() * acts_par.cols());
208 return v_ldmx;
209}
210
211inline Acts::BoundVector boundState(const ldmx::Track& trk) {
212 Acts::BoundVector paramVec;
213 paramVec << trk.getD0(), trk.getZ0(), trk.getPhi(), trk.getTheta(),
214 trk.getQoP(), trk.getT();
215 return paramVec;
216}
217
218inline Acts::BoundVector boundState(const ldmx::Track::TrackState& ts) {
219 Acts::BoundVector paramVec;
220 paramVec << ts.params[0], ts.params[1], ts.params[2], ts.params[3],
221 ts.params[4], ts.params[5];
222 return paramVec;
223}
224
225inline Acts::BoundTrackParameters boundTrackParameters(
226 const ldmx::Track& trk, std::shared_ptr<Acts::PerigeeSurface> perigee) {
227 Acts::BoundVector paramVec = boundState(trk);
228 Acts::BoundSquareMatrix covMat = unpackCov(trk.getPerigeeCov());
229 auto partHypo{Acts::SinglyChargedParticleHypothesis::electron()};
230 // auto
231 // part{Acts::GenericParticleHypothesis(Acts::ParticleHypothesis(Acts::PdgParticle(trk.getPdgID())))};
232 // return Acts::BoundTrackParameters(perigee, paramVec, std::move(covMat));
233 // need to add particle hypothesis
234 return Acts::BoundTrackParameters(perigee, paramVec, std::move(covMat),
235 partHypo);
236}
237
238inline Acts::BoundTrackParameters btp(const ldmx::Track::TrackState& ts,
239 std::shared_ptr<Acts::Surface> surf,
240 int pdgid) {
241 Acts::BoundVector paramVec = boundState(ts);
242 Acts::BoundSquareMatrix covMat = unpackCov(ts.cov);
243 auto partHypo{Acts::SinglyChargedParticleHypothesis::electron()};
244 // auto
245 // part{Acts::GenericParticleHypothesis(Acts::ParticleHypothesis(Acts::PdgParticle(pdgid)))};
246 return Acts::BoundTrackParameters(surf, paramVec, std::move(covMat),
247 partHypo);
248}
249
250// Return an unbound surface
251inline const std::shared_ptr<Acts::PlaneSurface> unboundSurface(
252 double xloc, double yloc = 0., double zloc = 0.) {
253 // Define the target surface - be careful:
254 // x - downstream
255 // y - left (when looking along x)
256 // z - up
257 // Passing identity here means that your target surface is oriented in the
258 // same way
259 Acts::RotationMatrix3 surf_rotation = Acts::RotationMatrix3::Zero();
260 // u direction along +Y
261 surf_rotation(1, 0) = 1;
262 // v direction along +Z
263 surf_rotation(2, 1) = 1;
264 // w direction along +X
265 surf_rotation(0, 2) = 1;
266
267 Acts::Vector3 pos(xloc, yloc, zloc);
268 Acts::Translation3 surf_translation(pos);
269 Acts::Transform3 surf_transform(surf_translation * surf_rotation);
270
271 // Unbounded surface
272 const std::shared_ptr<Acts::PlaneSurface> target_surface =
273 Acts::Surface::makeShared<Acts::PlaneSurface>(surf_transform);
274
275 return Acts::Surface::makeShared<Acts::PlaneSurface>(surf_transform);
276}
277
278// This method returns a source link index
279inline std::size_t sourceLinkHash(const Acts::SourceLink& a) {
280 return static_cast<std::size_t>(
282}
283
284// This method checks if two source links are equal by index
285inline bool sourceLinkEquality(const Acts::SourceLink& a,
286 const Acts::SourceLink& b) {
287 return a.get<ActsExamples::IndexSourceLink>().index() ==
288 b.get<ActsExamples::IndexSourceLink>().index();
289}
290
291} // namespace utils
292} // namespace sim
293} // namespace tracking
294
295#endif
Class which encapsulates information from a hit in a simulated tracking detector.
Represents a simulated tracker hit in the simulation.
int getModuleID() const
Get the module ID associated with a hit.
float getEdep() const
Get the energy deposited on the hit [MeV].
std::vector< float > getPosition() const
Get the XYZ position of the hit [mm].
int getID() const
Get the detector ID of the hit.
float getTime() const
Get the global time of the hit [ns].
int getLayerID() const
Get the geometric layer ID of the hit.
Implementation of a track object.
Definition Track.h:53
The measurement calibrator can be a function or a class/struct able to retrieve the sim hits containe...