root / ase / optimize / basin.py @ 1
Historique | Voir | Annoter | Télécharger (3,84 ko)
1 | 1 | tkerber | import numpy as np |
---|---|---|---|
2 | 1 | tkerber | |
3 | 1 | tkerber | from ase.optimize.optimize import Dynamics |
4 | 1 | tkerber | from ase.optimize.fire import FIRE |
5 | 1 | tkerber | from ase.units import kB |
6 | 1 | tkerber | from ase.parallel import world |
7 | 1 | tkerber | from ase.io.trajectory import PickleTrajectory |
8 | 1 | tkerber | |
9 | 1 | tkerber | class BasinHopping(Dynamics): |
10 | 1 | tkerber | """Basin hopping algorythm.
|
11 | 1 | tkerber |
|
12 | 1 | tkerber | After Wales and Doye, J. Phys. Chem. A, vol 101 (1997) 5111-5116"""
|
13 | 1 | tkerber | |
14 | 1 | tkerber | def __init__(self, atoms, |
15 | 1 | tkerber | temperature=100 * kB,
|
16 | 1 | tkerber | optimizer=FIRE, |
17 | 1 | tkerber | fmax=0.1,
|
18 | 1 | tkerber | dr=.1,
|
19 | 1 | tkerber | logfile='-',
|
20 | 1 | tkerber | trajectory='lowest.traj',
|
21 | 1 | tkerber | optimizer_logfile='-',
|
22 | 1 | tkerber | local_minima_trajectory='local_minima.traj',
|
23 | 1 | tkerber | adjust_cm=True):
|
24 | 1 | tkerber | Dynamics.__init__(self, atoms, logfile, trajectory)
|
25 | 1 | tkerber | self.kT = temperature
|
26 | 1 | tkerber | self.optimizer = optimizer
|
27 | 1 | tkerber | self.fmax = fmax
|
28 | 1 | tkerber | self.dr = dr
|
29 | 1 | tkerber | if adjust_cm:
|
30 | 1 | tkerber | self.cm = atoms.get_center_of_mass()
|
31 | 1 | tkerber | else:
|
32 | 1 | tkerber | self.cm = None |
33 | 1 | tkerber | |
34 | 1 | tkerber | self.optimizer_logfile = optimizer_logfile
|
35 | 1 | tkerber | self.lm_trajectory = local_minima_trajectory
|
36 | 1 | tkerber | if isinstance(local_minima_trajectory, str): |
37 | 1 | tkerber | self.lm_trajectory = PickleTrajectory(local_minima_trajectory,
|
38 | 1 | tkerber | 'w', atoms)
|
39 | 1 | tkerber | |
40 | 1 | tkerber | self.initialize()
|
41 | 1 | tkerber | |
42 | 1 | tkerber | def initialize(self): |
43 | 1 | tkerber | self.positions = 0. * self.atoms.get_positions() |
44 | 1 | tkerber | self.Emin = self.get_energy(self.atoms.get_positions()) |
45 | 1 | tkerber | self.rmin = self.atoms.get_positions() |
46 | 1 | tkerber | self.positions = self.atoms.get_positions() |
47 | 1 | tkerber | self.call_observers()
|
48 | 1 | tkerber | self.log(-1, self.Emin, self.Emin) |
49 | 1 | tkerber | |
50 | 1 | tkerber | def run(self, steps): |
51 | 1 | tkerber | """Hop the basins for defined number of steps."""
|
52 | 1 | tkerber | |
53 | 1 | tkerber | ro = self.positions
|
54 | 1 | tkerber | Eo = self.get_energy(ro)
|
55 | 1 | tkerber | |
56 | 1 | tkerber | for step in range(steps): |
57 | 1 | tkerber | rn = self.move(ro)
|
58 | 1 | tkerber | En = self.get_energy(rn)
|
59 | 1 | tkerber | |
60 | 1 | tkerber | if En < self.Emin: |
61 | 1 | tkerber | # new minimum found
|
62 | 1 | tkerber | self.Emin = En
|
63 | 1 | tkerber | self.rmin = self.atoms.get_positions() |
64 | 1 | tkerber | self.call_observers()
|
65 | 1 | tkerber | rn = self.rmin
|
66 | 1 | tkerber | self.log(step, En, self.Emin) |
67 | 1 | tkerber | |
68 | 1 | tkerber | accept = np.exp((Eo - En) / self.kT) > np.random.uniform()
|
69 | 1 | tkerber | if accept:
|
70 | 1 | tkerber | ro = rn |
71 | 1 | tkerber | Eo = En |
72 | 1 | tkerber | |
73 | 1 | tkerber | def log(self, step, En, Emin): |
74 | 1 | tkerber | if self.logfile is None: |
75 | 1 | tkerber | return
|
76 | 1 | tkerber | name = self.__class__.__name__
|
77 | 1 | tkerber | self.logfile.write('%s: step %d, energy %15.6f, emin %15.6f\n' |
78 | 1 | tkerber | % (name, step, En, self.Emin))
|
79 | 1 | tkerber | self.logfile.flush()
|
80 | 1 | tkerber | |
81 | 1 | tkerber | def move(self, ro): |
82 | 1 | tkerber | atoms = self.atoms
|
83 | 1 | tkerber | # displace coordinates
|
84 | 1 | tkerber | disp = np.random.uniform(-1., 1., (len(atoms), 3)) |
85 | 1 | tkerber | rn = ro + self.dr * disp
|
86 | 1 | tkerber | atoms.set_positions(rn) |
87 | 1 | tkerber | if self.cm is not None: |
88 | 1 | tkerber | cm = atoms.get_center_of_mass() |
89 | 1 | tkerber | atoms.translate(self.cm - cm)
|
90 | 1 | tkerber | rn = atoms.get_positions() |
91 | 1 | tkerber | if world is not None: |
92 | 1 | tkerber | world.broadcast(rn, 0)
|
93 | 1 | tkerber | atoms.set_positions(rn) |
94 | 1 | tkerber | return atoms.get_positions()
|
95 | 1 | tkerber | |
96 | 1 | tkerber | def get_minimum(self): |
97 | 1 | tkerber | atoms = self.atoms.copy()
|
98 | 1 | tkerber | atoms.set_positions(self.rmin)
|
99 | 1 | tkerber | return self.Emin, atoms |
100 | 1 | tkerber | |
101 | 1 | tkerber | def get_energy(self, positions): |
102 | 1 | tkerber | """Return the energy of the nearest local minimum."""
|
103 | 1 | tkerber | if np.sometrue(self.positions != positions): |
104 | 1 | tkerber | self.positions = positions
|
105 | 1 | tkerber | self.atoms.set_positions(positions)
|
106 | 1 | tkerber | |
107 | 1 | tkerber | try:
|
108 | 1 | tkerber | opt = self.optimizer(self.atoms, logfile=self.optimizer_logfile) |
109 | 1 | tkerber | opt.run(fmax=self.fmax)
|
110 | 1 | tkerber | if self.lm_trajectory is not None: |
111 | 1 | tkerber | self.lm_trajectory.write(self.atoms) |
112 | 1 | tkerber | |
113 | 1 | tkerber | self.energy = self.atoms.get_potential_energy() |
114 | 1 | tkerber | except:
|
115 | 1 | tkerber | # the atoms are probably to near to each other
|
116 | 1 | tkerber | self.energy = 1.e32 |
117 | 1 | tkerber | |
118 | 1 | tkerber | return self.energy |