Statistiques
| Révision :

root / ase / optimize / bfgs.py @ 3

Historique | Voir | Annoter | Télécharger (3,61 ko)

1 1 tkerber
# -*- coding: utf-8 -*-
2 1 tkerber
import numpy as np
3 1 tkerber
from numpy.linalg import eigh, solve
4 1 tkerber
5 1 tkerber
from ase.optimize.optimize import Optimizer
6 1 tkerber
7 1 tkerber
8 1 tkerber
class BFGS(Optimizer):
9 1 tkerber
    def __init__(self, atoms, restart=None, logfile='-', trajectory=None,
10 1 tkerber
                 maxstep=None):
11 1 tkerber
        """BFGS optimizer.
12 1 tkerber

13 1 tkerber
        Parameters:
14 1 tkerber

15 1 tkerber
        restart: string
16 1 tkerber
            Pickle file used to store hessian matrix. If set, file with
17 1 tkerber
            such a name will be searched and hessian matrix stored will
18 1 tkerber
            be used, if the file exists.
19 1 tkerber
        trajectory: string
20 1 tkerber
            Pickle file used to store trajectory of atomic movement.
21 1 tkerber
        maxstep: float
22 1 tkerber
            Used to set the maximum distance an atom can move per
23 1 tkerber
            iteration (default value is 0.04 Å).
24 1 tkerber
        """
25 1 tkerber
26 1 tkerber
        Optimizer.__init__(self, atoms, restart, logfile, trajectory)
27 1 tkerber
28 1 tkerber
        if maxstep is not None:
29 1 tkerber
            if maxstep > 1.0:
30 1 tkerber
                raise ValueError('You are using a much too large value for ' +
31 1 tkerber
                                 'the maximum step size: %.1f Å' % maxstep)
32 1 tkerber
            self.maxstep = maxstep
33 1 tkerber
34 1 tkerber
    def initialize(self):
35 1 tkerber
        self.H = None
36 1 tkerber
        self.r0 = None
37 1 tkerber
        self.f0 = None
38 1 tkerber
        self.maxstep = 0.04
39 1 tkerber
40 1 tkerber
    def read(self):
41 1 tkerber
        self.H, self.r0, self.f0, self.maxstep = self.load()
42 1 tkerber
43 1 tkerber
    def step(self, f):
44 1 tkerber
        atoms = self.atoms
45 1 tkerber
        r = atoms.get_positions()
46 1 tkerber
        f = f.reshape(-1)
47 1 tkerber
        self.update(r.flat, f, self.r0, self.f0)
48 1 tkerber
        omega, V = eigh(self.H)
49 1 tkerber
        dr = np.dot(V, np.dot(f, V) / np.fabs(omega)).reshape((-1, 3))
50 1 tkerber
        #dr = solve(self.H, f).reshape((-1, 3))
51 1 tkerber
        steplengths = (dr**2).sum(1)**0.5
52 1 tkerber
        dr = self.determine_step(dr, steplengths)
53 1 tkerber
        atoms.set_positions(r + dr)
54 1 tkerber
        self.r0 = r.flat.copy()
55 1 tkerber
        self.f0 = f.copy()
56 1 tkerber
        self.dump((self.H, self.r0, self.f0, self.maxstep))
57 1 tkerber
58 1 tkerber
    def determine_step(self, dr, steplengths):
59 1 tkerber
        """Determine step to take according to maxstep
60 1 tkerber

61 1 tkerber
        Normalize all steps as the largest step. This way
62 1 tkerber
        we still move along the eigendirection.
63 1 tkerber
        """
64 1 tkerber
        maxsteplength = np.max(steplengths)
65 1 tkerber
        if maxsteplength >= self.maxstep:
66 1 tkerber
            dr *= self.maxstep / maxsteplength
67 1 tkerber
68 1 tkerber
        return dr
69 1 tkerber
70 1 tkerber
    def update(self, r, f, r0, f0):
71 1 tkerber
        if self.H is None:
72 1 tkerber
            self.H = np.eye(3 * len(self.atoms)) * 70.0
73 1 tkerber
            return
74 1 tkerber
        dr = r - r0
75 1 tkerber
76 1 tkerber
        if np.abs(dr).max() < 1e-7:
77 1 tkerber
            # Same configuration again (maybe a restart):
78 1 tkerber
            return
79 1 tkerber
80 1 tkerber
        df = f - f0
81 1 tkerber
        a = np.dot(dr, df)
82 1 tkerber
        dg = np.dot(self.H, dr)
83 1 tkerber
        b = np.dot(dr, dg)
84 1 tkerber
        self.H -= np.outer(df, df) / a + np.outer(dg, dg) / b
85 1 tkerber
86 1 tkerber
    def replay_trajectory(self, traj):
87 1 tkerber
        """Initialize hessian from old trajectory."""
88 1 tkerber
        if isinstance(traj, str):
89 1 tkerber
            from ase.io.trajectory import PickleTrajectory
90 1 tkerber
            traj = PickleTrajectory(traj, 'r')
91 1 tkerber
        self.H = None
92 1 tkerber
        atoms = traj[0]
93 1 tkerber
        r0 = atoms.get_positions().ravel()
94 1 tkerber
        f0 = atoms.get_forces().ravel()
95 1 tkerber
        for atoms in traj:
96 1 tkerber
            r = atoms.get_positions().ravel()
97 1 tkerber
            f = atoms.get_forces().ravel()
98 1 tkerber
            self.update(r, f, r0, f0)
99 1 tkerber
            r0 = r
100 1 tkerber
            f0 = f
101 1 tkerber
102 1 tkerber
        self.r0 = r0
103 1 tkerber
        self.f0 = f0
104 1 tkerber
105 1 tkerber
class oldBFGS(BFGS):
106 1 tkerber
    def determine_step(self, dr, steplengths):
107 1 tkerber
        """Old BFGS behaviour for scaling step lengths
108 1 tkerber

109 1 tkerber
        This keeps the behaviour of truncating individual steps. Some might
110 1 tkerber
        depend of this as some absurd kind of stimulated annealing to find the
111 1 tkerber
        global minimum.
112 1 tkerber
        """
113 1 tkerber
        dr /= np.maximum(steplengths / self.maxstep, 1.0).reshape(-1, 1)
114 1 tkerber
        return dr