Skip to content

Commit 6f21b8d

Browse files
committed
Add more documentation, a test and timing code in the test_time_zeeman.py file.
1 parent 5d9b303 commit 6f21b8d

File tree

6 files changed

+184
-27
lines changed

6 files changed

+184
-27
lines changed

fidimag/common/lib/common_clib.pyx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ def init_vector_func_fast(m0, mesh, double[:] field, norm=False, *args):
212212
must handle evaluating the function at different
213213
coordinate points. It needs to be able to handle
214214
the spatial dependence itself, and write the
215-
field valuse into the field array. This can
215+
field valuse into the field array. This can
216216
be written with Cython which will give much
217217
better performance. For example:
218218
@@ -225,8 +225,7 @@ def init_vector_func_fast(m0, mesh, double[:] field, norm=False, *args):
225225
field[3*i+1] = Bmax * axis[1] * sin(fc*t)
226226
field[3*i+2] = Bmax * axis[2] * sin(fc*t)
227227
228-
"""
229-
# field = np.zeros(mesh.n * 3)
228+
"""
230229
m0(mesh, field, *args)
231230
if norm:
232231
normalise(field)

fidimag/micro/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from .demag import Demag
33
from .exchange import UniformExchange
44
from .exchange_rkky import ExchangeRKKY
5-
from .zeeman import Zeeman, TimeZeeman, SimpleTimeZeeman, TimeZeemanFast
5+
from .zeeman import Zeeman, TimeZeeman, TimeZeemanSimple, TimeZeemanFast
66
from .anisotropy import UniaxialAnisotropy
77
from .dmi import DMI
88
from .baryakhtar import LLBar, LLBarFull

fidimag/micro/zeeman.py

Lines changed: 63 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import numpy as np
2-
32
from fidimag.common.constant import mu_0
43
import fidimag.common.helper as helper
54
import inspect
@@ -113,7 +112,6 @@ def compute_energy(self):
113112

114113

115114
class TimeZeeman(Zeeman):
116-
117115
"""
118116
The time dependent external field, also can vary with space
119117
@@ -127,13 +125,31 @@ def time_fun(pos, t):
127125
Bz = ...
128126
return (Bx, By, Bz)
129127
128+
Extra arguments can be passed to the function to allow more
129+
general code. These must be set when initialising the TimeZeeman class. For
130+
example:
131+
132+
freq = 10e9
133+
134+
def time_fun(pos, t, frequency):
135+
x, y, z = pos
136+
if x < 50:
137+
return (0.0, 0.0, np.sin(frequency*t))
138+
else:
139+
return (0.0, 0.0, 0.0)
140+
141+
zee = TimeZeeman(time_fun, extra_args=[freq])
142+
143+
These arguments are then passed into the time_fun code function in
144+
order.
130145
131146
"""
132147

133-
def __init__(self, time_fun, name='TimeZeeman'):
148+
def __init__(self, time_fun, extra_args=[], name='TimeZeeman'):
134149
self.time_fun = time_fun
135150
self.name = name
136151
self.jac = True
152+
self.extra_args = extra_args
137153

138154
def setup(self, mesh, spin, Ms):
139155
self.mesh = mesh
@@ -154,19 +170,19 @@ def setup(self, mesh, spin, Ms):
154170
self.field = np.zeros(3 * self.n)
155171

156172
def compute_field(self, t=0, spin=None):
157-
self.field[:] = helper.init_vector_func_fast(self.time_fun,
158-
self.mesh,
159-
False,
160-
t)
173+
self.field[:] = helper.init_vector(self.time_fun,
174+
self.mesh,
175+
False,
176+
t, *self.extra_args)
161177
return self.field
162178

163179

164-
class SimpleTimeZeeman(Zeeman):
180+
class TimeZeemanSimple(Zeeman):
165181

166182
"""
167-
The time dependent external field, also can vary with space
183+
Time Dependent Zeeman Interaction with no spatial dependence.
168184
169-
The function time_fun must be a function which takes two arguments:
185+
The function time_fun must be a function which takes one argument:
170186
171187
def time_fun(t):
172188
x, y, z = pos
@@ -177,13 +193,29 @@ def time_fun(t):
177193
return (Bx, By, Bz)
178194
179195
196+
Extra arguments can be passed to the function to allow more
197+
general code. These must be set when initialising the TimeZeeman class. For
198+
example:
199+
200+
freq = 10e9
201+
202+
def time_fun(t, frequency):
203+
return (0.0, 0.0, np.sin(frequency*t))
204+
205+
zee = SimpleTimeZeeman(time_fun, extra_args=[freq])
206+
207+
These arguments are then passed into the time_fun code function in
208+
order.
209+
210+
180211
"""
181212

