Statistiques
| Révision :

root / ase / calculators / emt.py @ 1

Historique | Voir | Annoter | Télécharger (11,07 ko)

1 1 tkerber
"""Effective medium theory potential."""
2 1 tkerber
3 1 tkerber
from math import sqrt, exp, log, pi
4 1 tkerber
5 1 tkerber
import numpy as np
6 1 tkerber
import sys
7 1 tkerber
8 1 tkerber
from ase.data import atomic_numbers, chemical_symbols
9 1 tkerber
from ase.units import Bohr
10 1 tkerber
11 1 tkerber
12 1 tkerber
parameters = {
13 1 tkerber
#          E0     s0    V0     eta2    kappa   lambda  n0
14 1 tkerber
#          eV     bohr  eV     bohr^-1 bohr^-1 bohr^-1 bohr^-3
15 1 tkerber
    'H':  (-2.21, 0.71, 2.132, 1.652,  2.790,  1.892,  0.00547, 'dimer'),
16 1 tkerber
    'Al': (-3.28, 3.00, 1.493, 1.240,  2.000,  1.169,  0.00700, 'fcc'),
17 1 tkerber
    'Cu': (-3.51, 2.67, 2.476, 1.652,  2.740,  1.906,  0.00910, 'fcc'),
18 1 tkerber
    'Ag': (-2.96, 3.01, 2.132, 1.652,  2.790,  1.892,  0.00547, 'fcc'),
19 1 tkerber
    'Au': (-3.80, 3.00, 2.321, 1.674,  2.873,  2.182,  0.00703, 'fcc'),
20 1 tkerber
    'Ni': (-4.44, 2.60, 3.673, 1.669,  2.757,  1.948,  0.01030, 'fcc'),
21 1 tkerber
    'Pd': (-3.90, 2.87, 2.773, 1.818,  3.107,  2.155,  0.00688, 'fcc'),
22 1 tkerber
    'Pt': (-5.85, 2.90, 4.067, 1.812,  3.145,  2.192,  0.00802, 'fcc'),
23 1 tkerber
    'C':  (-1.97, 1.18, 0.132, 3.652,  5.790,  2.892,  0.01322, 'dimer'),
24 1 tkerber
    'N':  (-4.97, 1.18, 0.132, 2.652,  3.790,  2.892,  0.01222, 'dimer'),
25 1 tkerber
    'O':  (-2.97, 1.25, 2.132, 3.652,  5.790,  4.892,  0.00850, 'dimer')}
26 1 tkerber
27 1 tkerber
beta = 1.809     #(16 * pi / 3)**(1.0 / 3) / 2**0.5
28 1 tkerber
#                 but preserve historical rounding.
29 1 tkerber
30 1 tkerber
#eta1 = 0.5 / Bohr
31 1 tkerber
32 1 tkerber
class EMT:
33 1 tkerber
    disabled = False  # Set to True to disable (asap does this).
34 1 tkerber
35 1 tkerber
    def __init__(self, fix_alloys=False):
36 1 tkerber
        self.energy = None
37 1 tkerber
        self.fix_alloys = fix_alloys
38 1 tkerber
        if self.disabled:
39 1 tkerber
            print >>sys.stderr, """
40 1 tkerber
            ase.EMT has been disabled by Asap.  Most likely, you
41 1 tkerber
            intended to use Asap's EMT calculator, but accidentally
42 1 tkerber
            imported ase's EMT calculator after Asap's.  This could
43 1 tkerber
            happen if your script contains the lines
44 1 tkerber

45 1 tkerber
              from asap3 import *
46 1 tkerber
              from ase.calculators.emt import EMT
47 1 tkerber
            Swap the two lines to solve the problem.
48 1 tkerber

49 1 tkerber
            (or 'from ase import *' in older versions of ASE.) Swap
50 1 tkerber
            the two lines to solve the problem.
51 1 tkerber

52 1 tkerber
            In the UNLIKELY event that you actually wanted to use
53 1 tkerber
            ase.calculators.emt.EMT although asap3 is loaded into memory, please
54 1 tkerber
            reactivate it with the command
55 1 tkerber
              ase.calculators.emt.EMT.disabled = False
56 1 tkerber
            """
57 1 tkerber
            raise RuntimeError('ase.EMT has been disabled.  ' +
58 1 tkerber
                               'See message printed above.')
59 1 tkerber
60 1 tkerber
    def get_spin_polarized(self):
61 1 tkerber
        return False
62 1 tkerber
63 1 tkerber
    def initialize(self, atoms):
64 1 tkerber
        self.par = {}
