Skip to content

Commit c08531a

Browse files
Keep some Track members in registers
The track variables are loaded at the beginning of the kernel and written back when the track survives. The signature of InitAsSecondary() had to be changed to not load from the track again.
1 parent 34d5100 commit c08531a

File tree

3 files changed

+85
-62
lines changed

3 files changed

+85
-62
lines changed

examples/Example19/electrons.cu

Lines changed: 53 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,21 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
4747
for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < activeSize; i += blockDim.x * gridDim.x) {
4848
const int globalSlot = (*active)[i];
4949
Track &currentTrack = electrons[globalSlot];
50-
const auto volume = currentTrack.navState.Top();
50+
auto energy = currentTrack.energy;
51+
auto pos = currentTrack.pos;
52+
auto dir = currentTrack.dir;
53+
auto navState = currentTrack.navState;
54+
const auto volume = navState.Top();
5155
const int volumeID = volume->id();
5256
// the MCC vector is indexed by the logical volume id
5357
const int lvolID = volume->GetLogicalVolume()->id();
5458
const int theMCIndex = MCIndex[lvolID];
5559

5660
auto survive = [&](bool push = true) {
61+
currentTrack.energy = energy;
62+
currentTrack.pos = pos;
63+
currentTrack.dir = dir;
64+
currentTrack.navState = navState;
5765
if (push) activeQueue->push_back(globalSlot);
5866
};
5967

@@ -63,9 +71,9 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
6371
// Init a track with the needed data to call into G4HepEm.
6472
G4HepEmElectronTrack elTrack;
6573
G4HepEmTrack *theTrack = elTrack.GetTrack();
66-
theTrack->SetEKin(currentTrack.energy);
74+
theTrack->SetEKin(energy);
6775
theTrack->SetMCIndex(theMCIndex);
68-
theTrack->SetOnBoundary(currentTrack.navState.IsOnBoundary());
76+
theTrack->SetOnBoundary(navState.IsOnBoundary());
6977
theTrack->SetCharge(Charge);
7078
G4HepEmMSCTrackData *mscData = elTrack.GetMSCTrackData();
7179
mscData->fIsFirstStep = currentTrack.initialRange < 0;
@@ -80,8 +88,8 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
8088

8189
// Compute safety, needed for MSC step limit.
8290
double safety = 0;
83-
if (!currentTrack.navState.IsOnBoundary()) {
84-
safety = BVHNavigator::ComputeSafety(currentTrack.pos, currentTrack.navState);
91+
if (!navState.IsOnBoundary()) {
92+
safety = BVHNavigator::ComputeSafety(pos, navState);
8593
}
8694
theTrack->SetSafety(safety);
8795

@@ -102,9 +110,9 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
102110

103111
bool restrictedPhysicalStepLength = false;
104112
if (BzFieldValue != 0) {
105-
const double momentumMag = sqrt(currentTrack.energy * (currentTrack.energy + 2.0 * Mass));
113+
const double momentumMag = sqrt(energy * (energy + 2.0 * Mass));
106114
// Distance along the track direction to reach the maximum allowed error
107-
const double safeLength = fieldPropagatorBz.ComputeSafeLength(momentumMag, Charge, currentTrack.dir);
115+
const double safeLength = fieldPropagatorBz.ComputeSafeLength(momentumMag, Charge, dir);
108116

109117
constexpr int MaxSafeLength = 10;
110118
double limit = MaxSafeLength * safeLength;
@@ -145,22 +153,20 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
145153
vecgeom::NavStateIndex nextState;
146154
if (BzFieldValue != 0) {
147155
geometryStepLength = fieldPropagatorBz.ComputeStepAndNextVolume<BVHNavigator>(
148-
currentTrack.energy, Mass, Charge, geometricalStepLengthFromPhysics, currentTrack.pos, currentTrack.dir,
149-
currentTrack.navState, nextState, propagated, safety);
156+
energy, Mass, Charge, geometricalStepLengthFromPhysics, pos, dir, navState, nextState, propagated, safety);
150157
} else {
151-
geometryStepLength =
152-
BVHNavigator::ComputeStepAndNextVolume(currentTrack.pos, currentTrack.dir, geometricalStepLengthFromPhysics,
153-
currentTrack.navState, nextState, kPush);
154-
currentTrack.pos += geometryStepLength * currentTrack.dir;
158+
geometryStepLength = BVHNavigator::ComputeStepAndNextVolume(pos, dir, geometricalStepLengthFromPhysics, navState,
159+
nextState, kPush);
160+
pos += geometryStepLength * dir;
155161
}
156162

157163
// Set boundary state in navState so the next step and secondaries get the
158-
// correct information (currentTrack.navState = nextState only if relocated
164+
// correct information (navState = nextState only if relocated
159165
// in case of a boundary; see below)
160-
currentTrack.navState.SetBoundaryState(nextState.IsOnBoundary());
166+
navState.SetBoundaryState(nextState.IsOnBoundary());
161167

162168
// Propagate information from geometrical step to MSC.
163-
theTrack->SetDirection(currentTrack.dir.x(), currentTrack.dir.y(), currentTrack.dir.z());
169+
theTrack->SetDirection(dir.x(), dir.y(), dir.z());
164170
theTrack->SetGStepLength(geometryStepLength);
165171
theTrack->SetOnBoundary(nextState.IsOnBoundary());
166172

@@ -169,7 +175,7 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
169175

170176
// Collect the direction change and displacement by MSC.
171177
const double *direction = theTrack->GetDirection();
172-
currentTrack.dir.Set(direction[0], direction[1], direction[2]);
178+
dir.Set(direction[0], direction[1], direction[2]);
173179
if (!nextState.IsOnBoundary()) {
174180
const double *mscDisplacement = mscData->GetDisplacement();
175181
vecgeom::Vector3D<Precision> displacement(mscDisplacement[0], mscDisplacement[1], mscDisplacement[2]);
@@ -186,18 +192,18 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
186192
// Apply displacement, depending on how close we are to a boundary.
187193
// 1a. Far away from geometry boundary:
188194
if (reducedSafety > 0.0 && dispR <= reducedSafety) {
189-
currentTrack.pos += displacement;
195+
pos += displacement;
190196
} else {
191197
// Recompute safety.
192-
safety = BVHNavigator::ComputeSafety(currentTrack.pos, currentTrack.navState);
198+
safety = BVHNavigator::ComputeSafety(pos, navState);
193199
reducedSafety = sFact * safety;
194200

195201
// 1b. Far away from geometry boundary:
196202
if (reducedSafety > 0.0 && dispR <= reducedSafety) {
197-
currentTrack.pos += displacement;
203+
pos += displacement;
198204
// 2. Push to boundary:
199205
} else if (reducedSafety > kGeomMinLength) {
200-
currentTrack.pos += displacement * (reducedSafety / dispR);
206+
pos += displacement * (reducedSafety / dispR);
201207
}
202208
// 3. Very small safety: do nothing.
203209
}
@@ -209,7 +215,7 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
209215
atomicAdd(&scoringPerVolume->chargedTrackLength[volumeID], elTrack.GetPStepLength());
210216

211217
// Collect the changes in energy and deposit.
212-
currentTrack.energy = theTrack->GetEKin();
218+
energy = theTrack->GetEKin();
213219
double energyDeposit = theTrack->GetEnergyDeposit();
214220
atomicAdd(&globalScoring->energyDeposit, energyDeposit);
215221
atomicAdd(&scoringPerVolume->energyDeposit[volumeID], energyDeposit);
@@ -234,13 +240,13 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
234240
double sinPhi, cosPhi;
235241
sincos(phi, &sinPhi, &cosPhi);
236242

237-
gamma1.InitAsSecondary(/*parent=*/currentTrack);
243+
gamma1.InitAsSecondary(pos, navState);
238244
newRNG.Advance();
239245
gamma1.rngState = newRNG;
240246
gamma1.energy = copcore::units::kElectronMassC2;
241247
gamma1.dir.Set(sint * cosPhi, sint * sinPhi, cost);
242248

243-
gamma2.InitAsSecondary(/*parent=*/currentTrack);
249+
gamma2.InitAsSecondary(pos, navState);
244250
// Reuse the RNG state of the dying track.
245251
gamma2.rngState = currentTrack.rngState;
246252
gamma2.energy = copcore::units::kElectronMassC2;
@@ -256,10 +262,10 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
256262

257263
// Kill the particle if it left the world.
258264
if (nextState.Top() != nullptr) {
259-
BVHNavigator::RelocateToNextVolume(currentTrack.pos, currentTrack.dir, nextState);
265+
BVHNavigator::RelocateToNextVolume(pos, dir, nextState);
260266

261267
// Move to the next boundary.
262-
currentTrack.navState = nextState;
268+
navState = nextState;
263269
survive();
264270
}
265271
continue;
@@ -313,14 +319,21 @@ __device__ void ElectronInteraction(int const globalSlot, SOAData const & /*soaD
313319
GlobalScoring *globalScoring, ScoringPerVolume *scoringPerVolume)
314320
{
315321
Track &currentTrack = particles[globalSlot];
316-
const auto volume = currentTrack.navState.Top();
322+
auto energy = currentTrack.energy;
323+
const auto pos = currentTrack.pos;
324+
auto dir = currentTrack.dir;
325+
const auto navState = currentTrack.navState;
326+
const auto volume = navState.Top();
317327
// the MCC vector is indexed by the logical volume id
318328
const int lvolID = volume->GetLogicalVolume()->id();
319329
const int theMCIndex = MCIndex[lvolID];
320330

321-
auto survive = [&] { activeQueue->push_back(globalSlot); };
331+
auto survive = [&] {
332+
currentTrack.dir = dir;
333+
currentTrack.energy = energy;
334+
activeQueue->push_back(globalSlot);
335+
};
322336

323-
const double energy = currentTrack.energy;
324337
const double theElCut = g4HepEmData.fTheMatCutData->fMatCutData[theMCIndex].fSecElProdCutE;
325338

326339
RanluxppDouble newRNG{currentTrack.rngState.Branch()};
@@ -331,20 +344,20 @@ __device__ void ElectronInteraction(int const globalSlot, SOAData const & /*soaD
331344
double deltaEkin = (IsElectron) ? G4HepEmElectronInteractionIoni::SampleETransferMoller(theElCut, energy, &rnge)
332345
: G4HepEmElectronInteractionIoni::SampleETransferBhabha(theElCut, energy, &rnge);
333346

334-
double dirPrimary[] = {currentTrack.dir.x(), currentTrack.dir.y(), currentTrack.dir.z()};
347+
double dirPrimary[] = {dir.x(), dir.y(), dir.z()};
335348
double dirSecondary[3];
336349
G4HepEmElectronInteractionIoni::SampleDirections(energy, deltaEkin, dirSecondary, dirPrimary, &rnge);
337350

338351
Track &secondary = secondaries.electrons.NextTrack();
339352
atomicAdd(&globalScoring->numElectrons, 1);
340353

341-
secondary.InitAsSecondary(/*parent=*/currentTrack);
354+
secondary.InitAsSecondary(pos, navState);
342355
secondary.rngState = newRNG;
343356
secondary.energy = deltaEkin;
344357
secondary.dir.Set(dirSecondary[0], dirSecondary[1], dirSecondary[2]);
345358

346-
currentTrack.energy = energy - deltaEkin;
347-
currentTrack.dir.Set(dirPrimary[0], dirPrimary[1], dirPrimary[2]);
359+
energy -= deltaEkin;
360+
dir.Set(dirPrimary[0], dirPrimary[1], dirPrimary[2]);
348361
survive();
349362
} else if constexpr (ProcessIndex == 1) {
350363
// Invoke model for Bremsstrahlung: either SB- or Rel-Brem.
@@ -355,24 +368,24 @@ __device__ void ElectronInteraction(int const globalSlot, SOAData const & /*soaD
355368
: G4HepEmElectronInteractionBrem::SampleETransferRB(&g4HepEmData, energy, logEnergy,
356369
theMCIndex, &rnge, IsElectron);
357370

358-
double dirPrimary[] = {currentTrack.dir.x(), currentTrack.dir.y(), currentTrack.dir.z()};
371+
double dirPrimary[] = {dir.x(), dir.y(), dir.z()};
359372
double dirSecondary[3];
360373
G4HepEmElectronInteractionBrem::SampleDirections(energy, deltaEkin, dirSecondary, dirPrimary, &rnge);
361374

362375
Track &gamma = secondaries.gammas.NextTrack();
363376
atomicAdd(&globalScoring->numGammas, 1);
364377

365-
gamma.InitAsSecondary(/*parent=*/currentTrack);
378+
gamma.InitAsSecondary(pos, navState);
366379
gamma.rngState = newRNG;
367380
gamma.energy = deltaEkin;
368381
gamma.dir.Set(dirSecondary[0], dirSecondary[1], dirSecondary[2]);
369382

370-
currentTrack.energy = energy - deltaEkin;
371-
currentTrack.dir.Set(dirPrimary[0], dirPrimary[1], dirPrimary[2]);
383+
energy -= deltaEkin;
384+
dir.Set(dirPrimary[0], dirPrimary[1], dirPrimary[2]);
372385
survive();
373386
} else if constexpr (ProcessIndex == 2) {
374387
// Invoke annihilation (in-flight) for e+
375-
double dirPrimary[] = {currentTrack.dir.x(), currentTrack.dir.y(), currentTrack.dir.z()};
388+
double dirPrimary[] = {dir.x(), dir.y(), dir.z()};
376389
double theGamma1Ekin, theGamma2Ekin;
377390
double theGamma1Dir[3], theGamma2Dir[3];
378391
G4HepEmPositronInteractionAnnihilation::SampleEnergyAndDirectionsInFlight(
@@ -382,12 +395,12 @@ __device__ void ElectronInteraction(int const globalSlot, SOAData const & /*soaD
382395
Track &gamma2 = secondaries.gammas.NextTrack();
383396
atomicAdd(&globalScoring->numGammas, 2);
384397

385-
gamma1.InitAsSecondary(/*parent=*/currentTrack);
398+
gamma1.InitAsSecondary(pos, navState);
386399
gamma1.rngState = newRNG;
387400
gamma1.energy = theGamma1Ekin;
388401
gamma1.dir.Set(theGamma1Dir[0], theGamma1Dir[1], theGamma1Dir[2]);
389402

390-
gamma2.InitAsSecondary(/*parent=*/currentTrack);
403+
gamma2.InitAsSecondary(pos, navState);
391404
// Reuse the RNG state of the dying track.
392405
gamma2.rngState = currentTrack.rngState;
393406
gamma2.energy = theGamma2Ekin;

examples/Example19/example.cuh

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ struct Track {
3636

3737
__host__ __device__ double Uniform() { return rngState.Rndm(); }
3838

39-
__host__ __device__ void InitAsSecondary(const Track &parent)
39+
__host__ __device__ void InitAsSecondary(const vecgeom::Vector3D<Precision> &parentPos,
40+
const vecgeom::NavStateIndex &parentNavState)
4041
{
4142
// The caller is responsible to branch a new RNG state and to set the energy.
4243
this->numIALeft[0] = -1.0;
@@ -49,8 +50,8 @@ struct Track {
4950

5051
// A secondary inherits the position of its parent; the caller is responsible
5152
// to update the directions.
52-
this->pos = parent.pos;
53-
this->navState = parent.navState;
53+
this->pos = parentPos;
54+
this->navState = parentNavState;
5455
}
5556
};
5657

0 commit comments

Comments
 (0)