Skip to content

Commit feec815

Browse files
Implementing integrator
1 parent 0c57c63 commit feec815

File tree

3 files changed

+116
-11
lines changed

3 files changed

+116
-11
lines changed

Diff for: fidimag/common/chain_method_integrators.py

+97-5
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010

1111
class StepIntegrator(BaseIntegrator):
1212
"""
13-
A simple integrator where spins are normalised at every inetegrator step
14-
Integrator options are Euler and RK4
13+
A simple integrator where spins are normalised at every integrator step.
14+
Integrator options are `euler` and `rk4`
1515
"""
1616
def __init__(self, spins, rhs_fun, step="euler", stepsize=1e-15):
1717
super(StepIntegrator, self).__init__(spins, rhs_fun)
@@ -36,13 +36,13 @@ def set_options(self, rtol=1e-8, atol=1e-8):
3636
def set_step(self, step):
3737
step_choices = {'euler': euler_step, 'rk4': runge_kutta_step}
3838
if step not in step_choices:
39-
raise NotImplemented("step must be euler or rk4")
39+
raise NotImplementedError("step must be euler or rk4")
4040
self._step = step_choices[step]
4141

4242

4343
class VerletIntegrator(BaseIntegrator):
44-
"""
45-
A quick Verlet integration in Cartesian coordinates
44+
"""A quick Verlet integration in Cartesian coordinates
45+
4646
See: J. Chem. Theory Comput., 2017, 13 (7), pp 3250–3259
4747
"""
4848
def __init__(self, band, forces, rhs_fun, n_images, n_dofs_image,
@@ -142,6 +142,98 @@ def _step(self, t, y, h, f):
142142
return tp
143143

144144

145+
# -----------------------------------------------------------------------------
146+
# NEBM integrator for F-S algorithm
147+
148+
149+
class FSIntegrator(BaseIntegrator):
150+
"""A step integrator considering the action of the band
151+
"""
152+
def __init__(self, band, forces, action, rhs_fun, n_images, n_dofs_image,
153+
max_steps=1000):
154+
super(FSIntegrator, self).__init__(band, rhs_fun)
155+
156+
self.i_step = 0
157+
self.n_images = n_images
158+
self.n_dofs_image = n_dofs_image
159+
self.forces_prev = np.zeros_like(band).reshape(n_images, -1)
160+
# self.G :
161+
self.forces = forces
162+
self.max_steps = max_steps
163+
164+
def run_until(self, t):
165+
pass
166+
167+
def run_for(self, n_steps):
168+
# while abs(self.i_step - steps) > EPSILON:
169+
st = 1
170+
while st < n_steps:
171+
self.i_step = self._step(self.t, self.y, self.stepsize, self.rhs)
172+
173+
self.rhs_evals_nb += 0
174+
175+
if self.i_step > self.max_steps:
176+
break
177+
178+
st += 1
179+
return 0
180+
181+
def set_options(self):
182+
pass
183+
184+
def _step(self, t, y, h, f):
185+
"""
186+
"""
187+
188+
f(t, y)
189+
force_images = self.forces
190+
force_images.shape = (self.n_images, -1)
191+
# In this case f represents the force: a = dy/dt = f/m
192+
# * self.m_inv[:, np.newaxis]
193+
y.shape = (self.n_images, -1)
194+
# print(force_images[2])
195+
196+
# Loop through every image in the band
197+
for i in range(1, self.n_images - 1):
198+
199+
force = force_images[i]
200+
velocity = self.velocity[i]
201+
velocity_new = self.velocity_new[i]
202+
203+
# Update coordinates from Newton eq, which uses the "acceleration"
204+
# At step 0 velocity is zero
205+
y[i][:] = y[i] + h * (velocity + (h / (2 * self.mass)) * force)
206+
207+
# Update the velocity from a mean with the prev step
208+
# (Velocity Verlet)
209+
velocity[:] = velocity_new[:] + (h / (2 * self.mass)) * (self.forces_prev[i] + force)
210+
211+
# Project the force of the image into the velocity vector: < v | F >
212+
velocity_proj = np.einsum('i,i', force, velocity)
213+
214+
# Set velocity to zero when the proj = 0
215+
if velocity_proj <= 0:
216+
velocity_new[:] = 0.0
217+
else:
218+
# Norm of the force squared <F | F>
219+
force_norm_2 = np.einsum('i,i', force, force)
220+
factor = velocity_proj / force_norm_2
221+
# Set updated velocity: v = v * (<v|F> / |F|^2)
222+
velocity_new[:] = factor * force
223+
224+
# New velocity from Newton equation (old Verlet)
225+
# velocity[:] = velocity_new + (h / self.mass) * force
226+
227+
# Store the force for the Velocity Verlet algorithm
228+
self.forces_prev[:] = force_images
229+
230+
y.shape = (-1,)
231+
force_images.shape = (-1,)
232+
normalise_spins(y)
233+
tp = t + h
234+
return tp
235+
236+
145237
def normalise_spins(y):
146238
# Normalise an array of spins y with 3 * N elements
147239
y.shape = (-1, 3)

Diff for: fidimag/common/nebm_FS.py

+15
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,21 @@ def initialise_energies(self):
148148
self.energies[i] = self.sim.compute_energy()
149149
self.band = self.band.reshape(-1)
150150

151+
def initialise_integrator(self):
152+
self.t = 0
153+
self.iterations = 0
154+
self.ode_count = 1
155+
156+
self.integrator = FSIntegrator(self.band, # y
157+
self.G, # forces
158+
self.step_RHS,
159+
self.n_images,
160+
self.n_dofs_image,
161+
stepsize=1e-4)
162+
self.integrator.set_options()
163+
# In Verlet algorithm we only use the total force G and not YxYxG:
164+
self._llg_evolve = False
165+
151166
def generate_initial_band(self, method='linear'):
152167
"""
153168
method :: linear, rotation

Diff for: fidimag/common/string_method.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,7 @@ def compute_distances(self):
252252
self.path_distances[1:] /= self.path_distances[-1]
253253

254254
def step_RHS(self, t, y):
255-
"""
256-
Use Step integrators from the chain_method_integrators library
257-
255+
"""Use Step integrators from the `chain_method_integrators` library
258256
"""
259257

260258
self.ode_count += 1
@@ -282,9 +280,9 @@ def Sundials_RHS(self, t, y, ydot):
282280
we are solving dy/dt = 0
283281
284282
WARNING: The variable step integrator from Sundials does not work well
285-
with the StringMethod, making the algorithm overshoot the solutions for
286-
large time steps and driving the images toward the extrema images. We
287-
could poossibly fix this by redefining the positions of the images
283+
with the `StringMethod`, making the algorithm overshoot the solutions
284+
for large time steps and driving the images toward the extrema images.
285+
We could possibly fix this by redefining the positions of the images
288286
after every integrator step, instead of redefining them after a certain
289287
number of steps, however this requires to tune the Sundials Python
290288
wrapper. In addition, we would need to check the stopping criteria of

0 commit comments

Comments
 (0)