Skip to content

Commit 0bd9fc7

Browse files
Documented anisotropy and DMI atomistic classes
1 parent 2bf91b2 commit 0bd9fc7

File tree

4 files changed

+135
-39
lines changed

4 files changed

+135
-39
lines changed

fidimag/atomistic/anisotropy.py

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,49 @@
77
class Anisotropy(Energy):
88

99
"""
10-
compute the anisotropy field with the energy density E = - K (m.u)^2
10+
11+
This class provides an anisotropy term to the system energy, which
12+
is defined as
13+
14+
__ -> ^ 2
15+
E = - \ K_i ( S_i * u_i )
16+
/__
17+
i
18+
19+
with K_i the anisotropy constant at the i-th site and u_i the unitary
20+
direction of the anisotropy vector at the i-th site, thus the magnitude and
21+
axis can be space dependent.
22+
23+
OPTIONAL ARGUMENTS --------------------------------------------------------
24+
25+
Ku :: The anisotropy constant. Can be a constant or a space
26+
dependent scalar field, given as a function or array.
27+
28+
axis :: The unitary axis vector. It can be a 3 tuple, list
29+
or array (uniaxial anisotropy), or a space dependent
30+
vector field, gicen as a function or array.
31+
32+
name :: Interaction name
33+
34+
USAGE ---------------------------------------------------------------------
35+
36+
Considering a simulation object *Sim*, an uniaxial anisotropy along
37+
the z direction can be defined as
38+
39+
K = 1 * meV
40+
Sim.add(Anisotropy(K, axis=(0, 0, 1)))
41+
42+
For a space dependent anisotropy along the x direction, we can define a
43+
scalar field for the magnitude and a vector field for the anisotropy axes.
44+
1145
"""
1246

13-
def __init__(self, Ku, axis=(1, 0, 0), name='anis', direction=None):
47+
def __init__(self, Ku, axis=(1, 0, 0), name='anis'):
1448
self.Ku = Ku
1549
self.name = name
1650
self.axis = axis
1751
self.jac = True
1852

19-
if direction is not None:
20-
self.axis = direction
21-
2253
def setup(self, mesh, spin, mu_s):
2354
super(Anisotropy, self).setup(mesh, spin, mu_s)
2455

fidimag/atomistic/dmi.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ class DMI(Energy):
1111
term, defined as
1212
1313
__ -> -> ->
14-
E = - \ D_ij * ( S_i X S_j )
14+
E = \ D_ij * ( S_i X S_j )
1515
/__
16-
i, j
16+
<i, j>
1717
i != j
1818
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
19+
where D_ij is the Dzyaloshinskii vector, S_i and S_j are the total spin
20+
vectors at the i-th and j-th lattice sites, and <i, j> means counting the
21+
interaction between neighbouring spins only once. The Dzyaloshinskii vector
2122
magnitude can vary with space.
2223
2324
Currently, there are implemented two kinds of DMI, that depend on the

fidimag/atomistic/exchange.py

Lines changed: 89 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,39 @@
66
class UniformExchange(Energy):
77

88
"""
9-
The Hamiltonian is defined as
109
11-
Hamiltonian = - J \sum_<i,j> S_i \cdot S_j
10+
This class provides the Exchange Interaction energy term for a
11+
homogeneous material, defined as
1212
13-
where the brackets represent the nearest neighbours and only evaluate once
14-
for each pair, which means for two spins case, the total energy is
15-
-J S_1 S_2. Therefore, the effective field at site i is,
13+
__ -> ->
14+
E = - \ J_ij S_i * S_j
15+
/__
16+
<i, j>
17+
i != j
1618
17-
H_i = J \sum_<i,j> S_j
19+
where J_ij is the exchange tensor, S_i and S_j are the total spin vectors
20+
at the i-th and j-th lattice sites, and <i, j> means counting the
21+
interaction between neighbouring spins only once (notice that there is no
22+
factor of 2 associated with J)
23+
24+
This class only computes a uniform exchange field, thus J_ij is a
25+
diagonal tensor with constant magnitude, J_ij -> J
26+
27+
28+
OPTIONAL ARGUMENTS: -------------------------------------------------------
29+
30+
J :: A number for the exchange tensor magnitude
31+
name :: Interaction name
32+
33+
USAGE: --------------------------------------------------------------------
34+
35+
For a homogeneous material, it can be specified in a simulation object
36+
*Sim* as
37+
38+
Sim.add(UniformExchange(J))
39+
40+
where J is a float.
1841
19-
notice that there is no factor of 2 associated with J.
2042
"""
2143

2244
def __init__(self, J=0, name='exch'):
@@ -64,42 +86,84 @@ def compute_energy_directly(self):
6486
class Exchange(Energy):
6587

