We are still using Geant4 10.7 in my experiment. Is there a way to inactivate processes by region, other than the Geant4-DNA stuff? This doesn’t appear to be possible, but I thought I’d ask, and also ask about workarounds (e.g., set biasing of zero in a region, so the process is just skipped).
We’re specifically interested in turning off optical physics processes outside of the “inner detector” region (if we attach optical properties to copper, for example, we’ll get optical physics stuff both in the housing that holds our detectors, but also in the six-stage cryostat and shielding).
We really don’t want to go down the road of custom materials, some with and some without optical properties.
Could you group everything that you don’t want the optical process together in a region and then disable Auger, Pixe, and Fluorescence using G4EmOptions? I am not too familiar with optical physics lists. You could also set the electron/proton production cuts in that region to be very large.
In fact, we’re already doing that for the relevant G4EmOptions and the production cuts (we certainly don’t need to track all the nuclear recoils from neutron scatters in our lead shield!).
It’s specifically the processes that create or act on optical photons (G4Cherenkov, G4Scintillation, G4OpBoundaryProcess) that I’d like to disable outside of our “inner region.” The boundary process doesn’t need to have surfaces defined: if the adjacent volumes both have RINDEX, then any optical photons will get reflected/refracted, and chew up CPU time. So we’d very much like to turn those off, but keep them on and running in the space near our detectors, where the optical phonons can contribute to noise/background.
I see. I can’t think of another physics level way to do that then. The only other option that comes to mind is to set some kind of user information for the photons that merely counts the number of times that it moves from the inner detector and its nearest neighbors and to just kill the track if that number is greater than some threshold. And/Or you could also look at incident angles since I imagine that TIR could be the biggest offender in wasted CPU time if it exists.
EDIT - It appears that you can access TIR status in GetProcess() with
Yeah, we’re considering a couple of options, along the lines you describe: We could leverage StackingAction to selectively kill tracks when they’re created, possibly including a “region check”. We might also add a “region check” in our own optical TCR process (which handles both transition radiation and Cherenkov). The first option would handle all the other optical-photon creating processes as well.
Yeah, something like that. Since you want to kill them when created you could do it in the PreUserTrackingAction to avoid any of the tracks from even touching the stack. You could create user region information with a flag to “enable” the killing of these tracks that you could check and set with UI commands. That way you can disable or enable tracking in each named region. That should minimize the CPU time and memory overhead as much as can be done outside of the ideal which would be production cuts (or even better, physics lists).
Yep, thanks for talking this through with me. The CDMS simulation framework has an extensive set of UI commands, so the enable/disable by region will be very easy to implement.
I’m not a huge fan of the PreUserTrackingAction option because it takes a const G4Track*, which means having to const_cast<> in order to set the kill status. StackingAction::ClassifyNewTrack() allows you to return fKill without having to modify the track object itself. That said, we already have a TrackingAction in the framework, so we may just go with it.
There is a user request to suppress the Cerenkov process per logical volume. This is on the work plan for 2025. It seems logical to extend it to the rest of the optical processes, and per region. Please let me know if you have more details about the interface and functionality, etc., you’d like to see.
I guess the general configurations would be under /process/optical/<name>? E.g., /process/optical/cerenkov/activateInRegion [name] or inactivateInRegion [name] (or both)?
Or would it become the fully general case like I was asking about here (/process/inactivateInRegion [process] [particle] [region])? The latter would make arbitrary user processes open to the same suppression, rather than just specific Geant4-defined processes.
Hi Daren. I think for logical consistency it might be nice if this could be done on the macro or command level. Something similar to G4EmOptions functionality for regions and how it allows for disabling Auger, Fluor, and Deexc in one line since I imagine that it is fairly typical to want to disable certain physics in “background” regions which may compose quite a few different logical volumes and materials.
I was thinking optical processes specifically. Actually when I wrote my previous post, I didn’t realize you were looking for the ability to deactivate an arbitrary process. Doing it for optical only is much simpler (to me, at least), because adding the possibility to disable a process could be done for each process and there are only a few processes. For the general case we’d need to think it through. We track user requests so I encourage you to create one. Let me look into the process of creating a user request.
I agree that following the G4EmParameters (which used to be G4EmOptions) pattern is a good idea.
Thanks, Daren! I wasn’t directly thinking of arbitrary Geant4 processes, but my particular need is for a locally written optical process which is a nasty CPU hog. You are quite right that with a small number of processes, it’s easy to make each one skippable (and I’ve done that for now in our code, see below). Depending on the approach you choose, it could be generic or it could be specific to optics (or to EM).
For our locally written OpticalTCR process, what I have done to add a std::set<G4String> which can be filled with a list of region names. I have a UI command that talks to our physics builder and populates the std::set<> during PreInit. I could see something similar being done via G4EmOptions.
The builder passes the std::set<> into our OpticalTCR process, which then uses GetMeanFreePath() to set G4ForceCondition::InActivated if the track’s current region is in the list:
// Get name of region where track is currently moving
const G4LogicalVolume* trackLV = track.GetVolume()->GetLogicalVolume();
const G4Region* trackRegion = trackLV->GetRegion();
G4bool skip = (!trackRegion || (skipRegions.find(trackRegion->GetName())
!= skipRegions.end()));
*condition = (skip ? InActivated : Forced); // Don't track in bad regions!
(I think GetRegion() always returns a valid pointer, but I’m trying to be careful).
I may have mis-written from memory; G4EmParameters is what we are using to set region-specific flags. We’re stuck on G4 10.7 for CDMS, until we can invest the manpower to do a full migration and revalidate our backgrounds.
For unwanted particles, you’re right, and we have implemented track killing via PreUserTrackingAction (we have a StackingAction coming from a different library, so we can’t use that). Our goal here is to avoid spending CPU to create optical photons at a volume boundary and then immediately kill them.
Right. But that only works for the built-in X-ray related processes, not generically, and not for user-written processes.
That is true in general, but consider: if we specify the volumes/regions via macro command, then we must start with name strings. If the underlying code queries the geometry and stores pointers, then the stored pointers will become stale if the geometry gets rebuilt between runs. Storing the list of names, avoids that problem.
You may create a dummy PreUserTrackingAction that just calls your list of PreUserTrackingAction in a library “above” the others. I recognize I do not know how much time would take creating an optical photon and kill it in the stacking action, but probably is not course. Of course a more elegant solution would be to use plugins. You can have a look at GAMOS and copy freely the code you like.