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