65 1 tkerber
        self.rc = 0.0
66 1 tkerber
        self.numbers = atoms.get_atomic_numbers()
67 1 tkerber
        maxseq = 0.0
68 1 tkerber
        seen = {}
69 1 tkerber
        for Z in self.numbers:
70 1 tkerber
            if Z not in seen:
71 1 tkerber
                seen[Z] = True
72 1 tkerber
                ss = parameters[chemical_symbols[Z]][1] * Bohr
73 1 tkerber
                if maxseq < ss:
74 1 tkerber
                    maxseq = ss
75 1 tkerber
        rc = self.rc = beta * maxseq * 0.5 * (sqrt(3) + sqrt(4))
76 1 tkerber
        rr = rc * 2 * sqrt(4) / (sqrt(3) + sqrt(4))
77 1 tkerber
        self.acut = np.log(9999.0) / (rr - rc)
78 1 tkerber
        for Z in self.numbers:
79 1 tkerber
            if Z not in self.par:
80 1 tkerber
                p = parameters[chemical_symbols[Z]]
81 1 tkerber
                s0 = p[1] * Bohr
82 1 tkerber
                eta2 = p[3] / Bohr
83 1 tkerber
                kappa = p[4] / Bohr
84 1 tkerber
                x = eta2 * beta * s0
85 1 tkerber
                gamma1 = 0.0
86 1 tkerber
                gamma2 = 0.0
87 1 tkerber
                if p[7] == 'fcc':
88 1 tkerber
                    for i, n in enumerate([12, 6, 24, 12]):
89 1 tkerber
                        r = s0 * beta * sqrt(i + 1)
90 1 tkerber
                        x = n / (12 * (1.0 + exp(self.acut * (r - rc))))
91 1 tkerber
                        gamma1 += x * exp(-eta2 * (r - beta * s0))
92 1 tkerber
                        gamma2 += x * exp(-kappa / beta * (r - beta * s0))
93 1 tkerber
                elif p[7] == 'dimer':
94 1 tkerber
                    r = s0 * beta
95 1 tkerber
                    n = 1
96 1 tkerber
                    x = n / (12 * (1.0 + exp(self.acut * (r - rc))))
97 1 tkerber
                    gamma1 += x * exp(-eta2 * (r - beta * s0))
98 1 tkerber
                    gamma2 += x * exp(-kappa / beta * (r - beta * s0))
99 1 tkerber
                else:
100 1 tkerber
                    raise RuntimeError
101 1 tkerber
102 1 tkerber
                self.par[Z] = {'E0': p[0],
103 1 tkerber
                               's0': s0,
104 1 tkerber
                               'V0': p[2],
105 1 tkerber
                               'eta2': eta2,
106 1 tkerber
                               'kappa': kappa,
107 1 tkerber
                               'lambda': p[5] / Bohr,
108 1 tkerber
                               'n0': p[6] / Bohr**3,
109 1 tkerber
                               'rc': rc,
110 1 tkerber
                               'gamma1': gamma1,
111 1 tkerber
                               'gamma2': gamma2}
112 1 tkerber
                #if rc + 0.5 > self.rc:
113 1 tkerber
                #    self.rc = rc + 0.5
114 1 tkerber
115 1 tkerber
        self.ksi = {}
116 1 tkerber
        for s1, p1 in self.par.items():
117 1 tkerber
            self.ksi[s1] = {}
118 1 tkerber
            for s2, p2 in self.par.items():
119 1 tkerber
                #self.ksi[s1][s2] = (p2['n0'] / p1['n0'] *
120 1 tkerber
                #                    exp(eta1 * (p1['s0'] - p2['s0'])))
121 1 tkerber
                self.ksi[s1][s2] = p2['n0'] / p1['n0']
122 1 tkerber
123 1 tkerber
        self.forces = np.empty((len(atoms), 3))
124 1 tkerber
        self.sigma1 = np.empty(len(atoms))
125 1 tkerber
        self.deds = np.empty(len(atoms))
126 1 tkerber
127 1 tkerber
    def update(self, atoms):
128 1 tkerber
        if (self.energy is None or
129 1 tkerber
            len(self.numbers) != len(atoms) or
130 1 tkerber
            (self.numbers != atoms.get_atomic_numbers()).any()):
131 1 tkerber
            self.initialize(atoms)
132 1 tkerber
            self.calculate(atoms)
133 1 tkerber
        elif ((self.positions != atoms.get_positions()).any() or
134 1 tkerber
              (self.pbc != atoms.get_pbc()).any() or
135 1 tkerber
              (self.cell != atoms.get_cell()).any()):
