|
7 | 7 | from .chain_method_tools import m_to_zero_nomaterial
|
8 | 8 | from .chain_method_base import ChainMethodBase
|
9 | 9 |
|
| 10 | +from .chain_method_integrators import FSIntegrator |
| 11 | + |
10 | 12 | import scipy.integrate as spi
|
11 | 13 |
|
12 | 14 | import logging
|
13 | 15 | logging.basicConfig(level=logging.DEBUG)
|
14 | 16 | log = logging.getLogger(name="fidimag")
|
15 | 17 |
|
16 | 18 |
|
| 19 | +# TODO: we can just inherit from the geodesic nebm class! |
17 | 20 | class NEBM_FS(ChainMethodBase):
|
18 | 21 | """
|
19 | 22 | ARGUMENTS -----------------------------------------------------------------
|
@@ -153,16 +156,9 @@ def initialise_integrator(self):
|
153 | 156 | self.iterations = 0
|
154 | 157 | self.ode_count = 1
|
155 | 158 |
|
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 |
| - |
| 159 | + # Use default integrator parameters. Pass this class object to the integrator |
| 160 | + self.integrator = FSIntegrator(self) |
| 161 | + |
166 | 162 | def generate_initial_band(self, method='linear'):
|
167 | 163 | """
|
168 | 164 | method :: linear, rotation
|
@@ -258,7 +254,9 @@ def compute_effective_field_and_energy(self, y):
|
258 | 254 | self.energies[i] = self.sim.compute_energy()
|
259 | 255 |
|
260 | 256 | # Compute the gradient norm per every image
|
261 |
| - self.gradientENorm[:] = np.linalg.norm(self.gradientE, axis=1) |
| 257 | + Gnorms2 = np.sum(self.gradientE.reshape(-1, 3)**2, axis=1) |
| 258 | + # Compute the root mean square per image |
| 259 | + self.gradientENorm[:] = np.sqrt(np.mean(Gnorms2.reshape(self.n_images, -1), axis=1)) |
262 | 260 |
|
263 | 261 | y = y.reshape(-1)
|
264 | 262 | self.gradientE = self.gradientE.reshape(-1)
|
@@ -314,9 +312,39 @@ def compute_spring_force(self, y):
|
314 | 312 | )
|
315 | 313 |
|
316 | 314 | def compute_action(self):
|
| 315 | + """ |
| 316 | + """ |
| 317 | + # Check that action is computed AFTER calculating and projecting the forces |
| 318 | + |
| 319 | + # nebm_clib.image_distances_GreatCircle(self.distances, |
| 320 | + # self.path_distances, |
| 321 | + # y, |
| 322 | + # self.n_images, |
| 323 | + # self.n_dofs_image, |
| 324 | + # self._material_int, |
| 325 | + # self.n_dofs_image_material |
| 326 | + # ) |
| 327 | + |
317 | 328 | # TODO: we can use a better quadrature such as Gaussian
|
| 329 | + # notice that the gradient norm here is using the RMS |
318 | 330 | action = spi.trapezoid(self.gradientENorm, self.distances)
|
319 |
| - # TODO: Add spring fore term to the action |
| 331 | + |
| 332 | + # The spring term in the action is added as |F_k|^2 / (2 * self.k) = self.k * x^2 / 2 |
| 333 | + # (CHECK) This assumes the spring force is orthogonal to the force gradient (after projection) |
| 334 | + # Knorms2 = np.sum(self.spring_force.reshape(-1, 3)**2, axis=1) |
| 335 | + # # Compute the root mean square per image |
| 336 | + # springF_norms = np.sqrt(np.mean(Knorms2.reshape(self.n_images, -1), axis=1)) |
| 337 | + |
| 338 | + # Norm of the spring force per image (assuming tangents as unit vectors) |
| 339 | + # These are the norms of the inner images |
| 340 | + dist_plus_norm = self.distances[1:] |
| 341 | + dist_minus_norm = self.distances[:-1] |
| 342 | + # dY_plus_norm = distances[i]; |
| 343 | + # dY_minus_norm = distances[i - 1]; |
| 344 | + springF2 = self.k * ((dist_plus_norm - dist_minus_norm)**2) |
| 345 | + # CHECK: do we need to scale? |
| 346 | + action += np.sum(springF2) / (self.n_images - 2) |
| 347 | + |
320 | 348 | return action
|
321 | 349 |
|
322 | 350 | def compute_min_action(self):
|
|
0 commit comments