182-
def __init__(self, time_fun, name='TimeZeeman'):
213+
def __init__(self, time_fun, extra_args=[], name='TimeZeemanFast'):
183214
self.time_fun = time_fun
184215
self.name = name
185216
self.jac = True
186217
self._v = np.zeros(3)
218+
self.extra_args = extra_args
187219

188220
def setup(self, mesh, spin, Ms):
189221
self.mesh = mesh
@@ -204,7 +236,7 @@ def setup(self, mesh, spin, Ms):
204236
self.field = np.zeros(3 * self.n)
205237

206238
def compute_field(self, t=0, spin=None):
207-
v = self.time_fun(t)
239+
v = self.time_fun(t, *self.extra_args)
208240
self.field[0::3] = v[0]
209241
self.field[1::3] = v[1]
210242
self.field[2::3] = v[2]
@@ -215,24 +247,32 @@ def compute_field(self, t=0, spin=None):
215247
class TimeZeemanFast(Zeeman):
216248

217249
"""
218-
The time dependent external field, also can vary with space
250+
The time dependent external field, also can vary with space. This uses
251+
an unsafe setting function. Should not be used except by advanced users.
219252
220-
The function time_fun must be a function which takes two arguments:
253+
The function must handle coordinates
221254
222-
def time_fun(mesh, t):
223-
x, y, z = pos
224-
# compute Bx, By, Bz as a function of x y, z and t.
225-
Bx = ...
226-
By = ...
227-
Bz = ...
228-
return (Bx, By, Bz)
255+
The function time_fun must be a function which takes three or more arguments. The time variable is always passed in as the first argument
256+
in params.
229257
230-
Add the function to the user modules and recompile.
258+
e.g.
259+
260+
from libc.math cimport sin
261+
262+
def fast_sin_init(mesh, double[:] field, *params):
263+
t, axis, Bmax, fc = params
264+
for i in range(mesh.n):
265+
x, y, z = mesh.coordinates[i]
266+
if x < 10:
267+
field[3*i+0] = Bmax * axis[0] * sin(fc*t)
268+
field[3*i+1] = Bmax * axis[1] * sin(fc*t)
269+
field[3*i+2] = Bmax * axis[2] * sin(fc*t)
231270
271+
Add the function to a user Cython module in fidimag/user/ and recompile.
232272
233273
"""
234274

235-
def __init__(self, time_fun, extra_args, name='TimeZeeman'):
275+
def __init__(self, time_fun, extra_args=[], name='TimeZeemanFast'):
236276
self.time_fun = time_fun
237277
self.name = name
238278
self.jac = True

fidimag/user/example/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from fidimag.extensions.user.example import *

fidimag/user/example/example.pyx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from libc.math cimport cos, sin
2+
3+
def fast_sin_init(mesh, double[:] field, *params):
4+
t, axis, Bmax, fc = params
5+
for i in range(mesh.n):
6+
field[3*i+0] = Bmax * axis[0] * sin(fc*t)
7+
field[3*i+1] = Bmax * axis[1] * sin(fc*t)
8+
field[3*i+2] = Bmax * axis[2] * sin(fc*t)
9+
10+
def TimeZeemanFast_test_time_fun(mesh, double[:] field, *params):
11+
cdef int i
12+
t, frequency = params
13+
for i in range(mesh.n):
14+
field[3*i+0] = 0
15+
field[3*i+1] = 0
16+
field[3*i+2] = 10 * cos(frequency * t)

