Particle moves between logical volumes with no boundary process?

I am using Geant4.10.06.p01 for tracking of ultra-cold neutrons (UCNs). I am experiencing a problem which seems to come from a failure to trigger a boundary process when UCNs move between logical volumes. I would like some help understanding a section of Geant4 code that I think might be related to this problem.

A quick word about the physics involved. One of the physics processes for UCNs is reflection and transmission at surfaces. There are two simple rules regarding transmission (G4UCNBoundaryProcess):

  1. If the component of the UCN velocity normal to a surface is less than a “critical velocity” (related to the “Fermi potential” of that material), the UCN is never transmitted.
  2. If its normal velocity is above this critical velocity, then it is transmitted, and its velocity is reduced by an amount related to the difference between the potential of the material into which it travels, and the potential of the material from which it came.

The issue is as follows: I am putting UCNs in an empty container (with a Fermi potential big enough so that no UCNs should be able to escape), and then tracking their motion. They should bounce around until they are lost via beta decay or absorption on the walls. Every once in while (about 0.001% of the time or so, depending on the geometry), a UCN manages to enter the logical volume of the container without losing any kinetic energy. When it leaves the container, it then picks up some energy via rule 2 mentioned above.

I would like to learn more about tracking in Geant4 to understand why this is happening. I was hoping someone could help me understand the first few lines of the PostStepDoIt method of G4UCNBoundaryProcess:

G4UCNBoundaryProcess::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep)

  // Get hyperStep from  G4ParallelWorldProcess
  //  NOTE: PostSetpDoIt of this process should be
  //        invoked after G4ParallelWorldProcess!

  const G4Step* pStep = &aStep;

  const G4Step* hStep = G4ParallelWorldProcess::GetHyperStep();

  if (hStep) pStep = hStep;

  G4bool isOnBoundary =
          (pStep->GetPostStepPoint()->GetStepStatus() == fGeomBoundary);

  if (isOnBoundary) {
     Material1 = pStep->GetPreStepPoint()->GetMaterial();
     Material2 = pStep->GetPostStepPoint()->GetMaterial();
  } else {
     theStatus = NotAtBoundary;
     if ( verboseLevel > 1 ) BoundaryProcessVerbose();
     return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);

  if (aTrack.GetStepLength()<=kCarTolerance/2) {
     theStatus = StepTooSmall;
     if ( verboseLevel > 0 ) BoundaryProcessVerbose();
     return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);

For one, I have had trouble finding more information about G4ParallelWorldProcess and the hyper step. I do not know what those lines are doing. I also have had trouble finding more information about the surface tolerance. I gather that every logical volume has a skin thickness that is set to 1e-9*mm in G4GeometryTolerance, but I do not understand how this comes into play when a particle is being tracked. If someone could recommend some references to me regarding either of these, or offer any insight, I would be very grateful.

There are a few other other things to perhaps mention. One, I am importing my geometry using the GDML parser. If the container is something like a hollow cylinder made using a few of the tube solids, the issue happens about 0.001% of the time. If instead I import a more complicated geometry as a tesselated solid, the issue happens much more frequently, about 0.1% of the time. Two, there are also bulk processes for UCNs if they make it into the container (which they shouldn’t be able to). If I disable these processes, this seems to amplify the issue by a factor of two or three, again depending on the geometry. I am not sure what to make of this.

Thanks very much for any help.

Do you have a parallel geometry (or mesh scoring) with the exact same boundary?

Hello, thank you for the reply. I do not have anything like that. As far as I know, there is nothing internal to the G4UCN classes which does either. I guess that means those couple lines are not applicable for me?

Just in case anyone has this or a similar problem in the future, it is almost definitely as a result of using complicated tesselated solids generated from STL CAD files (what I was doing). If these are replaced by the less complicated native GDML solids (tubes, boxes, etc.) the issue goes away.

There must be something very different about the way intersections are calculated between these two set of solids. Gravity is involved, and I tried unsuccessfully to play around with the transportation tolerance parameters.