Hamiltonian Programming

This is a long post. On mobile some equations may go overfull.

The goal of this post is to elegantly program the Spin Hamiltonian governing recombination in Silicon Carbide. Our system involves two electrons and two nuclei.

We define our orthonormal basis as follows:

The ,{\uparrow, \downarrow} spin basis is called the Zeeman basis. I define the basis with the two electrons coupled and the nuclei in the Zeeman Basis as the coupled basis. Every state in our two-electron + two-nuclei system is given by

s,melectronsmI1mI2nuclei. \underbrace{|s, m\rangle}_{\text{electrons}} \underbrace{|m_{I_1}\rangle |m_{I_2}\rangle}_{\text{nuclei}}.

We will evaluate H^Z,H^HF,H^ZFS\hat{H}_Z, \hat{H}_{HF}, \hat{H}_{ZFS}, and H^EX\hat{H}_{EX} on the above state(s).

Zeeman#

The Zeeman Hamiltonian, from Part 1, is defined in the coupled basis via

H^Zs,mmI1mI2=(mgeμBB0+mI1gn1μNB0+mI2gn2μNB0)energiess,mmI1mI2. \begin{align} &\hat{H}_Z|s, m\rangle |m_{I_1}\rangle |m_{I_2}\rangle = \\ &\underbrace{\left( mg_e \mu_B B_0 + m_{I_1} g_{n_1} \mu_N B_0 + m_{I_2} g_{n_2} \mu_N B_0\right)}_{\text{energies}}|s, m\rangle |m_{I_1}\rangle |m_{I_2}\rangle. \end{align}

Here, geg_e is g\simeq g-factor for the electron, gn1g_{n_1} is the gg-factor for the first nucleus (silicon), and gn2g_{n_2} is the gg-factor for the second nucleus (carbon). μB\mu_B and μN\mu_N are the Bohr Magneton and Nuclear Magneton respectively.

Implementation#

The coupled-basis is itself the eigenbasis. To build the Zeeman Hamiltonian, we first define the coupled basis:

import sympy as sp 

// electron |s, m> pairs 
electron_pairs = [
    (1, +1),
    (1,  0),
    (0,  0),
    (1, -1),
]

// nuclear |mI1>|mI2> pairs 
nuclear_pairs = [
    ( sp.Rational(+1,2), sp.Rational(+1,2) ),
    ( sp.Rational(+1,2), sp.Rational(-1,2) ),
    ( sp.Rational(-1,2), sp.Rational(+1,2) ),
    ( sp.Rational(-1,2), sp.Rational(-1,2) ),
]

Now we apply Equation (1-2) to every basis state; every combination of the above electron + nuclei pairs. This will generate our 16 ×\times 16 Zeeman Hamiltonian. It will be a diagonal matrix with entries because the coupled-basis is already the eigenbasis.

// zeeman constants
g_e  = sp.symbol("g_e")
g_n1 = sp.symbol("g_n1") 
// ... 

// zeeman frequencies
omega_e  = g_e  * mu_B * B0
omega_n1 = g_n1 * mu_N * B0
omega_n2 = g_n2 * mu_N * B0

energies = []
for s, m in electron_pairs:         // electrons run slow  
    for mI1, mI2 in nuclear_pairs:  // nuclei run fast 
        energies.append(
            m*omega_e    +  // electron
            mI1*omega_n1 +  // nucleus 1 
            mI2*omega_n2    // nucleus 2 
        )

// zeeman hamiltonian  
H_Z = sp.diag(*energies) 

However, we have to be careful. We rendered the Zeeman Hamiltonian in a nested for-loop over the coupled-basis states. This ordering needs to be immutable for calculating all Hamiltonians.


Hyperfine#

The Hyperfine Hamiltonian is simplest when all electrons and nuclei are in the Zeeman {,}\{ \uparrow, \downarrow \} basis. We’ll first attack solving a two-electron (a,ba, b) + one-nucleus (II) system in Zeeman basis. Then we’ll expand to the two-electron + two-nuclei system and ultimately convert to the coupled-basis at the end via a Clebsch-Gordan transformation.

Two electrons and one nucleus#

The Hyperfine Hamiltonian, from Part 1, is defined as

H^HF=S^aAaI^+S^bAbI^, \begin{align} \hat{H}_{HF} = \hat{S}_a \cdot A_a \cdot \hat{I} + \hat{S}_b \cdot A_b \cdot \hat{I}, \end{align}

