root / ase / gui / images.py @ 15
Historique | Voir | Annoter | Télécharger (12,65 ko)
1 | 1 | tkerber | from math import sqrt |
---|---|---|---|
2 | 1 | tkerber | |
3 | 1 | tkerber | import numpy as np |
4 | 1 | tkerber | |
5 | 1 | tkerber | from ase.data import covalent_radii |
6 | 1 | tkerber | from ase.atoms import Atoms |
7 | 1 | tkerber | from ase.calculators.singlepoint import SinglePointCalculator |
8 | 1 | tkerber | from ase.io import read, write, string2index |
9 | 1 | tkerber | from ase.constraints import FixAtoms |
10 | 1 | tkerber | |
11 | 1 | tkerber | |
12 | 1 | tkerber | class Images: |
13 | 1 | tkerber | def __init__(self, images=None): |
14 | 1 | tkerber | |
15 | 1 | tkerber | if images is not None: |
16 | 1 | tkerber | self.initialize(images)
|
17 | 1 | tkerber | |
18 | 1 | tkerber | def initialize(self, images, filenames=None, init_magmom=False): |
19 | 1 | tkerber | |
20 | 1 | tkerber | self.natoms = len(images[0]) |
21 | 1 | tkerber | |
22 | 1 | tkerber | self.nimages = len(images) |
23 | 1 | tkerber | if filenames is None: |
24 | 1 | tkerber | filenames = [None] * self.nimages |
25 | 1 | tkerber | self.filenames = filenames
|
26 | 1 | tkerber | self.P = np.empty((self.nimages, self.natoms, 3)) |
27 | 1 | tkerber | self.E = np.empty(self.nimages) |
28 | 1 | tkerber | self.K = np.empty(self.nimages) |
29 | 1 | tkerber | self.F = np.empty((self.nimages, self.natoms, 3)) |
30 | 1 | tkerber | self.M = np.empty((self.nimages, self.natoms)) |
31 | 1 | tkerber | self.T = np.empty((self.natoms)) |
32 | 1 | tkerber | self.A = np.empty((self.nimages, 3, 3)) |
33 | 1 | tkerber | self.Z = images[0].get_atomic_numbers() |
34 | 1 | tkerber | self.pbc = images[0].get_pbc() |
35 | 1 | tkerber | warning = False
|
36 | 1 | tkerber | for i, atoms in enumerate(images): |
37 | 1 | tkerber | natomsi = len(atoms)
|
38 | 1 | tkerber | if (natomsi != self.natoms or |
39 | 1 | tkerber | (atoms.get_atomic_numbers() != self.Z).any()):
|
40 | 1 | tkerber | raise RuntimeError('Can not handle different images with ' + |
41 | 1 | tkerber | 'different numbers of atoms or different ' +
|
42 | 1 | tkerber | 'kinds of atoms!')
|
43 | 1 | tkerber | self.P[i] = atoms.get_positions()
|
44 | 1 | tkerber | self.A[i] = atoms.get_cell()
|
45 | 1 | tkerber | if (atoms.get_pbc() != self.pbc).any(): |
46 | 1 | tkerber | warning = True
|
47 | 1 | tkerber | try:
|
48 | 1 | tkerber | self.E[i] = atoms.get_potential_energy()
|
49 | 1 | tkerber | except RuntimeError: |
50 | 1 | tkerber | self.E[i] = np.nan
|
51 | 1 | tkerber | self.K[i] = atoms.get_kinetic_energy()
|
52 | 1 | tkerber | try:
|
53 | 1 | tkerber | self.F[i] = atoms.get_forces(apply_constraint=False) |
54 | 1 | tkerber | except RuntimeError: |
55 | 1 | tkerber | self.F[i] = np.nan
|
56 | 1 | tkerber | try:
|
57 | 1 | tkerber | if init_magmom:
|
58 | 1 | tkerber | self.M[i] = atoms.get_initial_magnetic_moments()
|
59 | 1 | tkerber | else:
|
60 | 1 | tkerber | self.M[i] = atoms.get_magnetic_moments()
|
61 | 1 | tkerber | except (RuntimeError, AttributeError): |
62 | 1 | tkerber | self.M[i] = 0.0 |
63 | 1 | tkerber | |
64 | 1 | tkerber | # added support for tags
|
65 | 1 | tkerber | try:
|
66 | 1 | tkerber | self.T = atoms.get_tags()
|
67 | 1 | tkerber | except RuntimeError: |
68 | 1 | tkerber | self.T = np.nan
|
69 | 1 | tkerber | |
70 | 1 | tkerber | |
71 | 1 | tkerber | if warning:
|
72 | 1 | tkerber | print('WARNING: Not all images have the same bondary conditions!')
|
73 | 1 | tkerber | |
74 | 1 | tkerber | self.selected = np.zeros(self.natoms, bool) |
75 | 1 | tkerber | self.selected_ordered = []
|
76 | 1 | tkerber | self.atoms_to_rotate_0 = np.zeros(self.natoms, bool) |
77 | 1 | tkerber | self.visible = np.ones(self.natoms, bool) |
78 | 1 | tkerber | self.nselected = 0 |
79 | 1 | tkerber | self.set_dynamic(constraints = images[0].constraints) |
80 | 1 | tkerber | self.repeat = np.ones(3, int) |
81 | 1 | tkerber | self.set_radii(0.89) |
82 | 1 | tkerber | |
83 | 1 | tkerber | def prepare_new_atoms(self): |
84 | 1 | tkerber | "Marks that the next call to append_atoms should clear the images."
|
85 | 1 | tkerber | self.next_append_clears = True |
86 | 1 | tkerber | |
87 | 1 | tkerber | def append_atoms(self, atoms, filename=None): |
88 | 1 | tkerber | "Append an atoms object to the images already stored."
|
89 | 1 | tkerber | assert len(atoms) == self.natoms |
90 | 1 | tkerber | if self.next_append_clears: |
91 | 1 | tkerber | i = 0
|
92 | 1 | tkerber | else:
|
93 | 1 | tkerber | i = self.nimages
|
94 | 1 | tkerber | for name in ('P', 'E', 'K', 'F', 'M', 'A'): |
95 | 1 | tkerber | a = getattr(self, name) |
96 | 1 | tkerber | newa = np.empty( (i+1,) + a.shape[1:] ) |
97 | 1 | tkerber | if not self.next_append_clears: |
98 | 1 | tkerber | newa[:-1] = a
|
99 | 1 | tkerber | setattr(self, name, newa) |
100 | 1 | tkerber | self.next_append_clears = False |
101 | 1 | tkerber | self.P[i] = atoms.get_positions()
|
102 | 1 | tkerber | self.A[i] = atoms.get_cell()
|
103 | 1 | tkerber | try:
|
104 | 1 | tkerber | self.E[i] = atoms.get_potential_energy()
|
105 | 1 | tkerber | except RuntimeError: |
106 | 1 | tkerber | self.E[i] = np.nan
|
107 | 1 | tkerber | self.K[i] = atoms.get_kinetic_energy()
|
108 | 1 | tkerber | try:
|
109 | 1 | tkerber | self.F[i] = atoms.get_forces(apply_constraint=False) |
110 | 1 | tkerber | except RuntimeError: |
111 | 1 | tkerber | self.F[i] = np.nan
|
112 | 1 | tkerber | try:
|
113 | 1 | tkerber | self.M[i] = atoms.get_magnetic_moments()
|
114 | 1 | tkerber | except (RuntimeError, AttributeError): |
115 | 1 | tkerber | self.M[i] = np.nan
|
116 | 1 | tkerber | self.nimages = i + 1 |
117 | 1 | tkerber | self.filenames.append(filename)
|
118 | 1 | tkerber | self.set_dynamic()
|
119 | 1 | tkerber | return self.nimages |
120 | 1 | tkerber | |
121 | 1 | tkerber | def set_radii(self, scale): |
122 | 1 | tkerber | self.r = covalent_radii[self.Z] * scale |
123 | 1 | tkerber | |
124 | 1 | tkerber | def read(self, filenames, index=-1): |
125 | 1 | tkerber | images = [] |
126 | 1 | tkerber | names = [] |
127 | 1 | tkerber | for filename in filenames: |
128 | 1 | tkerber | i = read(filename, index) |
129 | 1 | tkerber | |
130 | 1 | tkerber | if not isinstance(i, list): |
131 | 1 | tkerber | i = [i] |
132 | 1 | tkerber | images.extend(i) |
133 | 1 | tkerber | names.extend([filename] * len(i))
|
134 | 1 | tkerber | |
135 | 1 | tkerber | self.initialize(images, names)
|
136 | 1 | tkerber | |
137 | 1 | tkerber | def import_atoms(self, filename, cur_frame): |
138 | 1 | tkerber | if filename:
|
139 | 1 | tkerber | filename = filename[0]
|
140 | 1 | tkerber | old_a = self.get_atoms(cur_frame)
|
141 | 1 | tkerber | imp_a = read(filename, -1)
|
142 | 1 | tkerber | new_a = old_a + imp_a |
143 | 1 | tkerber | self.initialize([new_a], [filename])
|
144 | 1 | tkerber | |
145 | 1 | tkerber | def repeat_images(self, repeat): |
146 | 1 | tkerber | n = self.repeat.prod()
|
147 | 1 | tkerber | repeat = np.array(repeat) |
148 | 1 | tkerber | self.repeat = repeat
|
149 | 1 | tkerber | N = repeat.prod() |
150 | 1 | tkerber | natoms = self.natoms // n
|
151 | 1 | tkerber | P = np.empty((self.nimages, natoms * N, 3)) |
152 | 1 | tkerber | M = np.empty((self.nimages, natoms * N))
|
153 | 1 | tkerber | T = np.empty(natoms * N, int)
|
154 | 1 | tkerber | F = np.empty((self.nimages, natoms * N, 3)) |
155 | 1 | tkerber | Z = np.empty(natoms * N, int)
|
156 | 1 | tkerber | r = np.empty(natoms * N) |
157 | 1 | tkerber | dynamic = np.empty(natoms * N, bool)
|
158 | 1 | tkerber | a0 = 0
|
159 | 1 | tkerber | for i0 in range(repeat[0]): |
160 | 1 | tkerber | for i1 in range(repeat[1]): |
161 | 1 | tkerber | for i2 in range(repeat[2]): |
162 | 1 | tkerber | a1 = a0 + natoms |
163 | 1 | tkerber | for i in range(self.nimages): |
164 | 1 | tkerber | P[i, a0:a1] = (self.P[i, :natoms] +
|
165 | 1 | tkerber | np.dot((i0, i1, i2), self.A[i]))
|
166 | 1 | tkerber | F[:, a0:a1] = self.F[:, :natoms]
|
167 | 1 | tkerber | M[:, a0:a1] = self.M[:, :natoms]
|
168 | 1 | tkerber | T[a0:a1] = self.T[:natoms]
|
169 | 1 | tkerber | Z[a0:a1] = self.Z[:natoms]
|
170 | 1 | tkerber | r[a0:a1] = self.r[:natoms]
|
171 | 1 | tkerber | dynamic[a0:a1] = self.dynamic[:natoms]
|
172 | 1 | tkerber | a0 = a1 |
173 | 1 | tkerber | self.P = P
|
174 | 1 | tkerber | self.F = F
|
175 | 1 | tkerber | self.Z = Z
|
176 | 1 | tkerber | self.T = T
|
177 | 1 | tkerber | self.M = M
|
178 | 1 | tkerber | self.r = r
|
179 | 1 | tkerber | self.dynamic = dynamic
|
180 | 1 | tkerber | self.natoms = natoms * N
|
181 | 1 | tkerber | self.selected = np.zeros(natoms * N, bool) |
182 | 1 | tkerber | self.atoms_to_rotate_0 = np.zeros(self.natoms, bool) |
183 | 1 | tkerber | self.visible = np.ones(natoms * N, bool) |
184 | 1 | tkerber | self.nselected = 0 |
185 | 1 | tkerber | |
186 | 1 | tkerber | def graph(self, expr): |
187 | 1 | tkerber | import ase.units as units |
188 | 1 | tkerber | code = compile(expr + ',', 'atoms.py', 'eval') |
189 | 1 | tkerber | |
190 | 1 | tkerber | n = self.nimages
|
191 | 1 | tkerber | def d(n1, n2): |
192 | 1 | tkerber | return sqrt(((R[n1] - R[n2])**2).sum()) |
193 | 1 | tkerber | def a(n1, n2, n3): |
194 | 1 | tkerber | v1 = R[n1]-R[n2] |
195 | 1 | tkerber | v2 = R[n3]-R[n2] |
196 | 1 | tkerber | arg = np.vdot(v1,v2)/(sqrt((v1**2).sum()*(v2**2).sum())) |
197 | 1 | tkerber | if arg > 1.0: arg = 1.0 |
198 | 1 | tkerber | if arg < -1.0: arg = -1.0 |
199 | 1 | tkerber | return 180.0*np.arccos(arg)/np.pi |
200 | 1 | tkerber | def dih(n1, n2, n3, n4): |
201 | 1 | tkerber | # vector 0->1, 1->2, 2->3 and their normalized cross products:
|
202 | 1 | tkerber | a = R[n2]-R[n1] |
203 | 1 | tkerber | b = R[n3]-R[n2] |
204 | 1 | tkerber | c = R[n4]-R[n3] |
205 | 1 | tkerber | bxa = np.cross(b,a) |
206 | 1 | tkerber | bxa /= np.sqrt(np.vdot(bxa,bxa)) |
207 | 1 | tkerber | cxb = np.cross(c,b) |
208 | 1 | tkerber | cxb /= np.sqrt(np.vdot(cxb,cxb)) |
209 | 1 | tkerber | angle = np.vdot(bxa,cxb) |
210 | 1 | tkerber | # check for numerical trouble due to finite precision:
|
211 | 1 | tkerber | if angle < -1: angle = -1 |
212 | 1 | tkerber | if angle > 1: angle = 1 |
213 | 1 | tkerber | angle = np.arccos(angle) |
214 | 1 | tkerber | if (np.vdot(bxa,c)) > 0: angle = 2*np.pi-angle |
215 | 1 | tkerber | return angle*180.0/np.pi |
216 | 1 | tkerber | # get number of mobile atoms for temperature calculation
|
217 | 1 | tkerber | ndynamic = 0
|
218 | 1 | tkerber | for dyn in self.dynamic: |
219 | 1 | tkerber | if dyn: ndynamic += 1 |
220 | 1 | tkerber | S = self.selected
|
221 | 1 | tkerber | D = self.dynamic[:, np.newaxis]
|
222 | 1 | tkerber | E = self.E
|
223 | 1 | tkerber | s = 0.0
|
224 | 1 | tkerber | data = [] |
225 | 1 | tkerber | for i in range(n): |
226 | 1 | tkerber | R = self.P[i]
|
227 | 1 | tkerber | F = self.F[i]
|
228 | 1 | tkerber | A = self.A[i]
|
229 | 1 | tkerber | f = ((F * D)**2).sum(1)**.5 |
230 | 1 | tkerber | fmax = max(f)
|
231 | 1 | tkerber | fave = f.mean() |
232 | 1 | tkerber | epot = E[i] |
233 | 1 | tkerber | ekin = self.K[i]
|
234 | 1 | tkerber | e = epot + ekin |
235 | 1 | tkerber | T = 2.0 * ekin / (3.0 * ndynamic * units.kB) |
236 | 1 | tkerber | data = eval(code)
|
237 | 1 | tkerber | if i == 0: |
238 | 1 | tkerber | m = len(data)
|
239 | 1 | tkerber | xy = np.empty((m, n)) |
240 | 1 | tkerber | xy[:, i] = data |
241 | 1 | tkerber | if i + 1 < n: |
242 | 1 | tkerber | s += sqrt(((self.P[i + 1] - R)**2).sum()) |
243 | 1 | tkerber | return xy
|
244 | 1 | tkerber | |
245 | 1 | tkerber | def set_dynamic(self, constraints = None): |
246 | 1 | tkerber | if self.nimages == 1: |
247 | 1 | tkerber | self.dynamic = np.ones(self.natoms, bool) |
248 | 1 | tkerber | else:
|
249 | 1 | tkerber | self.dynamic = np.zeros(self.natoms, bool) |
250 | 1 | tkerber | R0 = self.P[0] |
251 | 1 | tkerber | for R in self.P[1:]: |
252 | 1 | tkerber | self.dynamic |= (np.abs(R - R0) > 1.0e-10).any(1) |
253 | 1 | tkerber | if constraints is not None: |
254 | 1 | tkerber | for con in constraints: |
255 | 1 | tkerber | if isinstance(con,FixAtoms): |
256 | 1 | tkerber | self.dynamic[con.index] = False |
257 | 1 | tkerber | |
258 | 1 | tkerber | def write(self, filename, rotations='', show_unit_cell=False, bbox=None): |
259 | 1 | tkerber | indices = range(self.nimages) |
260 | 1 | tkerber | p = filename.rfind('@')
|
261 | 1 | tkerber | if p != -1: |
262 | 1 | tkerber | try:
|
263 | 1 | tkerber | slice = string2index(filename[p + 1:])
|
264 | 1 | tkerber | except ValueError: |
265 | 1 | tkerber | pass
|
266 | 1 | tkerber | else:
|
267 | 1 | tkerber | indices = indices[slice]
|
268 | 1 | tkerber | filename = filename[:p] |
269 | 1 | tkerber | if isinstance(indices, int): |
270 | 1 | tkerber | indices = [indices] |
271 | 1 | tkerber | |
272 | 1 | tkerber | images = [self.get_atoms(i) for i in indices] |
273 | 1 | tkerber | if len(filename) > 4 and filename[-4:] in ['.eps', '.png', '.pov']: |
274 | 1 | tkerber | write(filename, images, |
275 | 1 | tkerber | rotation=rotations, show_unit_cell=show_unit_cell, |
276 | 1 | tkerber | bbox=bbox) |
277 | 1 | tkerber | else:
|
278 | 1 | tkerber | write(filename, images) |
279 | 1 | tkerber | |
280 | 1 | tkerber | def get_atoms(self, frame): |
281 | 1 | tkerber | atoms = Atoms(positions=self.P[frame],
|
282 | 1 | tkerber | numbers=self.Z,
|
283 | 1 | tkerber | magmoms=self.M[0], |
284 | 1 | tkerber | tags=self.T,
|
285 | 1 | tkerber | cell=self.A[frame],
|
286 | 1 | tkerber | pbc=self.pbc)
|
287 | 1 | tkerber | |
288 | 1 | tkerber | # check for constrained atoms and add them accordingly:
|
289 | 1 | tkerber | if not self.dynamic.all(): |
290 | 1 | tkerber | atoms.set_constraint(FixAtoms(mask=1-self.dynamic)) |
291 | 1 | tkerber | |
292 | 1 | tkerber | atoms.set_calculator(SinglePointCalculator(self.E[frame],
|
293 | 1 | tkerber | self.F[frame],
|
294 | 1 | tkerber | None, None, atoms)) |
295 | 1 | tkerber | return atoms
|
296 | 1 | tkerber | |
297 | 1 | tkerber | def delete(self, i): |
298 | 1 | tkerber | self.nimages -= 1 |
299 | 1 | tkerber | P = np.empty((self.nimages, self.natoms, 3)) |
300 | 1 | tkerber | F = np.empty((self.nimages, self.natoms, 3)) |
301 | 1 | tkerber | A = np.empty((self.nimages, 3, 3)) |
302 | 1 | tkerber | E = np.empty(self.nimages)
|
303 | 1 | tkerber | P[:i] = self.P[:i]
|
304 | 1 | tkerber | P[i:] = self.P[i + 1:] |
305 | 1 | tkerber | self.P = P
|
306 | 1 | tkerber | F[:i] = self.F[:i]
|
307 | 1 | tkerber | F[i:] = self.F[i + 1:] |
308 | 1 | tkerber | self.F = F
|
309 | 1 | tkerber | A[:i] = self.A[:i]
|
310 | 1 | tkerber | A[i:] = self.A[i + 1:] |
311 | 1 | tkerber | self.A = A
|
312 | 1 | tkerber | E[:i] = self.E[:i]
|
313 | 1 | tkerber | E[i:] = self.E[i + 1:] |
314 | 1 | tkerber | self.E = E
|
315 | 1 | tkerber | del self.filenames[i] |
316 | 1 | tkerber | |
317 | 1 | tkerber | def aneb(self): |
318 | 1 | tkerber | n = self.nimages
|
319 | 1 | tkerber | assert n % 5 == 0 |
320 | 1 | tkerber | levels = n // 5
|
321 | 1 | tkerber | n = self.nimages = 2 * levels + 3 |
322 | 1 | tkerber | P = np.empty((self.nimages, self.natoms, 3)) |
323 | 1 | tkerber | F = np.empty((self.nimages, self.natoms, 3)) |
324 | 1 | tkerber | E = np.empty(self.nimages)
|
325 | 1 | tkerber | for L in range(levels): |
326 | 1 | tkerber | P[L] = self.P[L * 5] |
327 | 1 | tkerber | P[n - L - 1] = self.P[L * 5 + 4] |
328 | 1 | tkerber | F[L] = self.F[L * 5] |
329 | 1 | tkerber | F[n - L - 1] = self.F[L * 5 + 4] |
330 | 1 | tkerber | E[L] = self.E[L * 5] |
331 | 1 | tkerber | E[n - L - 1] = self.E[L * 5 + 4] |
332 | 1 | tkerber | for i in range(3): |
333 | 1 | tkerber | P[levels + i] = self.P[levels * 5 - 4 + i] |
334 | 1 | tkerber | F[levels + i] = self.F[levels * 5 - 4 + i] |
335 | 1 | tkerber | E[levels + i] = self.E[levels * 5 - 4 + i] |
336 | 1 | tkerber | self.P = P
|
337 | 1 | tkerber | self.F = F
|
338 | 1 | tkerber | self.E = E
|
339 | 1 | tkerber | |
340 | 1 | tkerber | def interpolate(self, m): |
341 | 1 | tkerber | assert self.nimages == 2 |
342 | 1 | tkerber | self.nimages = 2 + m |
343 | 1 | tkerber | P = np.empty((self.nimages, self.natoms, 3)) |
344 | 1 | tkerber | F = np.empty((self.nimages, self.natoms, 3)) |
345 | 1 | tkerber | A = np.empty((self.nimages, 3, 3)) |
346 | 1 | tkerber | E = np.empty(self.nimages)
|
347 | 1 | tkerber | P[0] = self.P[0] |
348 | 1 | tkerber | F[0] = self.F[0] |
349 | 1 | tkerber | A[0] = self.A[0] |
350 | 1 | tkerber | E[0] = self.E[0] |
351 | 1 | tkerber | for i in range(1, m + 1): |
352 | 1 | tkerber | x = i / (m + 1.0)
|
353 | 1 | tkerber | y = 1 - x
|
354 | 1 | tkerber | P[i] = y * self.P[0] + x * self.P[1] |
355 | 1 | tkerber | F[i] = y * self.F[0] + x * self.F[1] |
356 | 1 | tkerber | A[i] = y * self.A[0] + x * self.A[1] |
357 | 1 | tkerber | E[i] = y * self.E[0] + x * self.E[1] |
358 | 1 | tkerber | P[-1] = self.P[1] |
359 | 1 | tkerber | F[-1] = self.F[1] |
360 | 1 | tkerber | A[-1] = self.A[1] |
361 | 1 | tkerber | E[-1] = self.E[1] |
362 | 1 | tkerber | self.P = P
|
363 | 1 | tkerber | self.F = F
|
364 | 1 | tkerber | self.A = A
|
365 | 1 | tkerber | self.E = E
|
366 | 1 | tkerber | self.filenames[1:1] = [None] * m |
367 | 1 | tkerber | |
368 | 1 | tkerber | if __name__ == '__main__': |
369 | 1 | tkerber | import os |
370 | 1 | tkerber | os.system('python gui.py') |