-
Notifications
You must be signed in to change notification settings - Fork 4
/
sp4_simple.py
114 lines (97 loc) · 4.27 KB
/
sp4_simple.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# Copyright (C) 2014 Claas Abert
#
# This file is part of "70 lines of NumPy".
#
# "70 lines of NumPy" is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# "70 lines of NumPy" is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with magnum.fe. If not, see <http://www.gnu.org/licenses/>.
import numpy as np
from math import asinh, atan, sqrt, pi
# setup mesh and material constants
n = (100, 25, 1)
dx = (5e-9, 5e-9, 3e-9)
mu0 = 4e-7 * pi
gamma = 2.211e5
ms = 8e5
A = 1.3e-11
alpha = 0.02
# a very small number
eps = 1e-18
# newell f
def f(p):
x, y, z = abs(p[0]), abs(p[1]), abs(p[2])
return + y / 2.0 * (z**2 - x**2) * asinh(y / (sqrt(x**2 + z**2) + eps)) \
+ z / 2.0 * (y**2 - x**2) * asinh(z / (sqrt(x**2 + y**2) + eps)) \
- x*y*z * atan(y*z / (x * sqrt(x**2 + y**2 + z**2) + eps)) \
+ 1.0 / 6.0 * (2*x**2 - y**2 - z**2) * sqrt(x**2 + y**2 + z**2)
# newell g
def g(p):
x, y, z = p[0], p[1], abs(p[2])
return + x*y*z * asinh(z / (sqrt(x**2 + y**2) + eps)) \
+ y / 6.0 * (3.0 * z**2 - y**2) * asinh(x / (sqrt(y**2 + z**2) + eps)) \
+ x / 6.0 * (3.0 * z**2 - x**2) * asinh(y / (sqrt(x**2 + z**2) + eps)) \
- z**3 / 6.0 * atan(x*y / (z * sqrt(x**2 + y**2 + z**2) + eps)) \
- z * y**2 / 2.0 * atan(x*z / (y * sqrt(x**2 + y**2 + z**2) + eps)) \
- z * x**2 / 2.0 * atan(y*z / (x * sqrt(x**2 + y**2 + z**2) + eps)) \
- x*y * sqrt(x**2 + y**2 + z**2) / 3.0
# demag tensor setup
def set_n_demag(c, permute, func):
it = np.nditer(n_demag[:,:,:,c], flags=['multi_index'], op_flags=['writeonly'])
while not it.finished:
value = 0.0
for i in np.rollaxis(np.indices((2,)*6), 0, 7).reshape(64, 6):
idx = map(lambda k: (it.multi_index[k] + n[k] - 1) % (2*n[k] - 1) - n[k] + 1, range(3))
value += (-1)**sum(i) * func(map(lambda j: (idx[j] + i[j] - i[j+3]) * dx[j], permute))
it[0] = - value / (4 * pi * np.prod(dx))
it.iternext()
# compute effective field (demag + exchange)
def h_eff(m):
# demag field
m_pad[:n[0],:n[1],:n[2],:] = m
f_m_pad = np.fft.fftn(m_pad, axes = filter(lambda i: n[i] > 1, range(3)))
f_h_demag_pad = np.zeros(f_m_pad.shape, dtype=f_m_pad.dtype)
f_h_demag_pad[:,:,:,0] = (f_n_demag[:,:,:,(0, 1, 2)]*f_m_pad).sum(axis = 3)
f_h_demag_pad[:,:,:,1] = (f_n_demag[:,:,:,(1, 3, 4)]*f_m_pad).sum(axis = 3)
f_h_demag_pad[:,:,:,2] = (f_n_demag[:,:,:,(2, 4, 5)]*f_m_pad).sum(axis = 3)
h_demag = np.fft.ifftn(f_h_demag_pad, axes = filter(lambda i: n[i] > 1, range(3)))[:n[0],:n[1],:n[2],:].real
# exchange field
h_ex = - 2 * m * sum([1/x**2 for x in dx])
for i in range(6):
h_ex += np.repeat(m, 1 if n[i%3] == 1 else [i/3*2] + [1]*(n[i%3]-2) + [2-i/3*2], axis = i%3) / dx[i%3]**2
return ms*h_demag + 2*A/(mu0*ms)*h_ex
# compute llg step with optional zeeman field
def llg(m, dt, h_zee = 0.0):
h = h_eff(m) + h_zee
dmdt = - gamma/(1+alpha**2) * np.cross(m, h) - alpha*gamma/(1+alpha**2) * np.cross(m, np.cross(m, h))
m += dt * dmdt
return m/np.repeat(np.sqrt((m*m).sum(axis=3)), 3).reshape(m.shape)
# setup demag tensor
n_demag = np.zeros([2*i-1 for i in n] + [6])
for i, t in enumerate(((f,0,1,2),(g,0,1,2),(g,0,2,1),(f,1,2,0),(g,1,2,0),(f,2,0,1))):
set_n_demag(i, t[1:], t[0])
m_pad = np.zeros([2*i-1 for i in n] + [3])
f_n_demag = np.fft.fftn(n_demag, axes = filter(lambda i: n[i] > 1, range(3)))
# initialize magnetization that relaxes into s-state
m = np.zeros(n + (3,))
m[1:-1,:,:,0] = 1.0
m[(-1,0),:,:,1] = 1.0
# relax
alpha = 1.00
for i in range(5000): llg(m, 2e-13)
# switch
alpha = 0.02
dt = 5e-15
h_zee = np.tile([-24.6e-3/mu0, +4.3e-3/mu0, 0.0], np.prod(n)).reshape(m.shape)
with open('sp4.dat', 'w') as f:
for i in range(int(1e-9/dt)):
f.write("%f %f %f %f\n" % ((i*1e9*dt,) + tuple(map(lambda i: np.mean(m[:,:,:,i]), range(3)))))
llg(m, dt, h_zee)