Skip to content

Commit 232fb4f

Browse files
Merge pull request #88 from computationalmodelling/NEBM-refactoring
Nebm refactoring
2 parents 3c9f59a + 890366f commit 232fb4f

40 files changed

+3810
-1777
lines changed

doc/ipynb/1d_domain_wall.ipynb

Lines changed: 8 additions & 11 deletions
Large diffs are not rendered by default.

examples/neb/domain_wall/dw.py renamed to examples/neb_micromagnetic/domain_wall/dw.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
import numpy as np
66
from fidimag.micro import Sim, UniformExchange, Demag, UniaxialAnisotropy
77
from fidimag.common import CuboidMesh
8-
from fidimag.common.neb_cartesian import NEB_Sundials
9-
from fidimag.common.helper import plot_energy_2d, plot_energy_3d
8+
from fidimag.common.nebm_cartesian import NEBM_Cartesian
9+
# TODO: FIX the plotting functions
10+
# from fidimag.common.helper import plot_energy_2d, plot_energy_3d
1011
#from finmag.sim.neb import plot_energy_2d, plot_energy_3d
1112

1213

@@ -52,13 +53,14 @@ def relax_system(sim):
5253

5354
init_images = [(-1, 0, 0), init_dw, (1, 0, 0)]
5455

55-
neb = NEB_Sundials(
56-
sim, init_images, interpolations=[6, 6], name='neb', spring=1e8)
56+
neb = NEBM_Cartesian(
57+
sim, init_images, interpolations=[6, 6], name='neb',
58+
spring_constant=1e8)
5759

5860
# neb.add_noise(0.1)
5961

60-
neb.relax(dt=1e-8, max_steps=5000, save_vtk_steps=500,
61-
save_npy_steps=500, stopping_dmdt=100)
62+
neb.relax(dt=1e-8, max_iterations=5000, save_vtks_every=500,
63+
save_npys_every=500, stopping_dYdt=100)
6264

6365
if __name__ == "__main__":
6466

