Energy equation#
The energy of a magnetic system can be computed using Hamiltonian, which consists of different energy terms. In addition, the effective field which affects the magnetisation dynamics in the LLG equation, is also computed from the system’s Hamiltonian.
In this tutorial, we explore different energy terms that can occur in the Hamiltonian.
Zeeman energy#
The Zeeman energy tends to align all magnetic moments parallel to the external magnetic field \(\mathbf{H}\), so that the energy density \(w_\text{z} = -\mu_{0}M_\text{s}\mathbf{m}\cdot\mathbf{H}\) is minimum, where \(\mu_{0}\) is the magnetic constant and \(M_\text{s}\) is the magnetisation saturation.
To demonstrate the effect of Zeeman energy we will apply an external magnetic field \(H = 10^{6} \,\text{A}\,\text{m}^{-1}\) in the positive \(z\)-direction to the one-dimensional array of magnetic moments. For the initial magnetisation configuration, we will take the \((1, 0, 1)\) direction with \(M_\text{s} = 8 \times 10^{6} \,\text{A}\,\text{m}^{-1}\).
[1]:
import oommfc as oc
import discretisedfield as df
import micromagneticmodel as mm
Our mesh is a one-dimensional array of discretisation cells.
[2]:
p1 = (0, 0, 0)
p2 = (10e-9, 1e-9, 1e-9)
cell = (1e-9, 1e-9, 1e-9)
region = df.Region(p1=p1, p2=p2)
mesh = df.Mesh(p1=p1, p2=p2, cell=cell)
mesh.mpl()
[3]:
system = mm.System(name="zeeman") # create the (micromagnetic) system object
H = (0, 0, 1e6) # external magnetic field (A/m)
Ms = 8e6 # saturation magnetisation (A/m)
system.energy = mm.Zeeman(H=H) # define system's Hamiltonian
system.m = df.Field(
mesh, nvdim=3, value=(1, 0, 1), norm=Ms
) # define initial magnetisation
system.m.sel("y").mpl()
After we defined our system, we can minimize its energy using MinDriver
.
[4]:
md = oc.MinDriver() # create energy minimisation driver
md.drive(system) # run energy minimisation
system.m.sel("y").mpl()
Running OOMMF (ExeOOMMFRunner)[2023/10/23 15:52]... (0.4 s)
We can see that after applying the magnetic field, all magnetic moments align parallel to \(\mathbf{H}\).
We can change the direction of applied field to be in the negative \(x\) direction and inspect the minimum magnetisation state.
[5]:
system.energy.zeeman.H = (-1e6, 0, 0)
md.drive(system)
system.m.sel("y").mpl()
Running OOMMF (ExeOOMMFRunner)[2023/10/23 15:52]... (0.2 s)
Uniaxial anisotropy#
Uniaxial anisotropy energy tends to align magnetic moments to be on the anisotropy axis either parallel or antiparallel without a preferred direction. Its energy density is \(w_\text{a} = -K(\mathbf{m} \cdot \mathbf{u})^{2}\), where \(K\) is the anisotropy constant and \(\mathbf{u}\) is the anisotropy axis.
Let’s assume our anisotropy axis is in the \((1, 0, 1)\) direction with \(K = 6 \times 10^{6} \,\text{J}\,\text{m}^{-3}\) and the initial magnetisation is defined as
with \(M_\text{s} = 8 \times 10^{6} \,\text{A}\,\text{m}^{-1}\).
[6]:
system = mm.System(name="uniaxial_anisotropy")
system.energy = mm.UniaxialAnisotropy(K=6e6, u=(1, 0, 1))
def m_initial(pos):
x, y, z = pos
if x <= 5e-9:
return (-1, 0, -0.1)
else:
return (1, 0, 0.1)
system.m = df.Field(mesh, nvdim=3, value=m_initial, norm=Ms)
system.m.sel("y").mpl()
We can now relax the magnetisation.
[7]:
md.drive(system)
system.m.sel("y").mpl()
Running OOMMF (ExeOOMMFRunner)[2023/10/23 15:52]... (0.2 s)
We see that in the relaxed state, all magnetic moments are aligned with the aniostropy axis. The initial configuration affects which orientation along the anisotropy direction is chosen.
Exchange energy#
The Zeeman and uniaxial anisotropy are local energy terms; they only depend on the magnetisation at a given location. In contrast, the exchange energy represents a short range interaction and tends to align all spins parallel to each other without a preferential direction.
The exchange energy density is \(w_\text{ex} = A[(\nabla m_{x})^{2} + (\nabla m_{y})^{2} + (\nabla m_{z})^{2}]\), where \(A\) is the exchange energy constant. To demonstrate how it affects the magnetisation configuration, we will use \(A = 8 \,\text{pJ}\,\text{m}^{-1}\) on a non-uniform magnetisation configuration.
[8]:
system = mm.System(name="exchange")
system.energy = mm.Exchange(A=8e-12)
def m_initial(pos):
x, y, z = pos
if x <= 5e-9:
return (0, 0, 1)
else:
return (1, 0, 0)
system.m = df.Field(mesh, nvdim=3, value=m_initial, norm=Ms)
system.m.sel("y").mpl()
[9]:
md.drive(system)
system.m.sel("y").mpl()
Running OOMMF (ExeOOMMFRunner)[2023/10/23 15:52]... (0.2 s)
Dzyaloshinskii-Moriya energy#
While the exchange interaction aims to align (neighbouring) magnetic moments parallel to each other, the Dzyaloshinskii-Moriya (DM) energy wants to align them perpendicular to each other.
The (interfacial) DMI energy density is \(w_\text{dmi} = D[m_{z}\nabla\cdot\mathbf{m} - (\mathbf{m}\cdot\nabla)m_{z}]\) (crystallographic class \(C_\text{nv}\)), with \(D\) being the DM constant. Again, we demonstrate its effect by starting from a uniform configuration, with \(D = 3\times10^{3} \,\text{J}\,\text{m}^{-2}\).
[10]:
system = mm.System(name="dmi")
system.energy = mm.DMI(crystalclass="Cnv_z", D=3e-3)
system.m = df.Field(mesh, nvdim=3, value=(0, 0, 1), norm=Ms)
md.drive(system)
system.m.sel("y").mpl()
Running OOMMF (ExeOOMMFRunner)[2023/10/23 15:52]... (0.2 s)
Ubermag supports crystalographic classes: T
, O
, Cnv
, or D2d
.
Exchange and Zeeman energies#
So far, we investigated the effect of individual energy terms in the Hamiltonian. Now, we look at how multiple energies in the Hamiltoninan contribute to the final magnetisation configuration. We start with the simplest example where only exchange and Zeeman energies are present. As we showed before, exchange energy wants to align all magnetic moments parallel to each other without a preferential direction, while Zeeman energy wants them to be parallel to the external magnetic field. Therefore, we can expect that the minimum energy configuration is going to be the uniform state in the direction of an applied field \(\mathbf{H}\).
[11]:
system = mm.System(name="exchange_and_zeeman")
# We can add multiple interactions using the 'plus' operator
system.energy = mm.Exchange(A=8e-12) + mm.Zeeman(H=(0, 0, -1e6))
def m_initial(pos):
x, y, z = pos
if x <= 5e-9:
return (0, 0, 1)
else:
return (1, 0, 0)
system.m = df.Field(mesh, nvdim=3, value=m_initial, norm=Ms)
system.m.sel("y").mpl()
[12]:
md.drive(system)
system.m.sel("y").mpl()
Running OOMMF (ExeOOMMFRunner)[2023/10/23 15:52]... (0.2 s)
Both energies are minimal in the above relaxed state: the magnetisation is uniform (minimising the exchange energy) and is aligned with the external field (minimising the Zeeman energy).
Competition of DMI and exchange#
Here, we study the competition of the exchange and (interfacial) DMI energy.
We relax a one-dimensional chain of magnetic moments of length \(L = 20 \,\text{nm}\) with discretisation cell size of \((d, d, d)\), with \(d = 1 \,\text{nm}\). The Hamiltonian should consist of:
exchange energy with \(A=1 \times 10^{-11} \,\text{J}\,\text{m}^{-1}\), and
Dzyaloshinskii-Moriya energy with \(D = 4\pi A/L \approx 6.28 \times 10^{-3} \,\text{J}\,\text{m}^{-2}\).
The magnetisation saturation is \(M_\mathrm{s} = 8 \times 10^{6} \,\text{A}\,\text{m}^{-1}\). Initialise the system with any uniform state.
Questions:
What is the relaxed state?
Double the value of DMI constant to be \(D = 12.56 \times 10^{3} \,\text{J}\,\text{m}^{-2}\). What has changed?
[13]:
system = mm.System(name="exchange_and_DMI")
A = 1e-11 # exchange energy constant (J/m)
D = 6.28e-3 # DMI energy constant (J/m**2)
Ms = 8e6 # Saturation magnetisation (A/m)
region = df.Region(p1=(0, 0, 0), p2=(20e-9, 1e-9, 1e-9))
mesh = df.Mesh(region=region, cell=(1e-9, 1e-9, 1e-9))
m_initial = (0, 1, 1) # uniform initial magnetisation
system.m = df.Field(mesh, nvdim=3, value=m_initial, norm=Ms)
system.m.sel("y").mpl()
[14]:
system.energy = mm.Exchange(A=A) + mm.DMI(D=D, crystalclass="Cnv_z")
md = oc.MinDriver() # create energy minimisation driver
md.drive(system)
system.m.sel("y").mpl()
Running OOMMF (ExeOOMMFRunner)[2023/10/23 15:52]... (0.3 s)
We can also sample the magnetisation along the sample.
[15]:
line = system.m.line(p1=system.m.mesh.region.pmin, p2=system.m.mesh.region.pmax, n=19)
line.mpl(marker="o")
We can have a look at D
parameter from the DMI energy.
[16]:
system.energy.dmi.D
[16]:
0.00628
We can now double the strength of D
to see how the system will change.
[17]:
system.energy.dmi.D = 2 * D
md.drive(system)
system.m.sel("y").mpl()
Running OOMMF (ExeOOMMFRunner)[2023/10/23 15:52]... (0.2 s)
[18]:
line = system.m.line(p1=system.m.mesh.region.pmin, p2=system.m.mesh.region.pmax, n=19)
line.mpl(marker="o")
We can now see that the period has decreased.
Skyrmion in a disk#
We can assemble the appropriate energy equation in order to obtain a skyrmion state in a disk with \(100 \,\text{nm}\) diameter and \(5 \,\text{nm}\) thickness. In addition, we choose the appropriate initial magnetisation state.
[19]:
d = 100e-9
thickness = 5e-9
cell = (5e-9, 5e-9, 5e-9)
p1 = (-d / 2, -d / 2, 0)
p2 = (d / 2, d / 2, thickness)
region = df.Region(p1=p1, p2=p2)
mesh = df.Mesh(region=region, cell=cell)
system = mm.System(name="skyrmion")
system.energy = (
mm.Exchange(A=8.78e-12) + mm.DMI(D=1.58e-3, crystalclass="T") + mm.Demag()
)
def m_initial(point):
x, y, z = point
if x**2 + y**2 < (d / 4) ** 2:
return (0, 0, -1)
else:
return (0, 0, 1)
def Ms_fun(point):
x, y, z = point
if x**2 + y**2 < (d / 2) ** 2:
return 3.84e5
else:
return 0
system.m = df.Field(mesh, nvdim=3, value=m_initial, norm=Ms_fun, valid="norm")
md.drive(system)
system.m.sel("z").mpl()
Running OOMMF (ExeOOMMFRunner)[2023/10/23 15:52]... (0.3 s)