Scattering functions and the refractive index

You can also calculate scattering cross sections, scattering lengths, scattering matrices or refractive indices of elements, materials, layers or samples.

Electronic scattering cross sections

Here, various electronic scattering cross sections calculations are shown. Klein-Nishina scattering is calculated after [KleinNishina]. Photoeffect cross sections are calculated after [Smith]. The electronic cross section is the sum of both contributions.

import nexus as nx

Au = nx.Element(element = "Au")

klein = nx.KleinNishinaCrossSection(Au, 14.4125e3)
print(klein)

photo = nx.PhotoCrossSection(Au, 14.4125e3)
print(photo)

elec = nx.ElectronicCrossSection(Au, 14.4125e3)
print(elec)

the functions return the cross section in \(m^2\).

4.979260700505022e-27
5.847566888130204e-24
5.852546148830709e-24

Scattering Length

The scattering length can be calculated with the cross sections calculated in the previous example or with tabulated values from the CXRO webpage [Henke] and [CXRO]. If the CXRO values are the standard values. If the cross section calculation should be used, use the appropriate set method.

# Change Nexus calculation method for the atomic scattering factors
nx.SetAtomicScatteringFactorCXRO(False)

# Get method
print(nx.GetAtomicScatteringFactorCXRO())

In the following example, the cross section calculation is used.

import nexus as nx
import numpy as np
import matplotlib.pyplot as plt

scat = nx.ElectronicScatteringLength(Au, 14.4125e3, cxro = False)
print(scat)

scat_matrix = nx.ElectronicScatteringLengthMatrix(Au, 14.4125e3, False)
print(scat_matrix)

the functions return the scattering length in \(m\).

(-2.2007448586170272e-13+3.4016359521004525e-14j)
[[-2.20074486e-13+3.40163595e-14j  0.00000000e+00+0.00000000e+00j]
 [ 0.00000000e+00+0.00000000e+00j -2.20074486e-13+3.40163595e-14j]]

To calculate the nuclear scattering length use

detuning  = np.linspace(-100, 100, 5)

Fe = nx.Material.Template(nx.lib.material.Fe)

site = nx.Hyperfine(magnetic_field = 33)

Fe.hyperfine_sites = [site]

nuc_scat = nx.NuclearScatteringLength(Fe, nx.lib.moessbauer.Fe57, detuning)

print(np.squeeze(nuc_scat))

You will get a a list with 2x2 matrices

[[[ 7.83414010e-15+6.65456280e-17j -4.84239721e-17+3.34860264e-15j]
  [ 4.84239721e-17-3.34860264e-15j  7.83414010e-15+6.65456280e-17j]]

 [[-4.03270478e-14+4.75658449e-15j -4.69310792e-15-4.81382836e-14j]
  [ 4.69310792e-15+4.81382836e-14j -4.03270478e-14+4.75658449e-15j]]

 [[-1.02636288e-30+1.05490530e-15j  0.00000000e+00+8.91495773e-15j]
  [ 0.00000000e+00-8.91495773e-15j -1.02636288e-30+1.05490530e-15j]]

 [[ 4.03270478e-14+4.75658449e-15j  4.69310792e-15-4.81382836e-14j]
  [-4.69310792e-15+4.81382836e-14j  4.03270478e-14+4.75658449e-15j]]

 [[-7.83414010e-15+6.65456280e-17j  4.84239721e-17+3.34860264e-15j]
  [-4.84239721e-17-3.34860264e-15j -7.83414010e-15+6.65456280e-17j]]]

Scattering factors, matrices and the refractive index

In order to calculate electronic or nuclear scattering factors, refractive indices or matrices of a material have a look to the Scattering Matrix section.

Here a few examples are given.

Calculation of the refractive index and the pure electronic scattering factor in grazing incidence geometry.

material = nx.Material(id = "my_material",
                       composition = [["Fe", 2], ["O", 3]],
                       density = 5.24)


# refractive index at 20 keV
refractive_index = nx.ElectronicRefractiveIndex(material, 20e3)

print(refractive_index)


# grazing indcidence scattering factor at 20 keV

# k-vector along layer direction at an angle of 0.1 degree
kz = nx.conversions.EnergyToKvectorZ(20e3, 0.1)

scattering_factor = nx.ElectronicGrazingScatteringFactor(material, 20e3, kz)
print(scattering_factor)
(0.9999973883454211+4.5329294878545176e-08j)
(-1516637870.2120943+26323590.339101084j)

Calculation of the total (nuclear + electronic) forward scattering matrix

# scattering matrix at 57-Fe transition energy
mat_Fe = nx.Material.Template(nx.lib.material.Fe_enriched)

site1 = nx.Hyperfine(magnetic_field = 33)

mat_Fe.hyperfine_sites = [site1]

detuning = np.linspace(-100, 100, 5)

scattering_matrix = nx.ForwardScatteringMatrix(mat_Fe, nx.lib.moessbauer.Fe57, detuning)

print(np.squeeze(scattering_matrix))
[[[-4.70744567e+05 +24417.51152663j -3.29906733e+02 +22813.62949622j]
  [ 3.29906733e+02 -22813.62949622j -4.70744567e+05 +24417.51152663j]]

 [[-7.98860983e+05 +56370.18560938j -3.19735833e+04-327960.37172931j]
  [ 3.19735833e+04+327960.37172931j -7.98860983e+05 +56370.18560938j]]

 [[-5.24117627e+05 +31151.08782692j  0.00000000e+00 +60736.54132636j]
  [ 0.00000000e+00 -60736.54132636j -5.24117627e+05 +31151.08782692j]]

 [[-2.49374272e+05 +56370.18560802j  3.19735833e+04-327960.37172931j]
  [-3.19735833e+04+327960.37172931j -2.49374272e+05 +56370.18560802j]]

 [[-5.77490687e+05 +24417.51152392j  3.29906733e+02 +22813.62949622j]
  [-3.29906733e+02 -22813.62949622j -5.77490687e+05 +24417.51152392j]]]

