celeritas icon indicating copy to clipboard operation
celeritas copied to clipboard

Directly offload to optical TrackingManager for validation/testing

Open sethrj opened this issue 1 month ago • 5 comments

Add support for using the existing tracking manager (and integration) to offload optical photons directly from Geant4 into the optical tracking loop.

Suggested approach:

  • Add an optical primary generator[^1] that stores a vector of initial states (position, direction, wavelength) as aux data, and the "generator" instantiates tracks from those. @hhollenb will create this by adapting from his unit test.
  • Subclass the OffloadInterface [^2] with another interface class TrackOffloadInterface, maybe rename LocalOpticalOffload to LocalOpticalGenOffload, add LocalOpticalTrackOffload that subclasses TrackOffloadInterface
  • Update celeritas::TrackingManager to take a TrackOffloadInterface rather than the EM-specific one
  • Update TrackingManagerConstructor so that instead of its LocalTransporterFromThread function returning integration.local_transporter(), it will return integration.optical_offload if the opts.offload_particles is set to optical photons
  • For now the optical params setup can create generators for optical, cherenkov, and the "primary"; but as an optimization we should only create for the modes that are supported (done in the constructor of the different OffloadInterface subclasses)

I will definitely need @amandalund's view of whether this is sensible and fits into our structure without too much hassle, and I will get #2099 and company reviewed pronto.

[^1]: Our names for this are really confusing right now because of how the primaries/initialzers/generators/optical generators have evolved. I think "generator" is what we should name an object/action that creates tracks/initializers. I hesitate to use "primary" at all because an optical photon could have many "primaries" (suppose that we have a photon that came from a wavelength shifted photon, which came from a scintillation photon, which came from an EM track secondary in Celeritas, which came from an EM particle offloaded from Geant4, which came from an actual hadronic primary.) The current "optical primary generator" should perhaps be a "general distribution generator" or something.

[^2]: Speaking of names, this might be a good time to rename LocalTransporter to LocalOffload (and perhaps alias to LocalEmOffload for the time being since we don't support hadrons)

sethrj avatar Nov 09 '25 11:11 sethrj

I think this is the right approach. A couple thoughts:

  • It makes sense for LocalTransporter and LocalOpticalTrackOffload to inherit from a TrackOffloadInterface since they should be used in the same way. I expect the implementation of LocalOpticalTrackOffload will be nearly identical to LocalOpticalOffload though.
  • Not sure I understand the last bullet: I don't know if we should (or can?) create the generators in the local offload classes since the generators are shared. We also should really just have a single shared optical::Transporter (and I moved its construction out of the offload class).
  • The order we currently need to construct things in is generators -> transporter -> state/aux.
  • I agree we should work on the names. We misuse the term "primary" a bit in Celeritas to mean any track that was not generated from another Celeritas track (has a null parent ID) rather than a particle that came from an event generator or particle gun. I actually think it's a better fit for the current PrimaryGeneratorAction, since these really are always tracks that exist before any tracking rather than something that may have been produced during the simulation. It's the optical equivalent of our core PrimaryGenerator + ExtendFromPrimariesAction + InitializeTracksAction, while the new generator would be the equivalent of just the latter two. That said, I don't have any objection to dropping "primary" entirely and coming up with better names.

amandalund avatar Nov 09 '25 15:11 amandalund

  • Agreed, we should do our best to avoid duplication across the setups, but I think having at least two separate concrete classes for the use case of optical generator offload (integrated via stepping action/process) and "primary" offload (where we "capture" a track).
  • What I meant was that for now we can create all generator actions in all cases; but we should consider how to only create the generators needed for the given use case. (That is, we shouldn't create the 'primary' generator if only pushing distributions from G4/Celeritas EM tracks, and we shouldn't create scint/cherenkov if we're using a strictly optical photon loop in geant4.)
  • I'll add a to-do item on https://github.com/celeritas-project/celeritas/issues/721

Related: #1860

sethrj avatar Nov 10 '25 14:11 sethrj

Oh yes, we should only create the generator for the offload mode we're using. Right now we have a variant generator type in the inp and some validation in the local offload classes, so we at least should catch it if an incompatible generator is used.

amandalund avatar Nov 10 '25 15:11 amandalund

Oh also note that there's currently a placeholder method in the core state:

template<MemSpace M>
void CoreState<M>::insert_primaries(Span<TrackInitializer const>)
{
    CELER_NOT_IMPLEMENTED("primary insertion");
}

so we need to implement or delete that.

sethrj avatar Nov 10 '25 16:11 sethrj

I think we'll want to delete that: the insertion should be done through the generator.

amandalund avatar Nov 10 '25 16:11 amandalund

I would guess PR #2092 takes care of the generator offloading part of the issue.

Rashika-Gupta avatar Nov 25 '25 18:11 Rashika-Gupta