Hysteresis simulations#
In this tutorial, we summarise some of the convenience methods offered by Ubermag that can be used for simulating hysteresis. Let us first define a simple system object. For details on how to define simulations, please refer to other tutorials.
[1]:
import oommfc as mc
import discretisedfield as df
import micromagneticmodel as mm
region = df.Region(p1=(-50e-9, -50e-9, -50e-9), p2=(50e-9, 50e-9, 50e-9))
mesh = df.Mesh(region=region, cell=(5e-9, 5e-9, 5e-9))
system = mm.System(name='hysteresis')
system.energy = mm.Exchange(A=1e-12) + mm.UniaxialAnisotropy(K=4e5, u=(0, 0, 1)) + mm.DMI(D=1e-3, crystalclass='T')# + mm.Demag()
def Ms_fun(point):
x, y, z = point
if x**2 + y**2 + z**2 <= 50e-9**2:
return 1e6
else:
return 0
system.m = df.Field(mesh, nvdim=3, value=(0, 0, -1), norm=Ms_fun, valid="norm")
Now that we have system
object we can simulate hysteresis using HysteresisDriver
. Like all other drivers, HysteresisDriver
has drive
method. As input arguments it takes system
object (as usual) and:
Hmin
- the starting value of magnetic fieldHmin
- the end value of magnetic fieldn
- the number of points betweenHmin
andHmax
For instance, let us say we want to simulate hysteresis between \(-1\,\text{T}\) and \(1\,\text{T}\) applied along the \(z\)-direction in steps of \(0.2\,\text{T}\). Accordingly, Hmin
and Hmax
are:
[2]:
Hmin = (0, 0, -1/mm.consts.mu0)
Hmax = (0, 0, 1/mm.consts.mu0)
The number of steps n
should be 21, so that the values of magnetic field are: \(-1\,\text{T}\), \(-0.9\,\text{T}\), \(-0.8\,\text{T}\), …, \(0.9\,\text{T}\), \(1\,\text{T}\), \(0.9\,\text{T}\), \(0.8\,\text{T}\), …, \(-0.9\,\text{T}\), \(-1\,\text{T}\).
[3]:
n = 21
We can now create HysteresisDriver
and drive the system.
[4]:
hd = mc.HysteresisDriver()
hd.drive(system, Hmin=Hmin, Hmax=Hmax, n=n)
Running OOMMF (ExeOOMMFRunner)[2023/10/23 16:08]... (1.6 s)
After the simulation is complete, we can have a look at the last magnetisation step:
[5]:
system.m.sel('y').mpl()
Similarly, table can be viewed:
[6]:
system.table.data.head()
[6]:
max_mxHxm | E | delta_E | bracket_count | line_min_count | conjugate_cycle_count | cycle_count | cycle_sub_count | energy_calc_count | E_exchange | ... | B_hysteresis | Bx_hysteresis | By_hysteresis | Bz_hysteresis | iteration | stage_iteration | stage | mx | my | mz | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.081187 | -5.296243e-16 | -3.944305e-31 | 9.0 | 9.0 | 1.0 | 8.0 | 7.0 | 19.0 | 1.178506e-19 | ... | 1000.0 | 0.0 | 0.0 | -1000.0 | 18.0 | 18.0 | 0.0 | -6.890111e-21 | -4.478572e-20 | -0.998400 |
1 | 0.079349 | -4.769135e-16 | -7.888609e-31 | 16.0 | 15.0 | 2.0 | 15.0 | 6.0 | 33.0 | 1.301416e-19 | ... | 900.0 | 0.0 | 0.0 | -900.0 | 32.0 | 13.0 | 1.0 | -4.375221e-19 | -2.067033e-20 | -0.998216 |
2 | 0.056383 | -4.242133e-16 | -9.860761e-32 | 23.0 | 22.0 | 3.0 | 22.0 | 6.0 | 48.0 | 1.445097e-19 | ... | 800.0 | 0.0 | 0.0 | -800.0 | 47.0 | 14.0 | 2.0 | -1.584726e-19 | -5.167584e-20 | -0.997999 |
3 | 0.086409 | -3.715256e-16 | -1.972152e-31 | 31.0 | 29.0 | 4.0 | 29.0 | 6.0 | 64.0 | 1.614662e-19 | ... | 700.0 | 0.0 | 0.0 | -700.0 | 62.0 | 14.0 | 3.0 | -2.652693e-19 | -3.100550e-20 | -0.997739 |
4 | 0.053104 | -3.188531e-16 | -3.944305e-31 | 40.0 | 36.0 | 5.0 | 37.0 | 7.0 | 81.0 | 1.816966e-19 | ... | 600.0 | 0.0 | 0.0 | -600.0 | 78.0 | 15.0 | 4.0 | 6.166650e-19 | -3.100550e-20 | -0.997422 |
5 rows × 26 columns
From the table, we can see at what external magnetic field the system was relaxed:
[7]:
system.table.data['B_hysteresis']
[7]:
0 1000.0
1 900.0
2 800.0
3 700.0
4 600.0
5 500.0
6 400.0
7 300.0
8 200.0
9 100.0
10 0.0
11 100.0
12 200.0
13 300.0
14 400.0
15 500.0
16 600.0
17 700.0
18 800.0
19 900.0
20 1000.0
21 900.0
22 800.0
23 700.0
24 600.0
25 500.0
26 400.0
27 300.0
28 200.0
29 100.0
30 0.0
31 100.0
32 200.0
33 300.0
34 400.0
35 500.0
36 600.0
37 700.0
38 800.0
39 900.0
40 1000.0
Name: B_hysteresis, dtype: float64
The units of \(B\) are:
[8]:
system.table.units['B_hysteresis']
[8]:
'mT'
Plotting hysteresis loop#
Using Table
object, we can plot different values as a function of external magnetic field. For that, as usual, we use mpl
method. We have to specify to that method what do we want to have on the \(y\)-axis.
[9]:
system.table.mpl(y=['mz'])
This does not look like a hysteresis loop as we expected. The reason is that on the horizontal axis we have the magnitude B
by default, which is always positive. We can change that by passing Bz
for x
:
[10]:
system.table.mpl(x='Bz_hysteresis', y=['mz'])
Table.mpl
is based on matplotlib.pyplot.plot
, so any keyword argument accepted by it can be passed:
[11]:
system.table.mpl(x='Bz_hysteresis', y=['mz'], marker='o', linewidth=2, linestyle='dashed')
micromagneticdata
analysis#
We can also analyse magnetisation fields at different values of external magnetic field as well as building interactive plots using micromagneticdata
package.
[12]:
import micromagneticdata as md
We can create a data object by passing system’s name.
[13]:
data = md.Data(name=system.name)
Now, we can have a look at all drives we did so far:
[14]:
data.info
[14]:
drive_number | date | time | driver | Hmin | Hmax | n | n_threads | |
---|---|---|---|---|---|---|---|---|
0 | 0 | 2022-10-20 | 15:13:27 | HysteresisDriver | [0, 0, -795774.7154594767] | [0, 0, 795774.7154594767] | 21 | NaN |
1 | 1 | 2022-10-20 | 15:27:16 | HysteresisDriver | [0, 0, -795774.7154594767] | [0, 0, 795774.7154594767] | 21 | NaN |
2 | 2 | 2023-10-23 | 16:08:27 | HysteresisDriver | [0, 0, -795774.7154594767] | [0, 0, 795774.7154594767] | 21 | NaN |
There is only one drive with index 0
. We can get if by indexing the data object:
[15]:
drive = data[0]
The number of steps saved is:
[16]:
drive.n
[16]:
41
We can get an individual step by passing a value between 0 and 40 as an index:
[17]:
drive[0].sel('x').mpl()
We can also interactively plot all individual steps by using drive.hv
. For more details on creating interactive plots, please refer to other tutorials.
[18]:
drive.hv(kdims=["x", "y"])
[18]: