Logo

A physics toolbox for laser spectroscopy.

Static Badge Static Badge Static Badge

Static Badge Static Badge

© 2025 Patrick Müller. All rights reserved.

Simulation of k-multipole emission patterns

In this tutorial, an electric octupole transition (E3) of a vastly simplified atom, consisting of only two magnetic substates, is excited and the photon scattering rate is calculated for all emission angles.

import numpy as np
import qspec as qs
import qspec.simulate as sim
import matplotlib.pyplot as plt

f_eg = 7e8  # Transition frequency
a_eg = 10.  # Einstein coefficient

g_hyper = [0.]  # HFS A-constant of the g state
e_hyper = [5.]  # HFS A-constant of the e state

i, jg, je = 0., 2., 5.
dm = 1  # The change of the m quantum number

g = sim.State(0., parity='e', j=jg, i=i, f=jg + i, m=jg + i,
              hyper_const=g_hyper, label='g')
e = sim.State(f_eg, parity='o', j=je, i=i, f=je + i, m=jg + i + dm,
              hyper_const=e_hyper, label='e')

states = [g, e]
decay = sim.DecayMap(labels=[('g', 'e')], a=[a_eg], k_max=int(je - jg))
atom = sim.Atom(states=states, decay_map=decay)
print(atom.get_multipole_types('g', 'e'))
# >>> {'e3'}

intensity = 1e3
pol_eg = sim.Polarization([1., 0, 1j], vec_as_q=False)
laser_eg = sim.Laser(freq=f_eg, polarization=pol_eg,
                     intensity=intensity, k=[0., 1., 0.])

B = [0., 0., 1e-6]  # The B-field vector
env = sim.Environment(B=B)
inter = sim.Interaction(atom=atom, lasers=[laser_eg, ],
                        environment=env, delta_max=1000.)

t = np.linspace(0., 1., 301)  # Create an array of times to simulate
y0 = qs.unit_vector(0, 2, dtype=float)  # Create initial population [1., 0.]

rho = inter.master(t, y0=y0)
y = sim.density_matrix_diagonal(rho, axis=1)[0]

plt.figure(figsize=(6, 4))
plt.plot(t, y[0], label=g.label)
plt.plot(t, y[1], label=e.label)
plt.legend()
plt.xlabel(r'Time ($\mu$s)')
plt.ylabel('Population')
plt.show()

Using atom.scattering_rate, we can calculate the photon scattering for the angle pairs (θ, φ) to generate a 3D plot of the emission pattern.

n_theta, n_phi = 128, 256
theta = np.linspace(0., np.pi, n_theta)
phi = np.linspace(0., 2 * np.pi, n_phi)
theta, phi = np.meshgrid(theta, phi, indexing='ij')

r = atom.scattering_rate(rho[0, :, :, -1], theta=theta, phi=phi,
                         x_vec=None, axis=0)
r /= np.max(r)
r = r.reshape((n_theta, n_phi))

x = r * np.sin(theta) * np.cos(phi)
y = r * np.sin(theta) * np.sin(phi)
z = r * np.cos(theta)

fig, ax = plt.subplots(subplot_kw={'projection': '3d'})

cm = plt.get_cmap('plasma')
ax.plot_surface(x, y, z, facecolors=cm(r), rcount=128, ccount=256,
                linewidth=0, antialiased=False)

xyz_lim = 0.7
ax.set_xlim(-xyz_lim, xyz_lim)
ax.set_ylim(-xyz_lim, xyz_lim)
ax.set_zlim(-xyz_lim, xyz_lim)
ax.set_box_aspect((1., 1., 1.))
ax.set_axis_off()
plt.subplots_adjust(left=0., bottom=0., right=1., top=1.)
plt.show()