Skip to content

Commit f64df7a

Browse files
author
davidcorteso
committed
Updated micromagnetic DMI function calculation
Simplified the DMI calculation for multiple DMI constants/vectors. For now we only allow the same D magnitude in every mesh node when using custom DMI vectors (maybe can be generalised later) Fixed tests according to the changes. Examples for passing a custom DMI vector/vectors are in the test Updated documentation in C and Python class
1 parent 404549f commit f64df7a

File tree

6 files changed

+292
-231
lines changed

6 files changed

+292
-231
lines changed

fidimag/common/helper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import numpy as np
66

77
import matplotlib.pyplot as plt
8-
from mpl_toolkits.mplot3d import Axes3D
8+
# from mpl_toolkits.mplot3d import Axes3D
99
from matplotlib.colors import colorConverter
1010
from matplotlib.collections import PolyCollection, LineCollection
1111
from fidimag.extensions.common_clib import normalise, init_scalar, init_vector, init_vector_func_fast

fidimag/micro/dmi.py

Lines changed: 142 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -48,25 +48,25 @@ class DMI(Energy):
4848
known as anti-skyrmions are stabilised with this
4949
DMI type
5050
51+
custom :: Pass n number of DMI constants as the main argument and
52+
specify a dmi_vector array of length 18 * n. This array
53+
has the dmi vector components for every NN in the order
54+
55+
[D1x(-x) D1y(-x) D1z(-x) D1x(+x) D1y(+x) ... D1z(+z)
56+
D2x(-x) D2y(-x) ... D2z(+z)
57+
...
58+
]
59+
5160
ARGUMENTS: ----------------------------------------------------------------
5261
5362
D :: DMI vector norm which can be specified as an int, float, (X * n)
54-
array (X=6 for bulk DMI and X=4 for interfacial DMI), (n) array
5563
or spatially dependent scalar field function. The units are
5664
Joules / ( meter **2 ).
5765
5866
int, float: D will have the same magnitude for every NN of the
5967
spins at every mesh node, given by this magnitude
6068
61-
(n) array: D will have the same magnitude for every NN on every
62-
mesh node but will vary according to the values of the array,
63-
i.e. the value of D for the 6 NNs at the i-th mesh site will be
64-
given by the i-th value of the array
65-
66-
(X * n) array: Manually specify the DMI vector norm for every NN
67-
at every mesh node. The bulk DMI considers the 6 NNs from every
68-
node and interfacial and D_2d DMI are 2D so they only consider 4
69-
NNs from the xy plane.
69+
(n) array or list: D for every DMI constant
7070
7171
OPTIONAL ARGUMENTS: -------------------------------------------------------
7272
@@ -75,18 +75,19 @@ class DMI(Energy):
7575
7676
"""
7777

78-
def __init__(self, D, name='DMI', dmi_type='bulk', D2=None):
78+
def __init__(self, D, name='DMI', dmi_type='bulk', dmi_vector=None):
7979
"""
8080
"""
8181
self.D = D
8282
self.name = name
8383
self.jac = True
8484
self.dmi_type = dmi_type
85+
self.dmi_vector = dmi_vector
8586

8687
# Number of NNs for the calculation of the corresponding DMI
8788
# Interfacial or D_2d are 2D so we use 4 ngbs
88-
types = ['bulk', 'interfacial', 'D_n', 'C_n', 'D_2d']
89-
if self.dmi_type not in ['bulk', 'interfacial', 'D_n', 'C_n', 'D_2d']:
89+
types = ['bulk', 'interfacial', 'D_n', 'C_n', 'D_2d', 'custom']
90+
if self.dmi_type not in types:
9091
raise Exception(
9192
"Unsupported DMI type: {}, " +
9293
"available options:\n {}".format(self.dmi_type, *types)
@@ -98,142 +99,159 @@ def __init__(self, D, name='DMI', dmi_type='bulk', D2=None):
9899
# raise Exception("For C_n and D_n symmetry, you must also pass a D2 value"
99100
# " as this material class has multiple DMI constants")
100101

101-
102102
def setup(self, mesh, spin, Ms, Ms_inv):
103103
super(DMI, self).setup(mesh, spin, Ms, Ms_inv)
104104

105105
if self.dmi_type == 'bulk':
106106
self.dmi_vector = np.array([-1., 0, 0,
107-
1., 0, 0,
108-
0, -1., 0,
109-
0, 1., 0,
110-
0, 0, -1.,
111-
0, 0, 1.
112-
])
107+
1., 0, 0,
108+
0, -1., 0,
109+
0, 1., 0,
110+
0, 0, -1.,
111+
0, 0, 1.
112+
])
113113

114114
elif self.dmi_type == 'interfacial':
115115
self.dmi_vector = np.array([0, -1., 0, # -x
116-
0, 1., 0, # +x
117-
1., 0, 0, # -y
118-
-1., 0, 0, # +y
119-
0, 0, 0, # -z
120-
0, 0, 0 # +z
121-
])
116+
0, 1., 0, # +x
117+
1., 0, 0, # -y
118+
-1., 0, 0, # +y
119+
0, 0, 0, # -z
120+
0, 0, 0 # +z
121+
])
122122

123123
elif self.dmi_type == 'D_2d':
124124
self.dmi_vector = np.array([1., 0, 0, # -x
125-
-1., 0, 0, # +x
126-
0, -1., 0, # -y
127-
0, 1., 0, # +y
128-
0, 0, 0, # -z
129-
0, 0, 0 # +z
130-
])
125+
-1., 0, 0, # +x
126+
0, -1., 0, # -y
127+
0, 1., 0, # +y
128+
0, 0, 0, # -z
129+
0, 0, 0 # +z
130+
])
131131

132132
elif self.dmi_type == 'D_n':
133-
self.dmi_vector = np.array([1.0, 0, 0, # D1 components
134-
-1, 0, 0,
135-
0, -1, 0,
136-
0, 1, 0,
137-
0, 0, 0,
138-
0, 0, 0,
139-
0, 0, 0, # D2 components
140-
0, 0, 0,
141-
0, 0, 0,
142-
0, 0, 0,
143-
0, 0, 1,
144-
0, 0, -1,
145-
])
133+
self.dmi_vector = np.array([1.0, 0, 0, # D1 components
134+
-1, 0, 0,
135+
0, -1, 0,
136+
0, 1, 0,
137+
0, 0, 0,
138+
0, 0, 0,
139+
0, 0, 0, # D2 components
140+
0, 0, 0,
141+
0, 0, 0,
142+
0, 0, 0,
143+
0, 0, 1,
144+
0, 0, -1,
145+
])
146146

147147
elif self.dmi_type == 'C_n':
148-
self.dmi_vector =np.array([0, -1., 0, # -x
149-
0, 1., 0, # +x
150-
1., 0, 0, # -y
151-
-1., 0, 0, # +y
152-
0, 0, 0, # -z
153-
0, 0, 0, # +z
154-
1, 0, 0, # D2 components
155-
-1, 0, 0,
156-
0, -1, 0,
157-
0, 1, 0,
158-
0, 0, 0,
159-
0, 0, 0,
160-
])
148+
self.dmi_vector = np.array([0, -1., 0, # -x
149+
0, 1., 0, # +x
150+
1., 0, 0, # -y
151+
-1., 0, 0, # +y
152+
0, 0, 0, # -z
153+
0, 0, 0, # +z
154+
1, 0, 0, # D2 components
155+
-1, 0, 0,
156+
0, -1, 0,
157+
0, 1, 0,
158+
0, 0, 0,
159+
0, 0, 0,
160+
])
161+
elif self.dmi_type == 'custom':
162+
self.dmi_vector = np.array(self.dmi_vector)
163+
# Example:
164+
# self.DMI_vector = [ 0, 0, D1, # DMI 1
165+
# 0, 0, -D1,
166+
# 0, 0, 0,
167+
# 0, 0, 0,
168+
# 0, 0, 0,
169+
# 0, 0, 0,
170+
# 0, 0, 0, # DMI 2
171+
# 0, 0, 0,
172+
# 0, D2, 0,
173+
# 0, -D2, 0,
174+
# 0, 0, 0,
175+
# 0, 0, 0,
176+
# ]
177+
n_Ds = len(self.dmi_vector) // 18
178+
179+
if len(self.dmi_vector) % 18 != 0:
180+
raise Exception('The DMI vector length must be a mult of 18: '
181+
' N of DMIs times 3 * number of ngbs = 18')
182+
183+
if n_Ds > 1:
184+
self.Ds = helper.init_vector(self.D, self.mesh, dim=n_Ds)
185+
else:
186+
self.Ds = helper.init_scalar(self.D, self.mesh)
187+
188+
self.n_dmis = n_Ds
189+
161190
if self.dmi_type == 'C_n' or self.dmi_type == 'D_n':
162191
self.Ds = helper.init_vector(self.D, self.mesh, dim=2)
163-
D0 = self.Ds[::2]
164-
D1 = self.Ds[1::2]
165-
self.Ds[:] = np.hstack([D0, D1])
192+
self.n_dmis = 2
166193
else:
167194
self.Ds = helper.init_scalar(self.D, self.mesh)
168-
195+
self.n_dmis = 1
169196

170197
def compute_field(self, t=0, spin=None):
171198
if spin is not None:
172199
m = spin
173200
else:
174201
m = self.spin
175202

176-
177-
178-
if self.dmi_type == 'D_n' or self.dmi_type == 'C_n':
179-
# Now have two vaues for D,
180-
# so what we can do is intersperse the D values, i.e.
181-
# [D^1_0, D^2_0, D^1_1, D^2_1, ... D^1_n, D^2_n]
182-
# So to address cell i's values, you can use
183-
# D1 = 2*i
184-
# D2 = 2*i + 1
185-
186-
micro_clib.compute_dmi_field(m,
187-
self.field,
188-
self.energy,
189-
self.Ms_inv,
190-
self.Ds[:self.n],
191-
self.dmi_vector[:18],
192-
self.dx,
193-
self.dy,
194-
self.dz,
195-
self.n,
196-
self.neighbours
197-
)
198-
199-
field0 = np.zeros_like(self.field)
200-
micro_clib.compute_dmi_field(m,
201-
field0,
202-
self.energy,
203-
self.Ms_inv,
204-
self.Ds[self.n:],
205-
self.dmi_vector[18:],
206-
self.dx,
207-
self.dy,
208-
self.dz,
209-
self.n,
210-
self.neighbours
211-
)
212-
# print('field0 minmax = ', np.min(field0), np.max(field0))
213-
# print('D0 minmax = ', np.min(self.Ds[:self.n]), np.max(self.Ds[:self.n]))
214-
# print('D1 minmax = ', np.min(self.Ds[self.n:]), np.max(self.Ds[self.n:]))
215-
self.field += field0
216-
217-
218-
219-
220-
221-
222-
223-
224-
225-
else:
226-
micro_clib.compute_dmi_field(m,
227-
self.field,
228-
self.energy,
229-
self.Ms_inv,
230-
self.Ds,
231-
self.dmi_vector,
232-
self.dx,
233-
self.dy,
234-
self.dz,
235-
self.n,
236-
self.neighbours
237-
)
203+
# if self.dmi_type == 'D_n' or self.dmi_type == 'C_n':
204+
# # Now have two vaues for D,
205+
# # so what we can do is intersperse the D values, i.e.
206+
# # [D^1_0, D^2_0, D^1_1, D^2_1, ... D^1_n, D^2_n]
207+
# # So to address cell i's values, you can use
208+
# # D1 = 2*i
209+
# # D2 = 2*i + 1
210+
211+
# micro_clib.compute_dmi_field(m,
212+
# self.field,
213+
# self.energy,
214+
# self.Ms_inv,
215+
# self.Ds[:self.n],
216+
# self.dmi_vector[:18],
217+
# self.dx,
218+
# self.dy,
219+
# self.dz,
220+
# self.n,
221+
# self.neighbours
222+
# )
223+
224+
# field0 = np.zeros_like(self.field)
225+
# micro_clib.compute_dmi_field(m,
226+
# field0,
227+
# self.energy,
228+
# self.Ms_inv,
229+
# self.Ds[self.n:],
230+
# self.dmi_vector[18:],
231+
# self.dx,
232+
# self.dy,
233+
# self.dz,
234+
# self.n,
235+
# self.neighbours
236+
# )
237+
# # print('field0 minmax = ', np.min(field0), np.max(field0))
238+
# # print('D0 minmax = ', np.min(self.Ds[:self.n]), np.max(self.Ds[:self.n]))
239+
# # print('D1 minmax = ', np.min(self.Ds[self.n:]), np.max(self.Ds[self.n:]))
240+
# self.field += field0
241+
242+
# else:
243+
micro_clib.compute_dmi_field(m,
244+
self.field,
245+
self.energy,
246+
self.Ms_inv,
247+
self.Ds,
248+
self.n_dmis,
249+
self.dmi_vector,
250+
self.dx,
251+
self.dy,
252+
self.dz,
253+
self.n,
254+
self.neighbours
255+
)
238256

239257
return self.field

0 commit comments

Comments
 (0)