for a two-electron (a,ba, b) and one-nuclei (II) system. This is equivalent to

H^HF=k{a,b}AkxSkxIx+AkySkyIy+AkzSkzIz. \begin{align} \hat{H}_{HF} = \sum_{k \in \{a, b\}} A_{kx} S_{kx} I_x + A_{ky}S_{ky}I_y + A_{kz}S_{kz}I_z. \end{align}

We use ladder operators S^+\hat{S}_+ and S^\hat{S}_- that give

S^x=12(S^++S^)S^y=12i(S^+S^), \hat{S}_x = \frac{1}{2}\left(\hat{S}_+ + \hat{S}_- \right) \quad \hat{S}_y = \frac{1}{2i} \left(\hat{S}_+ - \hat{S}_-\right),

and likewise for I^x\hat{I}_x and I^y\hat{I}_y. Plugging this into Equation (4) yields

H^HF=kAkx(12(S^k++S^k))(12(I^++I^))+Aky(12i(S^k+S^k))(12i(I^+I^))+AkzSkzIz=kAkx4(S^k+I^++S^k+I^+S^kI^++S^kI^)Aky4(S^k+I^+S^k+I^S^kI^++S^kI^)+AkzSkzIz. \begin{align*} \hat{H}_{HF} &= \sum_k A_{kx} \left(\frac{1}{2}(\hat{S}_{k+} + \hat{S}_{k-}) \right)\left( \frac{1}{2} ( \hat{I}_+ + \hat{I}_- ) \right) \\ &\qquad +A_{ky} \left( \frac{1}{2i} (\hat{S}_{k+} - \hat{S}_{k-} ) \right) \left( \frac{1}{2i} (\hat{I}_+ - \hat{I}_-) \right) + A_{kz} S_{kz} I_z \\ &= \sum_k \frac{A_{kx}}{4} ( \hat{S}_{k+} \hat{I}_+ + \hat{S}_{k+} \hat{I}_- + \hat{S}_{k-} \hat{I}_+ + \hat{S}_{k-} \hat{I}_-) \\ &\qquad - \frac{A_{ky}}{4} (\hat{S}_{k+}\hat{I}_+ - \hat{S}_{k+}\hat{I}_- - \hat{S}_{k-}\hat{I}_+ + \hat{S}_{k-}\hat{I}_- ) + A_{kz} S_{kz} I_z. \end{align*}

We are almost done. From ladder operators, we know

S^±s,m=s(s+1)m(m±1)s,m±1. \begin{align} \hat{S}_{\pm} |s, m\rangle = \hbar \sqrt{s (s+1) - m(m\pm 1)} |s, m\pm 1\rangle. \end{align}

I’ll again emphasize we are working in the purely Zeeman basis for two electrons and one nucleus. Each basis state is of the form ma,mb,mI|m_a, m_b, m_I\rangle, where each mi{,}m_i \in \{\uparrow, \downarrow \}.

Let’s go step by step to evaluate H^HFma,mb,mI\hat{H}_{HF} |m_a, m_b, m_I\rangle. From Equation (5), we find

S^+=0S^+=S^=0S^=S^zm=mm,m{,}. \begin{align*} \hat{S}_+ |\uparrow\rangle = 0 \qquad \hat{S}_+|\downarrow\rangle = \hbar|\uparrow\rangle \\ \hat{S}_- |\downarrow\rangle = 0 \qquad \hat{S}_-|\uparrow\rangle = \hbar|\downarrow\rangle \\ \hat{S}_z|m\rangle = m\hbar |m\rangle, \quad m \in \{\uparrow, \downarrow \}. \end{align*}

Likewise for the nuclear state, where we use m{,}m\in \{\Uparrow, \Downarrow\},

I^+=0I^+=I^=0I^=I^zmI=mImI,mI{,}.. \begin{align*} \hat{I}_+ |\Uparrow\rangle = 0 \qquad \hat{I}_+|\Downarrow\rangle = \hbar|\Uparrow\rangle \\ \hat{I}_- |\Downarrow\rangle = 0 \qquad \hat{I}_-|\Uparrow\rangle = \hbar|\Downarrow\rangle \\ \hat{I}_z|m_I\rangle = m_I\hbar |m_I\rangle, \quad m_I \in \{\Uparrow, \Downarrow \}. \end{align*}.

