Directly offload to optical TrackingManager for validation/testing
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 classTrackOffloadInterface, maybe renameLocalOpticalOffloadtoLocalOpticalGenOffload, addLocalOpticalTrackOffloadthat subclassesTrackOffloadInterface - Update
celeritas::TrackingManagerto take aTrackOffloadInterfacerather than the EM-specific one - Update
TrackingManagerConstructorso that instead of itsLocalTransporterFromThreadfunction returningintegration.local_transporter(), it will returnintegration.optical_offloadif theopts.offload_particlesis 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)
I think this is the right approach. A couple thoughts:
- It makes sense for
LocalTransporterandLocalOpticalTrackOffloadto inherit from aTrackOffloadInterfacesince they should be used in the same way. I expect the implementation ofLocalOpticalTrackOffloadwill be nearly identical toLocalOpticalOffloadthough. - 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 corePrimaryGenerator+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.
- 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
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.
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.
I think we'll want to delete that: the insertion should be done through the generator.
I would guess PR #2092 takes care of the generator offloading part of the issue.