Skip to content

Commit 580bbe6

Browse files
committed
Merge branch 'master' of github.com:computationalmodelling/fidimag
2 parents c1c6214 + 5fea09a commit 580bbe6

File tree

7 files changed

+277
-100
lines changed

7 files changed

+277
-100
lines changed

doc/ipynb/runtimes.org

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
* <2016-05-01 Sun>
2+
3+
To see which tests run long:
4+
5+
cd doc/ipynb && py.test . -v --nbval --duration=10 --sanitize-with sanitize_file
6+
7+
========================== slowest 10 test durations ===========================
8+
17209.34s call doc/ipynb/isolated_skyrmion.ipynb::Cell 13
9+
4098.12s call doc/ipynb/standard_problem_4.ipynb::Cell 19
10+
967.73s call doc/ipynb/spin-polarised-current-driven-skyrmion.ipynb::Cell 14
11+
703.63s call doc/ipynb/standard_problem_4.ipynb::Cell 15
12+
20.86s call doc/ipynb/tutorial-basics.ipynb::Cell 21
13+
6.32s call doc/ipynb/spin-waves-in-periodic-system.ipynb::Cell 13
14+
6.16s call doc/ipynb/isolated_skyrmion.ipynb::Cell 11
15+
5.76s call doc/ipynb/current-driven-domain-wall.ipynb::Cell 24
16+
1.95s call doc/ipynb/current-driven-domain-wall.ipynb::Cell 18
17+
1.67s call doc/ipynb/spin-polarised-current-driven-skyrmion.ipynb::Cell 11

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: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,74 @@
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, 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
22+
magnitude can vary with space.
23+
24+
Currently, there are implemented two kinds of DMI, that depend on the
25+
Dzyaloshinskii vector definition. Calling D_i the Dzyaloshinskii vector
26+
magnitude at the i-th site:
27+
28+
BULK:
29+
-> ^
30+
D_ij = D_i r_ij with r_ij as the unit vector pointing from the i-th
31+
towards the j-th site
32+
(only working for square lattices)
33+
34+
INTERFACIAL:
35+
36+
-> ^ ^
37+
D_ij = D_i ( r_ij X z ) with r_ij as the unit vector pointing from the
38+
i-th towards the j-th site and z the unitary
39+
vector perpendicular to the magnetic material
40+
plane which, in theory, is in contact with a
41+
material with larger SOC (e.g. a metal).
42+
Thus, this DMI is defined in 2D, for
43+
interfaces or thin films.
44+
45+
For further details about the DMI calculations, take a look
46+
to the C library documentation (dmi.c)
47+
48+
49+
OPTIONAL ARGUMENTS: -------------------------------------------------------
50+
51+
dmi_type :: 'bulk' or 'interfacial'
52+
name :: Interaction name
53+
54+
USAGE: --------------------------------------------------------------------
55+
56+
If the DMI is homogeneous, it can be specified in a simulation object
57+
*Sim* as
58+
59+
Sim.add(DMI(D, dmi_type='bulk'))
60+
61+
where D is a float.
62+
63+
Otherwise, it can be specified as any Fidimag scalar field, passing a
64+
function or an array. For example, a space dependent DMI that changes
65+
linearly in the x-direction can be defined as:
66+
67+
def my_DMI(pos):
68+
D = 0.01 * meV
69+
return D * pos[0]
70+
71+
# Add DMI to Simulation object
72+
Sim.add(DMI(my_DMI))
73+
1174
"""
1275

13-
def __init__(self, D, name='dmi', dmi_type='bulk'):
76+
def __init__(self, D, name='DMI', dmi_type='bulk'):
1477
self.D = D
1578

1679
self.name = name
@@ -32,20 +95,20 @@ def setup(self, mesh, spin, mu_s):
3295
# We will generate the Dzyaloshinskii vectors according
3396
# to the lattice, for the Interfacial DMI
3497
self.DMI_vector = self.compute_DMI_vectors(self.nneighbours)
35-
98+
3699
if self.dmi_type == 'bulk':
37100
self._D = np.zeros(self.neighbours.shape)
38101
if isinstance(self.D, (int, float)):
39-
self._D[:,:] = self.D
102+
self._D[:, :] = self.D
40103
elif hasattr(self.D, '__call__'):
41-
n = self.mesh.n
104+
n = self.mesh.n
42105
for i in range(n):
43106
value = self.D(self.coordinates[i])
44107
if len(value) == 6:
45-
self._D[i,:] = value[:]
108+
self._D[i, :] = value[:]
46109
else:
47110
raise Exception('The given spatial function for D is not acceptable!')
48-
111+
49112

50113
def compute_field(self, t=0, spin=None):
51114

@@ -55,7 +118,7 @@ def compute_field(self, t=0, spin=None):
55118
m = self.spin
56119

57120
if self.dmi_type == 'bulk':
58-
clib.compute_dmi_field(m,
121+
clib.compute_dmi_field(m,
59122
self.field,
60123
self.energy,
61124
self._D,

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

0 commit comments

Comments
 (0)