Skip to content

Commit 293bc43

Browse files
authored
Merge pull request #114 from computationalmodelling/current-time-dependence
Current time dependence
2 parents 4499c63 + 331569b commit 293bc43

File tree

11 files changed

+389
-124
lines changed

11 files changed

+389
-124
lines changed
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
import matplotlib as mpl
2+
mpl.use("Agg")
3+
import matplotlib.pyplot as plt
4+
5+
import numpy as np
6+
from fidimag.micro import Sim
7+
from fidimag.common import CuboidMesh
8+
9+
# The energies, we can use DMI in a future simulation
10+
from fidimag.micro import UniformExchange
11+
from fidimag.micro import UniaxialAnisotropy
12+
# from micro import DMI
13+
14+
mu0 = 4 * np.pi * 1e-7
15+
16+
# Initial State, a rough DW ina 1D chain
17+
18+
19+
def init_m(pos):
20+
21+
x = pos[0]
22+
23+
if x < 400:
24+
return (-1, 0, 0)
25+
elif 400 <= x < 500:
26+
return (0, 1, 1)
27+
else:
28+
return (1, 0, 0)
29+
30+
31+
def relax_system(mesh):
32+
33+
# Only relaxation
34+
sim = Sim(mesh, name='relax')
35+
36+
# Simulation parameters
37+
sim.driver.set_tols(rtol=1e-8, atol=1e-10)
38+
sim.driver.alpha = 0.5
39+
sim.driver.gamma = 2.211e5
40+
sim.Ms = 8.6e5
41+
sim.driver.do_precession = False
42+
43+
# The initial state passed as a function
44+
sim.set_m(init_m)
45+
# sim.set_m(np.load('m0.npy'))
46+
# Energies
47+
A = 1.3e-11
48+
exch = UniformExchange(A=A)
49+
sim.add(exch)
50+
anis = UniaxialAnisotropy(5e4)
51+
sim.add(anis)
52+
# Start relaxation and save the state in m0.npy
53+
sim.relax(dt=1e-14, stopping_dmdt=0.01, max_steps=5000,
54+
save_m_steps=None, save_vtk_steps=50)
55+
56+
np.save('m0.npy', sim.spin)
57+
58+
59+
def deal_plot(_list, output_file):
60+
"""
61+
The list contain any number of list with two entries:
62+
the _file path and the component of the magnetisation
63+
in the formats:
64+
65+
mx, my, mz
66+
67+
e.g.
68+
_list = [ ['m0.npy', 'mz'], ... ]
69+
70+
output_file :: output file name
71+
72+
"""
73+
74+
plt.figure()
75+
76+
comp = {'mx': 0, 'my': 1, 'mz': 2}
77+
78+
for element in _list:
79+
# element[0] --> _file
80+
# element[1] --> m component: mx, my or mz
81+
82+
data = np.load(element[0])
83+
84+
data.shape = (3, -1)
85+
86+
mx = data[comp[element[1]]]
87+
88+
plt.plot(mx, '--',
89+
label=element[1] + ' / %s' % element[0],
90+
dashes=(2, 2))
91+
92+
plt.legend()
93+
# plt.xlim([0, 0.012])
94+
# plt.ylim([-5, 100])
95+
plt.xlabel(r'x [ nm ]')
96+
plt.savefig(output_file)
97+
98+
99+
# THIS NEEDS REVISION
100+
def deal_plot_dynamics(spin, m_component='mz', output_file='output.pdf'):
101+
"""
102+
The dynamics of the m_component of the i-th spin
103+
of the chain, from the magnetisation snapshot
104+
m_{i} files, located at dyn_npys
105+
106+
m_component :: 'mx', 'my' or 'mz'
107+
108+
"""
109+
110+
comp = {'mx': 0, 'my': 1, 'mz': 2}
111+
112+
plt.figure()
113+
114+
_all = []
115+
for i in range(500):
116+
data = np.load('dyn2_npys/m_%d.npy' % i)
117+
data.shape = (3, -1)
118+
_all.append(data[comp[m_component]][spin])
119+
120+
plt.plot(_all, '--', label=m_component)
121+
122+
plt.xlabel(r't')
123+
# plt.ylabel('Susceptibility')
124+
plt.savefig(output_file)
125+
126+
127+
# This function excites the system with a
128+
# current in the x-direction using Spin Transfer Torque
129+
# formalism
130+
def excite_system(mesh):
131+
132+
# Specify the stt dynamics in the simulation
133+
sim = Sim(mesh, name='dyn2', driver='llg_stt')
134+
sim.driver.set_tols(rtol=1e-12, atol=1e-14)
135+
sim.driver.alpha = 0.2
136+
sim.driver.gamma = 2.211e5
137+
sim.Ms = 8.6e5
138+
139+
# sim.set_m(init_m)
140+
sim.set_m(np.load('m0.npy'))
141+
142+
# Energies
143+
A = 1.3e-11
144+
exch = UniformExchange(A=A)
145+
sim.add(exch)
146+
147+
anis = UniaxialAnisotropy(5e4)
148+
sim.add(anis)
149+
150+
# dmi = DMI(D=8e-4)
151+
# sim.add(dmi)
152+
153+
# Set the current in the x direction, in A / m
154+
# beta is the parameter in the STT torque
155+
def jx_func(pos, t):
156+
T = 1e-9
157+
return (-1e12 + -0.1e12 * np.sin(t/T))
158+
159+
sim.driver.jx_function = jx_func
160+
sim.driver.beta = 0.01
161+
162+
# The simulation will run for 5 ns and save
163+
# 500 snapshots of the system in the process
164+
ts = np.linspace(0, 10e-9, 1001)
165+
166+
for t in ts:
167+
print('time', t)
168+
sim.driver.run_until(t)
169+
print('j = {}'.format(sim.driver._jx[0]))
170+
sim.save_vtk()
171+
sim.save_m()
172+
173+
if __name__ == '__main__':
174+
# We will crate a mesh with 1000 elements of elements
175+
# in the x direction, and 1 along y and z
176+
# (so we have a 1D system)
177+
mesh = CuboidMesh(nx=1000, ny=1, nz=1,
178+
dx=2, dy=2, dz=2.0,
179+
unit_length=1e-9)
180+
181+
# Relax the initial state
182+
relax_system(mesh)
183+
deal_plot([['m0.npy', 'mx']], 'initial_state.pdf')
184+
185+
# Now we excite the system with the current
186+
excite_system(mesh)
187+
188+
# Plot the dynamics of a single spin
189+
deal_plot_dynamics(0)
190+
191+
# We can plot the m_z component for a number snapshots
192+
# to observe the DW motion
193+
# We will plot the 200th and 499th file (the last one
194+
# is the system at ~5 ns)
195+
deal_plot([['m0.npy', 'mx'],
196+
['dyn2_npys/m_200.npy', 'mx'],
197+
['dyn2_npys/m_499.npy', 'mx']
198+
],
199+
'dw_motion_stt.pdf')

