A problem with electron momentum change when crossing a surface

We are studying low energy ( < 20 keV) electrons emission from flat samples. There is a problem with the momentum change at the point where an electron leaves the surface (process: Transportation).

The distributions of change between preStepPoint->GetMomentumDirection() and postStepPoint->GetMomentumDirection() is highly asymmetric along the y axis, (see the figure). While changes in x and z axis are approximately symmetric, the difference in y-direction is almost always negative. This behavior is independent of the emission energy. The surface is in the x-y plane.

The sample is a simple box, 1 mm big in every direction, position of the center is (-0.5, 0, 0). Electrons are being shot in direction perpendicular to its surface from the distance of 1 um (along the z axis). The box is either gold, silicon or carbon (the problem is with all of them) and is surrounded by vacuum.

What could be wrong?

Geant4 Version: 11.4.1
Operating System: Windows 11
Compiler/Version: Visual studio 2022
CMake Version: 4.3.0


1 Like

Hello,

is it possible to reproduce the problem in example/extended/electromagnetic/TestEm5? Is the problem when moving from the vacuum to the solid target or inverse?

VI

Hello,

thank you for the answer. Inn the example you mentioned we did not notice this behavior. On the other hand, it does not use the G4MicroElecSurface. We transformed the functionality from it to a python script to test it and the behavior is definitely caused by it.

What could be wrong?

The python code used for testing:


import numpy as np
import matplotlib.pyplot as plt

eV = 1e-6   #geant const

#surface normal
theFacetNormal = np.array([0,0,1])

#value found during debugging for Au->vacuum
energyThreshold = 5 * eV


#energy of electron
ekint = 6 * eV


N = int(1e5)
phi = np.random.sample(N)*2*np.pi
theta = np.random.sample(N)*np.pi/2

in_arr = np.stack((np.cos(phi)*np.sin(theta), np.sin(phi)*np.sin(theta), -np.cos(theta))).T
# in_arr = np.random.sample((3,N)).T*2 - 1

# %%
def orthogonal(vec):
    """
    inline Hep3Vector Hep3Vector::orthogonal() const {
      double xx = x() < 0.0 ? -x() : x();
      double yy = y() < 0.0 ? -y() : y();
      double zz = z() < 0.0 ? -z() : z();
      if (xx < yy) {
        return xx < zz ? Hep3Vector(0,z(),-y()) : Hep3Vector(y(),-x(),0);
      }else{
        return yy < zz ? Hep3Vector(-z(),0,x()) : Hep3Vector(y(),-x(),0);
      }
    }
    """

    x = vec[0]
    y = vec[1]
    z = vec[2]
    
    # return np.array((-1,-1,-1))
    # res = np.cross(vec, np.random.sample(3))
        
    if abs(x) < abs(y):
        if abs(x) < abs(z):
            res =  np.array([0, z, -y])
        else:
            return np.array([y, -x, 0])
    else:
        if abs(y) < abs(z):
            res = np.array([-z, 0, x])
        else:
            res = np.array([y, -x, 0])
        
    return res/np.linalg.norm(res)

# %%

out_arr = np.zeros((len(in_arr), 3))
for i, incoming in enumerate(in_arr):
    # incoming[-1] = -1
    #momentum of electron - unit vector
    incoming = np.array(incoming)
    incoming = incoming / np.linalg.norm(incoming)
    
    #supporting method from G4MicroelecSurface
    def GetIncidentAngle(oldMomentum):
        PdotN = np.dot(oldMomentum, theFacetNormal)
        magP = np.linalg.norm(oldMomentum)
        magN = np.linalg.norm(theFacetNormal)
        
        incidentangle = np.asin(PdotN/(magP*magN))
        # incidentangle = np.acos(PdotN/(magP*magN))
        # incidentangle = 
        return incidentangle
       
    #a ted uz hura na ty vypocty    
    thetat = GetIncidentAngle(incoming)  #angle d incidence
    
    thetat_alt = np.atan(incoming[2]/np.sqrt(incoming[0]**2 + incoming[1]**2))
    # print(f"{incoming}")
    # print(f"{thetat = } rad")
    # print(f"{thetat_alt = } rad\n")
    ekinNormalt = ekint * np.cos(thetat)**2
    
    sin_thetaft = np.sqrt(ekint/(ekint+energyThreshold)) * np.sin(thetat)
    #Refraction angle
    if (1.0-sin_thetaft**2 ) > 0:
        cos_thetaft = np.sqrt(1.0-sin_thetaft**2);
    else:
        cos_thetaft = 0.0;
      
    # print(cos_thetaft)
    #finalni vypocet
    cos_thetaft = cos_thetaft*np.cos(thetat) + sin_thetaft*np.sin(thetat)
    
    zVerst = incoming
    xVerst = orthogonal(zVerst)       #zVerst.orthogonal()
    yVerst = np.cross(zVerst,xVerst)
    
    xDirt = np.sqrt(1. - cos_thetaft**2);
    yDirt = xDirt;
    
    zPrimeVerst=((xDirt*xVerst + yDirt*yVerst + cos_thetaft*zVerst));
    		
    #aParticleChange.ProposeMomentumDirection(zPrimeVerst.unit());
    #->unit
    
    unitVecResult =  zPrimeVerst / np.linalg.norm(zPrimeVerst)
    
    out_arr[i] = unitVecResult
    # print(f" in: {incoming} \nout: {unitVecResult} \n")


out_arr = out_arr.T
in_arr = in_arr.T
# %%

fig, ax = plt.subplots()
for x, d in zip(in_arr, ("x_in", "y_in", "z_in")):
# for x, d in zip(in_arr.T, ("x", "y", "z")):
    ax. hist(x, 
             label = d, 
             bins = 50,
             histtype = "step"
             )
ax.legend()

fig, ax = plt.subplots()
for x, d in zip(out_arr, ("x", "y", "z")):
# for x, d in zip(in_arr.T, ("x", "y", "z")):
    ax. hist(x, 
             label = d, 
             bins = 50,
             histtype = "step"
             )
ax.legend()

diff_arr = out_arr - in_arr
fig, ax = plt.subplots()
for x, d in zip(diff_arr, ("x_diff", "y_diff", "z_diff")):
# for x, d in zip(in_arr.T, ("x", "y", "z")):
    ax. hist(x, 
             label = d, 
             bins = 50,
             histtype = "step"
             )
ax.legend()

fig, ax = plt.subplots()
r = np.sqrt(out_arr[0]**2 + out_arr[1]**2)

out_phi = np.atan2(out_arr[1],out_arr[0])
# out_phi = np.asin(out_arr[1]/r)
# out_phi = np.arccos(out_arr[0]/r)
out_theta = np.arctan(out_arr[2]/r)

for d, name in zip((
        out_phi, 
        out_theta
        ), (
            "phi", 
            "theta"
            )):
    ax.hist(d, 
            bins = 70,
            label = name,
            histtype = "step"
            )

ax.legend()


Hello František, Thanks for the reproducer. I have created a Geant4 bugzilla ticket based on this discussion: 2713 – Possible bug in G4MicroElecSurface: asymmetric momentum change at flat boundary.