6688
"""
67-
The Hamiltonian is defined as
89+
This class provides the Exchange Interaction energy term, defined as
90+
91+
__ -> ->
92+
E = - \ J_ij S_i * S_j
93+
/__
94+
<i, j>
95+
i != j
96+
97+
where J_ij is the exchange tensor, S_i and S_j are the total spin vectors
98+
at the i-th and j-th lattice sites, and <i, j> means counting the
99+
interaction between neighbouring spins only once (notice that there is no
100+
factor of 2 associated with J)
101+
102+
In general, J_ij is space dependent and must be specified for every
103+
neighbour. For a homogeneous material, J_ij is a diagonal tensor with
104+
constant magnitude, i.e. J_ij -> J.
105+
106+
107+
OPTIONAL ARGUMENTS: -------------------------------------------------------
108+
109+
J_fun :: The exchange tensor which can be a number (same
110+
magnitude for every neighbour at every lattice site)
111+
or a space dependent function that returns 6
112+
components, one for every nearest neighbour (NN).
113+
For a square lattice the NNs are defined in 3D as:
114+
[-x +x -y +y -z +z], thus the exchange components
115+
are specified in that order. In a hexagonal lattice
116+
the NNs are only in a 2D plane as the cardinal
117+
positions: [W E NE SW NW SE].
68118
69-
Hamiltonian = - \sum_<i,j> J_ij S_i \cdot S_j
119+
name :: Interaction name
70120
71-
where the brackets represent the nearest neighbours and only evaluate once
72-
for each pair, which means for two spins case, the total energy is
73-
-J S_1 S_2. Therefore, the effective field at site i is,
121+
USAGE: --------------------------------------------------------------------
122+
123+
For a homogeneous material, it can be specified in a simulation object
124+
*Sim* as
125+
126+
Sim.add(Exchange(J))
127+
128+
where J is a float.
129+
130+
Otherwise, the exchange tensor is spatial dependent, and must be specified
131+
using a function. For a cubic mesh, for example, if we want a linear
132+
dependence only with in plane components:
133+
134+
def my_exchange(pos):
135+
J = 1 * meV
136+
x, y, z = pos[0], pos[1], pos[2]
137+
138+
return (x * J, x * J, y * J, y * J, 0, 0)
139+
140+
Sim.add(Exchange(my_exchange))
74141
75-
H_i = \sum_<i,j> J_ij S_j
76142
77-
notice that there is no factor of 2 associated with J_ij.
78143
"""
79144

80145
def __init__(self, J_fun, name='exch'):
81146
self.J_fun = J_fun
82147
self.name = name
83148
self.jac = False
84-
149+
85150
def setup(self, mesh, spin, mu_s):
86151
super(Exchange, self).setup(mesh, spin, mu_s)
87152

88153
self._J = np.zeros(self.neighbours.shape)
89154

90155
if isinstance(self.J_fun, (int, float)):
91-
self._J[:,:] = self.J_fun
156+
self._J[:, :] = self.J_fun
92157
elif hasattr(self.J_fun, '__call__'):
93-
n = self.mesh.n
158+
n = self.mesh.n
94159
for i in range(n):
95160
value = self.J_fun(self.coordinates[i])
96161
if len(value) == 6:
97-
self._J[i,:] = value[:]
162+
self._J[i, :] = value[:]
98163
else:
99164
raise Exception('The given spatial function for J is not acceptable!')
100165
pass
101-
102-
166+
103167
def compute_field(self, t=0, spin=None):
104168

105169
if spin is not None:
@@ -108,10 +172,10 @@ def compute_field(self, t=0, spin=None):
108172
m = self.spin
109173

110174
clib.compute_exchange_field_spatial(m,
111-
self.field,
112-
self.energy,
113-
self._J,
114-
self.neighbours,
115-
self.n)
175+
self.field,
176+
self.energy,
177+
self._J,
178+
self.neighbours,
179+
self.n)
116180

117181
return self.field * self.mu_s_inv

fidimag/atomistic/lib/exch.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ void compute_exch_field(double *spin, double *field, double *energy,
2020
for (int i = 0; i < n; i++) {
2121

2222
int id = 0;
23-
int idv = 6 * i; // index for the neighbours
23+
int id_nn = 6 * i; // index for the neighbours
2424

2525
double fx = 0, fy = 0, fz = 0;
2626

@@ -46,9 +46,9 @@ void compute_exch_field(double *spin, double *field, double *energy,
4646

4747
for (int j = 0; j < 6; j++) {
4848

49-
if (ngbs[idv + j] >= 0) {
49+
if (ngbs[id_nn + j] >= 0) {
5050

51-
id = 3 * ngbs[idv + j];
51+
id = 3 * ngbs[id_nn + j];
5252
fx += Jx * spin[id];
5353
fy += Jy * spin[id + 1];
5454
fz += Jz * spin[id + 2];
@@ -141,7 +141,7 @@ void compute_exch_field_spatial(double *spin, double *field, double *energy,
141141
for (int i = 0; i < n; i++) {
142142

143143
int id = 0;
144-
int idv = 6 * i; // index for the neighbours
144+
int id_nn = 6 * i; // index for the neighbours
145145

146146
double fx = 0, fy = 0, fz = 0;
147147

@@ -169,7 +169,7 @@ void compute_exch_field_spatial(double *spin, double *field, double *energy,
169169

170170
for (int j = 0; j < 6; j++) {
171171

172-
int p = idv+j;
172+
int p = id_nn + j;
173173

174174
if (ngbs[p] >= 0) {
175175

0 commit comments

Comments
 (0)