fidimag/atomistic/llg_stt.py

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ class LLG_STT(AtomisticDriver):
2323
dt 2
2424
( 1 + a )
2525
26-
u
26+
u
2727
+ -------- s X [ (1 + a * b) (j . grad) s - (b - a) s X (j . grad) s ]
2828
2
2929
( 1 + a )
3030
31-
31+
3232
with g mu_B P
3333
u = --------
3434
2 mu_s e
@@ -67,10 +67,13 @@ def __init__(self, mesh, spin, mu_s, mu_s_inv, field, pins,
6767

6868
self.p = 0.5
6969
self.beta = 0
70-
self.update_j_fun = None
70+
self.jx_function = None
71+
self.jy_function = None
72+
self.jz_function = None
7173

7274
# FIXME: change the u0 to spatial
73-
v = self.mesh.dx * self.mesh.dy * self.mesh.dz * (self.mesh.unit_length ** 3)
75+
v = self.mesh.dx * self.mesh.dy * \
76+
self.mesh.dz * (self.mesh.unit_length ** 3)
7477
self.u0 = const.g_e * const.mu_B / (2 * const.c_e) * v
7578

7679
def get_jx(self):
@@ -98,38 +101,28 @@ def set_jz(self, value):
98101
jz = property(get_jz, set_jz)
99102

100103
def sundials_rhs(self, t, y, ydot):
101-
102104
self.t = t
103-
104105
# already synchronized when call this funciton
105106
# self.spin[:]=y[:]
106-
107107
self.compute_effective_field(t)
108-
109-
if self.update_j_fun is not None:
110-
clib.compute_stt_field(self.spin,
111-
self.field_stt,
112-
self._jx * self.update_j_fun(t),
113-
self._jy * self.update_j_fun(t),
114-
self._jz * self.update_j_fun(t),
115-
self.mesh.dx * self.mesh.unit_length,
116-
self.mesh.dy * self.mesh.unit_length,
117-
self.mesh.dz * self.mesh.unit_length,
118-
self.mesh.neighbours,
119-
self.n
120-
)
121-
else:
122-
clib.compute_stt_field(self.spin,
123-
self.field_stt,
124-
self._jx,
125-
self._jy,
126-
self._jz,
127-
self.mesh.dx * self.mesh.unit_length,
128-
self.mesh.dy * self.mesh.unit_length,
129-
self.mesh.dz * self.mesh.unit_length,
130-
self.mesh.neighbours,
131-
self.n
132-
)
108+
if self.jx_function:
109+
self.set_jx(self.jx_function, t)
110+
if self.jy_function:
111+
self.set_jy(self.jy_function, t)
112+
if self.jz_function:
113+
self.set_jz(self.jz_function, t)
114+
115+
clib.compute_stt_field(self.spin,
116+
self.field_stt,
117+
self._jx,
118+
self._jy,
119+
self._jz,
120+
self.mesh.dx * self.mesh.unit_length,
121+
self.mesh.dy * self.mesh.unit_length,
122+
self.mesh.dz * self.mesh.unit_length,
123+
self.mesh.neighbours,
124+
self.n
125+
)
133126

134127
clib.compute_llg_stt_rhs(ydot,
135128
self.spin,

fidimag/atomistic/llg_stt_cpp.py

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,14 @@ def __init__(self, mesh, spin, mu_s, mu_s_inv, field, pins,
4747

4848
self.a_J = 1
4949
self.beta = 0
50-
self.J_time_fun = None
50+
self.j_function = None
5151

5252
def get_p(self):
5353
return self._p
5454

5555
def set_p(self, value):
5656
self._p[:] = helper.init_vector(value, self.mesh)
57+
5758
p = property(get_p, set_p)
5859

5960
def get_a_J(self):
@@ -73,25 +74,16 @@ def sundials_rhs(self, t, y, ydot):
7374

7475
self.compute_effective_field(t)
7576

76-
if self.J_time_fun is not None:
77-
clib.compute_llg_stt_cpp(ydot,
78-
self.spin,
79-
self.field,
80-
self._p,
81-
self._alpha,
82-
self._pins,
83-
self._a_J*self.J_time_fun(t),
84-
self.beta,
85-
self.gamma,
86-
self.n)
87-
else:
88-
clib.compute_llg_stt_cpp(ydot,
89-
self.spin,
90-
self.field,
91-
self._p,
92-
self._alpha,
93-
self._pins,
94-
self._a_J,
95-
self.beta,
96-
self.gamma,
97-
self.n)
77+
if self.j_function is not None:
78+
self.set_a_J(self.j_function)
79+
80+
clib.compute_llg_stt_cpp(ydot,
81+
self.spin,
82+
self.field,
83+
self._p,
84+
self._alpha,
85+
self._pins,
86+
self._a_J,
87+
self.beta,
88+
self.gamma,
89+
self.n)

fidimag/common/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
from .citation import citation
55
from .cuboid_mesh import CuboidMesh
66
#from .neb_cartesian import NEB_Sundials
7+
from .helper import init_scalar, init_vector

fidimag/common/helper.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def normalise(a):
2424
a.shape = (-1,)
2525

2626

27-
def init_vector(m0, mesh, norm=False):
27+
def init_vector(m0, mesh, norm=False, *args):
2828

2929
n = mesh.n
3030

@@ -36,7 +36,7 @@ def init_vector(m0, mesh, norm=False):
3636

3737
elif hasattr(m0, '__call__'):
3838
for i in range(n):
39-
v = m0(mesh.coordinates[i])
39+
v = m0(mesh.coordinates[i], *args)
4040
if len(v) != 3:
4141
raise Exception(
4242
'The length of the value in init_vector method must be 3.')
@@ -58,7 +58,7 @@ def init_vector(m0, mesh, norm=False):
5858
return spin
5959

6060

61-
def init_scalar(value, mesh):
61+
def init_scalar(value, mesh, *args):
6262

6363
n = mesh.n
6464

@@ -68,7 +68,7 @@ def init_scalar(value, mesh):
6868
mesh_v[:] = value
6969
elif hasattr(value, '__call__'):
7070
for i in range(n):
71-
mesh_v[i] = value(mesh.coordinates[i])
71+
mesh_v[i] = value(mesh.coordinates[i], *args)
7272

7373
elif isinstance(value, np.ndarray):
7474
if value.shape == mesh_v.shape:

0 commit comments

Comments
 (0)