File: TrdImplementation.h

package info (click to toggle)
vecgeom 1.2.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 23,928 kB
  • sloc: cpp: 88,717; ansic: 6,894; python: 1,035; sh: 582; sql: 538; makefile: 29
file content (522 lines) | stat: -rw-r--r-- 19,379 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
// This file is part of VecGeom and is distributed under the
// conditions in the file LICENSE.txt in the top directory.
// For the full list of authors see CONTRIBUTORS.txt and `git log`.

/// This file implements the algorithms for Trd
/// @file volumes/kernel/TrdImplementation.h
/// @author Georgios Bitzes

#ifndef VECGEOM_VOLUMES_KERNEL_TRDIMPLEMENTATION_H_
#define VECGEOM_VOLUMES_KERNEL_TRDIMPLEMENTATION_H_

#include "VecGeom/base/Global.h"
#include "VecGeom/volumes/kernel/GenericKernels.h"
#include "VecGeom/volumes/TrdStruct.h"
#include "VecGeom/volumes/kernel/shapetypes/TrdTypes.h"
#include <stdlib.h>
#include <cstdio>

namespace vecgeom {

VECGEOM_DEVICE_DECLARE_CONV_TEMPLATE(struct, TrdImplementation, typename);

inline namespace VECGEOM_IMPL_NAMESPACE {

namespace TrdUtilities {

/*
 * Checks whether a point (x, y) falls on the left or right half-plane
 * of a line. The line is defined by a (vx, vy) vector, extended to infinity.
 *
 * Of course this can only be used for lines that pass through (0, 0), but
 * you can supply transformed coordinates for the point to check for any line.
 *
 * This simply calculates the magnitude of the cross product of vectors (px, py)
 * and (vx, vy), which is defined as |x| * |v| * sin theta.
 *
 * If the cross product is positive, the point is clockwise of V, or the "right"
 * half-plane. If it's negative, the point is CCW and on the "left" half-plane.
 */

template <typename Real_v>
VECGEOM_FORCE_INLINE
VECCORE_ATT_HOST_DEVICE
void PointLineOrientation(Real_v const &px, Real_v const &py, Precision const &vx, Precision const &vy,
                          Real_v &crossProduct)
{
  crossProduct = vx * py - vy * px;
}

/*
 * Check intersection of the trajectory of a particle with a segment
 * that's bound from -Ylimit to +Ylimit.j
 *
 * All points of the along-vector of a plane lie on
 * s * (alongX, alongY)
 * All points of the trajectory of the particle lie on
 * (x, y) + t * (vx, vy)
 * Thefore, it must hold that s * (alongX, alongY) == (x, y) + t * (vx, vy)
 * Solving by t we get t = (alongY*x - alongX*y) / (vy*alongX - vx*alongY)
 *
 * t gives the distance, but how to make sure hitpoint is inside the
 * segment and not just the infinite line defined by the segment?
 *
 * Check that |hity| <= Ylimit
 */

template <typename Real_v>
VECGEOM_FORCE_INLINE
VECCORE_ATT_HOST_DEVICE
void PlaneTrajectoryIntersection(Real_v const &alongX, Real_v const &alongY, Real_v const &ylimit, Real_v const &posx,
                                 Real_v const &posy, Real_v const &dirx, Real_v const &diry, Real_v &dist,
                                 vecCore::Mask_v<Real_v> &ok)
{
  dist = (alongY * posx - alongX * posy) / (diry * alongX - dirx * alongY);

  Real_v hity = posy + dist * diry;
  ok          = vecCore::math::Abs(hity) <= ylimit && dist > 0;
}

template <typename Real_v, bool forY, bool mirroredPoint, bool toInside>
VECGEOM_FORCE_INLINE
VECCORE_ATT_HOST_DEVICE
void FaceTrajectoryIntersection(TrdStruct<Precision> const &trd, Vector3D<Real_v> const &pos,
                                Vector3D<Real_v> const &dir, Real_v &dist, vecCore::Mask_v<Real_v> &ok)
{
  Real_v alongV, posV, dirV, posK, dirK, fV, fK, halfKplus, v1, ndotv;
  //    fNormals[0].Set(-fCalfX, 0., fFx*fCalfX);
  //    fNormals[1].Set(fCalfX, 0., fFx*fCalfX);
  //    fNormals[2].Set(0., -fCalfY, fFy*fCalfY);
  //    fNormals[3].Set(0., fCalfY, fFy*fCalfY);
  if (forY) {
    alongV    = trd.fY2minusY1;
    v1        = trd.fDY1;
    posV      = pos.y();
    posK      = pos.x();
    dirV      = dir.y();
    dirK      = dir.x();
    fK        = trd.fFx;
    fV        = trd.fFy;
    halfKplus = trd.fHalfX1plusX2;
  } else {
    alongV    = trd.fX2minusX1;
    v1        = trd.fDX1;
    posV      = pos.x();
    posK      = pos.y();
    dirV      = dir.x();
    dirK      = dir.y();
    fK        = trd.fFy;
    fV        = trd.fFx;
    halfKplus = trd.fHalfY1plusY2;
  }
  if (mirroredPoint) {
    posV *= Real_v(-1.);
    dirV *= Real_v(-1.);
  }

  ndotv = dirV + fV * dir.z();
  if (toInside)
    ok = ndotv < Real_v(0.);
  else
    ok = ndotv > Real_v(0.);
  if (vecCore::MaskEmpty(ok)) return;
  Real_v alongZ = Real_v(2.0) * trd.fDZ;

  // distance from trajectory to face
  dist = (alongZ * (posV - v1) - alongV * (pos.z() + trd.fDZ)) / (dir.z() * alongV - dirV * alongZ + kTiny);
  ok &= dist > Real_v(MakeMinusTolerant<true>(0.));
  if (!vecCore::MaskEmpty(ok)) {
    // need to make sure z hit falls within bounds
    Real_v hitz = pos.z() + dist * dir.z();
    ok &= vecCore::math::Abs(hitz) <= trd.fDZ;
    // need to make sure hit on varying dimension falls within bounds
    Real_v hitk = posK + dist * dirK;
    Real_v dK   = halfKplus - fK * hitz; // calculate the width of the varying dimension at hitz
    ok &= vecCore::math::Abs(hitk) <= dK;
    vecCore::MaskedAssign(dist, ok & (vecCore::math::Abs(dist) < kHalfTolerance), Real_v(0.0));
  }
}

template <typename Real_v, typename trdTypeT, bool inside>
VECGEOM_FORCE_INLINE
VECCORE_ATT_HOST_DEVICE
void Safety(TrdStruct<Precision> const &trd, Vector3D<Real_v> const &pos, Real_v &dist)
{
  using namespace TrdTypes;
  using Bool_v = vecCore::Mask_v<Real_v>;

  Real_v safz = trd.fDZ - vecCore::math::Abs(pos.z());
  // std::cout << "safz: " << safz << std::endl;
  dist = safz;

  Real_v distx = trd.fHalfX1plusX2 - trd.fFx * pos.z();
  Bool_v okx   = distx >= 0;
  Real_v safx  = (distx - vecCore::math::Abs(pos.x())) * trd.fCalfX;
  vecCore::MaskedAssign(dist, okx && safx < dist, safx);
  // std::cout << "safx: " << safx << std::endl;

  if (checkVaryingY<trdTypeT>(trd)) {
    Real_v disty = trd.fHalfY1plusY2 - trd.fFy * pos.z();
    Bool_v oky   = disty >= 0;
    Real_v safy  = (disty - vecCore::math::Abs(pos.y())) * trd.fCalfY;
    vecCore::MaskedAssign(dist, oky && safy < dist, safy);
  } else {
    Real_v safy = trd.fDY1 - vecCore::math::Abs(pos.y());
    vecCore::MaskedAssign(dist, safy < dist, safy);
  }
  if (!inside) dist = -dist;
}

template <typename Real_v, typename trdTypeT, bool surfaceT>
VECGEOM_FORCE_INLINE
VECCORE_ATT_HOST_DEVICE
static void UnplacedInside(TrdStruct<Precision> const &trd, Vector3D<Real_v> const &point,
                           vecCore::Mask_v<Real_v> &completelyinside, vecCore::Mask_v<Real_v> &completelyoutside)
{

  using namespace TrdUtilities;
  using namespace TrdTypes;

  Real_v pzPlusDz = point.z() + trd.fDZ;

  // inside Z?
  completelyoutside = vecCore::math::Abs(point.z()) > MakePlusTolerant<surfaceT>(trd.fDZ);
  if (surfaceT) completelyinside = vecCore::math::Abs(point.z()) < MakeMinusTolerant<surfaceT>(trd.fDZ);

  // inside X?
  Real_v cross;
  // Note: we cannot compare directly the cross product with the surface tolerance, but with
  // the tolerance multiplied by the length of the lateral segment connecting dx1 and dx2
  PointLineOrientation<Real_v>(vecCore::math::Abs(point.x()) - trd.fDX1, pzPlusDz, trd.fX2minusX1, 2.0 * trd.fDZ,
                               cross);
  if (surfaceT) {
    completelyoutside |= cross < -trd.fToleranceX;
    completelyinside &= cross > trd.fToleranceX;
  } else {
    completelyoutside |= cross < 0;
  }

  // inside Y?
  if (HasVaryingY<trdTypeT>::value != TrdTypes::kNo) {
    // If Trd type is unknown don't bother with a runtime check, assume the general case
    PointLineOrientation<Real_v>(vecCore::math::Abs(point.y()) - trd.fDY1, pzPlusDz, trd.fY2minusY1, 2.0 * trd.fDZ,
                                 cross);
    if (surfaceT) {
      completelyoutside |= cross < -trd.fToleranceY;
      completelyinside &= cross > trd.fToleranceY;
    } else {
      completelyoutside |= cross < 0;
    }
  } else {
    completelyoutside |= vecCore::math::Abs(point.y()) > MakePlusTolerant<surfaceT>(trd.fDY1);
    if (surfaceT) completelyinside &= vecCore::math::Abs(point.y()) < MakeMinusTolerant<surfaceT>(trd.fDY1);
  }
}

} // namespace TrdUtilities

template <typename T>
class SPlacedTrd;
template <typename T>
class SUnplacedTrd;

template <typename T>
struct TrdStruct;

template <typename trdTypeT>
struct TrdImplementation {

  using UnplacedStruct_t = TrdStruct<Precision>;
  using UnplacedVolume_t = SUnplacedTrd<trdTypeT>;
  using PlacedShape_t    = SPlacedTrd<UnplacedVolume_t>;

  VECCORE_ATT_HOST_DEVICE
  static void PrintType() {}

  template <typename Stream>
  static void PrintType(Stream &s, int transCodeT = translation::kGeneric, int rotCodeT = rotation::kGeneric)
  {
    s << "SpecializedTrd<" << transCodeT << "," << rotCodeT << ">";
  }

  template <typename Stream>
  static void PrintImplementationType(Stream & /*s*/)
  {
  }

  template <typename Stream>
  static void PrintUnplacedType(Stream & /*s*/)
  {
  }

  template <typename Real_v, typename Bool_v>
  VECGEOM_FORCE_INLINE
  VECCORE_ATT_HOST_DEVICE
  static void UnplacedContains(UnplacedStruct_t const &trd, Vector3D<Real_v> const &point, Bool_v &inside)
  {

    Bool_v unused;
    TrdUtilities::UnplacedInside<Real_v, trdTypeT, false>(trd, point, unused, inside);
    inside = !inside;
  }

  template <typename Real_v, typename Bool_v>
  VECGEOM_FORCE_INLINE
  VECCORE_ATT_HOST_DEVICE
  static void Contains(UnplacedStruct_t const &trd, Vector3D<Real_v> const &point, Bool_v &inside)
  {

    Bool_v unused;
    TrdUtilities::UnplacedInside<Real_v, trdTypeT, false>(trd, point, unused, inside);
    inside = !inside;
  }

  template <typename Real_v, typename Inside_v>
  VECGEOM_FORCE_INLINE
  VECCORE_ATT_HOST_DEVICE
  static void Inside(UnplacedStruct_t const &trd, Vector3D<Real_v> const &point, Inside_v &inside)
  {
    // use double-based vector for result, as Bool_v is a mask for precision_v
    using Bool_v = vecCore::Mask_v<Real_v>;
    const Real_v in(EInside::kInside);
    const Real_v out(EInside::kOutside);
    Bool_v inmask  = Bool_v(false);
    Bool_v outmask = Bool_v(false);
    Real_v result(EInside::kSurface);

    TrdUtilities::UnplacedInside<Real_v, trdTypeT, true>(trd, point, inmask, outmask);

    vecCore::MaskedAssign(result, inmask, in);
    vecCore::MaskedAssign(result, outmask, out);

    // Manual conversion from double to int here is necessary because int_v and
    // precision_v have different number of elements in SIMD vector, so Bool_v
    // (mask for precision_v) cannot be cast to mask for inside, which is a
    // different type and does not exist in the current backend system
    for (size_t i = 0; i < vecCore::VectorSize(result); i++)
      vecCore::Set(inside, i, vecCore::Get(result, i));
  }

  template <typename Real_v>
  VECGEOM_FORCE_INLINE
  VECCORE_ATT_HOST_DEVICE
  static void DistanceToIn(UnplacedStruct_t const &trd, Vector3D<Real_v> const &point,
                           Vector3D<Real_v> const &direction, Real_v const & /*stepMax*/, Real_v &distance)
  {

    using namespace TrdUtilities;
    using namespace TrdTypes;
    using Bool_v = vecCore::Mask_v<Real_v>;

    Real_v hitx, hity;
    // Real_v hitz;

    Vector3D<Real_v> pos_local;
    Vector3D<Real_v> dir_local;
    distance = InfinityLength<Real_v>();

    // hit Z faces?
    Bool_v inz   = vecCore::math::Abs(point.z()) < Real_v(MakeMinusTolerant<true>(trd.fDZ));
    Real_v distx = trd.fHalfX1plusX2 - trd.fFx * point.z();
    Bool_v inx   = (distx - vecCore::math::Abs(point.x())) * trd.fCalfX > Real_v(MakePlusTolerant<true>(0.));
    Real_v disty;
    Bool_v iny;
    if (checkVaryingY<trdTypeT>(trd)) {
      disty = trd.fHalfY1plusY2 - trd.fFy * point.z();
      iny   = (disty - vecCore::math::Abs(point.y())) * trd.fCalfY > Real_v(MakePlusTolerant<true>(0.));
    } else {
      disty = vecCore::math::Abs(point.y()) - trd.fDY1;
      iny   = disty < Real_v(MakeMinusTolerant<true>(0.));
    }
    Bool_v inside = inx & iny & inz;
    vecCore__MaskedAssignFunc(distance, inside, Real_v(-1.));
    Bool_v done = inside;
    Bool_v okz  = point.z() * direction.z() < Real_v(0.);
    okz &= !inz;
    if (!vecCore::MaskEmpty(okz)) {
      Real_v distz = (vecCore::math::Abs(point.z()) - trd.fDZ) / vecCore::math::Abs(direction.z());
      // exclude case in which particle is going away
      hitx = vecCore::math::Abs(point.x() + distz * direction.x());
      hity = vecCore::math::Abs(point.y() + distz * direction.y());

      // hitting top face?
      Bool_v okzt = point.z() > (trd.fDZ - kHalfTolerance) && hitx <= trd.fDX2 && hity <= trd.fDY2;
      // hitting bottom face?
      Bool_v okzb = point.z() < (-trd.fDZ + kHalfTolerance) && hitx <= trd.fDX1 && hity <= trd.fDY1;

      okz &= (okzt | okzb);
      vecCore::MaskedAssign(distance, okz, distz);
    }
    done |= okz;
    if (vecCore::MaskFull(done)) {
      vecCore::MaskedAssign(distance, vecCore::math::Abs(distance) < kHalfTolerance, Real_v(0.0));
      return;
    }

    // hitting X faces?
    Bool_v okx = Bool_v(false);
    if (!vecCore::MaskFull(inx)) {

      FaceTrajectoryIntersection<Real_v, false, false, true>(trd, point, direction, distx, okx);
      vecCore::MaskedAssign(distance, okx, distx);

      FaceTrajectoryIntersection<Real_v, false, true, true>(trd, point, direction, distx, okx);
      vecCore::MaskedAssign(distance, okx, distx);
    }
    done |= okx;
    if (vecCore::MaskFull(done)) {
      vecCore::MaskedAssign(distance, vecCore::math::Abs(distance) < kHalfTolerance, Real_v(0.0));
      return;
    }

    // hitting Y faces?
    Bool_v oky;
    if (checkVaryingY<trdTypeT>(trd)) {
      if (!vecCore::MaskFull(iny)) {
        FaceTrajectoryIntersection<Real_v, true, false, true>(trd, point, direction, disty, oky);
        vecCore::MaskedAssign(distance, oky, disty);

        FaceTrajectoryIntersection<Real_v, true, true, true>(trd, point, direction, disty, oky);
        vecCore::MaskedAssign(distance, oky, disty);
      }
    } else {
      if (!vecCore::MaskFull(iny)) {
        disty /= vecCore::math::Abs(direction.y());
        Real_v zhit = point.z() + disty * direction.z();
        Real_v xhit = point.x() + disty * direction.x();
        Real_v dx   = trd.fHalfX1plusX2 - trd.fFx * zhit;
        oky         = point.y() * direction.y() < 0 && disty > -kHalfTolerance && vecCore::math::Abs(xhit) < dx &&
              vecCore::math::Abs(zhit) < trd.fDZ;
        vecCore::MaskedAssign(distance, oky, disty);
      }
    }
    vecCore::MaskedAssign(distance, vecCore::math::Abs(distance) < kHalfTolerance, Real_v(0.0));
  }

  template <typename Real_v>
  VECGEOM_FORCE_INLINE
  VECCORE_ATT_HOST_DEVICE
  static void DistanceToOut(UnplacedStruct_t const &trd, Vector3D<Real_v> const &point, Vector3D<Real_v> const &dir,
                            Real_v const & /*stepMax*/, Real_v &distance)
  {

    using namespace TrdUtilities;
    using namespace TrdTypes;
    using Bool_v = vecCore::Mask_v<Real_v>;

    Real_v hitx, hity;
    // Real_v hitz;
    distance = Real_v(0.0);

    // hit top Z face?
    Real_v invdir = Real_v(1.) / vecCore::math::Abs(dir.z() + kTiny);
    Real_v safz   = trd.fDZ - vecCore::math::Abs(point.z());
    Bool_v out    = safz < Real_v(MakeMinusTolerant<true>(0.));
    Real_v distx  = trd.fHalfX1plusX2 - trd.fFx * point.z();
    out |= (distx - vecCore::math::Abs(point.x())) * trd.fCalfX < Real_v(MakeMinusTolerant<true>(0.));
    Real_v disty;
    if (checkVaryingY<trdTypeT>(trd)) {
      disty = trd.fHalfY1plusY2 - trd.fFy * point.z();
      out |= (disty - vecCore::math::Abs(point.y())) * trd.fCalfY < Real_v(MakeMinusTolerant<true>(0.));
    } else {
      disty = trd.fDY1 - vecCore::math::Abs(point.y());
      out |= disty < Real_v(MakeMinusTolerant<true>(0.));
    }
    if (/*vecCore::EarlyReturnAllowed() && */ vecCore::MaskFull(out)) {
      distance = Real_v(-1.);
      return;
    }
    Bool_v okzt = dir.z() > Real_v(0.);
    if (!vecCore::MaskEmpty(okzt)) {
      Real_v distz = (trd.fDZ - point.z()) * invdir;
      hitx         = vecCore::math::Abs(point.x() + distz * dir.x());
      hity         = vecCore::math::Abs(point.y() + distz * dir.y());
      okzt &= hitx <= trd.fDX2 && hity <= trd.fDY2;
      vecCore::MaskedAssign(distance, okzt, distz);
      if (vecCore::EarlyReturnAllowed() && vecCore::MaskFull(okzt)) {
        vecCore::MaskedAssign(distance, vecCore::math::Abs(distance) < kHalfTolerance, Real_v(0.0));
        return;
      }
    }

    // hit bottom Z face?
    Bool_v okzb = dir.z() < Real_v(0.);
    if (!vecCore::MaskEmpty(okzb)) {
      Real_v distz = (point.z() + trd.fDZ) * invdir;
      hitx         = vecCore::math::Abs(point.x() + distz * dir.x());
      hity         = vecCore::math::Abs(point.y() + distz * dir.y());
      okzb &= hitx <= trd.fDX1 && hity <= trd.fDY1;
      vecCore::MaskedAssign(distance, okzb, distz);
      if (vecCore::EarlyReturnAllowed() && vecCore::MaskFull(okzb)) {
        vecCore::MaskedAssign(distance, vecCore::math::Abs(distance) < kHalfTolerance, Real_v(0.0));
        return;
      }
    }

    // hitting X faces?
    Bool_v okx;

    FaceTrajectoryIntersection<Real_v, false, false, false>(trd, point, dir, distx, okx);

    vecCore::MaskedAssign(distance, okx, distx);
    if (vecCore::EarlyReturnAllowed() && vecCore::MaskFull(okx)) {
      vecCore::MaskedAssign(distance, vecCore::math::Abs(distance) < kHalfTolerance, Real_v(0.0));
      return;
    }

    FaceTrajectoryIntersection<Real_v, false, true, false>(trd, point, dir, distx, okx);
    vecCore::MaskedAssign(distance, okx, distx);
    if (vecCore::EarlyReturnAllowed() && vecCore::MaskFull(okx)) {
      vecCore::MaskedAssign(distance, vecCore::math::Abs(distance) < kHalfTolerance, Real_v(0.0));
      return;
    }

    // hitting Y faces?
    Bool_v oky;

    if (checkVaryingY<trdTypeT>(trd)) {
      FaceTrajectoryIntersection<Real_v, true, false, false>(trd, point, dir, disty, oky);
      vecCore::MaskedAssign(distance, oky, disty);
      if (vecCore::EarlyReturnAllowed() && vecCore::MaskFull(oky)) {
        vecCore::MaskedAssign(distance, vecCore::math::Abs(distance) < kHalfTolerance, Real_v(0.0));
        return;
      }

      FaceTrajectoryIntersection<Real_v, true, true, false>(trd, point, dir, disty, oky);
      vecCore::MaskedAssign(distance, oky, disty);
    } else {
      Real_v plane = trd.fDY1;
      vecCore__MaskedAssignFunc(plane, dir.y() < Real_v(0.), Real_v(-trd.fDY1));
      disty       = (plane - point.y()) / dir.y();
      Real_v zhit = point.z() + disty * dir.z();
      Real_v xhit = point.x() + disty * dir.x();
      Real_v dx   = trd.fHalfX1plusX2 - trd.fFx * zhit;
      oky         = vecCore::math::Abs(xhit) < dx && vecCore::math::Abs(zhit) < trd.fDZ;
      vecCore::MaskedAssign(distance, oky, disty);
    }
    vecCore__MaskedAssignFunc(distance, vecCore::math::Abs(distance) < kHalfTolerance, Real_v(0.0));
    vecCore__MaskedAssignFunc(distance, out, Real_v(-1.0));
  }

  template <typename Real_v>
  VECGEOM_FORCE_INLINE
  VECCORE_ATT_HOST_DEVICE
  static void SafetyToIn(UnplacedStruct_t const &trd, Vector3D<Real_v> const &point, Real_v &safety)
  {
    using namespace TrdUtilities;
    Safety<Real_v, trdTypeT, false>(trd, point, safety);
  }

  template <typename Real_v>
  VECGEOM_FORCE_INLINE
  VECCORE_ATT_HOST_DEVICE
  static void SafetyToOut(UnplacedStruct_t const &trd, Vector3D<Real_v> const &point, Real_v &safety)
  {
    using namespace TrdUtilities;
    Safety<Real_v, trdTypeT, true>(trd, point, safety);
  }
};
} // namespace VECGEOM_IMPL_NAMESPACE
} // namespace vecgeom

#endif // VECGEOM_VOLUMES_KERNEL_TRDIMPLEMENTATION_H_