@@ -67,5 +69,5 @@ def relax_system(sim):
6769
sim = create_simulation(mesh)
6870
# relax_two_state(mesh)
6971
relax_system(sim)
70-
plot_energy_2d('neb')
71-
plot_energy_3d('neb')
72+
# plot_energy_2d('neb')
73+
# plot_energy_3d('neb')
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
from __future__ import print_function
2+
import pytest
3+
4+
"""
5+
6+
Test of the NEBM on an elongated particle of cylindrical shape, based on [1],
7+
where a series of simple magnetic systems are tested using the NEBM in
8+
Spherical coordinates with an Euclidean distance. For the alongated particle
9+
test, the system is a 70 nm long and 12 nm wide (originally it is 13 nm)
10+
nanocylinder, with an uniaxial anisotropy in the direction of the long axis.The
11+
test goal is to find the minimum energy path (MEP) between two degenerate
12+
ferromagnetic states (saturated states along the anisotropy axis), which are
13+
the ground states of this system. The MEP is given by a transverse domain wall
14+
propagation that reverse the ferromagnetic state towards the opposite
15+
anisotropic direction.
16+
17+
In the test, we use the Geodesic and Cartesian NEBM codes (there are issues
18+
with the definition of the angles in the Spherical code). For the Geodesic code
19+
we also describe the magnetisation in Cartesian coordinates but we use a
20+
Geodesic distance as in [2] and a projection of the tangents. In the case of
21+
the Cartesian code we use an Euclidean distance and we do not use projections.
22+
The initial energy band we provide for the algorithm is similar to a coherent
23+
rotation of the spins, which is not the optimal path.
24+
25+
For this particular code, the cylinder long axis (and so the anisotropy axis)
26+
is defined along the y direction
27+
28+
* The Cartesian code is still very slow, we suggest using a less symmetric
29+
middle state for the initial_images, such as
30+
31+
def middle_state(r):
32+
if r[1] >= 35:
33+
return (0.5, 0.5, 0)
34+
else:
35+
return (-0.5, 0.5, 0)
36+
37+
[1] Dittrich et al., JMMM 250 (2002) L12-L19
38+
[2] Bessarab et al., Computer Physics Communications 196 (2015) 335-347
39+
40+
"""
41+
42+
# FIDIMAG:
43+
from fidimag.micro import Sim
44+
from fidimag.common import CuboidMesh
45+
from fidimag.micro import UniformExchange, UniaxialAnisotropy, Demag
46+
from fidimag.common.nebm_geodesic import NEBM_Geodesic
47+
from fidimag.common.nebm_cartesian import NEBM_Cartesian
48+
import numpy as np
49+
50+
# Material Parameters ---------------------------------------------------------
51+
52+
A = 10e-12
53+
Kx = 3e5
54+
Ms = 3.98e5
55+
56+
# -----------------------------------------------------------------------------
57+
58+
59+
def relax_neb(sim, k, maxst, simname, initial_images, interpolations,
60+
save_every=10000, method='Geodesic',
61+
interpolation_method='linear'
62+
):
63+
"""
64+
Relax a Fidimag simulation using the NEBM:
65+
66+
sim :: Simulation object with the system specifications
67+
k :: NEBM spring constant
68+
maxst :: NEBM max steps for the algorithm evolution
69+
simname :: NEBM simulation name
70+
initial_images :: NEBM images
71+
interpolations :: A list with the number of inteprolations between
72+
the NEBM images
73+
save_every :: Save VTK or NPY files every certain number of steps
74+
method :: NEBM coordinates: 'Cartesian', 'Geodesic'
75+
interpolation_method :: Method for interpolating the initial_images,
76+
'linear' or 'rotation' (Rodrigues formulae)
77+
"""
78+
79+
method_dict = {'Cartesian': NEBM_Cartesian, 'Geodesic': NEBM_Geodesic}
80+
81+
neb = method_dict[method](sim,
82+
initial_images,
83+
interpolations=interpolations,
84+
spring_constant=k,
85+
name=simname,
86+
interpolation_method='rotation',
87+
openmp=True
88+
)
89+
90+
neb.relax(max_iterations=maxst,
91+
save_vtks_every=save_every,
92+
save_npys_every=save_every,
93+
stopping_dYdt=1)
94+
95+
# x, E_interp = neb.compute_polynomial_approximation(200)
96+
# np.savetxt('interpolated_band_GEODESIC.dat',
97+
# np.column_stack((x, E_interp))
98+
# )
99+
100+
101+
# Mesh ------------------------------------------------------------------------
102+
103+
# Define an elongated cylinder along the y direction
104+
def cylinder(r, centre, radius):
105+
if (r[0] - centre[0]) ** 2. + (r[2] - centre[1]) ** 2 <= radius ** 2.:
106+
return Ms
107+
else:
108+
return 0
109+
110+
# Finite differences mesh
111+
mesh = CuboidMesh(nx=6, ny=35, nz=6,
112+
dx=2, dy=2, dz=2,
113+
unit_length=1e-9)
114+
115+
centre = (np.max(mesh.coordinates[:, 0]) * 0.5,
116+
np.max(mesh.coordinates[:, 2]) * 0.5)
117+
118+
119+
# Prepare simulation ----------------------------------------------------------
120+
121+
def elongated_part_sim():
122+
sim = Sim(mesh)
123+
sim.Ms = lambda r: cylinder(r, centre, 8)
124+
sim.add(UniformExchange(A=A))
125+
sim.add(UniaxialAnisotropy(Kx, axis=(0, 1, 0))) # Anisotropy along y
126+
sim.add(Demag())
127+
128+
return sim
129+
130+
131+
# -----------------------------------------------------------------------------
132+
133+
barriers = {}
134+
135+
136+
def test_energy_barrier_cylinder():
137+
init_im = [(0, -1, 0), (0.9, 0.1, 0), (0, 1, 0)]
138+
interp = [8, 8]
139+
140+
for method in ['Geodesic', 'Cartesian']:
141+
relax_neb(elongated_part_sim(),
142+
1e4, 2000,
143+
'neb_cylinder_y-axis_{}'.format(method),
144+
init_im,
145+
interp,
146+
save_every=5000,
147+
method=method
148+
)
149+
150+
# Get the energies from the last state
151+
data = np.loadtxt('neb_cylinder_y-axis_{}_energy.ndt'.format(method))[-1][1:]
152+
ebarrier = np.abs(np.max(data) - np.min(data)) / (1.602e-19)
153+
barriers[method] = ebarrier
154+
155+
# assert ebarrier < 0.017
156+
# assert ebarrier > 0.005
157+
158+
for key in barriers.keys():
159+
print(key, barriers)
160+
161+
162+
if __name__ == '__main__':
163+
test_energy_barrier_cylinder()
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
from __future__ import print_function
2+
import pytest
3+
4+
"""
5+
6+
Test of the NEBM on an elongated particle of cylindrical shape, based on [1],
7+
where a series of simple magnetic systems are tested using the NEBM in
8+
Spherical coordinates with an Euclidean distance. For the elongated particle
9+
test, the system is a 70 nm long and 12 nm wide (originally it is 13 nm)
10+
nanocylinder, with a uniaxial anisotropy in the direction of the long axis.The
11+
test goal is to find the minimum energy path (MEP) between two degenerate
12+
ferromagnetic states (saturated states along the anisotropy axis), which are
13+
the ground states of this system. The MEP is given by a transverse domain wall
14+
propagation that reverse the ferromagnetic state towards the opposite
15+
anisotropic direction.
16+
17+
In the test, we use the Geodesic and Cartesian NEBM codes (there are issues
18+
with the definition of the angles in the Spherical code). For the Geodesic code
19+
we also describe the magnetisation in Cartesian coordinates but we use a
20+
Geodesic distance as in [2] and a projection of the tangents. In the case of
21+
the Cartesian code we use an Euclidean distance and we do not use projections.
22+
The initial energy band we provide for the algorithm is similar to a coherent
23+
rotation of the spins, which is not the optimal path.
24+
25+
For this particular code, the cylinder long axis (and so the anisotropy axis)
26+
is defined along the z direction. In case we used spherical coordinates,
27+
the angles that define the spin directions are not completely defined when
28+
the spins point in the z direction (poles) thus the algorithm struggles
29+
to find the minimum energy path. It seems this is also the case for Cartesian
30+
coordinates since we haven't projected the tangents.
31+
32+
An interesting test would be to compare the convergences when using a more
33+
symmetrical initial band, like
34+
initial_images = [[0, 0, -1], [0, 1, 0], [0, 0, 1]]
35+
36+
According to our tests, the Geodesic code is the one that converges faster
37+
and not having much issues with the spin directions.
38+
39+
[1] Dittrich et al., JMMM 250 (2002) L12-L19
40+
[2] Bessarab et al., Computer Physics Communications 196 (2015) 335-347
41+
42+
"""
43+
44+
# FIDIMAG:
45+
from fidimag.micro import Sim
46+
from fidimag.common import CuboidMesh
47+
from fidimag.micro import UniformExchange, UniaxialAnisotropy, Demag
48+
from fidimag.common.nebm_geodesic import NEBM_Geodesic
49+
from fidimag.common.nebm_cartesian import NEBM_Cartesian
50+
import numpy as np
51+
52+
# Material Parameters ---------------------------------------------------------
53+
54+
A = 10e-12
55+
Kx = 3e5
56+
Ms = 3.98e5
57+
58+
# -----------------------------------------------------------------------------
59+
60+
61+
def relax_neb(sim, k, maxst, simname, initial_images, interpolations,
62+
save_every=10000, method='Geodesic',
63+
interpolation_method='linear'
64+
):
65+
"""
66+
Relax a Fidimag simulation using the NEBM:
67+
68+
sim :: Simulation object with the system specifications
69+
k :: NEBM spring constant
70+
maxst :: NEBM max steps for the algorithm evolution
71+
simname :: NEBM simulation name
72+
initial_images :: NEBM images
73+
interpolations :: A list with the number of inteprolations between
74+
the NEBM images
75+
save_every :: Save VTK or NPY files every certain number of steps
76+
method :: NEBM coordinates: 'Cartesian', 'Geodesic'
77+
interpolation_method :: Method for interpolating the initial_images,
78+
'linear' or 'rotation' (Rodrigues formulae)
79+
"""
80+
81+
method_dict = {'Cartesian': NEBM_Cartesian, 'Geodesic': NEBM_Geodesic}
82+
83+
neb = method_dict[method](sim,
84+
initial_images,
85+
interpolations=interpolations,
86+
spring_constant=k,
87+
name=simname,
88+
interpolation_method='rotation',
89+
openmp=True
90+
)
91+
92+
neb.relax(max_iterations=maxst,
93+
save_vtks_every=save_every,
94+
save_npys_every=save_every,
95+
stopping_dYdt=1)
96+
97+
# x, E_interp = neb.compute_polynomial_approximation(200)
98+
# np.savetxt('interpolated_band_GEODESIC.dat',
99+
# np.column_stack((x, E_interp))
100+
# )
101+
102+
103+
# Mesh ------------------------------------------------------------------------
104+
105+
# Define an elongated cylinder along the y direction
106+
def cylinder(r, centre, radius):
107+
if (r[0] - centre[0]) ** 2. + (r[1] - centre[1]) ** 2 <= radius ** 2.:
108+
return Ms
109+
else:
110+
return 0
111+
112+
# Finite differences mesh
113+
mesh = CuboidMesh(nx=6, ny=6, nz=35,
114+
dx=2, dy=2, dz=2,
115+
unit_length=1e-9)
116+
117+
centre = (np.max(mesh.coordinates[:, 0]) * 0.5,
118+
np.max(mesh.coordinates[:, 1]) * 0.5)
119+
120+
121+
# Prepare simulation ----------------------------------------------------------
122+
123+
def elongated_part_sim():
124+
sim = Sim(mesh)
125+
sim.Ms = lambda r: cylinder(r, centre, 8)
126+
sim.add(UniformExchange(A=A))
127+
sim.add(UniaxialAnisotropy(Kx, axis=(0, 0, 1))) # Anisotropy along y
128+
sim.add(Demag())
129+
130+
return sim
131+
132+
133+
# -----------------------------------------------------------------------------
134+
135+
barriers = {}
136+
137+
138+
def test_energy_barrier_cylinder():
139+
init_im = [(0, 0, -1), (0, 0.9, 0.1), (0, 0, 1)]
140+
interp = [8, 8]
141+
142+
for method in ['Geodesic', 'Cartesian']:
143+
relax_neb(elongated_part_sim(),
144+
1e4, 2000,
145+
'neb_cylinder_z-axis_{}'.format(method),
146+
init_im,
147+
interp,
148+
save_every=5000,
149+
method=method
150+
)
151+
152+
# Get the energies from the last state
153+
data = np.loadtxt('neb_cylinder_z-axis_{}_energy.ndt'.format(method))[-1][1:]
154+
ebarrier = np.abs(np.max(data) - np.min(data)) / (1.602e-19)
155+
barriers[method] = ebarrier
156+
157+
# assert ebarrier < 0.017
158+
# assert ebarrier > 0.005
159+
160+
for key in barriers.keys():
161+
print(key, barriers)
162+
163+
164+
if __name__ == '__main__':
165+
test_energy_barrier_cylinder()
File renamed without changes.
File renamed without changes.

examples/neb/skyrmion/relaxation/skyrmion_down_relax.py renamed to examples/neb_micromagnetic/skyrmion/relaxation/skyrmion_down_relax.py

File renamed without changes.

examples/neb/skyrmion/relaxation/skyrmion_relax.py renamed to examples/neb_micromagnetic/skyrmion/relaxation/skyrmion_relax.py

File renamed without changes.
File renamed without changes.

examples/neb_atomistic/1D_spin_chain/neb_helicoid-fm.py renamed to examples/nebm_atomistic/1D_spin_chain/neb_helicoid-fm.py

File renamed without changes.

0 commit comments

Comments
 (0)