3131template <bool IsElectron>
3232static __device__ __forceinline__ void TransportElectrons (Track *electrons, const adept::MParray *active,
3333 Secondaries &secondaries, adept::MParray *activeQueue,
34- GlobalScoring *globalScoring,
35- ScoringPerVolume *scoringPerVolume, SOAData soaData )
34+ Interactions interactions, GlobalScoring *globalScoring,
35+ ScoringPerVolume *scoringPerVolume)
3636{
3737#ifdef VECGEOM_FLOAT_PRECISION
3838 const Precision kPush = 10 * vecgeom::kTolerance ;
@@ -57,9 +57,6 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
5757 if (push) activeQueue->push_back (globalSlot);
5858 };
5959
60- // Signal that this globalSlot doesn't undergo an interaction (yet)
61- soaData.nextInteraction [i] = -1 ;
62-
6360 // Init a track with the needed data to call into G4HepEm.
6461 G4HepEmElectronTrack elTrack;
6562 G4HepEmTrack *theTrack = elTrack.GetTrack ();
@@ -285,151 +282,150 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
285282 continue ;
286283 }
287284
288- soaData. nextInteraction [i] = winnerProcessIndex;
285+ interactions. queues [ winnerProcessIndex]-> push_back (globalSlot) ;
289286
290287 survive (false );
291288 }
292289}
293290
294291// Instantiate kernels for electrons and positrons.
295292__global__ void TransportElectrons (Track *electrons, const adept::MParray *active, Secondaries secondaries,
296- adept::MParray *activeQueue, GlobalScoring *globalScoring,
297- ScoringPerVolume *scoringPerVolume, SOAData soaData )
293+ adept::MParray *activeQueue, Interactions interactions, GlobalScoring *globalScoring,
294+ ScoringPerVolume *scoringPerVolume)
298295{
299- TransportElectrons</* IsElectron*/ true >(electrons, active, secondaries, activeQueue, globalScoring, scoringPerVolume ,
300- soaData );
296+ TransportElectrons</* IsElectron*/ true >(electrons, active, secondaries, activeQueue, interactions, globalScoring ,
297+ scoringPerVolume );
301298}
302299__global__ void TransportPositrons (Track *positrons, const adept::MParray *active, Secondaries secondaries,
303- adept::MParray *activeQueue, GlobalScoring *globalScoring,
304- ScoringPerVolume *scoringPerVolume, SOAData soaData )
300+ adept::MParray *activeQueue, Interactions interactions, GlobalScoring *globalScoring,
301+ ScoringPerVolume *scoringPerVolume)
305302{
306- TransportElectrons</* IsElectron*/ false >(positrons, active, secondaries, activeQueue, globalScoring, scoringPerVolume ,
307- soaData );
303+ TransportElectrons</* IsElectron*/ false >(positrons, active, secondaries, activeQueue, interactions, globalScoring ,
304+ scoringPerVolume );
308305}
309306
310307template <bool IsElectron, int ProcessIndex>
311- __device__ void ElectronInteraction (int const globalSlot, SOAData const & /* soaData */ , int const /* soaSlot */ ,
312- Track *particles, Secondaries secondaries, adept::MParray *activeQueue,
313- GlobalScoring *globalScoring, ScoringPerVolume *scoringPerVolume)
308+ __device__ void ElectronInteraction (Track *particles, const adept::MParray *active, Secondaries secondaries ,
309+ adept::MParray *activeQueue, GlobalScoring *globalScoring ,
310+ ScoringPerVolume *scoringPerVolume)
314311{
315- Track ¤tTrack = particles[globalSlot];
316- const auto volume = currentTrack.navState .Top ();
317- // the MCC vector is indexed by the logical volume id
318- const int lvolID = volume->GetLogicalVolume ()->id ();
319- const int theMCIndex = MCIndex[lvolID];
320-
321- auto survive = [&] { activeQueue->push_back (globalSlot); };
322-
323- const double energy = currentTrack.energy ;
324- const double theElCut = g4HepEmData.fTheMatCutData ->fMatCutData [theMCIndex].fSecElProdCutE ;
325-
326- RanluxppDouble newRNG{currentTrack.rngState .Branch ()};
327- G4HepEmRandomEngine rnge{¤tTrack.rngState };
328-
329- if constexpr (ProcessIndex == 0 ) {
330- // Invoke ionization (for e-/e+):
331- double deltaEkin = (IsElectron) ? G4HepEmElectronInteractionIoni::SampleETransferMoller (theElCut, energy, &rnge)
332- : G4HepEmElectronInteractionIoni::SampleETransferBhabha (theElCut, energy, &rnge);
333-
334- double dirPrimary[] = {currentTrack.dir .x (), currentTrack.dir .y (), currentTrack.dir .z ()};
335- double dirSecondary[3 ];
336- G4HepEmElectronInteractionIoni::SampleDirections (energy, deltaEkin, dirSecondary, dirPrimary, &rnge);
337-
338- Track &secondary = secondaries.electrons .NextTrack ();
339- atomicAdd (&globalScoring->numElectrons , 1 );
340-
341- secondary.InitAsSecondary (/* parent=*/ currentTrack);
342- secondary.rngState = newRNG;
343- secondary.energy = deltaEkin;
344- secondary.dir .Set (dirSecondary[0 ], dirSecondary[1 ], dirSecondary[2 ]);
345-
346- currentTrack.energy = energy - deltaEkin;
347- currentTrack.dir .Set (dirPrimary[0 ], dirPrimary[1 ], dirPrimary[2 ]);
348- survive ();
349- } else if constexpr (ProcessIndex == 1 ) {
350- // Invoke model for Bremsstrahlung: either SB- or Rel-Brem.
351- double logEnergy = std::log (energy);
352- double deltaEkin = energy < g4HepEmPars.fElectronBremModelLim
353- ? G4HepEmElectronInteractionBrem::SampleETransferSB (&g4HepEmData, energy, logEnergy,
354- theMCIndex, &rnge, IsElectron)
355- : G4HepEmElectronInteractionBrem::SampleETransferRB (&g4HepEmData, energy, logEnergy,
356- theMCIndex, &rnge, IsElectron);
357-
358- double dirPrimary[] = {currentTrack.dir .x (), currentTrack.dir .y (), currentTrack.dir .z ()};
359- double dirSecondary[3 ];
360- G4HepEmElectronInteractionBrem::SampleDirections (energy, deltaEkin, dirSecondary, dirPrimary, &rnge);
361-
362- Track &gamma = secondaries.gammas .NextTrack ();
363- atomicAdd (&globalScoring->numGammas , 1 );
364-
365- gamma.InitAsSecondary (/* parent=*/ currentTrack);
366- gamma.rngState = newRNG;
367- gamma.energy = deltaEkin;
368- gamma.dir .Set (dirSecondary[0 ], dirSecondary[1 ], dirSecondary[2 ]);
369-
370- currentTrack.energy = energy - deltaEkin;
371- currentTrack.dir .Set (dirPrimary[0 ], dirPrimary[1 ], dirPrimary[2 ]);
372- survive ();
373- } else if constexpr (ProcessIndex == 2 ) {
374- // Invoke annihilation (in-flight) for e+
375- double dirPrimary[] = {currentTrack.dir .x (), currentTrack.dir .y (), currentTrack.dir .z ()};
376- double theGamma1Ekin, theGamma2Ekin;
377- double theGamma1Dir[3 ], theGamma2Dir[3 ];
378- G4HepEmPositronInteractionAnnihilation::SampleEnergyAndDirectionsInFlight (
379- energy, dirPrimary, &theGamma1Ekin, theGamma1Dir, &theGamma2Ekin, theGamma2Dir, &rnge);
380-
381- Track &gamma1 = secondaries.gammas .NextTrack ();
382- Track &gamma2 = secondaries.gammas .NextTrack ();
383- atomicAdd (&globalScoring->numGammas , 2 );
384-
385- gamma1.InitAsSecondary (/* parent=*/ currentTrack);
386- gamma1.rngState = newRNG;
387- gamma1.energy = theGamma1Ekin;
388- gamma1.dir .Set (theGamma1Dir[0 ], theGamma1Dir[1 ], theGamma1Dir[2 ]);
389-
390- gamma2.InitAsSecondary (/* parent=*/ currentTrack);
391- // Reuse the RNG state of the dying track.
392- gamma2.rngState = currentTrack.rngState ;
393- gamma2.energy = theGamma2Ekin;
394- gamma2.dir .Set (theGamma2Dir[0 ], theGamma2Dir[1 ], theGamma2Dir[2 ]);
395-
396- // The current track is killed by not enqueuing into the next activeQueue.
312+ int activeSize = active->size ();
313+ for (int i = blockIdx .x * blockDim .x + threadIdx .x ; i < activeSize; i += blockDim .x * gridDim .x ) {
314+ const int globalSlot = (*active)[i];
315+ Track ¤tTrack = particles[globalSlot];
316+ const auto volume = currentTrack.navState .Top ();
317+ // the MCC vector is indexed by the logical volume id
318+ const int lvolID = volume->GetLogicalVolume ()->id ();
319+ const int theMCIndex = MCIndex[lvolID];
320+
321+ auto survive = [&] { activeQueue->push_back (globalSlot); };
322+
323+ const double energy = currentTrack.energy ;
324+ const double theElCut = g4HepEmData.fTheMatCutData ->fMatCutData [theMCIndex].fSecElProdCutE ;
325+
326+ RanluxppDouble newRNG{currentTrack.rngState .Branch ()};
327+ G4HepEmRandomEngine rnge{¤tTrack.rngState };
328+
329+ if constexpr (ProcessIndex == 0 ) {
330+ // Invoke ionization (for e-/e+):
331+ double deltaEkin = (IsElectron) ? G4HepEmElectronInteractionIoni::SampleETransferMoller (theElCut, energy, &rnge)
332+ : G4HepEmElectronInteractionIoni::SampleETransferBhabha (theElCut, energy, &rnge);
333+
334+ double dirPrimary[] = {currentTrack.dir .x (), currentTrack.dir .y (), currentTrack.dir .z ()};
335+ double dirSecondary[3 ];
336+ G4HepEmElectronInteractionIoni::SampleDirections (energy, deltaEkin, dirSecondary, dirPrimary, &rnge);
337+
338+ Track &secondary = secondaries.electrons .NextTrack ();
339+ atomicAdd (&globalScoring->numElectrons , 1 );
340+
341+ secondary.InitAsSecondary (/* parent=*/ currentTrack);
342+ secondary.rngState = newRNG;
343+ secondary.energy = deltaEkin;
344+ secondary.dir .Set (dirSecondary[0 ], dirSecondary[1 ], dirSecondary[2 ]);
345+
346+ currentTrack.energy = energy - deltaEkin;
347+ currentTrack.dir .Set (dirPrimary[0 ], dirPrimary[1 ], dirPrimary[2 ]);
348+ survive ();
349+ } else if constexpr (ProcessIndex == 1 ) {
350+ // Invoke model for Bremsstrahlung: either SB- or Rel-Brem.
351+ double logEnergy = std::log (energy);
352+ double deltaEkin = energy < g4HepEmPars.fElectronBremModelLim
353+ ? G4HepEmElectronInteractionBrem::SampleETransferSB (&g4HepEmData, energy, logEnergy,
354+ theMCIndex, &rnge, IsElectron)
355+ : G4HepEmElectronInteractionBrem::SampleETransferRB (&g4HepEmData, energy, logEnergy,
356+ theMCIndex, &rnge, IsElectron);
357+
358+ double dirPrimary[] = {currentTrack.dir .x (), currentTrack.dir .y (), currentTrack.dir .z ()};
359+ double dirSecondary[3 ];
360+ G4HepEmElectronInteractionBrem::SampleDirections (energy, deltaEkin, dirSecondary, dirPrimary, &rnge);
361+
362+ Track &gamma = secondaries.gammas .NextTrack ();
363+ atomicAdd (&globalScoring->numGammas , 1 );
364+
365+ gamma.InitAsSecondary (/* parent=*/ currentTrack);
366+ gamma.rngState = newRNG;
367+ gamma.energy = deltaEkin;
368+ gamma.dir .Set (dirSecondary[0 ], dirSecondary[1 ], dirSecondary[2 ]);
369+
370+ currentTrack.energy = energy - deltaEkin;
371+ currentTrack.dir .Set (dirPrimary[0 ], dirPrimary[1 ], dirPrimary[2 ]);
372+ survive ();
373+ } else if constexpr (ProcessIndex == 2 ) {
374+ // Invoke annihilation (in-flight) for e+
375+ double dirPrimary[] = {currentTrack.dir .x (), currentTrack.dir .y (), currentTrack.dir .z ()};
376+ double theGamma1Ekin, theGamma2Ekin;
377+ double theGamma1Dir[3 ], theGamma2Dir[3 ];
378+ G4HepEmPositronInteractionAnnihilation::SampleEnergyAndDirectionsInFlight (
379+ energy, dirPrimary, &theGamma1Ekin, theGamma1Dir, &theGamma2Ekin, theGamma2Dir, &rnge);
380+
381+ Track &gamma1 = secondaries.gammas .NextTrack ();
382+ Track &gamma2 = secondaries.gammas .NextTrack ();
383+ atomicAdd (&globalScoring->numGammas , 2 );
384+
385+ gamma1.InitAsSecondary (/* parent=*/ currentTrack);
386+ gamma1.rngState = newRNG;
387+ gamma1.energy = theGamma1Ekin;
388+ gamma1.dir .Set (theGamma1Dir[0 ], theGamma1Dir[1 ], theGamma1Dir[2 ]);
389+
390+ gamma2.InitAsSecondary (/* parent=*/ currentTrack);
391+ // Reuse the RNG state of the dying track.
392+ gamma2.rngState = currentTrack.rngState ;
393+ gamma2.energy = theGamma2Ekin;
394+ gamma2.dir .Set (theGamma2Dir[0 ], theGamma2Dir[1 ], theGamma2Dir[2 ]);
395+
396+ // The current track is killed by not enqueuing into the next activeQueue.
397+ }
397398 }
398399}
399400
400401__global__ void IonizationEl (Track *particles, const adept::MParray *active, Secondaries secondaries,
401402 adept::MParray *activeQueue, GlobalScoring *globalScoring,
402- ScoringPerVolume *scoringPerVolume, SOAData const soaData )
403+ ScoringPerVolume *scoringPerVolume)
403404{
404- InteractionLoop<0 >(&ElectronInteraction<true , 0 >, active, soaData, particles, secondaries, activeQueue, globalScoring,
405- scoringPerVolume);
405+ ElectronInteraction<true , 0 >(particles, active, secondaries, activeQueue, globalScoring, scoringPerVolume);
406406}
407407__global__ void BremsstrahlungEl (Track *particles, const adept::MParray *active, Secondaries secondaries,
408408 adept::MParray *activeQueue, GlobalScoring *globalScoring,
409- ScoringPerVolume *scoringPerVolume, SOAData const soaData )
409+ ScoringPerVolume *scoringPerVolume)
410410{
411- InteractionLoop<1 >(&ElectronInteraction<true , 1 >, active, soaData, particles, secondaries, activeQueue, globalScoring,
412- scoringPerVolume);
411+ ElectronInteraction<true , 1 >(particles, active, secondaries, activeQueue, globalScoring, scoringPerVolume);
413412}
414413
415414__global__ void IonizationPos (Track *particles, const adept::MParray *active, Secondaries secondaries,
416415 adept::MParray *activeQueue, GlobalScoring *globalScoring,
417- ScoringPerVolume *scoringPerVolume, SOAData const soaData )
416+ ScoringPerVolume *scoringPerVolume)
418417{
419- InteractionLoop<0 >(&ElectronInteraction<false , 0 >, active, soaData, particles, secondaries, activeQueue,
420- globalScoring, scoringPerVolume);
418+ ElectronInteraction<false , 0 >(particles, active, secondaries, activeQueue, globalScoring, scoringPerVolume);
421419}
422420__global__ void BremsstrahlungPos (Track *particles, const adept::MParray *active, Secondaries secondaries,
423421 adept::MParray *activeQueue, GlobalScoring *globalScoring,
424- ScoringPerVolume *scoringPerVolume, SOAData const soaData )
422+ ScoringPerVolume *scoringPerVolume)
425423{
426- InteractionLoop<1 >(&ElectronInteraction<false , 1 >, active, soaData, particles, secondaries, activeQueue,
427- globalScoring, scoringPerVolume);
424+ ElectronInteraction<false , 1 >(particles, active, secondaries, activeQueue, globalScoring, scoringPerVolume);
428425}
429426__global__ void AnnihilationPos (Track *particles, const adept::MParray *active, Secondaries secondaries,
430427 adept::MParray *activeQueue, GlobalScoring *globalScoring,
431- ScoringPerVolume *scoringPerVolume, SOAData const soaData )
428+ ScoringPerVolume *scoringPerVolume)
432429{
433- InteractionLoop<2 >(&ElectronInteraction<false , 2 >, active, soaData, particles, secondaries, activeQueue,
434- globalScoring, scoringPerVolume);
430+ ElectronInteraction<false , 2 >(particles, active, secondaries, activeQueue, globalScoring, scoringPerVolume);
435431}
0 commit comments