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_ */
|