MinDriver
steps#
In this tutorial, we show how we can save individual steps during minimisation as well as how we can analyse them. We are going to minimise a simple system object. For details on how to define a system object, please have a look at other tutorials.
[1]:
import discretisedfield as df
import micromagneticmodel as mm
import oommfc as mc
region = df.Region(p1=(-50e-9, -50e-9, 0), p2=(50e-9, 50e-9, 10e-9))
mesh = df.Mesh(region=region, cell=(5e-9, 5e-9, 5e-9))
system = mm.System(name="mindriver_steps")
system.energy = mm.Zeeman(H=(0, 0, 1e5))
system.m = df.Field(mesh, nvdim=3, value=(1, 0, 0), norm=1.1e6)
We now have a system object and we can minimise it using MinDriver
. By default, MinDriver
saves only the data of the last step in the relexation. However, if we want to save all individual steps in between, we have to pass output_step=True
to the drive
method.
[2]:
md = mc.MinDriver()
md.drive(system, output_step=True)
Running OOMMF (ExeOOMMFRunner)[2023/10/18 12:39]... (0.4 s)
If we have a look at the table, we can see that multiple steps are saved:
[3]:
system.table.data
[3]:
max_mxHxm | E | delta_E | bracket_count | line_min_count | conjugate_cycle_count | cycle_count | cycle_sub_count | energy_calc_count | E_zeeman | iteration | stage_iteration | stage | mx | my | mz | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1.000000e+05 | 0.000000e+00 | 0.000000e+00 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 | 1.0 | 0.000000e+00 | 0.0 | 0.0 | 0.0 | 1.000000e+00 | 0.0 | 0.000000 |
1 | 9.999996e+04 | -1.206285e-20 | -1.206285e-20 | 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 2.0 | -1.206285e-20 | 1.0 | 1.0 | 0.0 | 9.999996e-01 | 0.0 | 0.000873 |
2 | 9.848078e+04 | -2.400340e-18 | -2.388277e-18 | 2.0 | 0.0 | 1.0 | 1.0 | 0.0 | 3.0 | -2.400340e-18 | 2.0 | 2.0 | 0.0 | 9.848078e-01 | 0.0 | 0.173648 |
3 | 9.396926e+04 | -4.727747e-18 | -2.327407e-18 | 3.0 | 0.0 | 2.0 | 2.0 | 0.0 | 4.0 | -4.727747e-18 | 3.0 | 3.0 | 0.0 | 9.396926e-01 | 0.0 | 0.342020 |
4 | 8.660254e+04 | -6.911504e-18 | -2.183757e-18 | 4.0 | 0.0 | 3.0 | 3.0 | 0.0 | 5.0 | -6.911504e-18 | 4.0 | 4.0 | 0.0 | 8.660254e-01 | 0.0 | 0.500000 |
5 | 7.660444e+04 | -8.885258e-18 | -1.973754e-18 | 5.0 | 0.0 | 4.0 | 4.0 | 0.0 | 6.0 | -8.885258e-18 | 5.0 | 5.0 | 0.0 | 7.660444e-01 | 0.0 | 0.642788 |
6 | 6.427876e+04 | -1.058904e-17 | -1.703780e-18 | 6.0 | 0.0 | 5.0 | 5.0 | 0.0 | 7.0 | -1.058904e-17 | 6.0 | 6.0 | 0.0 | 6.427876e-01 | 0.0 | 0.766044 |
7 | 5.000000e+04 | -1.197108e-17 | -1.382038e-18 | 7.0 | 0.0 | 6.0 | 6.0 | 0.0 | 8.0 | -1.197108e-17 | 7.0 | 7.0 | 0.0 | 5.000000e-01 | 0.0 | 0.866025 |
8 | 3.464669e+04 | -1.296684e-17 | -9.957653e-19 | 8.0 | 0.0 | 7.0 | 7.0 | 0.0 | 9.0 | -1.296684e-17 | 8.0 | 8.0 | 0.0 | 3.464669e-01 | 0.0 | 0.938062 |
9 | 3.420201e+04 | -1.298938e-17 | -2.253721e-20 | 9.0 | 0.0 | 7.0 | 7.0 | 0.0 | 10.0 | -1.298938e-17 | 9.0 | 9.0 | 0.0 | 3.420201e-01 | 0.0 | 0.939693 |
10 | 1.981052e+04 | -1.354905e-17 | -5.596679e-19 | 10.0 | 0.0 | 8.0 | 8.0 | 0.0 | 11.0 | -1.354905e-17 | 10.0 | 10.0 | 0.0 | 1.981052e-01 | 0.0 | 0.980181 |
11 | 1.736482e+04 | -1.361301e-17 | -6.395896e-20 | 11.0 | 0.0 | 8.0 | 8.0 | 0.0 | 12.0 | -1.361301e-17 | 11.0 | 11.0 | 0.0 | 1.736482e-01 | 0.0 | 0.984808 |
12 | 6.305027e+03 | -1.379550e-17 | -1.824996e-19 | 12.0 | 0.0 | 9.0 | 9.0 | 0.0 | 13.0 | -1.379550e-17 | 12.0 | 12.0 | 0.0 | 6.305027e-02 | 0.0 | 0.998010 |
13 | 3.143399e-11 | -1.382301e-17 | -2.750291e-20 | 13.0 | 0.0 | 9.0 | 9.0 | 0.0 | 14.0 | -1.382301e-17 | 13.0 | 13.0 | 0.0 | 3.143399e-16 | 0.0 | 1.000000 |
Using all the utility of the Table
object, we can analyse the data. For instance, we can plot the energy.
[4]:
system.table.mpl(y=["E"])
By fecault, iteration is showed on the \(x\)-axis. We can change that by passing x
variable. For example:
[5]:
system.table.mpl(x="mx", y=["E"])
micromagneticdata
analysis#
Similar to all other drivers, we can use micromagneticdata
package to analyse the data. We start by creationg the data object:
[6]:
import micromagneticdata as md
data = md.Data(name=system.name)
We can have a look at all drives we did so far:
[7]:
data.info
[7]:
drive_number | date | time | driver | t | n | n_threads | |
---|---|---|---|---|---|---|---|
0 | 0 | 2023-01-16 | 17:35:54 | MinDriver | NaN | NaN | NaN |
1 | 1 | 2023-01-16 | 17:35:58 | TimeDriver | 2.000000e-09 | 200.0 | 4.0 |
2 | 2 | 2023-01-16 | 17:37:00 | MinDriver | NaN | NaN | NaN |
3 | 3 | 2023-01-16 | 17:37:04 | TimeDriver | 2.000000e-09 | 200.0 | 4.0 |
4 | 4 | 2023-01-16 | 17:37:28 | MinDriver | NaN | NaN | NaN |
5 | 5 | 2023-01-16 | 17:38:02 | MinDriver | NaN | NaN | NaN |
6 | 6 | 2023-01-16 | 17:38:06 | TimeDriver | 2.000000e-09 | 200.0 | 4.0 |
7 | 7 | 2023-10-10 | 16:55:09 | MinDriver | NaN | NaN | NaN |
8 | 8 | 2023-10-10 | 16:55:13 | TimeDriver | 2.000000e-09 | 200.0 | 4.0 |
9 | 9 | 2023-10-18 | 12:37:23 | MinDriver | NaN | NaN | NaN |
10 | 10 | 2023-10-18 | 12:39:38 | MinDriver | NaN | NaN | NaN |
There is only one drive and we can get it by passing 0
(ot -1
) as an index:
[8]:
drive = data[0]
We can now plot the magnetisation at individual iterations, by indexing it again with the step number and do all usual operations allowed by discretisedfield.Field
object.
[9]:
drive[0]
[9]:
- Mesh
- Region
- pmin = [-5e-08, -5e-08, 0.0]
- pmax = [5e-08, 5e-08, 1e-08]
- dims = ['x', 'y', 'z']
- units = ['m', 'm', 'm']
- n = [20, 20, 2]
- Region
- nvdim = 3
- vdims:
- x
- y
- z
- unit = A/m
The number of steps in the drive is:
[10]:
drive.n
[10]:
14
Let us now create an interactive plot. For details on how to create custom interactive plots, please have a look at other tutorials.
[11]:
drive.register_callback(lambda f: f.sel("y")).hv(kdims=["x", "z"]).opts(frame_width=800)
[11]: