1- // SPDX-FileCopyrightText: 2021 CERN
1+ // SPDX-FileCopyrightText: 2022 CERN
22// SPDX-License-Identifier: Apache-2.0
33
44#include " example13.cuh"
@@ -47,18 +47,29 @@ 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 slot = (*active)[i];
4949 Track ¤tTrack = electrons[slot];
50- auto volume = currentTrack.navState .Top ();
51- int volumeID = volume->id ();
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 ();
55+ const int volumeID = volume->id ();
5256 // the MCC vector is indexed by the logical volume id
53- int lvolID = volume->GetLogicalVolume ()->id ();
54- int theMCIndex = MCIndex[lvolID];
57+ const int theMCIndex = MCIndex[volume->GetLogicalVolume ()->id ()];
58+
59+ auto survive = [&] {
60+ currentTrack.energy = energy;
61+ currentTrack.pos = pos;
62+ currentTrack.dir = dir;
63+ currentTrack.navState = navState;
64+ activeQueue->push_back (slot);
65+ };
5566
5667 // Init a track with the needed data to call into G4HepEm.
5768 G4HepEmElectronTrack elTrack;
5869 G4HepEmTrack *theTrack = elTrack.GetTrack ();
59- theTrack->SetEKin (currentTrack. energy );
70+ theTrack->SetEKin (energy);
6071 theTrack->SetMCIndex (theMCIndex);
61- theTrack->SetOnBoundary (currentTrack. navState .IsOnBoundary ());
72+ theTrack->SetOnBoundary (navState.IsOnBoundary ());
6273 theTrack->SetCharge (Charge);
6374 G4HepEmMSCTrackData *mscData = elTrack.GetMSCTrackData ();
6475 mscData->fIsFirstStep = currentTrack.initialRange < 0 ;
@@ -73,8 +84,8 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
7384
7485 // Compute safety, needed for MSC step limit.
7586 double safety = 0 ;
76- if (!currentTrack. navState .IsOnBoundary ()) {
77- safety = BVHNavigator::ComputeSafety (currentTrack. pos , currentTrack. navState );
87+ if (!navState.IsOnBoundary ()) {
88+ safety = BVHNavigator::ComputeSafety (pos, navState);
7889 }
7990 theTrack->SetSafety (safety);
8091
@@ -97,7 +108,6 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
97108 currentTrack.dynamicRangeFactor = mscData->fDynamicRangeFactor ;
98109 currentTrack.tlimitMin = mscData->fTlimitMin ;
99110
100-
101111 // Get result into variables.
102112 double geometricalStepLengthFromPhysics = theTrack->GetGStepLength ();
103113 // The phyiscal step length is the amount that the particle experiences
@@ -115,22 +125,20 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
115125 vecgeom::NavStateIndex nextState;
116126 if (BzFieldValue != 0 ) {
117127 geometryStepLength = fieldPropagatorBz.ComputeStepAndNextVolume <BVHNavigator>(
118- currentTrack.energy , Mass, Charge, geometricalStepLengthFromPhysics, currentTrack.pos , currentTrack.dir ,
119- currentTrack.navState , nextState, propagated, safety);
128+ energy, Mass, Charge, geometricalStepLengthFromPhysics, pos, dir, navState, nextState, propagated, safety);
120129 } else {
121- geometryStepLength =
122- BVHNavigator::ComputeStepAndNextVolume (currentTrack.pos , currentTrack.dir , geometricalStepLengthFromPhysics,
123- currentTrack.navState , nextState, kPush );
124- currentTrack.pos += geometryStepLength * currentTrack.dir ;
130+ geometryStepLength = BVHNavigator::ComputeStepAndNextVolume (pos, dir, geometricalStepLengthFromPhysics, navState,
131+ nextState, kPush );
132+ pos += geometryStepLength * dir;
125133 }
126134
127135 // Set boundary state in navState so the next step and secondaries get the
128- // correct information (currentTrack. navState = nextState only if relocated
136+ // correct information (navState = nextState only if relocated
129137 // in case of a boundary; see below)
130- currentTrack. navState .SetBoundaryState (nextState.IsOnBoundary ());
138+ navState.SetBoundaryState (nextState.IsOnBoundary ());
131139
132140 // Propagate information from geometrical step to MSC.
133- theTrack->SetDirection (currentTrack. dir .x (), currentTrack. dir .y (), currentTrack. dir .z ());
141+ theTrack->SetDirection (dir.x (), dir.y (), dir.z ());
134142 theTrack->SetGStepLength (geometryStepLength);
135143 theTrack->SetOnBoundary (nextState.IsOnBoundary ());
136144
@@ -139,7 +147,7 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
139147
140148 // Collect the direction change and displacement by MSC.
141149 const double *direction = theTrack->GetDirection ();
142- currentTrack. dir .Set (direction[0 ], direction[1 ], direction[2 ]);
150+ dir.Set (direction[0 ], direction[1 ], direction[2 ]);
143151 if (!nextState.IsOnBoundary ()) {
144152 const double *mscDisplacement = mscData->GetDisplacement ();
145153 vecgeom::Vector3D<Precision> displacement (mscDisplacement[0 ], mscDisplacement[1 ], mscDisplacement[2 ]);
@@ -156,18 +164,18 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
156164 // Apply displacement, depending on how close we are to a boundary.
157165 // 1a. Far away from geometry boundary:
158166 if (reducedSafety > 0.0 && dispR <= reducedSafety) {
159- currentTrack. pos += displacement;
167+ pos += displacement;
160168 } else {
161169 // Recompute safety.
162- safety = BVHNavigator::ComputeSafety (currentTrack. pos , currentTrack. navState );
170+ safety = BVHNavigator::ComputeSafety (pos, navState);
163171 reducedSafety = sFact * safety;
164172
165173 // 1b. Far away from geometry boundary:
166174 if (reducedSafety > 0.0 && dispR <= reducedSafety) {
167- currentTrack. pos += displacement;
175+ pos += displacement;
168176 // 2. Push to boundary:
169177 } else if (reducedSafety > kGeomMinLength ) {
170- currentTrack. pos += displacement * (reducedSafety / dispR);
178+ pos += displacement * (reducedSafety / dispR);
171179 }
172180 // 3. Very small safety: do nothing.
173181 }
@@ -179,7 +187,7 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
179187 atomicAdd (&scoringPerVolume->chargedTrackLength [volumeID], elTrack.GetPStepLength ());
180188
181189 // Collect the changes in energy and deposit.
182- currentTrack. energy = theTrack->GetEKin ();
190+ energy = theTrack->GetEKin ();
183191 double energyDeposit = theTrack->GetEnergyDeposit ();
184192 atomicAdd (&globalScoring->energyDeposit , energyDeposit);
185193 atomicAdd (&scoringPerVolume->energyDeposit [volumeID], energyDeposit);
@@ -204,13 +212,13 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
204212 double sinPhi, cosPhi;
205213 sincos (phi, &sinPhi, &cosPhi);
206214
207- gamma1.InitAsSecondary (/* parent= */ currentTrack );
215+ gamma1.InitAsSecondary (pos, navState );
208216 newRNG.Advance ();
209217 gamma1.rngState = newRNG;
210218 gamma1.energy = copcore::units::kElectronMassC2 ;
211219 gamma1.dir .Set (sint * cosPhi, sint * sinPhi, cost);
212220
213- gamma2.InitAsSecondary (/* parent= */ currentTrack );
221+ gamma2.InitAsSecondary (pos, navState );
214222 // Reuse the RNG state of the dying track.
215223 gamma2.rngState = currentTrack.rngState ;
216224 gamma2.energy = copcore::units::kElectronMassC2 ;
@@ -226,21 +234,21 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
226234
227235 // Kill the particle if it left the world.
228236 if (nextState.Top () != nullptr ) {
229- activeQueue->push_back (slot);
230- BVHNavigator::RelocateToNextVolume (currentTrack.pos , currentTrack.dir , nextState);
237+ BVHNavigator::RelocateToNextVolume (pos, dir, nextState);
231238
232239 // Move to the next boundary.
233- currentTrack.navState = nextState;
240+ navState = nextState;
241+ survive ();
234242 }
235243 continue ;
236244 } else if (!propagated) {
237245 // Did not yet reach the interaction point due to error in the magnetic
238246 // field propagation. Try again next time.
239- activeQueue-> push_back (slot );
247+ survive ( );
240248 continue ;
241249 } else if (winnerProcessIndex < 0 ) {
242250 // No discrete process, move on.
243- activeQueue-> push_back (slot );
251+ survive ( );
244252 continue ;
245253 }
246254
@@ -251,7 +259,7 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
251259 // Check if a delta interaction happens instead of the real discrete process.
252260 if (G4HepEmElectronManager::CheckDelta (&g4HepEmData, theTrack, currentTrack.Uniform ())) {
253261 // A delta interaction happened, move on.
254- activeQueue-> push_back (slot );
262+ survive ( );
255263 continue ;
256264 }
257265
@@ -262,7 +270,6 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
262270 // numbers after MSC used up a fair share for sampling the displacement.
263271 currentTrack.rngState .Advance ();
264272
265- const double energy = currentTrack.energy ;
266273 const double theElCut = g4HepEmData.fTheMatCutData ->fMatCutData [theMCIndex].fSecElProdCutE ;
267274
268275 switch (winnerProcessIndex) {
@@ -271,22 +278,21 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
271278 double deltaEkin = (IsElectron) ? G4HepEmElectronInteractionIoni::SampleETransferMoller (theElCut, energy, &rnge)
272279 : G4HepEmElectronInteractionIoni::SampleETransferBhabha (theElCut, energy, &rnge);
273280
274- double dirPrimary[] = {currentTrack. dir .x (), currentTrack. dir .y (), currentTrack. dir .z ()};
281+ double dirPrimary[] = {dir.x (), dir.y (), dir.z ()};
275282 double dirSecondary[3 ];
276283 G4HepEmElectronInteractionIoni::SampleDirections (energy, deltaEkin, dirSecondary, dirPrimary, &rnge);
277284
278285 Track &secondary = secondaries.electrons .NextTrack ();
279286 atomicAdd (&globalScoring->numElectrons , 1 );
280287
281- secondary.InitAsSecondary (/* parent= */ currentTrack );
288+ secondary.InitAsSecondary (pos, navState );
282289 secondary.rngState = newRNG;
283290 secondary.energy = deltaEkin;
284291 secondary.dir .Set (dirSecondary[0 ], dirSecondary[1 ], dirSecondary[2 ]);
285292
286- currentTrack.energy = energy - deltaEkin;
287- currentTrack.dir .Set (dirPrimary[0 ], dirPrimary[1 ], dirPrimary[2 ]);
288- // The current track continues to live.
289- activeQueue->push_back (slot);
293+ energy -= deltaEkin;
294+ dir.Set (dirPrimary[0 ], dirPrimary[1 ], dirPrimary[2 ]);
295+ survive ();
290296 break ;
291297 }
292298 case 1 : {
@@ -298,27 +304,26 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
298304 : G4HepEmElectronInteractionBrem::SampleETransferRB (&g4HepEmData, energy, logEnergy,
299305 theMCIndex, &rnge, IsElectron);
300306
301- double dirPrimary[] = {currentTrack. dir .x (), currentTrack. dir .y (), currentTrack. dir .z ()};
307+ double dirPrimary[] = {dir.x (), dir.y (), dir.z ()};
302308 double dirSecondary[3 ];
303309 G4HepEmElectronInteractionBrem::SampleDirections (energy, deltaEkin, dirSecondary, dirPrimary, &rnge);
304310
305311 Track &gamma = secondaries.gammas .NextTrack ();
306312 atomicAdd (&globalScoring->numGammas , 1 );
307313
308- gamma.InitAsSecondary (/* parent= */ currentTrack );
314+ gamma.InitAsSecondary (pos, navState );
309315 gamma.rngState = newRNG;
310316 gamma.energy = deltaEkin;
311317 gamma.dir .Set (dirSecondary[0 ], dirSecondary[1 ], dirSecondary[2 ]);
312318
313- currentTrack.energy = energy - deltaEkin;
314- currentTrack.dir .Set (dirPrimary[0 ], dirPrimary[1 ], dirPrimary[2 ]);
315- // The current track continues to live.
316- activeQueue->push_back (slot);
319+ energy -= deltaEkin;
320+ dir.Set (dirPrimary[0 ], dirPrimary[1 ], dirPrimary[2 ]);
321+ survive ();
317322 break ;
318323 }
319324 case 2 : {
320325 // Invoke annihilation (in-flight) for e+
321- double dirPrimary[] = {currentTrack. dir .x (), currentTrack. dir .y (), currentTrack. dir .z ()};
326+ double dirPrimary[] = {dir.x (), dir.y (), dir.z ()};
322327 double theGamma1Ekin, theGamma2Ekin;
323328 double theGamma1Dir[3 ], theGamma2Dir[3 ];
324329 G4HepEmPositronInteractionAnnihilation::SampleEnergyAndDirectionsInFlight (
@@ -328,12 +333,12 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
328333 Track &gamma2 = secondaries.gammas .NextTrack ();
329334 atomicAdd (&globalScoring->numGammas , 2 );
330335
331- gamma1.InitAsSecondary (/* parent= */ currentTrack );
336+ gamma1.InitAsSecondary (pos, navState );
332337 gamma1.rngState = newRNG;
333338 gamma1.energy = theGamma1Ekin;
334339 gamma1.dir .Set (theGamma1Dir[0 ], theGamma1Dir[1 ], theGamma1Dir[2 ]);
335340
336- gamma2.InitAsSecondary (/* parent= */ currentTrack );
341+ gamma2.InitAsSecondary (pos, navState );
337342 // Reuse the RNG state of the dying track.
338343 gamma2.rngState = currentTrack.rngState ;
339344 gamma2.energy = theGamma2Ekin;
0 commit comments