There are five nontrivial (that don’t end up = 0) operator products. One electron {,}\{\uparrow, \downarrow\} represents both electrons a,ba, b (i.e. ,=,,|\downarrow, \Downarrow\rangle = |\downarrow, \downarrow, \Downarrow\rangle).

productnonzero forresultS^k+I^+,2,S^k+I^,2,S^kI^+,2,S^kI^,2,S^kzI^zany2ma,bmIma,b,mI. \begin{align*} &\text{product} &&\text{nonzero for} &&&\text{result} \\ &\hat{S}_{k+} \hat{I}_+ && |\downarrow, \Downarrow\rangle &&& \hbar^2|\uparrow, \Uparrow\rangle \\ &\hat{S}_{k+} \hat{I}_- && |\downarrow, \Uparrow\rangle &&& \hbar^2 |\uparrow, \Downarrow\rangle \\ &\hat{S}_{k-} \hat{I}_+ && |\uparrow, \Downarrow\rangle &&& \hbar^2 |\downarrow, \Uparrow \rangle \\ &\hat{S}_{k-} \hat{I}_- && |\uparrow, \Uparrow\rangle &&& \hbar^2 |\downarrow, \Downarrow \rangle \\ &\hat{S}_{kz} \hat{I}_z &&\text{any} &&& \hbar^2 m_{a, b} m_I |m_{a, b}, m_I \rangle. \end{align*}

The last term contributes to diagonal terms only. It leaves the state ma,b,mI|m_{a, b}, m_I\rangle constant; adds no mixing.

We can construct the Hyperfine Hamiltonian in the Zeeman basis using this table.

H^HFma,mb,mI=k{a,b}24(AkxAky)S^k+I^+δmk,mImk,,mI    +24(AkxAky)S^k+I^δmk,mImk,,mI    +Akz2mkmImk,,mI. \begin{align*} \hat{H}_{HF} |m_a, m_b, m_I\rangle &= \sum_{k\in\{a, b\}} \frac{\hbar^2}{4} (A_{kx} - A_{ky}) \hat{S}_{k+} \hat{I}_+ \delta_{m_k, m_I} |-m_k, \quad, -m_I\rangle \\ &\qquad\;\; +\frac{\hbar^2}{4} (A_{kx} - A_{ky}) \hat{S}_{k+} \hat{I}_{-} \delta_{m_k, -m_I} |-m_k,\quad, -m_I\rangle \\ &\qquad\;\; + A_{kz} \hbar^2 m_k m_I |m_k, \quad, m_I\rangle. \end{align*}

A blank mbm_b means it can be either \uparrow or \downarrow. Expanding the summation,

H^HFma,mb,mI=2(AazmamI+AbzmbmI)ma,mb,mI+24[(AaxAay)δma,mI+(Aax+Aay)δma,mI]ma,mb,mI+24[(AbxAby)δmb,mI+(Abx+Aby)δmb,mI]ma,mb,mI, \begin{align*} \hat{H}_{HF} |m_a, m_b, m_I \rangle &= \hbar^2 (A_{az} m_a m_I + A_{bz}m_b m_I ) |m_a, m_b, m_I\rangle \\ &+ \frac{\hbar^2}{4} [ (A_{ax} - A_{ay}) \delta_{m_a, m_I} + (A_{ax} + A_{ay}) \delta_{m_a, -m_I}] |-m_a, m_b, -m_I\rangle \\ &+ \frac{\hbar^2}{4} [ (A_{bx} - A_{by}) \delta_{m_b, m_I} + (A_{bx} + A_{by}) \delta_{m_b, -m_I} ] |m_a, -m_b, m_I\rangle, \end{align*}

where ma,mb,mIm_a, m_b, m_I all run over {,}\{\uparrow, \downarrow\}. The equation above defines H^HF\hat{H}_{HF} for an 8 Zeeman-basis two-electron + one-nucleus system. Evolving it to our two-electron + two-nuclei system in silicon carbide is straightforward.

Two electrons and two nuclei#

For two electrons k{a,b}k\in\{a, b\} and two nuclei p{1,2}p \in \{1, 2\},

