Skip to content

Commit dc944fd

Browse files
committed
Better use of safety.
Implementing two safety features: 1. Safety caching: the tracks hold the point where safety is computed, and the safety value in that point. When safety is needed in a different point, the method track.GetSafety(new_point) will subtract from the cached value and return the positive remainder or zero otherwise. The GetSafety method can take an accurate limit value, and when the remainder is smaller than this limit the returned safety is zero. It is the user responsibility to call track.SetSafety(pos, safety) whenever the safety is fully recomputed in a new position. 2. Safety calculation usses a new surface model feature to only compute safety accurately when close to boundaries, and only use the aligned bounding box safety when far away. The distance limit is passed as third parameter to AdePTNavigator::ComputeSafety, and must be typically equal to the discrete interaction step.
1 parent 8d8251e commit dc944fd

File tree

4 files changed

+78
-28
lines changed

4 files changed

+78
-28
lines changed

include/AdePT/core/Track.cuh

+41-15
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,21 @@ struct Track {
2121
using Precision = vecgeom::Precision;
2222

2323
RanluxppDouble rngState;
24-
double eKin;
25-
double numIALeft[4];
26-
double initialRange;
27-
double dynamicRangeFactor;
28-
double tlimitMin;
29-
30-
double globalTime{0};
31-
double localTime{0};
32-
double properTime{0};
33-
34-
vecgeom::Vector3D<Precision> pos;
35-
vecgeom::Vector3D<Precision> dir;
36-
vecgeom::NavigationState navState;
24+
double eKin{0.};
25+
double numIALeft[4]{0., 0., 0., 0.};
26+
double initialRange{0.};
27+
double dynamicRangeFactor{0.};
28+
double tlimitMin{0.};
29+
30+
double globalTime{0.};
31+
double localTime{0.};
32+
double properTime{0.};
33+
34+
vecgeom::Vector3D<Precision> pos; ///< track position
35+
vecgeom::Vector3D<Precision> dir; ///< track direction
36+
vecgeom::Vector3D<float> safetyPos; ///< last position where the safety was computed
37+
float safety{0.f}; ///< last computed safety value
38+
vecgeom::NavigationState navState; ///< current navigation state
3739

3840
#ifdef USE_SPLIT_KERNELS
3941
// Variables used to store track info needed for scoring
@@ -46,7 +48,6 @@ struct Track {
4648

4749
// Variables used to store navigation results
4850
double geometryStepLength{0};
49-
double safety{0};
5051
long hitsurfID{0};
5152
#endif
5253

@@ -60,6 +61,29 @@ struct Track {
6061
bool stopped{false};
6162
#endif
6263

64+
/// @brief Get recomputed cached safety ay a given track position
65+
/// @param new_pos Track position
66+
/// @param accurate_limit Only return non-zero if the recomputed safety if larger than the accurate_limit
67+
/// @return Recomputed safety.
68+
__host__ __device__ VECGEOM_FORCE_INLINE float GetSafety(vecgeom::Vector3D<Precision> const &new_pos,
69+
float accurate_limit = 0.f) const
70+
{
71+
float dsafe = safety - accurate_limit;
72+
if (dsafe <= 0.f) return 0.f;
73+
float distSq = (vecgeom::Vector3D<float>(new_pos) - safetyPos).Mag2();
74+
if (dsafe * dsafe < distSq) return 0.f;
75+
return (safety - vecCore::math::Sqrt(distSq));
76+
}
77+
78+
/// @brief Set Safety value computed in a new point
79+
/// @param new_pos Position where the safety is computed
80+
/// @param safe Safety value
81+
__host__ __device__ VECGEOM_FORCE_INLINE void SetSafety(vecgeom::Vector3D<Precision> const &new_pos, float safe)
82+
{
83+
safetyPos.Set(static_cast<float>(new_pos[0]), static_cast<float>(new_pos[1]), static_cast<float>(new_pos[2]));
84+
safety = vecCore::math::Max(safe, 0.f);
85+
}
86+
6387
__host__ __device__ double Uniform() { return rngState.Rndm(); }
6488

6589
__host__ __device__ void InitAsSecondary(const vecgeom::Vector3D<Precision> &parentPos,
@@ -77,7 +101,9 @@ struct Track {
77101

78102
// A secondary inherits the position of its parent; the caller is responsible
79103
// to update the directions.
80-
this->pos = parentPos;
104+
this->pos = parentPos;
105+
this->safetyPos.Set(0.f, 0.f, 0.f);
106+
this->safety = 0.0f;
81107
this->navState = parentNavState;
82108

83109
// The global time is inherited from the parent

include/AdePT/kernels/electrons.cuh

+28-11
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,6 @@ static __device__ __forceinline__ void TransportElectrons(adept::TrackManager<Tr
110110
// used, this provides a fresh round of random numbers and reduces thread
111111
// divergence because the RNG state doesn't need to be advanced later.
112112
RanluxppDouble newRNG(currentTrack.rngState.BranchNoAdvance());
113-
114-
// Compute safety, needed for MSC step limit.
115-
double safety = 0;
116-
if (!navState.IsOnBoundary()) {
117-
safety = AdePTNavigator::ComputeSafety(pos, navState);
118-
}
119-
theTrack->SetSafety(safety);
120-
121113
G4HepEmRandomEngine rnge(&currentTrack.rngState);
122114

123115
// Sample the `number-of-interaction-left` and put it into the track.
@@ -132,6 +124,24 @@ static __device__ __forceinline__ void TransportElectrons(adept::TrackManager<Tr
132124

133125
G4HepEmElectronManager::HowFarToDiscreteInteraction(&g4HepEmData, &g4HepEmPars, &elTrack);
134126

127+
auto physicalStepLength = elTrack.GetPStepLength();
128+
// Compute safety, needed for MSC step limit. The accuracy range is physicalStepLength
129+
double safety = 0.;
130+
if (!navState.IsOnBoundary()) {
131+
// Get the remaining safety only if larger than physicalStepLength
132+
safety = currentTrack.GetSafety(pos);
133+
if (safety < physicalStepLength) {
134+
// Recompute safety and update it in the track.
135+
#ifdef ADEPT_USE_SURF
136+
// Use maximum accuracy only if safety is samller than physicalStepLength
137+
safety = AdePTNavigator::ComputeSafety(pos, navState, physicalStepLength);
138+
#else
139+
safety = AdePTNavigator::ComputeSafety(pos, navState);
140+
#endif
141+
currentTrack.SetSafety(pos, safety);
142+
}
143+
}
144+
theTrack->SetSafety(safety);
135145
bool restrictedPhysicalStepLength = false;
136146
if (BzFieldValue != 0) {
137147
const double momentumMag = sqrt(eKin * (eKin + 2.0 * restMass));
@@ -142,11 +152,11 @@ static __device__ __forceinline__ void TransportElectrons(adept::TrackManager<Tr
142152
double limit = MaxSafeLength * safeLength;
143153
limit = safety > limit ? safety : limit;
144154

145-
double physicalStepLength = elTrack.GetPStepLength();
146155
if (physicalStepLength > limit) {
147156
physicalStepLength = limit;
148157
restrictedPhysicalStepLength = true;
149158
elTrack.SetPStepLength(physicalStepLength);
159+
150160
// Note: We are limiting the true step length, which is converted to
151161
// a shorter geometry step length in HowFarToMSC. In that sense, the
152162
// limit is an over-approximation, but that is fine for our purpose.
@@ -201,6 +211,7 @@ static __device__ __forceinline__ void TransportElectrons(adept::TrackManager<Tr
201211
// correct information (navState = nextState only if relocated
202212
// in case of a boundary; see below)
203213
navState.SetBoundaryState(nextState.IsOnBoundary());
214+
if (nextState.IsOnBoundary()) currentTrack.SetSafety(pos, 0.);
204215

205216
// Propagate information from geometrical step to MSC.
206217
theTrack->SetDirection(dir.x(), dir.y(), dir.z());
@@ -222,7 +233,7 @@ static __device__ __forceinline__ void TransportElectrons(adept::TrackManager<Tr
222233
if (dLength2 > kGeomMinLength2) {
223234
const double dispR = std::sqrt(dLength2);
224235
// Estimate safety by subtracting the geometrical step length.
225-
safety -= geometryStepLength;
236+
safety = currentTrack.GetSafety(pos);
226237
constexpr double sFact = 0.99;
227238
double reducedSafety = sFact * safety;
228239

@@ -232,7 +243,13 @@ static __device__ __forceinline__ void TransportElectrons(adept::TrackManager<Tr
232243
pos += displacement;
233244
} else {
234245
// Recompute safety.
235-
safety = AdePTNavigator::ComputeSafety(pos, navState);
246+
#ifdef ADEPT_USE_SURF
247+
// Use maximum accuracy only if safety is samller than physicalStepLength
248+
safety = AdePTNavigator::ComputeSafety(pos, navState, dispR);
249+
#else
250+
safety = AdePTNavigator::ComputeSafety(pos, navState);
251+
#endif
252+
currentTrack.SetSafety(pos, safety);
236253
reducedSafety = sFact * safety;
237254

238255
// 1b. Far away from geometry boundary:

include/AdePT/magneticfield/fieldPropagatorConstBz.h

+5
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,12 @@ __host__ __device__ Precision fieldPropagatorConstBz::ComputeStepAndNextVolume(
142142
} else {
143143
Precision newSafety = 0;
144144
if (stepDone > 0) {
145+
#ifdef ADEPT_USE_SURF
146+
// Use maximum accuracy only if safety is samller than physicalStepLength
147+
newSafety = Navigator::ComputeSafety(position, current_state, remains);
148+
#else
145149
newSafety = Navigator::ComputeSafety(position, current_state);
150+
#endif
146151
}
147152
if (newSafety > chordLen) {
148153
move = chordLen;

include/AdePT/navigation/SurfNavigator.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,12 @@ class SurfNavigator {
4949
/// @brief Computes the isotropic safety from the globalpoint.
5050
/// @param globalpoint Point in global coordinates
5151
/// @param state Path where to compute safety
52+
/// @param limit Limit to which safety should be computed accurately
5253
/// @return Isotropic safe distance
53-
__host__ __device__ static Precision ComputeSafety(Vector3D const &globalpoint, vecgeom::NavigationState const &state)
54+
__host__ __device__ static Precision ComputeSafety(Vector3D const &globalpoint, vecgeom::NavigationState const &state,
55+
Precision limit = vecgeom::InfinityLength<Real_t>())
5456
{
55-
auto safety = vgbrep::protonav::BVHSurfNavigator<Real_t>::ComputeSafety(globalpoint, state);
57+
auto safety = vgbrep::protonav::BVHSurfNavigator<Real_t>::ComputeSafety(globalpoint, state, limit);
5658
return safety;
5759
}
5860

0 commit comments

Comments
 (0)