Plotting the refractive index

energies = np.linspace(1000, 10000)
refractive_index = []

for elem in energies:
    refractive_index.append(nx.ElectronicRefractiveIndex(material, elem))

plt.loglog(energies, 1 - np.real(refractive_index), label = "delta")
plt.loglog(energies, np.imag(refractive_index), label = "beta")
plt.legend()
plt.plot()
../../_images/ref_index.png

Scattering parameters of layers and samples

Similar functions exist for Layer and Sample objects. Please have a look to the Layer and Sample sections for a complete list.

For layers and samples, the functions to calculate scattering parameters and so on are class methods.

Calculate refractive index of a layer

import nexus as nx
import nexus as np

layer = nx.Layer(id = "iron oxide layer",
                 thickness = 100,
                 composition = [["Fe", 2], ["O", 3]],
                 density = 5.3)

# at 20 keV
print(layer.ElectronicRefractiveIndex(20e3))

(0.9999973584409794+4.584833260616212e-08j)

Calculate complete grazing incidence layer matrix

mat = nx.Material.Template(nx.lib.material.Fe_enriched)

site = nx.Hyperfine(magnetic_field = 33)

mat.hyperfine_sites = [site]

layer = nx.Layer(id = "my iron oxide layer",
                 thickness = 1000,  # in nanometer
                 material = mat,
                 roughness = 30,
                 thickness_fwhm = 50)

detuning = [0]

matrix = layer.GrazingLayerMatrix(nx.lib.moessbauer.Fe57, detuning, 0.2)

print(np.squeeze(matrix))

The output is a 4x4 matrix for zero detuning only.

[[-4.02131424e+63-3.71188107e+63j -3.71188107e+63+4.02131424e+63j
  -1.36403869e+63+5.83719668e+63j  5.83719668e+63+1.36403869e+63j]
 [ 3.71188107e+63-4.02131424e+63j -4.02131424e+63-3.71188107e+63j
  -5.83719668e+63-1.36403869e+63j -1.36403869e+63+5.83719668e+63j]
 [ 1.36403869e+63-5.83719668e+63j -5.83719668e+63-1.36403869e+63j
  -6.29886297e+63+1.85419632e+63j  1.85419632e+63+6.29886297e+63j]
 [ 5.83719668e+63+1.36403869e+63j  1.36403869e+63-5.83719668e+63j
  -1.85419632e+63-6.29886297e+63j -6.29886297e+63+1.85419632e+63j]]

For a Sample the ObjectMatrix() and the SampleMatrix() are the same.

mat = nx.Material.Template(nx.lib.material.Fe_enriched)

site = nx.Hyperfine(magnetic_field = 33)

mat.hyperfine_sites = [site]

layer = nx.Layer(id = "my iron oxide layer",
                 thickness = 1000,  # in nanometer
                 material = mat,
                 roughness = 30,
                 thickness_fwhm = 50)

sample = nx.Sample(layers = [layer],
                   geometry = "f")

detuning = [0]

matrix = sample.ObjectMatrix(nx.lib.moessbauer.Fe57, detuning, True)
# or
matrix = sample.SampleMatrix(nx.lib.moessbauer.Fe57, detuning)

print(np.squeeze(matrix))
[[-0.69665446+0.67094952j  0.04236449-0.04080134j]
 [-0.04236449+0.04080134j -0.69665446+0.67094952j]]

Transmission of a layer / sample

The transmission of a layer can be calculated via

layer = nx.Layer(thickness = 200,
                 material = nx.Material.Template(nx.lib.material.Al2O3))

energies = np.linspace(1000, 10000, 1001)

trans = []

for elem in energies:
    trans.append(layer.ElectronicForwardTransmission(elem))

plt.plot(energies, trans, label = "Al2O3 200 nm")
plt.xlabel("energy (eV)")
plt.ylabel("transmission")
plt.legend()
plt.show()
../../_images/transmission_layer.png

and for a sample via

layer_Al2O3= nx.Layer(thickness = 200,
                 material = nx.Material.Template(nx.lib.material.Al2O3))

layer_Fe = nx.Layer(thickness = 50,
                 material = nx.Material.Template(nx.lib.material.Fe))

sample = nx.Sample(layers = [layer_Al2O3, layer_Fe],
                   geometry = "f")

energies = np.linspace(1000, 10000, 1001)

trans_Al2O3 = []
trans_Fe = []
trans_sample = []

for elem in energies:
    trans_Al2O3.append(layer_Al2O3.ElectronicForwardTransmission(elem))
    trans_Fe.append(layer_Fe.ElectronicForwardTransmission(elem))
    trans_sample.append(sample.ElectronicTransmission(elem))
    # or use trans_sample.append(sample.ElectronicForwardTransmission(elem))

plt.plot(energies, trans_Al2O3, label = "Al2O3 200 nm")
plt.plot(energies, trans_Fe, label = "Fe 50 nm")
plt.plot(energies, trans_sample, label = "Sample")
plt.xlabel("energy (eV)")
plt.ylabel("transmission")
plt.legend()
plt.show()
../../_images/transmission_sample.png

Please have a look to the API Reference for more information.