Semiclassical EBK quantisation

In surface science, it is often of interest to investigate how collisions with surfaces can perturb the quantum states of molecules. In particular, for diatomic molecules, the rotational and vibrational quantum numbers can undergo significant changes when the molecule impacts the surface.

Einstein-Brillouinn-Keller (EBK) quantisation allows for a semiclassical investigation into these phenomena by providing a link between the quantum numbers and classical positions and velocities. The quantisation procedure allows the user to generate a classical distribution with a given set of quantum numbers, then perform semiclassical dynamics and extract the quantum numbers at the end by reversing the procedure.

These three steps can be applied to give insight into the processes taking place during surface scattering and allow us to attempt to predict the experimentally observed change in the quantum numbers.

A detailed yet approachable description of the theory is given by [4] so we shall not delve into the theory here. Briefly, the procedure for a diatomic molecule involves an optimisation process to find the bounds of an integral, then computing the integral to obtain the vibrational quantum number. The rotational quantum number comes directly from the classical angular momentum of the molecule.

Configurations can be generated by randomly selecting bond lengths from the appropriate probability distribution and selecting a matching radial velocity.

Example

In this example we will create a quantised distribution suitable for use as initial conditions for hydrogen scattering simulations.

The simulation can be set up in the usual way, by specifying the atoms along with the model and the simulation cell.

using NQCDynamics
using Unitful, UnitfulAtomic

atoms = Atoms([:H, :H])
model = DiatomicHarmonic()
cell = PeriodicCell(austrip.([5.883 -2.942 0; 0 5.095 0; 0 0 20] .* u"Å"))
sim = Simulation(atoms, model; cell=cell)
Simulation{Classical}:
  Atoms{Float64}([:H, :H], [1, 1], [1837.4715941070515, 1837.4715941070515])
  DiatomicHarmonic
  r₀: Float64 1.0

The distribution is generated using the QuantisedDiatomic.generate_configurations function. We have to provide the desired vibrational ν and rotational J quantum numbers, along with the number of samples and some other options as keyword arguments. In addition to the rotational and vibrational energy we have applied a translational impulse of 1 eV and positioned the molecule at a height of 10 bohr.

using NQCDynamics.InitialConditions: QuantisedDiatomic

ν, J = 2, 0
nsamples = 150

configurations = QuantisedDiatomic.generate_configurations(sim, ν, J;
    samples=nsamples, translational_energy=1u"eV", height=10)
