File: SimpleSafetyEstimator.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 (185 lines) | stat: -rw-r--r-- 6,847 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
/*
 * VSimpleSafetyEstimator.h
 *
 *  Created on: 28.08.2015
 *      Author: swenzel
 */

#ifndef NAVIGATION_SIMPLESAFETYESTIMATOR_H_
#define NAVIGATION_SIMPLESAFETYESTIMATOR_H_

#include "VecGeom/navigation/VSafetyEstimator.h"
//#include "VecGeom/base/Array.h"

namespace vecgeom {
inline namespace VECGEOM_IMPL_NAMESPACE {

/// Keep in dest the minimum between dest,temp for each corresponding element
static void VectMin(unsigned int nelem, Precision *__restrict__ dest, const Precision *__restrict__ temp) {
  using vecCore::FromPtr;
  using Real_v = vecgeom::VectorBackend::Real_v;

  // loop over all elements
  unsigned int i = 0;
  constexpr unsigned int nlanes = vecCore::VectorSize<Real_v>();
  const auto ilast = nelem - (nlanes-1);
  Real_v result;
  for ( ; i < ilast; i += nlanes) {
    result = vecCore::math::Min(FromPtr<Real_v>(dest + i), FromPtr<Real_v>(temp + i));
    vecCore::Store(result, &dest[i]);
  }

  // fall back to scalar interface for tail treatment
  for (; i < nelem; ++i) {
    if ( dest[i] > temp[i] ) dest[i] = temp[i];
  }
}

//! a simple safety estimator based on a brute force (O(N)) approach
class SimpleSafetyEstimator : public VSafetyEstimatorHelper<SimpleSafetyEstimator> {

public:
  static constexpr const char *gClassNameString = "SimpleSafetyEstimator";

  // estimate just the safety to daughters for a local point with respect to a logical volume
  // TODO: use this function in other interfaces to avoid code duplication
  VECCORE_ATT_HOST_DEVICE
  virtual Precision ComputeSafetyToDaughtersForLocalPoint(Vector3D<Precision> const &localpoint,
                                                          LogicalVolume const *lvol) const override
  {
    // safety to daughters
    double safety(kInfLength);
    auto daughters       = lvol->GetDaughtersp();
    auto numberdaughters = daughters->size();
    for (decltype(numberdaughters) d = 0; d < numberdaughters; ++d) {
      VPlacedVolume const *daughter = daughters->operator[](d);
      double tmp                    = daughter->SafetyToIn(localpoint);
      safety                        = Min(safety, tmp);
    }
    return safety;
  }

  VECGEOM_FORCE_INLINE
  VECCORE_ATT_HOST_DEVICE
  virtual Precision ComputeSafetyForLocalPoint(Vector3D<Precision> const &localpoint,
                                               VPlacedVolume const *pvol) const override
  {
    // safety to mother
    double safety = pvol->SafetyToOut(localpoint);

    // safety to daughters
    auto daughters       = pvol->GetLogicalVolume()->GetDaughtersp();
    auto numberdaughters = daughters->size();
    for (decltype(numberdaughters) d = 0; d < numberdaughters; ++d) {
      VPlacedVolume const *daughter = daughters->operator[](d);
      double tmp                    = daughter->SafetyToIn(localpoint);
      safety                        = Min(safety, tmp);
    }
    return safety;
  }

  VECGEOM_FORCE_INLINE
  VECCORE_ATT_HOST_DEVICE
  virtual Real_v ComputeSafetyForLocalPoint(Vector3D<Real_v> const &localpoint, VPlacedVolume const *pvol,
                                            Bool_v m) const override
  {
    // safety to mother
    Real_v safety(0.);
    if (!vecCore::MaskEmpty(m)) {
      safety = pvol->SafetyToOut(localpoint);

      // safety to daughters
      auto daughters       = pvol->GetLogicalVolume()->GetDaughtersp();
      auto numberdaughters = daughters->size();
      for (decltype(numberdaughters) d = 0; d < numberdaughters; ++d) {
        VPlacedVolume const *daughter = daughters->operator[](d);
        auto tmp                      = daughter->SafetyToIn(localpoint);
        safety                        = Min(safety, tmp);
      }
    }
    return safety;
  }


  VECGEOM_FORCE_INLINE
  virtual void ComputeSafetyForLocalPoints(SOA3D<Precision> const &localpoints, VPlacedVolume const *pvol,
                                           Precision *safeties) const override
  {
    auto npoints = localpoints.size();
    // a stack based workspace array
    // The following construct reserves stackspace WITHOUT initializing it
    char stackspace[npoints * sizeof(Precision)];
    Precision *tmpSafeties = reinterpret_cast<Precision *>(&stackspace);

    // // Array-based - transparently ensures proper alignment
    // // NavigBenchmark performance is actually worse than above though
    // Array<Precision> stackspace(npoints);
    // Precision *tmpSafeties = reinterpret_cast<Precision *>(stackspace.begin());

    pvol->SafetyToOut(localpoints, safeties);

    // safety to daughters; brute force but each function (possibly) vectorized
    Vector<Daughter> const *daughters = pvol->GetLogicalVolume()->GetDaughtersp();
    auto numberdaughters              = daughters->size();
    for (decltype(numberdaughters) d = 0; d < numberdaughters; ++d) {
      VPlacedVolume const *daughter = daughters->operator[](d);
      daughter->SafetyToIn(localpoints, tmpSafeties);

      //.. keep track of closest daughter
      VectMin(npoints, safeties, tmpSafeties);
    }
    // here the safeties array automatically contains the right values
  }

  // bring in interface from higher up
  using VSafetyEstimatorHelper<SimpleSafetyEstimator>::ComputeVectorSafety;

  // implementation (using VC that does not need a workspace) by doing the whole algorithm in little vector chunks
  virtual void ComputeVectorSafety(SOA3D<Precision> const &globalpoints, NavStatePool &states,
                                   Precision *safeties) const override
  {
    VPlacedVolume const *pvol = states[0]->Top();
    auto npoints              = globalpoints.size();

    constexpr auto kVS = vecCore::VectorSize<Real_v>();
    for (decltype(npoints) i = 0; i < npoints; i += kVS) {
      // do the transformation to local
      Vector3D<Real_v> local;
      for (size_t j = 0; j < kVS; ++j) {
        Transformation3D m;
        states[i + j]->TopMatrix(m);
        auto v = m.Transform(globalpoints[i + j]);

        using vecCore::AssignLane;
        AssignLane(local.x(), j, v.x());
        AssignLane(local.y(), j, v.y());
        AssignLane(local.z(), j, v.z());
      }

      auto safety          = pvol->SafetyToOut(local);
      auto daughters       = pvol->GetLogicalVolume()->GetDaughtersp();
      auto numberdaughters = daughters->size();
      for (decltype(numberdaughters) d = 0; d < numberdaughters; ++d) {
        VPlacedVolume const *daughter = daughters->operator[](d);
        safety                        = Min(safety, daughter->SafetyToIn(local));
      }
      vecCore::Store(safety, safeties + i);
    }
  }

#ifndef VECCORE_CUDA
  static VSafetyEstimator *Instance()
  {
    static SimpleSafetyEstimator instance;
    return &instance;
  }
#else
  VECCORE_ATT_DEVICE
  static VSafetyEstimator *Instance();
#endif

}; // end class
}
} // end namespaces

#endif /* NAVIGATION_SIMPLESAFETYESTIMATOR_H_ */