Skip to content

Commit e1a6c4e

Browse files
committed
Add global track as union
1 parent 805c97a commit e1a6c4e

5 files changed

Lines changed: 382 additions & 4 deletions

File tree

Lines changed: 360 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,360 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
/// \file GlobalTrack.h
13+
/// \brief Tagged-union track holding either a barrel or a forward parameterization.
14+
///
15+
/// A GlobalTrack holds exactly one of {TrackPar, TrackParFwd} at any time, plus
16+
/// a Frame tag identifying which. The storage is a real C++ union (active-member
17+
/// switching via placement-new) so that asBarrel() / asFwd() return genuine
18+
/// references to the currently-active leaf type without aliasing UB.
19+
///
20+
/// GlobalTrack is *not* persisted directly: callers should stream the underlying
21+
/// barrel or fwd track on disk and rebuild a GlobalTrack on read via the
22+
/// converting constructors or assignment operators ("adoption").
23+
24+
#ifndef ALICEO2_GLOBALTRACK_H
25+
#define ALICEO2_GLOBALTRACK_H
26+
27+
#include <cassert>
28+
#include <cstdint>
29+
#include <new>
30+
#include <utility>
31+
32+
#include "GPUCommonDef.h"
33+
#include "ReconstructionDataFormats/Track.h"
34+
#include "ReconstructionDataFormats/TrackFwd.h"
35+
36+
namespace o2::track
37+
{
38+
39+
enum class Frame : uint8_t {
40+
Barrel = 0,
41+
Fwd = 1,
42+
};
43+
44+
/// Param-only global track.
45+
class GlobalTrack
46+
{
47+
public:
48+
using value_t = float;
49+
50+
GPUd() GlobalTrack() noexcept : mFrame(Frame::Barrel) { ::new (&mRep.barrel) TrackPar(); }
51+
GPUd() GlobalTrack(const TrackPar& src) noexcept : mFrame(Frame::Barrel) { ::new (&mRep.barrel) TrackPar(src); }
52+
GPUd() GlobalTrack(const TrackParFwd& src) noexcept : mFrame(Frame::Fwd) { ::new (&mRep.fwd) TrackParFwd(src); }
53+
54+
GPUd() GlobalTrack(const GlobalTrack& o) noexcept : mFrame(o.mFrame)
55+
{
56+
if (isBarrel()) {
57+
::new (&mRep.barrel) TrackPar(o.mRep.barrel);
58+
} else {
59+
::new (&mRep.fwd) TrackParFwd(o.mRep.fwd);
60+
}
61+
}
62+
GPUd() GlobalTrack(GlobalTrack&& o) noexcept : mFrame(o.mFrame)
63+
{
64+
if (isBarrel()) {
65+
::new (&mRep.barrel) TrackPar(std::move(o.mRep.barrel));
66+
} else {
67+
::new (&mRep.fwd) TrackParFwd(std::move(o.mRep.fwd));
68+
}
69+
}
70+
GPUhd() GlobalTrack& operator=(const GlobalTrack& o) noexcept
71+
{
72+
if (this != &o) {
73+
destroyActive();
74+
mFrame = o.mFrame;
75+
if (isBarrel()) {
76+
::new (&mRep.barrel) TrackPar(o.mRep.barrel);
77+
} else {
78+
::new (&mRep.fwd) TrackParFwd(o.mRep.fwd);
79+
}
80+
}
81+
return *this;
82+
}
83+
GPUhd() GlobalTrack& operator=(GlobalTrack&& o) noexcept
84+
{
85+
destroyActive();
86+
mFrame = o.mFrame;
87+
if (isBarrel()) {
88+
::new (&mRep.barrel) TrackPar(std::move(o.mRep.barrel));
89+
} else {
90+
::new (&mRep.fwd) TrackParFwd(std::move(o.mRep.fwd));
91+
}
92+
return *this;
93+
}
94+
95+
/// Adoption: replace the current rep with a barrel/fwd track read from disk
96+
/// (or constructed elsewhere). Flips the frame tag if necessary.
97+
GPUhd() GlobalTrack& operator=(const TrackPar& src) noexcept
98+
{
99+
if (isBarrel()) {
100+
mRep.barrel = src;
101+
} else {
102+
mRep.fwd.~TrackParFwd();
103+
::new (&mRep.barrel) TrackPar(src);
104+
mFrame = Frame::Barrel;
105+
}
106+
return *this;
107+
}
108+
GPUhd() GlobalTrack& operator=(const TrackParFwd& src) noexcept
109+
{
110+
if (isFwd()) {
111+
mRep.fwd = src;
112+
} else {
113+
mRep.barrel.~TrackPar();
114+
::new (&mRep.fwd) TrackParFwd(src);
115+
mFrame = Frame::Fwd;
116+
}
117+
return *this;
118+
}
119+
120+
GPUd() ~GlobalTrack() noexcept { destroyActive(); }
121+
122+
GPUd() Frame getFrame() const noexcept { return mFrame; }
123+
GPUd() bool isBarrel() const noexcept { return mFrame == Frame::Barrel; }
124+
GPUd() bool isFwd() const noexcept { return mFrame == Frame::Fwd; }
125+
126+
/// Return a reference to the active barrel rep. With autoConvert=true the
127+
/// current fwd rep (if any) is converted in place first; otherwise a frame
128+
/// mismatch trips an assertion.
129+
TrackPar& asBarrel(bool autoConvert = false)
130+
{
131+
if (!isBarrel()) {
132+
assert(autoConvert && "GlobalTrack::asBarrel on fwd-frame without autoConvert");
133+
convertToBarrel();
134+
}
135+
return mRep.barrel;
136+
}
137+
GPUd() const TrackPar& asBarrel() const
138+
{
139+
assert(isBarrel() && "GlobalTrack::asBarrel const on fwd-frame");
140+
return mRep.barrel;
141+
}
142+
TrackParFwd& asFwd(bool autoConvert = false)
143+
{
144+
if (!isFwd()) {
145+
assert(autoConvert && "GlobalTrack::asFwd on barrel-frame without autoConvert");
146+
convertToFwd();
147+
}
148+
return mRep.fwd;
149+
}
150+
GPUd() const TrackParFwd& asFwd() const
151+
{
152+
assert(isFwd() && "GlobalTrack::asFwd const on barrel-frame");
153+
return mRep.fwd;
154+
}
155+
156+
/// Rewrite the storage in the requested frame, using the existing
157+
/// toBarrel/toFwd conversion routines. No-op if already there.
158+
void convertToBarrel()
159+
{
160+
if (isBarrel()) {
161+
return;
162+
}
163+
TrackPar tmp;
164+
mRep.fwd.toBarrelTrackPar(tmp);
165+
mRep.fwd.~TrackParFwd();
166+
::new (&mRep.barrel) TrackPar(tmp);
167+
mFrame = Frame::Barrel;
168+
}
169+
void convertToFwd()
170+
{
171+
if (isFwd()) {
172+
return;
173+
}
174+
TrackParFwd tmp;
175+
mRep.barrel.toFwdTrackPar(tmp);
176+
mRep.barrel.~TrackPar();
177+
::new (&mRep.fwd) TrackParFwd(tmp);
178+
mFrame = Frame::Fwd;
179+
}
180+
181+
private:
182+
union Rep {
183+
TrackPar barrel;
184+
TrackParFwd fwd;
185+
GPUd() Rep() noexcept {}
186+
GPUd() ~Rep() noexcept {}
187+
};
188+
Rep mRep;
189+
Frame mFrame;
190+
191+
GPUd() void destroyActive() noexcept
192+
{
193+
if (isBarrel()) {
194+
mRep.barrel.~TrackPar();
195+
} else {
196+
mRep.fwd.~TrackParFwd();
197+
}
198+
}
199+
};
200+
201+
/// Param + covariance flavour.
202+
class GlobalTrackCov
203+
{
204+
public:
205+
using value_t = float;
206+
207+
GPUd() GlobalTrackCov() noexcept : mFrame(Frame::Barrel) { ::new (&mRep.barrel) TrackParCov(); }
208+
GPUd() GlobalTrackCov(const TrackParCov& src) noexcept : mFrame(Frame::Barrel) { ::new (&mRep.barrel) TrackParCov(src); }
209+
GPUd() GlobalTrackCov(const TrackParCovFwd& src) noexcept : mFrame(Frame::Fwd) { ::new (&mRep.fwd) TrackParCovFwd(src); }
210+
211+
GPUd() GlobalTrackCov(const GlobalTrackCov& o) noexcept : mFrame(o.mFrame)
212+
{
213+
if (isBarrel()) {
214+
::new (&mRep.barrel) TrackParCov(o.mRep.barrel);
215+
} else {
216+
::new (&mRep.fwd) TrackParCovFwd(o.mRep.fwd);
217+
}
218+
}
219+
GPUd() GlobalTrackCov(GlobalTrackCov&& o) noexcept : mFrame(o.mFrame)
220+
{
221+
if (isBarrel()) {
222+
::new (&mRep.barrel) TrackParCov(std::move(o.mRep.barrel));
223+
} else {
224+
::new (&mRep.fwd) TrackParCovFwd(std::move(o.mRep.fwd));
225+
}
226+
}
227+
GPUhd() GlobalTrackCov& operator=(const GlobalTrackCov& o) noexcept
228+
{
229+
if (this != &o) {
230+
destroyActive();
231+
mFrame = o.mFrame;
232+
if (isBarrel()) {
233+
::new (&mRep.barrel) TrackParCov(o.mRep.barrel);
234+
} else {
235+
::new (&mRep.fwd) TrackParCovFwd(o.mRep.fwd);
236+
}
237+
}
238+
return *this;
239+
}
240+
GPUhd() GlobalTrackCov& operator=(GlobalTrackCov&& o) noexcept
241+
{
242+
destroyActive();
243+
mFrame = o.mFrame;
244+
if (isBarrel()) {
245+
::new (&mRep.barrel) TrackParCov(std::move(o.mRep.barrel));
246+
} else {
247+
::new (&mRep.fwd) TrackParCovFwd(std::move(o.mRep.fwd));
248+
}
249+
return *this;
250+
}
251+
252+
GPUhd() GlobalTrackCov& operator=(const TrackParCov& src) noexcept
253+
{
254+
if (isBarrel()) {
255+
mRep.barrel = src;
256+
} else {
257+
mRep.fwd.~TrackParCovFwd();
258+
::new (&mRep.barrel) TrackParCov(src);
259+
mFrame = Frame::Barrel;
260+
}
261+
return *this;
262+
}
263+
GPUhd() GlobalTrackCov& operator=(const TrackParCovFwd& src) noexcept
264+
{
265+
if (isFwd()) {
266+
mRep.fwd = src;
267+
} else {
268+
mRep.barrel.~TrackParCov();
269+
::new (&mRep.fwd) TrackParCovFwd(src);
270+
mFrame = Frame::Fwd;
271+
}
272+
return *this;
273+
}
274+
275+
GPUd() ~GlobalTrackCov() noexcept { destroyActive(); }
276+
277+
GPUd() Frame getFrame() const noexcept { return mFrame; }
278+
GPUd() bool isBarrel() const noexcept { return mFrame == Frame::Barrel; }
279+
GPUd() bool isFwd() const noexcept { return mFrame == Frame::Fwd; }
280+
281+
TrackParCov& asBarrel(bool autoConvert = false)
282+
{
283+
if (!isBarrel()) {
284+
assert(autoConvert && "GlobalTrackCov::asBarrel on fwd-frame without autoConvert");
285+
convertToBarrel();
286+
}
287+
return mRep.barrel;
288+
}
289+
GPUd() const TrackParCov& asBarrel() const
290+
{
291+
assert(isBarrel() && "GlobalTrackCov::asBarrel const on fwd-frame");
292+
return mRep.barrel;
293+
}
294+
TrackParCovFwd& asFwd(bool autoConvert = false)
295+
{
296+
if (!isFwd()) {
297+
assert(autoConvert && "GlobalTrackCov::asFwd on barrel-frame without autoConvert");
298+
[[maybe_unused]] auto ok = convertToFwd();
299+
assert(ok && "GlobalTrackCov::asFwd: barrel->fwd conversion failed");
300+
}
301+
return mRep.fwd;
302+
}
303+
GPUd() const TrackParCovFwd& asFwd() const
304+
{
305+
assert(isFwd() && "GlobalTrackCov::asFwd const on barrel-frame");
306+
return mRep.fwd;
307+
}
308+
309+
/// barrel-from-fwd is unconditional.
310+
void convertToBarrel()
311+
{
312+
if (isBarrel()) {
313+
return;
314+
}
315+
TrackParCov tmp;
316+
mRep.fwd.toBarrelTrackParCov(tmp);
317+
mRep.fwd.~TrackParCovFwd();
318+
::new (&mRep.barrel) TrackParCov(tmp);
319+
mFrame = Frame::Barrel;
320+
}
321+
/// fwd-from-barrel can fail (e.g. cov inversion). On failure the rep is
322+
/// left untouched and the call returns false.
323+
bool convertToFwd()
324+
{
325+
if (isFwd()) {
326+
return true;
327+
}
328+
TrackParCovFwd tmp;
329+
if (!mRep.barrel.toFwdTrackParCov(tmp)) {
330+
return false;
331+
}
332+
mRep.barrel.~TrackParCov();
333+
::new (&mRep.fwd) TrackParCovFwd(tmp);
334+
mFrame = Frame::Fwd;
335+
return true;
336+
}
337+
338+
private:
339+
union Rep {
340+
TrackParCov barrel;
341+
TrackParCovFwd fwd;
342+
GPUd() Rep() noexcept {}
343+
GPUd() ~Rep() noexcept {}
344+
};
345+
Rep mRep;
346+
Frame mFrame;
347+
348+
GPUd() void destroyActive() noexcept
349+
{
350+
if (isBarrel()) {
351+
mRep.barrel.~TrackParCov();
352+
} else {
353+
mRep.fwd.~TrackParCovFwd();
354+
}
355+
}
356+
};
357+
358+
} // namespace o2::track
359+
360+
#endif

DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,10 @@ class TrackParFwd : public TrackParametrizationData<float, 5>, public TrackParFw
7272
/// TANL = tangent of \lambda (dip angle)
7373
/// INVQPT = Inverse transverse momentum (GeV/c ** -1) times charge (assumed forward motion) </pre>
7474

75-
ClassDefNV(TrackParFwd, 1);
75+
// v2: storage entirely relocated into TrackParametrizationData<float, 5> base
76+
// (was SMatrix5 mParameters + Double_t mZ + Double_t mTrackChi2). Old persistent
77+
// data requires a TBufferIO read rule (SMatrix5 → mP[5], mZ → mX) to migrate.
78+
ClassDefNV(TrackParFwd, 2);
7679
};
7780

7881
class TrackParCovFwd : public TrackParFwd, public TrackCovarianceData<TrackParFwd::value_t, 15>, public TrackParCovFwdInterface<TrackParCovFwd, TrackParFwd::value_t>
@@ -121,7 +124,10 @@ class TrackParCovFwd : public TrackParFwd, public TrackCovarianceData<TrackParFw
121124
/// <X,PHI> <Y,PHI> <PHI,PHI> <TANL,PHI> <INVQPT,PHI>
122125
/// <X,TANL> <Y,TANL> <PHI,TANL> <TANL,TANL> <INVQPT,TANL>
123126
/// <X,INVQPT> <Y,INVQPT> <PHI,INVQPT> <TANL,INVQPT> <INVQPT,INVQPT> </pre>
124-
ClassDefNV(TrackParCovFwd, 1);
127+
// v2: cov storage relocated into TrackCovarianceData<float, 15> base (was SMatrix55Sym
128+
// mCovariances); chi2 also moved to that base. Old persistent data requires a
129+
// TBufferIO read rule (SMatrix55Sym → mC[15] packed) to migrate.
130+
ClassDefNV(TrackParCovFwd, 2);
125131
};
126132

127133
static_assert(sizeof(TrackParFwd) == sizeof(TrackParFwd::base_t));

DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,8 @@ class TrackParametrization : public TrackParametrizationData<value_T, kNParams>,
284284
private:
285285
static constexpr value_t InvalidX = -99999.f;
286286

287-
ClassDefNV(TrackParametrization, 3);
287+
// v4: mX/mP/mAlpha/mAbsCharge/mPID/mUserField relocated into TrackParametrizationData<value_T, kNParams> base.
288+
ClassDefNV(TrackParametrization, 4);
288289
};
289290

290291
//____________________________________________________________

0 commit comments

Comments
 (0)