Skip to content

Commit 5f0e70d

Browse files
author
davidcorteso
committed
Added minimiser base class. Cleaning up and documenting
1 parent c668d48 commit 5f0e70d

File tree

2 files changed

+220
-122
lines changed

2 files changed

+220
-122
lines changed

fidimag/common/minimiser_base.py

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
from __future__ import division
2+
import numpy as np
3+
import fidimag.extensions.common_clib as clib
4+
import fidimag.extensions.clib as atom_clib
5+
import fidimag.common.helper as helper
6+
import fidimag.common.constant as const
7+
from fidimag.common.vtk import VTK
8+
9+
from .driver_base import DriverBase
10+
11+
12+
class MinimiserBase(MinimiserBase):
13+
"""
14+
15+
This class is the driver to minimise a system using a Steepest Descent
16+
algorithm
17+
18+
NOTE: We are inheriting from DriverBase, but it would be better if we
19+
create a MinimiserBase class in the future, removing the
20+
methods from the Driver class that are not being used at all
21+
22+
"""
23+
24+
def __init__(self, mesh, spin,
25+
magnetisation, magnetisation_inv, field, pins,
26+
interactions,
27+
name,
28+
data_saver
29+
):
30+
31+
# ---------------------------------------------------------------------
32+
# These are (ideally) references to arrays taken from the Simulation
33+
# class. Variables with underscore are arrays changed by a property in
34+
# the simulation class
35+
self.mesh = mesh
36+
self.spin = spin
37+
38+
# A reference to either mu_s or Ms to use a common lib for this
39+
# minimiser
40+
self._magnetisation = magnetisation
41+
self._magnetisation_inv = magnetisation_inv
42+
43+
self.field = field
44+
self._pins = pins
45+
self.interactions = interactions
46+
# Strings are not referenced, this is a copy:
47+
self.name = name
48+
49+
self.data_saver = data_saver
50+
51+
# ---------------------------------------------------------------------
52+
# Variables defined in this class
53+
54+
self.spin_last = np.ones_like(self.spin)
55+
self.n = self.mesh.n
56+
57+
# VTK saver for the magnetisation/spin field
58+
self.VTK = VTK(self.mesh,
59+
directory='{}_vtks'.format(self.name),
60+
filename='m'
61+
)
62+
63+
self.scale = 1.
64+
65+
def normalise_field(self, a):
66+
norm = np.sqrt(np.sum(a.reshape(-1, 3) ** 2, axis=1))
67+
norm_a = a.reshape(-1, 3) / norm[:, np.newaxis]
68+
norm_a.shape = (-1,)
69+
return norm_a
70+
71+
def field_cross_product(self, a, b):
72+
aXb = np.cross(a.reshape(-1, 3), b.reshape(-1, 3))
73+
return aXb.reshape(-1,)
74+
75+
def run_step(self):
76+
"""
77+
Python implementation of the step
78+
"""
79+
pass
80+
81+
82+
def run_step_CLIB(self):
83+
"""
84+
Cython implementation of the step. Normally you would define
85+
functions called in this method, in the lib/ folder
86+
"""
87+
pass
88+
89+
90+
def minimise(self, stopping_dm=1e-2, max_steps=2000,
91+
save_data_steps=10, save_m_steps=None, save_vtk_steps=None,
92+
log_steps=1000):
93+
pass
94+
95+
def relax(self):
96+
print('Not implemented for the SD minimiser')
97+
98+
# -------------------------------------------------------------------------
99+
100+
def compute_effective_field(self, t=0):
101+
"""
102+
Compute the effective field from the simulation interactions,
103+
calling the method from the corresponding Energy class
104+
"""
105+
106+
self.field[:] = 0
107+
108+
for obj in self.interactions:
109+
self.field += obj.compute_field(t=0, spin=self.spin)
110+
111+
# -------------------------------------------------------------------------
112+
# SAVERS
113+
114+
def save_vtk(self):
115+
"""
116+
Save a VTK file with the magnetisation vector field and magnetic
117+
moments as cell data. Magnetic moments are saved in units of
118+
Bohr magnetons
119+
120+
NOTE: It is recommended to use a *cell to point data* filter in
121+
Paraview or Mayavi to plot the vector field
122+
"""
123+
self.VTK.reset_data()
124+
125+
# Here we save both Ms and spins as cell data
126+
self.VTK.save_scalar(self._magnetisation / const.mu_B, name='magnetisation')
127+
self.VTK.save_vector(self.spin.reshape(-1, 3), name='spins')
128+
129+
self.VTK.write_file(step=self.step)
130+
131+
def save_m(self, ZIP=False):
132+
"""
133+
Save the magnetisation/spin vector field as a numpy array in
134+
a NPY file. The files are saved in the `{name}_npys` folder, where
135+
`{name}` is the simulation name, with the file name `m_{step}.npy`
136+
where `{step}` is the simulation step (from the integrator)
137+
"""
138+
139+
if not os.path.exists('%s_npys' % self.name):
140+
os.makedirs('%s_npys' % self.name)
141+
name = '%s_npys/m_%g.npy' % (self.name, self.step)
142+
np.save(name, self.spin)
143+
if ZIP:
144+
with zipfile.ZipFile('%s_m.zip'%self.name, 'a') as myzip:
145+
myzip.write(name)
146+
try:
147+
os.remove(name)
148+
except OSError:
149+
pass
150+
151+
def save_skx(self):
152+
"""
153+
Save the skyrmion number density (sk number per mesh site)
154+
as a numpy array in a NPY file.
155+
The files are saved in the `{name}_skx_npys` folder, where
156+
`{name}` is the simulation name, with the file name `skx_{step}.npy`
157+
where `{step}` is the simulation step (from the integrator)
158+
"""
159+
if not os.path.exists('%s_skx_npys' % self.name):
160+
os.makedirs('%s_skx_npys' % self.name)
161+
name = '%s_skx_npys/m_%g.npy' % (self.name, self.step)
162+
163+
# The _skx_number array is defined in the SimBase class in Common
164+
np.save(name, self._skx_number)

0 commit comments

Comments
 (0)