Skip to content

Commit 2bf91b2

Browse files
Updated bulk DMI calculation in the atomistic C library. Added documentation to atomistic DMI and updated Zeeman doc
1 parent 6b3bebf commit 2bf91b2

File tree

3 files changed

+129
-65
lines changed

3 files changed

+129
-65
lines changed

fidimag/atomistic/dmi.py

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,73 @@
66
class DMI(Energy):
77

88
"""
9-
Hamiltonian = D*[S_i x S_j]
10-
==> H = D x S_j
9+
10+
This class provides the Dzyaloshinskii-Moriya Interaction (DMI) energy
11+
term, defined as
12+
13+
__ -> -> ->
14+
E = - \ D_ij * ( S_i X S_j )
15+
/__
16+
i, j
17+
i != j
18+
19+
where D_ij is the Dzyaloshinskii vector and S_i and S_j are the total spin
20+
vectors at the i-th and j-th lattice sites. The Dzyaloshinskii vector
21+
magnitude can vary with space.
22+
23+
Currently, there are implemented two kinds of DMI, that depend on the
24+
Dzyaloshinskii vector definition. Calling D_i the Dzyaloshinskii vector
25+
magnitude at the i-th site:
26+
27+
BULK:
28+
-> ^
29+
D_ij = D_i r_ij with r_ij as the unit vector pointing from the i-th
30+
towards the j-th site
31+
(only working for square lattices)
32+
33+
INTERFACIAL:
34+
35+
-> ^ ^
36+
D_ij = D_i ( r_ij X z ) with r_ij as the unit vector pointing from the
37+
i-th towards the j-th site and z the unitary
38+
vector perpendicular to the magnetic material
39+
plane which, in theory, is in contact with a
40+
material with larger SOC (e.g. a metal).
41+
Thus, this DMI is defined in 2D, for
42+
interfaces or thin films.
43+
44+
For further details about the DMI calculations, take a look
45+
to the C library documentation (dmi.c)
46+
47+
48+
OPTIONAL ARGUMENTS: -------------------------------------------------------
49+
50+
dmi_type :: 'bulk' or 'interfacial'
51+
name :: Interaction name
52+
53+
USAGE: --------------------------------------------------------------------
54+
55+
If the DMI is homogeneous, it can be specified in a simulation object
56+
*Sim* as
57+
58+
Sim.add(DMI(D, dmi_type='bulk'))
59+
60+
where D is a float.
61+
62+
Otherwise, it can be specified as any Fidimag scalar field, passing a
63+
function or an array. For example, a space dependent DMI that changes
64+
linearly in the x-direction can be defined as:
65+
66+
def my_DMI(pos):
67+
D = 0.01 * meV
68+
return D * pos[0]
69+
70+
# Add DMI to Simulation object
71+
Sim.add(DMI(my_DMI))
72+
1173
"""
1274

13-
def __init__(self, D, name='dmi', dmi_type='bulk'):
75+
def __init__(self, D, name='DMI', dmi_type='bulk'):
1476
self.D = D
1577

1678
self.name = name
@@ -32,20 +94,20 @@ def setup(self, mesh, spin, mu_s):
3294
# We will generate the Dzyaloshinskii vectors according
3395
# to the lattice, for the Interfacial DMI
3496
self.DMI_vector = self.compute_DMI_vectors(self.nneighbours)
35-
97+
3698
if self.dmi_type == 'bulk':
3799
self._D = np.zeros(self.neighbours.shape)
38100
if isinstance(self.D, (int, float)):
39-
self._D[:,:] = self.D
101+
self._D[:, :] = self.D
40102
elif hasattr(self.D, '__call__'):
41-
n = self.mesh.n
103+
n = self.mesh.n
42104
for i in range(n):
43105
value = self.D(self.coordinates[i])
44106
if len(value) == 6:
45-
self._D[i,:] = value[:]
107+
self._D[i, :] = value[:]
46108
else:
47109
raise Exception('The given spatial function for D is not acceptable!')
48-
110+
49111

50112
def compute_field(self, t=0, spin=None):
51113

@@ -55,7 +117,7 @@ def compute_field(self, t=0, spin=None):
55117
m = self.spin
56118

57119
if self.dmi_type == 'bulk':
58-
clib.compute_dmi_field(m,
120+
clib.compute_dmi_field(m,
59121
self.field,
60122
self.energy,
61123
self._D,

fidimag/atomistic/lib/dmi.c

Lines changed: 47 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -39,66 +39,62 @@ void dmi_field_bulk(double *spin, double *field,
3939
*
4040
* for every spin *i*
4141
*
42-
* --- Check this: can we use a SC lattice for this bulk DMI expression?
43-
* Since, for example, MnSi crystal structure is more complex
42+
* NOTES:
43+
*
44+
* 1. Check this: can we use a SC lattice for this bulk DMI expression?
45+
* Since, for example, MnSi crystal structure is more complex
46+
*
47+
* 2. This function is not defined for a hexagonal lattice, we can
48+
* generalise the code to solve this
49+
*
4450
*/
4551

46-
#pragma omp parallel for
52+
53+
/* The DMI vectors are the same according to the neighbours
54+
* positions. Thus we set them here to avoid compute them
55+
* every time in the loop . So, if we want the j-th NN,
56+
* the DMI vector will be
57+
* (D_x, D_y, D_z) --> ( dmivector[3 * j] ,
58+
* dmivector[3 * j + 1],
59+
* dmivector[3 * j + 2] )
60+
*/
61+
double dmivector[18] = {-1, 0, 0,
62+
1, 0, 0,
63+
0, -1, 0,
64+
0, 1, 0,
65+
0, 0, -1,
66+
0, 0, 1
67+
};
68+
69+
#pragma omp parallel for shared(dmivector)
4770
for (int i = 0; i < nxyz; i++) {
4871

4972
int id = 0;
50-
int idv = 6 * i; // index for the neighbours
73+
int id_nn = 6 * i; // index for the neighbours
5174

5275
double fx = 0, fy = 0, fz = 0;
5376
double D=0;
5477

55-
if (ngbs[idv]>=0) { // neighbour at x-1
56-
id = 3*ngbs[idv];
57-
D = _D[idv];
58-
fx += D*cross_x(-1,0,0,spin[id],spin[id+1],spin[id+2]);
59-
fy += D*cross_y(-1,0,0,spin[id],spin[id+1],spin[id+2]);
60-
fz += D*cross_z(-1,0,0,spin[id],spin[id+1],spin[id+2]);
61-
}
62-
63-
if (ngbs[idv+1]>=0) { // neighbour x+1
64-
id = 3*ngbs[idv+1];
65-
D = _D[idv+1];
66-
fx += D*cross_x(1,0,0,spin[id],spin[id+1],spin[id+2]);
67-
fy += D*cross_y(1,0,0,spin[id],spin[id+1],spin[id+2]);
68-
fz += D*cross_z(1,0,0,spin[id],spin[id+1],spin[id+2]);
69-
}
70-
71-
if (ngbs[idv+2]>=0) { // neighbour at y-1
72-
id = 3*ngbs[idv+2];
73-
D = _D[idv+2];
74-
fx += D*cross_x(0,-1,0,spin[id],spin[id+1],spin[id+2]);
75-
fy += D*cross_y(0,-1,0,spin[id],spin[id+1],spin[id+2]);
76-
fz += D*cross_z(0,-1,0,spin[id],spin[id+1],spin[id+2]);
77-
}
78-
79-
if (ngbs[idv+3]>=0) { // neighbour at y+1
80-
id = 3*ngbs[idv+3];
81-
D = _D[idv+3];
82-
fx += D*cross_x(0,1,0,spin[id],spin[id+1],spin[id+2]);
83-
fy += D*cross_y(0,1,0,spin[id],spin[id+1],spin[id+2]);
84-
fz += D*cross_z(0,1,0,spin[id],spin[id+1],spin[id+2]);
85-
}
86-
87-
if (ngbs[idv+4]>=0) { // neighbour at z-1
88-
id = 3*ngbs[idv+4];
89-
D = _D[idv+4];
90-
fx += D*cross_x(0,0,-1,spin[id],spin[id+1],spin[id+2]);
91-
fy += D*cross_y(0,0,-1,spin[id],spin[id+1],spin[id+2]);
92-
fz += D*cross_z(0,0,-1,spin[id],spin[id+1],spin[id+2]);
93-
}
94-
95-
if (ngbs[idv+5]>=0) { // neighbour at z+1
96-
id = 3*ngbs[idv+5];
97-
D = _D[idv+5];
98-
fx += D*cross_x(0,0,1,spin[id],spin[id+1],spin[id+2]);
99-
fy += D*cross_y(0,0,1,spin[id],spin[id+1],spin[id+2]);
100-
fz += D*cross_z(0,0,1,spin[id],spin[id+1],spin[id+2]);
101-
}
78+
// Compute the DMI contribution for every neighbour:
79+
// -x, +x, -y, +y, -z, +z
80+
for (int j = 0; j < 6; j++){
81+
if (ngbs[id_nn + j] >= 0) {
82+
id = 3 * ngbs[id_nn + j];
83+
D = _D[id_nn + j];
84+
fx += D * cross_x(dmivector[3 * j],
85+
dmivector[3 * j + 1],
86+
dmivector[3 * j + 2],
87+
spin[id], spin[id+1], spin[id+2]);
88+
fy += D * cross_y(dmivector[3 * j],
89+
dmivector[3 * j + 1],
90+
dmivector[3 * j + 2],
91+
spin[id], spin[id+1], spin[id+2]);
92+
fz += D * cross_z(dmivector[3 * j],
93+
dmivector[3 * j + 1],
94+
dmivector[3 * j + 2],
95+
spin[id], spin[id+1], spin[id+2]);
96+
}
97+
}
10298

10399
field[3 * i] = fx;
104100
field[3 * i + 1] = fy;

fidimag/atomistic/zeeman.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ class Zeeman(object):
99
A time independent external magnetic field that can be space dependent.
1010
The field energy is computed as:
1111
12-
__ -> ->
13-
E = - \ \mu_i \cdot B_i
12+
__ -> ->
13+
E = - \ \mu_i * B_i
1414
/__
1515
i
1616
@@ -19,14 +19,20 @@ class Zeeman(object):
1919
spin vector at the i-th site and B_i the bias field vector at the i-th
2020
site, given in Tesla units.
2121
22+
OPTIONAL ARGUMENTS: -------------------------------------------------------
23+
name :: Interaction name
24+
25+
USAGE: --------------------------------------------------------------------
26+
2227
If the field is homogeneous, it can be specified in a simulation object
2328
*Sim* as
2429
2530
Sim.add(Zeeman((B_x, B_y, B_z)))
2631
27-
Otherwise, it can be specified as any Fidimag field, passing a function or
28-
an array. For example, a space dependent field function that changes
29-
linearly in the x-direction, and only has a x-component, can be defined as:
32+
Otherwise, it can be specified as any Fidimag vector field, passing a
33+
function or an array. For example, a space dependent field function that
34+
changes linearly in the x-direction, and only has a x-component, can be
35+
defined as:
3036
3137
def my_Zeeman_field(pos):
3238
B = 0.01 # T

0 commit comments

Comments
 (0)