H^HF=k{a,b}p=12(AkpxSkxIpx+AkpySkyIpy+AkpzSkzIpz). \hat{H}_{HF} = \sum_{k\in\{a, b\}} \sum_{p=1}^2 ( A_{kpx} S_{kx} I_{px} + A_{kpy} S_{ky} I_{py} + A_{kpz} S_{kz} I_{pz}).

Following the same procedure as the one-nucleus system, we get the full Hyperfine Hamiltonian action on ma,mb,mI1,mI2|m_a, m_b, m_{I_1}, m_{I_2} \rangle.

H^HFma,mb,mI1,mI2=2p=12(AapzmamIp+AbpzmbmIp)ma,mb,mI1,mI2+24[(Aa1xAa1y)δma,mI1+(Aa1x+Aa1y)δma,mI1]ma,mb,mI1,mI2+24[(Aa2xAa2y)δma,mI2+(Aa2x+Aa2y)δma,mI2]ma,mb,mI1,mI2+24[(Ab1xAb1y)δmb,mI1+(Ab1x+Ab1y)δmb,mI1]ma,mb,mI1,mI2+24[(Ab2xAb2y)δmb,mI2+(Ab2x+Ab2y)δmb,mI2]ma,mb,mI1,mI2. \boxed{ \begin{align*} \hat{H}_{HF} &|m_a, m_b, m_{I_1}, m_{I_2} \rangle \\ &= \hbar^2 \sum_{p=1}^{2} (A_{apz} m_a m_{I_p} + A_{bpz} m_b m_{I_p}) |m_a, m_b, m_{I_1}, m_{I_2}\rangle \\ &+ \frac{\hbar^2}{4} [ (A_{a1x} - A_{a1y}) \delta_{m_a, m_{I_1}} + (A_{a1x} + A_{a1y}) \delta_{m_a, -m_{I_1}} ] |-m_a, m_b, -m_{I_1}, m_{I_2}\rangle \\ &+ \frac{\hbar^2}{4} [ (A_{a2x} - A_{a2y}) \delta_{m_a, m_{I_2}} + (A_{a2x} + A_{a2y}) \delta_{m_a, -m_{I_2}} ] |-m_a, m_b, m_{I_1}, -m_{I_2}\rangle \\ &+ \frac{\hbar^2}{4} [ (A_{b1x} - A_{b1y}) \delta_{m_b, m_{I_1}} + (A_{b1x} + A_{b1y}) \delta_{m_b, -m_{I_1}} ] |m_a, -m_b, -m_{I_1}, m_{I_2}\rangle \\ &+ \frac{\hbar^2}{4} [ (A_{b2x} - A_{b2y}) \delta_{m_b, m_{I_2}} + (A_{b2x} + A_{b2y}) \delta_{m_b, -m_{I_2}} ] |m_a, -m_b, m_{I_1}, -m_{I_2}\rangle. \end{align*} }

However, we must remember this is the Zeeman ,\uparrow, \downarrow basis. We need to convert it to the same coupled basis we used for defining the Zeeman Hamiltonian.

In Quantum mechanics, you learn about Clebsch-Gordan coefficients. These are coefficients that describe how to map the Zeeman ,|\uparrow, \downarrow\rangle basis to the coupled s,m|s, m\rangle basis. We make a matrix transformation out of these coefficients.

For mapping the coupled basis to the Zeeman basis, we have

()=(10000121200121200001)(11100011). \begin{pmatrix} |\uparrow \uparrow \rangle \\ |\uparrow \downarrow \rangle \\ |\downarrow \uparrow \rangle \\ |\downarrow \downarrow \rangle \end{pmatrix} = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} & 0 \\ 0 & \frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}} & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} |11\rangle \\ |10\rangle \\ |00\rangle \\ |1-1\rangle \end{pmatrix}.

Therefore, we cleverly define WW:

W=(10000121200121200001)(1000010000100001), \begin{align} W = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} & 0 \\ 0 & \frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{2}} & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix} \otimes \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}, \end{align}

where we I4\otimes \mathbb{I}_4 because we want to leave the nuclear mI1,mI2|m_{I_1}, m_{I_2}\rangle in the Zeeman basis and only couple the electrons into s,m|s, m\rangle. Then, once we have the full 16 ×\times 16 Hyperfine Hamiltonian in the Zeeman Basis, we can directly apply the transformation