136 1 tkerber
            self.calculate(atoms)
137 1 tkerber
138 1 tkerber
    def calculation_required(self, atoms, quantities):
139 1 tkerber
        if len(quantities) == 0:
140 1 tkerber
            return False
141 1 tkerber
142 1 tkerber
        return (self.energy is None or
143 1 tkerber
                len(self.numbers) != len(atoms) or
144 1 tkerber
                (self.numbers != atoms.get_atomic_numbers()).any() or
145 1 tkerber
                (self.positions != atoms.get_positions()).any() or
146 1 tkerber
                (self.pbc != atoms.get_pbc()).any() or
147 1 tkerber
                (self.cell != atoms.get_cell()).any())
148 1 tkerber
149 1 tkerber
    def get_potential_energy(self, atoms):
150 1 tkerber
        self.update(atoms)
151 1 tkerber
        return self.energy
152 1 tkerber
153 1 tkerber
    def get_numeric_forces(self, atoms):
154 1 tkerber
        self.update(atoms)
155 1 tkerber
        p = atoms.positions
156 1 tkerber
        p0 = p.copy()
157 1 tkerber
        forces = np.empty_like(p)
158 1 tkerber
        eps = 0.0001
159 1 tkerber
        for a in range(len(p)):
160 1 tkerber
            for c in range(3):
161 1 tkerber
                p[a, c] += eps
162 1 tkerber
                self.calculate(atoms)
163 1 tkerber
                de = self.energy
164 1 tkerber
                p[a, c] -= 2 * eps
165 1 tkerber
                self.calculate(atoms)
166 1 tkerber
                de -= self.energy
167 1 tkerber
                p[a, c] += eps
168 1 tkerber
                forces[a, c] = -de / (2 * eps)
169 1 tkerber
        p[:] = p0
170 1 tkerber
        return forces
171 1 tkerber
172 1 tkerber
    def get_forces(self, atoms):
173 1 tkerber
        self.update(atoms)
174 1 tkerber
        return self.forces.copy()
175 1 tkerber
176 1 tkerber
    def get_stress(self, atoms):
177 1 tkerber
        raise NotImplementedError
178 1 tkerber
179 1 tkerber
    def calculate(self, atoms):
180 1 tkerber
        self.positions = atoms.get_positions().copy()
181 1 tkerber
        self.cell = atoms.get_cell().copy()
182 1 tkerber
        self.pbc = atoms.get_pbc().copy()
183 1 tkerber
184 1 tkerber
        icell = np.linalg.inv(self.cell)
185 1 tkerber
        scaled = np.dot(self.positions, icell)
186 1 tkerber
        N = []
187 1 tkerber
        for i in range(3):
188 1 tkerber
            if self.pbc[i]:
189 1 tkerber
                scaled[:, i] %= 1.0
190 1 tkerber
                v = icell[:, i]
191 1 tkerber
                h = 1 / sqrt(np.dot(v, v))
192 1 tkerber
                N.append(int(self.rc / h) + 1)
193 1 tkerber
            else:
194 1 tkerber
                N.append(0)
195 1 tkerber
196 1 tkerber
        R = np.dot(scaled, self.cell)
197 1 tkerber
198 1 tkerber
        self.energy = 0.0
199 1 tkerber
        self.sigma1[:] = 0.0
200 1 tkerber
        self.forces[:] = 0.0
201 1 tkerber
202 1 tkerber
        N1, N2, N3 = N
203 1 tkerber
        natoms = len(atoms)
204 1 tkerber
        for i1 in range(-N1, N1 + 1):
205 1 tkerber
            for i2 in range(-N2, N2 + 1):
206 1 tkerber
                for i3 in range(-N3, N3 + 1):
207 1 tkerber
                    C = np.dot((i1, i2, i3), self.cell)
208 1 tkerber
                    Q = R + C
209 1 tkerber
                    c = (i1 == 0 and i2 == 0 and i3 == 0)
210 1 tkerber
                    for a1 in range(natoms):
211 1 tkerber
                        Z1 = self.numbers[a1]
212 1 tkerber
                        p1 = self.par[Z1]
213 1 tkerber
                        ksi = self.ksi[Z1]
214 1 tkerber
                        for a2 in range(natoms):
215 1 tkerber
                            if c and a2 == a1:
216 1 tkerber
                                continue
217 1 tkerber
                            d = Q[a2] - R[a1]
218 1 tkerber
                            r = sqrt(np.dot(d, d))
219 1 tkerber
                            if r < self.rc + 0.5:
220 1 tkerber
                                Z2 = self.numbers[a2]
221 1 tkerber
                                if self.fix_alloys:
222 1 tkerber
                                    p2 = self.par[Z2]
223 1 tkerber
                                else:
224 1 tkerber
                                    p2 = p1  # Old buggy behaviour
225 1 tkerber
                                self.interact1(a1, a2, d, r, p1, p2, ksi[Z2])
226 1 tkerber
227 1 tkerber
        for a in range(natoms):
228 1 tkerber
            Z = self.numbers[a]
229 1 tkerber
            p = self.par[Z]
230 1 tkerber
            try:
231 1 tkerber
                ds = -log(self.sigma1[a] / 12) / (beta * p['eta2'])
232 1 tkerber
            except (OverflowError, ValueError):
233 1 tkerber
                self.deds[a] = 0.0
234 1 tkerber
                self.energy -= p['E0']
235 1 tkerber
                continue
236 1 tkerber
            x = p['lambda'] * ds
237 1 tkerber
            y = exp(-x)
238 1 tkerber
            z = 6 * p['V0'] * exp(-p['kappa'] * ds)
239 1 tkerber
            self.deds[a] = ((x * y * p['E0'] * p['lambda'] + p['kappa'] * z) /
240 1 tkerber
                            (self.sigma1[a] * beta * p['eta2']))
241 1 tkerber
            e = p['E0'] * ((1 + x) * y - 1) + z
242 1 tkerber
            self.energy += p['E0'] * ((1 + x) * y - 1) + z
243 1 tkerber
244 1 tkerber
        for i1 in range(-N1, N1 + 1):
245 1 tkerber
            for i2 in range(-N2, N2 + 1):
246 1 tkerber
                for i3 in range(-N3, N3 + 1):
247 1 tkerber
                    C = np.dot((i1, i2, i3), self.cell)
248 1 tkerber
                    Q = R + C
249 1 tkerber
                    c = (i1 == 0 and i2 == 0 and i3 == 0)
250 1 tkerber
                    for a1 in range(natoms):
251 1 tkerber
                        Z1 = self.numbers[a1]
252 1 tkerber
                        p1 = self.par[Z1]
253 1 tkerber
                        ksi = self.ksi[Z1]
254 1 tkerber
                        for a2 in range(natoms):
255 1 tkerber
                            if c and a2 == a1:
256 1 tkerber
                                continue
257 1 tkerber
                            d = Q[a2] - R[a1]
258 1 tkerber
                            r = sqrt(np.dot(d, d))
259 1 tkerber
                            if r < self.rc + 0.5:
260 1 tkerber
                                Z2 = self.numbers[a2]
261 1 tkerber
                                if self.fix_alloys:
262 1 tkerber
                                    p2 = self.par[Z2]
263 1 tkerber
                                else:
264 1 tkerber
                                    p2 = p1  # Old buggy behaviour
265 1 tkerber
                                self.interact2(a1, a2, d, r, p1, p2, ksi[Z2])
266 1 tkerber
267 1 tkerber
    def interact1(self, a1, a2, d, r, p1, p2, ksi):
268 1 tkerber
        x = exp(self.acut * (r - self.rc))
269 1 tkerber
        theta = 1.0 / (1.0 + x)
270 1 tkerber
        y = (0.5 * p1['V0'] * exp(-p2['kappa'] * (r / beta - p2['s0'])) *
271 1 tkerber
             ksi / p1['gamma2'] * theta)
272 1 tkerber
        self.energy -= y
273 1 tkerber
        f = y * (p2['kappa'] / beta + self.acut * theta * x) * d / r
274 1 tkerber
        self.forces[a1] += f
275 1 tkerber
        self.forces[a2] -= f
276 1 tkerber
        self.sigma1[a1] += (exp(-p2['eta2'] * (r - beta * p2['s0'])) *
277 1 tkerber
                            ksi * theta / p1['gamma1'])
278 1 tkerber
279 1 tkerber
    def interact2(self, a1, a2, d, r, p1, p2, ksi):
280 1 tkerber
        x = exp(self.acut * (r - self.rc))
281 1 tkerber
        theta = 1.0 / (1.0 + x)
282 1 tkerber
        y = (exp(-p2['eta2'] * (r - beta * p2['s0'])) *
283 1 tkerber
             ksi / p1['gamma1'] * theta * self.deds[a1])
284 1 tkerber
        f = y * (p2['eta2'] + self.acut * theta * x) * d / r
285 1 tkerber
        self.forces[a1] -= f
286 1 tkerber
        self.forces[a2] += f