150-element Vector{Tuple{Matrix{Float64}, Matrix{Float64}}}:
 ([-0.0017065845706450455 0.0017065845706450455; -0.0012309391475201798 0.0012309391475201798; 0.0014835629496075618 -0.010427821509106544], [1.5469915553669698 1.2402287597590955; 5.172986008519258 4.951721653613168; 9.464724799027362 10.535275200972638])
 ([-0.003671481987511133 0.003671481987511133; 0.0006398543763918291 -0.0006398543763918291; -9.176936956798235e-5 -0.008852489189931], [-2.2331517508774246 -1.7277644788545787; 9.082925709733702 8.994848399569433; 10.301482909764399 9.698517090235601])
 ([0.0017200034697995319 -0.0017200034697995319; -0.0005466174884177667 0.0005466174884177667; -0.0006328174859201677 -0.008311441073578814], [4.529897468138888 4.807884666376406; 4.279685754751744 4.191341360812473; 9.689744948929881 10.310255051070119])
 ([-0.003201642327034053 0.003201642327034053; 0.0022912418330926763 -0.0022912418330926763; -0.00673180389627716 -0.0022124546632218225], [-0.7060190997036414 -1.621995634775002; 4.560129810082349 5.215644555613278; 10.323241748173844 9.676758251826156])
 ([0.0005002622648817872 -0.0005002622648817872; -2.6661005621027343e-5 2.6661005621027343e-5; -0.005137764961235074 -0.0038064935982639082], [1.91262996084064 2.2711235292188547; 7.840289935434991 7.821184358795322; 10.23850100981734 9.76149899018266])
 ([-0.0005408972254336332 0.0005408972254336332; -0.0005509004339772271 0.0005509004339772271; -0.004159107065339626 -0.004785151494159356], [5.838829502140775 6.226442540508558; 7.143013148272916 7.537794598447398; 10.11215762061522 9.88784237938478])
 ([0.0002513667323669415 -0.0002513667323669415; 0.0022539875960111136 -0.0022539875960111136; -0.0069604660005094954 -0.001983792558989487], [2.5854132826599905 2.5369693773865984; 6.905058764421659 6.470665714234068; 9.760221356156169 10.239778643843831])
 ([0.005726337445400868 -0.005726337445400868; -0.0019151265393312989 0.0019151265393312989; -0.002996749136118022 -0.00594750942338096], [4.9980182186334545 4.216390307336992; 8.094856582538453 8.356265619480242; 10.100692485470022 9.899307514529978])
 ([0.0032889998836047487 -0.0032889998836047487; -0.0022908946784383414 0.0022908946784383414; 0.0007310076691442327 -0.009675266228643214], [6.116918659814077 6.657822173906167; 1.2025175686498326 0.8257607958207458; 9.572150325393988 10.427849674606012])
 ([-0.002194043368012765 0.002194043368012765; 0.0057347308759614435 -0.0057347308759614435; -0.004868569854207722 -0.00407568870529126], [5.144866087934475 4.845588645166793; 3.689035823263031 4.4712790626357855; 10.027038144063823 9.972961855936177])
 ⋮
 ([-0.0025747865725515664 0.0025747865725515664; 0.0029446324731708805 -0.0029446324731708805; -0.006972423126740783 -0.001971835432758199], [-2.572524964721242 -2.964733693511116; 6.664181836803911 7.1127279692747045; 10.190430749053853 9.809569250946147])
 ([-0.002985384408183397 0.002985384408183397; -0.0007934346729096454 0.0007934346729096454; -0.00022098751621685026 -0.008723271043282133], [3.626674306177805 4.051653639186378; 6.198832265236662 6.311780312112877; 10.302582037046669 9.697417962953331])
 ([-0.00548991466275513 0.00548991466275513; 0.002770579020130641 -0.002770579020130641; -0.005959794459947968 -0.0029844640995510137], [6.1579804857059965 7.141649255898148; 4.881211614551576 4.384786401252475; 9.866721992220446 10.133278007779554])
 ([-0.0023525741459385005 0.0023525741459385005; -0.00031814244266696894 0.00031814244266696894; 0.0014372218408286938 -0.010381480400327676], [4.963171382746785 4.547153701825173; 4.265874613700502 4.209615863501472; 9.477509656140136 10.522490343859864])
 ([-0.0019280046049512576 0.0019280046049512576; -3.965308000344372e-5 3.965308000344372e-5; -0.006361890472861008 -0.0025823680866379735], [3.4769277863472 3.0282782393508954; 6.75333026615311 6.744102935297745; 10.219875124012505 9.780124875987495])
 ([0.0024023574508907513 -0.0024023574508907513; 0.0011920819364943502 -0.0011920819364943502; -0.00415973397682249 -0.004784524582676492], [4.791683202798938 4.23265104110315; 1.1398153327640268 0.8624160882719788; 10.036347426448579 9.963652573551421])
 ([-0.0012143578458732847 0.0012143578458732847; 0.0029970959739554644 -0.0029970959739554644; -0.0044843938613335806 -0.004459864698165401], [-1.9669061486578863 -1.4578097056239279; 9.45567316581559 8.199197650828602; 9.997429153654757 10.002570846345243])
 ([-0.0006645611949418996 0.0006645611949418996; -0.0027315630203000422 0.0027315630203000422; 0.000512682919575339 -0.009456941479074322], [8.112430677100663 8.253077002641716; 1.8283177879630559 2.4064200074623523; 10.527487554707838 9.472512445292162])
 ([0.00027326712543831013 -0.00027326712543831013; -0.006633023193412784 0.006633023193412784; -0.005194079730356331 -0.003750178829142651], [4.7131868061085065 4.755453521175086; 1.051452050462454 0.025510489082475885; 10.05583268375046 9.94416731624954])

The output contains both the positions and velocities, these can be passed directly to the DynamicalDistribution for use with dynamics. Here however, let's focus on the positions and visualise the distribution.

This collects the x and y coordinate for each atom:

r = last.(configurations)
x = hcat([i[1,:] for i in r]...)
y = hcat([i[2,:] for i in r]...)
2×150 Matrix{Float64}:
 5.17299  9.08293  4.27969  4.56013  7.84029  …  9.45567  1.82832  1.05145
 4.95172  8.99485  4.19134  5.21564  7.82118     8.1992   2.40642  0.0255105

Now we can plot the distribution:

using Plots

plt = plot(
    xlabel="x coordinate / bohr",
    ylabel="y coordinate / bohr",
    legend=false,
)

for i=1:nsamples
    plot!([x[1,i], x[2,i]], [y[1,i], y[2,i]], linewidth=5, color=:black)
    scatter!([x[1,i], x[2,i]], [y[1,i], y[2,i]])
end
plt
Example block output

Here we can see that the molecule is randomly distributed within the unit cell. Since we have used a harmonic potential, this could have been produced without using the EBK procedure, but this technique can use any arbitrary potential. In the hydrogen scattering example we build on this example and use the sample procedure to perform scattering simulations starting from this distribution.