root / ase / calculators / elk.py @ 16
Historique | Voir | Annoter | Télécharger (4,99 ko)
1 | 1 | tkerber | import os |
---|---|---|---|
2 | 1 | tkerber | |
3 | 1 | tkerber | import numpy as np |
4 | 1 | tkerber | |
5 | 1 | tkerber | from ase.units import Bohr, Hartree |
6 | 1 | tkerber | |
7 | 1 | tkerber | elk_parameters = { |
8 | 1 | tkerber | 'swidth': Hartree,
|
9 | 1 | tkerber | } |
10 | 1 | tkerber | |
11 | 1 | tkerber | class ELK: |
12 | 1 | tkerber | def __init__(self, dir='.', xc=None, kpts=None, tasks=[0], **kwargs): |
13 | 1 | tkerber | for key, value in kwargs.items(): |
14 | 1 | tkerber | if key in elk_parameters: |
15 | 1 | tkerber | kwargs[key] /= elk_parameters[key] |
16 | 1 | tkerber | |
17 | 1 | tkerber | if xc is not None: |
18 | 1 | tkerber | if 'xctype' in kwargs: |
19 | 1 | tkerber | raise ValueError("You can't use both 'xc' and 'xctype'!") |
20 | 1 | tkerber | else:
|
21 | 1 | tkerber | kwargs['xctype'] = {'LDA': 3, # PW92 |
22 | 1 | tkerber | 'PBE': 20, |
23 | 1 | tkerber | 'REVPBE': 21, |
24 | 1 | tkerber | 'PBESOL': 22, |
25 | 1 | tkerber | 'WC06': 26, |
26 | 1 | tkerber | 'AM05': 30}[xc.upper()] |
27 | 1 | tkerber | |
28 | 1 | tkerber | if kpts is not None: |
29 | 1 | tkerber | if 'autokpt' in kwargs: |
30 | 1 | tkerber | if kwargs['autokpt']: |
31 | 1 | tkerber | raise ValueError("You can't use both 'kpts' and 'autokpt'!") |
32 | 1 | tkerber | if 'ngridk' in kwargs: |
33 | 1 | tkerber | raise ValueError("You can't use both 'kpts' and 'ngridk'!") |
34 | 1 | tkerber | if 'vkloff' in kwargs: |
35 | 1 | tkerber | raise ValueError("You can't use both 'kpts' and 'vkloff'!") |
36 | 1 | tkerber | else:
|
37 | 1 | tkerber | kwargs['ngridk'] = kpts
|
38 | 1 | tkerber | vkloff = [] |
39 | 1 | tkerber | for nk in kpts: |
40 | 1 | tkerber | if nk % 2 == 0: # shift kpoint away from gamma point |
41 | 1 | tkerber | vkloff.append(0.5 / nk)
|
42 | 1 | tkerber | else:
|
43 | 1 | tkerber | vkloff.append(0)
|
44 | 1 | tkerber | kwargs['vkloff'] = vkloff
|
45 | 1 | tkerber | |
46 | 1 | tkerber | kwargs['tasks'] = tasks
|
47 | 1 | tkerber | |
48 | 1 | tkerber | self.parameters = kwargs
|
49 | 1 | tkerber | |
50 | 1 | tkerber | self.dir = dir |
51 | 1 | tkerber | self.energy = None |
52 | 1 | tkerber | |
53 | 1 | tkerber | self.converged = False |
54 | 1 | tkerber | |
55 | 1 | tkerber | def update(self, atoms): |
56 | 1 | tkerber | if (not self.converged or |
57 | 1 | tkerber | len(self.numbers) != len(atoms) or |
58 | 1 | tkerber | (self.numbers != atoms.get_atomic_numbers()).any()):
|
59 | 1 | tkerber | self.initialize(atoms)
|
60 | 1 | tkerber | self.calculate(atoms)
|
61 | 1 | tkerber | elif ((self.positions != atoms.get_positions()).any() or |
62 | 1 | tkerber | (self.pbc != atoms.get_pbc()).any() or |
63 | 1 | tkerber | (self.cell != atoms.get_cell()).any()):
|
64 | 1 | tkerber | self.calculate(atoms)
|
65 | 1 | tkerber | |
66 | 1 | tkerber | def initialize(self, atoms): |
67 | 1 | tkerber | self.numbers = atoms.get_atomic_numbers().copy()
|
68 | 1 | tkerber | self.write(atoms)
|
69 | 1 | tkerber | |
70 | 1 | tkerber | def get_potential_energy(self, atoms): |
71 | 1 | tkerber | self.update(atoms)
|
72 | 1 | tkerber | return self.energy |
73 | 1 | tkerber | |
74 | 1 | tkerber | def get_forces(self, atoms): |
75 | 1 | tkerber | self.update(atoms)
|
76 | 1 | tkerber | return self.forces.copy() |
77 | 1 | tkerber | |
78 | 1 | tkerber | def get_stress(self, atoms): |
79 | 1 | tkerber | self.update(atoms)
|
80 | 1 | tkerber | return self.stress.copy() |
81 | 1 | tkerber | |
82 | 1 | tkerber | def calculate(self, atoms): |
83 | 1 | tkerber | self.positions = atoms.get_positions().copy()
|
84 | 1 | tkerber | self.cell = atoms.get_cell().copy()
|
85 | 1 | tkerber | self.pbc = atoms.get_pbc().copy()
|
86 | 1 | tkerber | |
87 | 1 | tkerber | self.initialize(atoms)
|
88 | 1 | tkerber | assert os.system('cd %s; elk' % self.dir) == 0 |
89 | 1 | tkerber | self.read()
|
90 | 1 | tkerber | |
91 | 1 | tkerber | self.converged = True |
92 | 1 | tkerber | |
93 | 1 | tkerber | def write(self, atoms): |
94 | 1 | tkerber | if not os.path.isdir(self.dir): |
95 | 1 | tkerber | os.mkdir(self.dir)
|
96 | 1 | tkerber | fd = open('%s/elk.in' % self.dir, 'w') |
97 | 1 | tkerber | for key, value in self.parameters.items(): |
98 | 1 | tkerber | fd.write('%s\n' % key)
|
99 | 1 | tkerber | if isinstance(value, bool): |
100 | 1 | tkerber | fd.write('.%s.\n\n' % ('false', 'true')[value]) |
101 | 1 | tkerber | elif isinstance(value, (int, float)): |
102 | 1 | tkerber | fd.write('%s\n\n' % value)
|
103 | 1 | tkerber | else:
|
104 | 1 | tkerber | fd.write('%s\n\n' % ' '.join([str(x) for x in value])) |
105 | 1 | tkerber | |
106 | 1 | tkerber | fd.write('avec\n')
|
107 | 1 | tkerber | for vec in atoms.cell: |
108 | 1 | tkerber | fd.write('%.14f %.14f %.14f\n' % tuple(vec / Bohr)) |
109 | 1 | tkerber | fd.write('\n')
|
110 | 1 | tkerber | |
111 | 1 | tkerber | fd.write("sppath\n'%s'\n\n" % os.environ['ELK_SPECIES_PATH']) |
112 | 1 | tkerber | |
113 | 1 | tkerber | species = {} |
114 | 1 | tkerber | symbols = [] |
115 | 1 | tkerber | for a, symbol in enumerate(atoms.get_chemical_symbols()): |
116 | 1 | tkerber | if symbol in species: |
117 | 1 | tkerber | species[symbol].append(a) |
118 | 1 | tkerber | else:
|
119 | 1 | tkerber | species[symbol] = [a] |
120 | 1 | tkerber | symbols.append(symbol) |
121 | 1 | tkerber | fd.write('atoms\n%d\n' % len(species)) |
122 | 1 | tkerber | scaled = atoms.get_scaled_positions() |
123 | 1 | tkerber | for symbol in symbols: |
124 | 1 | tkerber | fd.write("'%s.in'\n" % symbol)
|
125 | 1 | tkerber | fd.write('%d\n' % len(species[symbol])) |
126 | 1 | tkerber | for a in species[symbol]: |
127 | 1 | tkerber | fd.write('%.14f %.14f %.14f 0.0 0.0 0.0\n' % tuple(scaled[a])) |
128 | 1 | tkerber | |
129 | 1 | tkerber | def read(self): |
130 | 1 | tkerber | fd = open('%s/TOTENERGY.OUT' % self.dir, 'r') |
131 | 1 | tkerber | self.energy = float(fd.readlines()[-1]) * Hartree |
132 | 1 | tkerber | # Forces:
|
133 | 1 | tkerber | INFO_file = '%s/INFO.OUT' % self.dir |
134 | 1 | tkerber | if os.path.isfile(INFO_file) or os.path.islink(INFO_file): |
135 | 1 | tkerber | text = open(INFO_file).read().lower()
|
136 | 1 | tkerber | assert 'convergence targets achieved' in text |
137 | 1 | tkerber | assert not 'reached self-consistent loops maximum' in text |
138 | 1 | tkerber | lines = iter(text.split('\n')) |
139 | 1 | tkerber | forces = [] |
140 | 1 | tkerber | atomnum = 0
|
141 | 1 | tkerber | for line in lines: |
142 | 1 | tkerber | if line.rfind('total force') > -1: |
143 | 1 | tkerber | forces.append(np.array([float(f) for f in line.split(':')[1].split()])) |
144 | 1 | tkerber | atomnum =+ 1
|
145 | 1 | tkerber | self.forces = np.array(forces)
|
146 | 1 | tkerber | else:
|
147 | 1 | tkerber | raise RuntimeError |
148 | 1 | tkerber | # Stress
|
149 | 1 | tkerber | self.stress = np.empty((3, 3)) |