tests/test_time_zeeman.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import numpy as np
2+
from fidimag.common import CuboidMesh
3+
from fidimag.micro import TimeZeeman, TimeZeemanSimple, TimeZeemanFast
4+
from fidimag.user.example import TimeZeemanFast_test_time_fun
5+
6+
7+
def time_fun_spatial(pos, t, frequency):
8+
return (0.0, 0.0, 10*np.cos(frequency*t))
9+
10+
def time_fun(t, frequency):
11+
return (0.0, 0.0, 10*np.cos(frequency*t))
12+
13+
14+
15+
def fixture_setup(nx, ny, nz):
16+
"""
17+
Fixtures for the tests
18+
"""
19+
dx = 10.0/nx
20+
spin = np.zeros(3*nx*ny*nz)
21+
Ms = np.zeros(nx*ny*nz)
22+
mesh = CuboidMesh(nx=nx, ny=ny, nz=nz, dx=dx, dy=1, dz=1, unit_length=1e-9)
23+
frequency = 10e9
24+
return mesh, frequency, spin, Ms
25+
26+
27+
def test_TimeZeeman():
28+
mesh, frequency, spin, Ms = fixture_setup(10, 10, 10)
29+
zee = TimeZeeman(time_fun_spatial, extra_args=[frequency])
30+
zee.setup(mesh, spin, Ms)
31+
field1 = zee.compute_field(t=0)
32+
assert field1[0] == 0
33+
assert field1[1] == 0
34+
assert field1[2] == 10
35+
36+
field2 = zee.compute_field(t=1)
37+
assert field2[0] == 0
38+
assert field2[1] == 0
39+
assert field2[2] == 10*np.cos(frequency)
40+
41+
def test_TimeZeemanSimple():
42+
mesh, frequency, spin, Ms = fixture_setup(10, 10, 10)
43+
zee = TimeZeemanSimple(time_fun, extra_args=[frequency])
44+
zee.setup(mesh, spin, Ms)
45+
field1 = zee.compute_field(t=0)
46+
assert field1[0] == 0
47+
assert field1[1] == 0
48+
assert field1[2] == 10
49+
50+
field2 = zee.compute_field(t=1)
51+
assert field2[0] == 0
52+
assert field2[1] == 0
53+
assert field2[2] == 10*np.cos(frequency)
54+
55+
def test_TimeZeemanFast():
56+
mesh, frequency, spin, Ms = fixture_setup(10, 10, 10)
57+
zee = TimeZeemanFast(TimeZeemanFast_test_time_fun, extra_args=[frequency])
58+
zee.setup(mesh, spin, Ms)
59+
field1 = zee.compute_field(t=0)
60+
assert field1[0] == 0
61+
assert field1[1] == 0
62+
assert field1[2] == 10
63+
64+
field2 = zee.compute_field(t=1)
65+
assert field2[0] == 0
66+
assert field2[1] == 0
67+
assert field2[2] == 10*np.cos(frequency)
68+
69+
if __name__ == "__main__":
70+
import time
71+
# Run the speed tests...
72+
for i in range(1, 5):
73+
nx = 10**i
74+
ny = nz = 10
75+
print('\nN = {} * {} * {} = '.format(nx, ny, nz, nx*ny*nz))
76+
mesh, frequency, spin, Ms = setup(nx, ny, nz)
77+
78+
zee = TimeZeeman(time_fun_spatial, extra_args=[frequency])
79+
zee.setup(mesh, spin, Ms)
80+
t1 = time.time()
81+
field1 = zee.compute_field(t=0)
82+
field2 = zee.compute_field(t=1)
83+
t2 = time.time()
84+
print(' Timing results for TimeZeeman = {}'.format(t2 - t1))
85+
86+
zee = TimeZeemanSimple(time_fun, extra_args=[frequency])
87+
zee.setup(mesh, spin, Ms)
88+
t3 = time.time()
89+
field1 = zee.compute_field(t=0)
90+
field2 = zee.compute_field(t=1)
91+
t4 = time.time()
92+
print(' Timing results for TimeZeemanSimple = {}'.format(t4 - t3))
93+
94+
zee = TimeZeemanFast(TimeZeemanFast_test_time_fun, extra_args=[frequency])
95+
zee.setup(mesh, spin, Ms)
96+
t5 = time.time()
97+
field1 = zee.compute_field(t=0)
98+
field2 = zee.compute_field(t=1)
99+
t6 = time.time()
100+
print(' Timing results for TimeZeemanFast = {}'.format(t6 - t5))
101+
print('\n Normalised: TimeZeeman = 1, TimeZeemanSimple = {}, TimeZeemanFast = {}'.format((t4-t3)/(t2-t1), (t6-t5)/(t2-t1)))

0 commit comments

Comments
 (0)