Skip to content

Commit a97fca9

Browse files
Added micromagnetic calculation of the skyrmion number, discretising the linear derivatives of the magnetisation for the calculation of the topological charge. Changed the *type* argument for the DMI in the micromagnetic library, to *dmi_type* as in the atomistic library. This will break some docs or notebook examples. Added test for the micromagnetic sk number and documented the atomistic test
1 parent 9271749 commit a97fca9

File tree

9 files changed

+271
-68
lines changed

9 files changed

+271
-68
lines changed

fidimag/micro/dmi.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ class DMI(Energy):
1212
compute the DMI field in micromagnetics
1313
"""
1414

15-
def __init__(self, D, name='dmi', type='bulk'):
15+
def __init__(self, D, name='dmi', dmi_type='bulk'):
1616
"""
1717
type could be 'interfacial' or 'bulk'
1818
"""
1919
self.D = D
2020
self.name = name
2121
self.jac = True
22-
self.type = type
22+
self.dmi_type = dmi_type
2323

2424
def setup(self, mesh, spin, Ms):
2525
super(DMI, self).setup(mesh, spin, Ms)
@@ -32,7 +32,7 @@ def compute_field(self, t=0, spin=None):
3232
else:
3333
m = self.spin
3434

35-
if self.type == 'bulk':
35+
if self.dmi_type == 'bulk':
3636
micro_clib.compute_dmi_field_bulk(m,
3737
self.field,
3838
self.energy,
@@ -45,7 +45,7 @@ def compute_field(self, t=0, spin=None):
4545
self.neighbours
4646
)
4747

48-
elif self.type == 'interfacial':
48+
elif self.dmi_type == 'interfacial':
4949
micro_clib.compute_dmi_field_interfacial(m,
5050
self.field,
5151
self.energy,
@@ -59,6 +59,6 @@ def compute_field(self, t=0, spin=None):
5959
)
6060
else:
6161
raise Exception(
62-
"Unsppourted dmi type:{}, avaiable type: 'bulk','interfacial'.".format(self.type))
62+
"Unsppourted dmi type:{}, avaiable type: 'bulk','interfacial'.".format(self.dmi_type))
6363

6464
return self.field

fidimag/micro/lib/micro_clib.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@ void dmi_field_interfacial(double *m, double *field, double *energy, double *Ms_
2626

2727
void compute_uniaxial_anis(double *m, double *field, double *energy, double *Ms_inv,
2828
double *Ku, double *axis, int nx, int ny, int nz);
29+
30+
double skyrmion_number(double *spin, double *charge,
31+
int nx, int ny, int nz, int *ngbs);

fidimag/micro/lib/micro_clib.pyx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ cdef extern from "micro_clib.h":
2222
double *energy, double *Ms_inv,
2323
double *Ku, double *axis,
2424
int nx, int ny, int nz)
25-
25+
26+
double skyrmion_number(double *m, double *charge,
27+
int nx, int ny, int nz, int *ngbs)
2628

2729

2830
def compute_exchange_field_micro(np.ndarray[double, ndim=1, mode="c"] m,
@@ -70,3 +72,10 @@ def compute_anisotropy_micro(np.ndarray[double, ndim=1, mode="c"] m,
7072

7173
compute_uniaxial_anis(&m[0], &field[0], &energy[0], &Ms_inv[0],
7274
&Ku[0], &axis[0], nx, ny, nz)
75+
76+
def compute_skyrmion_number(np.ndarray[double, ndim=1, mode="c"] m,
77+
np.ndarray[double, ndim=1, mode="c"] charge,
78+
nx, ny, nz,
79+
np.ndarray[int, ndim=2, mode="c"] ngbs):
80+
81+
return skyrmion_number(&m[0], &charge[0], nx, ny, nz, &ngbs[0, 0])

fidimag/micro/lib/util.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#include "micro_clib.h"
2+
3+
// Compute: S \cdot (S_i \times S_j)
4+
inline double volume(double S[3], double Si[3], double Sj[3]) {
5+
double tx = S[0] * (-Si[2] * Sj[1] + Si[1] * Sj[2]);
6+
double ty = S[1] * (Si[2] * Sj[0] - Si[0] * Sj[2]);
7+
double tz = S[2] * (-Si[1] * Sj[0] + Si[0] * Sj[1]);
8+
return tx + ty + tz;
9+
}
10+
11+
double skyrmion_number(double *spin, double *charge,
12+
int nx, int ny, int nz, int *ngbs) {
13+
14+
/* Compute the skyrmion number Q, defined as:
15+
* _
16+
* 1 / dM dM
17+
* Q = --- * / M . -- X -- dx dy
18+
* 4 PI _ / dx dy
19+
*
20+
*
21+
* for a two dimensional layer (it can be a slice of a
22+
* bulk system)
23+
*
24+
* Therefore, a finite differences discretisation of the
25+
* continuum magnetisation field, using central
26+
* differences, leads to:
27+
*
28+
* Q = M_i \cdot ( M_{i+1} \times M_{j+1} )
29+
* + M_i \cdot ( M_{i-1} \times M_{j-1} )
30+
* - M_i \cdot ( M_{i-1} \times M_{j+1} )
31+
* - M_i \cdot ( M_{i+1} \times M_{j-1} )
32+
*
33+
*
34+
* INPUTS:
35+
*
36+
* The *spin array is the vector field for a two dimensional
37+
* lattice with dimensions nx * ny
38+
* (we can take a slice of a bulk from Python and pass it here,
39+
* remember to do the ame for the neighbours matrix)
40+
* The array follows the order:
41+
* [Sx0 Sy0 Sz0 Sx1 Sy1 Sz1 ... ]
42+
*
43+
* Charge is a scalar field array used to store the spin chirality /
44+
* skyrmion number density (Q value per lattice site)
45+
*
46+
* *ngbs is the array with the neighbours information for every
47+
* lattice site. The array is like:
48+
* [ 0-x, 0+x, 0-y, 0+y, 0-z, 0+z, 1-x, 1+x, 1-y, ... ]
49+
* i=0 i=1 ...
50+
*
51+
* where 0-y is the index of the neighbour of the 0th spin,
52+
* in the -y direction, for example
53+
*/
54+
55+
int i, j;
56+
int index, id;
57+
58+
double sum = 0;
59+
60+
double S[3];
61+
62+
int nxy = nx * ny;
63+
64+
/* Store the spin directions of the nearest neighbours
65+
* in the order: [-x +x -y +y]
66+
*/
67+
double S_nn[12];
68+
69+
for (i = 0; i < nxy; i++) {
70+
index = 3 * i;
71+
72+
/* The starting index of the nearest neighbours for the
73+
* i-th spin */
74+
int id_nn = 6 * i;
75+
76+
S[0] = spin[index];
77+
S[1] = spin[index + 1];
78+
S[2] = spin[index + 2];
79+
80+
for (j = 0; j < 4; j++) {
81+
if (ngbs[id_nn + j] > 0) {
82+
id = 3 * ngbs[id_nn + j];
83+
S_nn[3 * j ] = spin[id];
84+
S_nn[3 * j + 1] = spin[id + 1];
85+
S_nn[3 * j + 2] = spin[id + 2];
86+
}
87+
}
88+
89+
charge[i] = volume(S, &S_nn[3], &S_nn[9])
90+
+ volume(S, &S_nn[0], &S_nn[6])
91+
- volume(S, &S_nn[0], &S_nn[9])
92+
- volume(S, &S_nn[3], &S_nn[6]);
93+
94+
charge[i] /= (16 * WIDE_PI);
95+
96+
sum += charge[i];
97+
}
98+
99+
return sum;
100+
101+
}

fidimag/micro/llg.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44
import time
55
import fidimag.extensions.clib as clib
6+
import fidimag.extensions.micro_clib as micro_clib
67
import numpy as np
78
from fidimag.common.fileio import DataSaver, DataReader
89
from fidimag.common.save_vtk import SaveVTK
@@ -303,7 +304,7 @@ def skyrmion_number(self):
303304
nx = self.mesh.nx
304305
ny = self.mesh.ny
305306
nz = self.mesh.nz
306-
number = clib.compute_skyrmion_number(
307+
number = micro_clib.compute_skyrmion_number(
307308
self.spin, self._skx_number, nx, ny, nz, self.mesh.neighbours)
308309
return number
309310

tests/test_oommf_without_run.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ def test_dmi_field_oommf(D=4.1e-3, Ms=2.6e5):
141141
sim = Sim(mesh)
142142
sim.Ms = Ms
143143

144-
dmi = DMI(D=D, type='interfacial')
144+
dmi = DMI(D=D, dmi_type='interfacial')
145145
sim.add(dmi)
146146

147147
def init_m(pos):

tests/test_prb88_184422.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def run_fidimag(mesh):
3535
sim.set_m((0, 0, 1))
3636

3737
sim.add(UniformExchange(A))
38-
sim.add(DMI(D, type='interfacial'))
38+
sim.add(DMI(D, dmi_type='interfacial'))
3939
sim.add(UniaxialAnisotropy(K, axis=(0, 0, 1)))
4040

4141
sim.relax(dt=1e-13, stopping_dmdt=0.01, max_steps=5000,

tests/test_sky_number.py

Lines changed: 0 additions & 59 deletions
This file was deleted.

0 commit comments

Comments
 (0)