H^HFcoupled=W(H^HFZeeman)W \begin{align} \hat{H}_{HF_{\text{coupled}}} = W \left(\hat{H}_{HF_{\text{Zeeman}}}\right) W^\dagger \end{align}

to get the final Hyperfine Hamiltonian in the coupled basis. We have to ensure that after this transformation, the ordering is identical to the ordering of the Zeeman Hamiltonian.

Implementation#

We first build the 16 Zeeman basis states in correct order. Electron states run slow. Nuclear states run fast.

/// builds correctly ordered zeeman basis 
def _generate_zeeman_basis(self):

    half = sp.Rational(1, 2)
    return [
        (m_a, m_b, m_I1, m_I2)
        for m_a in (half, -half)
        for m_b in (half, -half)
        for m_I1 in (half, -half)
        for m_I2 in (half, -half)
    ] // len 16 

The trickiest part is emulating the boxed equation above. To begin, we define the following helper functions for working with delta functions.

/// if spins are parallel
def _delta_parallel(self, m_e, m_I): 
    return m_e == m_I

/// if spins are antiparallel
def _delta_antiparallel(self, m_e, m_I):
    return m_e == -m_I

Next, we have to write a function that takes in a ma,mb,mI1,mI2|m_a, m_b, m_{I_1}, m_{I_2}\rangle and outputs the resulting coefficient in front from performing H^HFma,mb,mI1,mI2\hat{H}_{HF} |m_a, m_b, m_{I_1}, m_{I_2}\rangle.

The coefficients are of the form

24[(Ai1xAi1y)δmi,mIj+(Ai1x+Ai1y)δmi,mIj], \frac{\hbar^2}{4}\left[(A_{i1x} - A_{i1y}) \delta_{m_i, m_{I_j}} + (A_{i1x} + A_{i1y})\delta_{m_i, -m_{I_j}} \right],

where i{a,b}i \in \{a, b \} and j{1,2}j \in \{1, 2\}. We’ll do this by generating a dict[new_ket, coeff] that associates each key new_ket with its coeff in front step by step. In code we set =1\hbar = 1 to simplify. It’ll get included later.

  1. Hyperfine AA constants.#

    These are unknown constants that are present in H^HF\hat{H}_{HF}. We generate another dict[key, sp.Symbol]. where the sp.Symbols are the actual constants. We’ll access them via their key

     self.A = {}  
     for e in ('a', 'b'):
         for n in ('1', '2'):
             for comp in ('x', 'y', 'z'):
                 key = f'A{e}{n}{comp}'
                 self.A[key.upper()] = sp.symbols(key) 
    
  2. Diagonal S^zI^z\hat{S}_z\hat{I}_z terms.#

    The first term in the boxed H^HF\hat{H}_{HF} expression is simplest. It leaves ma,mb,mI1,mI2|m_a, m_b, m_{I_1}, m_{I_2}\rangle as an eigenstate. The coefficients in front are just products of Ama/bmI1,2A m_{a/b} m_{I_{1, 2}}. We’ll attack these first.

     def _action_on_ket(self, ket): 
         m_a, m_b, m_I1, m_I2 = ket
    
         // {new_ket: coeff} 
         psi = {}
    
         // diagonal S_z I_z term
         // A * m_e * m_I
         diag = (
             self.A['AA1Z'] * m_a * m_I1 + // A_{a1z}
             self.A['AB1Z'] * m_b * m_I1 + // A_{b1z} 
             self.A['AA2Z'] * m_a * m_I2 + // A_{a2z}
             self.A['AB2Z'] * m_b * m_I2   // A_{b2z}
         )
         psi[ket] = diag 
    
         // more to come
    
  3. Off-Diagonal δ\delta terms#

    These coefficients are more difficult. They involve delta functions that either do nothing or collapse states to 0 depending on spins mim_i and mIjm_{I_j} being parallel or antiparallel. This will be where we use our _delta_parallel and _delta_antiparallel helpers.

         /// off-diagonal flip-flop
         /// S_x I_x + S_y I_y -> (A_x - A_y)/4 
         def add_flip(m_e, m_I, x_key, y_key, new_ket):
             if self._delta_parallel(m_e, m_I):
                 coeff = (self.A[x_key] - self.A[y_key]) / 4
                 psi[new_ket] = coeff
             elif self._delta_antiparallel(m_e, m_I):
                 coeff = (self.A[x_key] + self.A[y_key]) / 4
                 psi[new_ket] = coeff
    
                                             // --- final states we know 
         add_flip(m_a, m_I1, 'AA1X', 'AA1Y', (-m_a,  m_b, -m_I1,  m_I2))
         add_flip(m_a, m_I2, 'AA2X', 'AA2Y', (-m_a,  m_b,  m_I1, -m_I2))
         add_flip(m_b, m_I1, 'AB1X', 'AB1Y', ( m_a, -m_b, -m_I1,  m_I2))
         add_flip(m_b, m_I2, 'AB2X', 'AB2Y', ( m_a, -m_b,  m_I1, -m_I2))
    
         return psi
    

Now, evaluating H^HF\hat{H}_{HF} on every Zeeman state gives us the full Hyperfine Hamiltonian in the Zeeman basis. We just iterate through and build. SymPy syntax isn’t important.

/// 16x16 hyperfine hamiltonian 
/// zeeman Basis 
def _build_zeeman_matrix(self):
    self.basis_ze = self._generate_zeeman_basis()  
    self.index_ze = { 
        ket: i for i, ket in enumerate(self.basis_ze)
    }

    size = len(self.basis_ze) 

    // initialize 16x16 matrix 
    H = sp.MutableDenseMatrix(size, size, lambda *_: 0)

    // iterate through zeeman states 
    for j, ket in enumerate(self.basis_ze):
        action = self._action_on_ket(ket)

        // input coefficients into matrix
        for new_ket, coeff in action.items():
            i = self.index_ze[new_ket]
            H[i, j] = coeff

    return H.as_immutable()

Now all that is left is to apply the Clebsch-Gordan WW transformation in Equation (7). Let’s first build WW from Equation (6). It’s a tensor product of a 4×44\times 4 Clebsch-Gordan matrix with the 4×44\times 4 identity.

/// builds the unitary Clebsch-Gordan transformation W 
def _build_cg_unitary(self):
    half = sp.sqrt(sp.Rational(1, 2))

    U = sp.Matrix([                    // 4x4 CG
        [1,    0,     0,    0],
        [0,  half,  half,   0],
        [0,  half, -half,   0],
        [0,    0,     0,    1]
    ])

    I4 = sp.eye(4)                     // 4x4 identity

    return sp.kronecker_product(U, I4) // W 

Finally! We can calculate H^HF\hat{H}_{HF} in our ordered coupled-basis.

    // zeeman basis 
    self.H_ze = self._build_zeeman_matrix() 

    // clebsch gordan W 
    self.W = self._build_cg_unitary()                       

    // final hyperfine hamiltonian 
    // coupled basis
    self.H_HF = sp.simplify(self.W * self.H_ze * self.W.H)

Zero-Field Splitting#

In Part 2 we derived H^ZFS\hat{H}_{ZFS}’s action on a general s,m|s, m\rangle.

H^ZFSs,m=Dm2s,mD3(s(s+1))s,m+E2(s(s+1)m(m+1))s,m+2+E2(s(s+1)m(m1))s,m2.. \begin{align} \hat{H}_{ZFS}|s, m\rangle &= Dm^2 |s, m\rangle - \frac{D}{3}(s(s+1))|s, m\rangle \\ &+ \frac{E}{2} (s(s+1) - m(m+1))|s, m+2\rangle \\ &+ \frac{E}{2} (s(s+1) - m(m-1))|s, m-2\rangle. \end{align}.

The last two terms give the forbidden m±2m \pm 2 transitions that create the half-field response (to be described later). This Hamiltonian acts on the electrons only. It’s a dipole-dipole interaction. Nuclear terms are left alone. That makes things quite easy.

Implementation#

We directly build H^ZFS\hat{H}_{ZFS} while maintaining the ordered basis. From the Zeeman Implementation, we have

// electron |s, m> pairs 
electron_pairs = [
    (1, +1),
    (1,  0),
    (0,  0),
    (1, -1),
]

We’ll just use that again to maintain the basis. The first term, Equation (8), give the diagonal elements (s,m|s, m\rangle are the eigenstates). Equation (9-10) give the off-diagonal elements that mix mm±2m \rightarrow m\pm 2.

// zfs constants
D = sp.symbols('D')
E = sp.symbols('E') 

// 4x4 
// zfs on coupled electrons
H_elec = sp.zeros(4)

for i, (s, m) in enumerate(electron_pairs):

    // diagonal term
    // D * m^2 - (D/3) * s(s+1)
    H_elec[i, i] = D*m**2 - (D/3)*s*(s + 1)

    // off-diagonal term 
    // coupling m -> m +/- 2
    for dm, expr in [
        (2, E/2*(s*(s + 1) - m*(m + 1))),
        (-2, E/2*(s*(s + 1) - m*(m - 1)))
    ]:
        // m +/- 2
        final_m = m + dm
        if (s, final_m) in electron_pairs:
            j = electron_pairs.index((s, final_m))

            H_elec[i, j] = expr
            H_elec[j, i] = expr

// 4x4 
// nuclei identity 
I_nuc = sp.eye(4)

// 16x16 zfs hamiltonian 
H_ZFS = sp.kronecker_product(H_elec, I_nuc)

We take the tensor product H^ZFSelectronI4\hat{H}_{ZFS_{\text{electron}}} \otimes \mathbb{I}_4 again to lift the electronic 4×44\times 4 Hamiltonian to a 16×1616\times 16 one in our Hilbert space. This gives H^ZFS\hat{H}_{ZFS} in the coupled-basis.

Exchange Interaction#

From Part 3, we derived

H^EX=JS^aS^b, \hat{H}_{EX} = -J \hat{S}_a \cdot \hat{S}_b,

Let’s take S^=S^a+S^b\hat{S} = \hat{S}_a + \hat{S}_b. Then

S^2=S^a2+S^b2+2S^aS^b. \hat{S}^2 = \hat{S}_a^2 + \hat{S}_b^2 + 2 \hat{S}_a \cdot \hat{S}_b.

Rearranging to calculate S^aS^b\hat{S}_a \cdot \hat{S}_b, we find that

S^aS^b=12(S^2S^a2S^b2). \hat{S}_a \cdot \hat{S}_b = \frac{1}{2}(\hat{S}^2 - \hat{S}_a^2 - \hat{S}_b^2).

Acting on the coupled electron basis s,m|s, m\rangle, the three terms in the parenthesis satisfy

S^2s,m=2s(s+1)s,m, S^a2s,m=324s,m, S^b2s,m=324s,m. \begin{align*} \hat{S}^2 |s, m\rangle &= \hbar^2 s(s+1)|s, m\rangle, \ \hat{S}_a^2 |s, m\rangle &= \frac{3\hbar^2}{4}|s, m\rangle, \ \hat{S}_b^2 |s, m\rangle &= \frac{3\hbar^2}{4}|s, m\rangle. \end{align*}

Hence,

S^aS^bs,m=22[s(s+1)32]s,m. \hat{S}_a \cdot \hat{S}_b |s, m\rangle = \frac{\hbar^2}{2}\left[ s(s+1) - \frac{3}{2} \right] |s, m\rangle.

H^EX\hat{H}_{EX} immediately follows:

H^EXs,m=J22[s(s+1)32]s,m. \hat{H}_{EX} |s, m\rangle = -J \frac{\hbar^2}{2} \left[ s(s+1) - \frac{3}{2}\right] |s, m\rangle.

We’ll also program this with =1\hbar = 1. H^EX\hat{H}_{EX} already acts on the coupled-basis (nuclear mI|m_I\rangle are left alone). Additionally, all states are eigenstates; H^EX\hat{H}_{EX} is diagonal. Programming this is the easiest.

// exchange constant 
J = sp.symbols('J')

// 4x4 
H_ex_elec = sp.zeros(4) 

for i, (s, m) in enumerate(electron_pairs): 
    H_ex_elec[i, i] = -J*(s*(s + 1) - 1.5) / 2 

// 4x4 
// nuclear identity 
I_nuc = sp.eye(4) 

// 16x16 exchange hamiltonian 
H_EX = sp.kronecker_product(H_ex_elec, I_nuc) 

Again, we take the tensor product of the 4×\times 4 electron Hamiltonian with the 4×\times 4 identity to yield the full 16×\times 16 H^EX\hat{H}_{EX} in our Hilbert space.

Full Spin#

The Spin Hamiltonian H\mathscr{H} is just

H_SPIN = H_Z + H_HF + H_ZFS + H_EX

Basis#

