|
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