root / ase / optimize / basin.py @ 14
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 |