The coupled-basis is shown below. Indices 0-15 indicate top-to-bottom and left-to-right row/column basis states in H\mathscr{H}’s matrix representation.

01,1+12,+1211,1+12,1221,112,+1231,112,1241,0+12,+1251,0+12,1261,012,+1271,012,1280,0+12,+1290,0+12,12100,012,+12110,012,12121,1+12,+12131,1+12,12141,112,+12151,112,12. \begin{align*} 0 && \qquad |1,1\rangle \otimes |+\tfrac{1}{2}, +\tfrac{1}{2}\rangle \\ 1 && \qquad |1,1\rangle \otimes |+\tfrac{1}{2}, -\tfrac{1}{2}\rangle \\ 2 && \qquad |1,1\rangle \otimes |-\tfrac{1}{2}, +\tfrac{1}{2}\rangle \\ 3 && \qquad |1,1\rangle \otimes |-\tfrac{1}{2}, -\tfrac{1}{2}\rangle \\ 4 && \qquad |1,0\rangle \otimes |+\tfrac{1}{2}, +\tfrac{1}{2}\rangle \\ 5 && \qquad |1,0\rangle \otimes |+\tfrac{1}{2}, -\tfrac{1}{2}\rangle \\ 6 && \qquad |1,0\rangle \otimes |-\tfrac{1}{2}, +\tfrac{1}{2}\rangle \\ 7 && \qquad |1,0\rangle \otimes |-\tfrac{1}{2}, -\tfrac{1}{2}\rangle \\ 8 && \qquad |0,0\rangle \otimes |+\tfrac{1}{2}, +\tfrac{1}{2}\rangle \\ 9 && \qquad |0,0\rangle \otimes |+\tfrac{1}{2}, -\tfrac{1}{2}\rangle \\ 10 && \qquad |0,0\rangle \otimes |-\tfrac{1}{2}, +\tfrac{1}{2}\rangle \\ 11 && \qquad |0,0\rangle \otimes |-\tfrac{1}{2}, -\tfrac{1}{2}\rangle \\ 12 && \qquad |1,-1\rangle \otimes |+\tfrac{1}{2}, +\tfrac{1}{2}\rangle \\ 13 && \qquad |1,-1\rangle \otimes |+\tfrac{1}{2}, -\tfrac{1}{2}\rangle \\ 14 && \qquad |1,-1\rangle \otimes |-\tfrac{1}{2}, +\tfrac{1}{2}\rangle \\ 15 && \qquad |1,-1\rangle \otimes |-\tfrac{1}{2}, -\tfrac{1}{2}\rangle \end{align*}.

+12=|+\frac{1}{2}\rangle = |\Uparrow\rangle and 12=|-\frac{1}{2}\rangle = |\Downarrow\rangle (nuclei-only).

Now we have a Spin Hamiltonian. However, it has many unknown constants.

geelectron g-factorgn1,gn2nuclear g-factor (Si, C)μBBohr magnetonμNNuclear magnetonB0external magnetic fieldAijx,Aijy,Aijzhyperfine tensorDaxial zero-fieldEtransverse zero-fieldJexchange coupling \begin{align*} &g_e && \quad \text{electron $g$-factor} \\ &g_{n_1}, \, g_{n_2} && \quad \text{nuclear $g$-factor (Si, C)} \\ &\mu_B &&\quad \text{Bohr magneton} \\ &\mu_N &&\quad \text{Nuclear magneton} \\ &B_0 &&\quad \text{external magnetic field} \\ &A_{ijx}, \, A_{ijy}, \, A_{ijz} &&\quad \text{hyperfine tensor} \\ &D &&\quad\text{axial zero-field} \\ &E &&\quad\text{transverse zero-field} \\ &J &&\quad \text{exchange coupling} \end{align*}

Our next challenge is to perform eigenenergy simulations. I want a plot like in Part 1 but for every combination of every sub-Hamiltonian in H\mathscr{H}, and for all 16 coupled-basis states.

This may seem ambitious, but it’s very straightforward. We already have matrices for all the Hamiltonians. We just need to substitute values for all the constants above and sweep over the B0B_0 field parameter in H^Z\hat{H}_Z. Then we’ll use LAPACK to calculate the energy eigenvalues at each B0B_0 field point. Consequently we’ll have our plots for B0B_0 vs. energy.