root / ase / io / eps.py @ 1
Historique | Voir | Annoter | Télécharger (6,04 ko)
1 | 1 | tkerber | import time |
---|---|---|---|
2 | 1 | tkerber | from math import sqrt |
3 | 1 | tkerber | |
4 | 1 | tkerber | import numpy as np |
5 | 1 | tkerber | |
6 | 1 | tkerber | from ase.utils import rotate |
7 | 1 | tkerber | from ase.data import covalent_radii |
8 | 1 | tkerber | from ase.data.colors import jmol_colors |
9 | 1 | tkerber | |
10 | 1 | tkerber | |
11 | 1 | tkerber | class EPS: |
12 | 1 | tkerber | def __init__(self, atoms, |
13 | 1 | tkerber | rotation='', show_unit_cell=False, radii=None, |
14 | 1 | tkerber | bbox=None, colors=None, scale=20): |
15 | 1 | tkerber | self.numbers = atoms.get_atomic_numbers()
|
16 | 1 | tkerber | self.colors = colors
|
17 | 1 | tkerber | if colors is None: |
18 | 1 | tkerber | self.colors = jmol_colors[self.numbers] |
19 | 1 | tkerber | |
20 | 1 | tkerber | if radii is None: |
21 | 1 | tkerber | radii = covalent_radii[self.numbers]
|
22 | 1 | tkerber | elif type(radii) is float: |
23 | 1 | tkerber | radii = covalent_radii[self.numbers] * radii
|
24 | 1 | tkerber | |
25 | 1 | tkerber | natoms = len(atoms)
|
26 | 1 | tkerber | |
27 | 1 | tkerber | if isinstance(rotation, str): |
28 | 1 | tkerber | rotation = rotate(rotation) |
29 | 1 | tkerber | |
30 | 1 | tkerber | A = atoms.get_cell() |
31 | 1 | tkerber | if show_unit_cell > 0: |
32 | 1 | tkerber | L, T, D = self.cell_to_lines(A)
|
33 | 1 | tkerber | C = np.empty((2, 2, 2, 3)) |
34 | 1 | tkerber | for c1 in range(2): |
35 | 1 | tkerber | for c2 in range(2): |
36 | 1 | tkerber | for c3 in range(2): |
37 | 1 | tkerber | C[c1, c2, c3] = np.dot([c1, c2, c3], A) |
38 | 1 | tkerber | C.shape = (8, 3) |
39 | 1 | tkerber | C = np.dot(C, rotation) # Unit cell vertices
|
40 | 1 | tkerber | else:
|
41 | 1 | tkerber | L = np.empty((0, 3)) |
42 | 1 | tkerber | T = None
|
43 | 1 | tkerber | D = None
|
44 | 1 | tkerber | C = None
|
45 | 1 | tkerber | |
46 | 1 | tkerber | nlines = len(L)
|
47 | 1 | tkerber | |
48 | 1 | tkerber | X = np.empty((natoms + nlines, 3))
|
49 | 1 | tkerber | R = atoms.get_positions() |
50 | 1 | tkerber | X[:natoms] = R |
51 | 1 | tkerber | X[natoms:] = L |
52 | 1 | tkerber | |
53 | 1 | tkerber | r2 = radii**2
|
54 | 1 | tkerber | for n in range(nlines): |
55 | 1 | tkerber | d = D[T[n]] |
56 | 1 | tkerber | if ((((R - L[n] - d)**2).sum(1) < r2) & |
57 | 1 | tkerber | (((R - L[n] + d)**2).sum(1) < r2)).any(): |
58 | 1 | tkerber | T[n] = -1
|
59 | 1 | tkerber | |
60 | 1 | tkerber | X = np.dot(X, rotation) |
61 | 1 | tkerber | R = X[:natoms] |
62 | 1 | tkerber | |
63 | 1 | tkerber | if bbox is None: |
64 | 1 | tkerber | X1 = (R - radii[:, None]).min(0) |
65 | 1 | tkerber | X2 = (R + radii[:, None]).max(0) |
66 | 1 | tkerber | if show_unit_cell == 2: |
67 | 1 | tkerber | X1 = np.minimum(X1, C.min(0))
|
68 | 1 | tkerber | X2 = np.maximum(X2, C.max(0))
|
69 | 1 | tkerber | M = (X1 + X2) / 2
|
70 | 1 | tkerber | S = 1.05 * (X2 - X1)
|
71 | 1 | tkerber | w = scale * S[0]
|
72 | 1 | tkerber | if w > 500: |
73 | 1 | tkerber | w = 500
|
74 | 1 | tkerber | scale = w / S[0]
|
75 | 1 | tkerber | h = scale * S[1]
|
76 | 1 | tkerber | offset = np.array([scale * M[0] - w / 2, scale * M[1] - h / 2, 0]) |
77 | 1 | tkerber | else:
|
78 | 1 | tkerber | w = (bbox[2] - bbox[0]) * scale |
79 | 1 | tkerber | h = (bbox[3] - bbox[1]) * scale |
80 | 1 | tkerber | offset = np.array([bbox[0], bbox[1], 0]) * scale |
81 | 1 | tkerber | |
82 | 1 | tkerber | self.w = w
|
83 | 1 | tkerber | self.h = h
|
84 | 1 | tkerber | |
85 | 1 | tkerber | X *= scale |
86 | 1 | tkerber | X -= offset |
87 | 1 | tkerber | |
88 | 1 | tkerber | if nlines > 0: |
89 | 1 | tkerber | D = np.dot(D, rotation)[:, :2] * scale
|
90 | 1 | tkerber | |
91 | 1 | tkerber | if C is not None: |
92 | 1 | tkerber | C *= scale |
93 | 1 | tkerber | C -= offset |
94 | 1 | tkerber | |
95 | 1 | tkerber | A = np.dot(A, rotation) |
96 | 1 | tkerber | A *= scale |
97 | 1 | tkerber | |
98 | 1 | tkerber | self.A = A
|
99 | 1 | tkerber | self.X = X
|
100 | 1 | tkerber | self.D = D
|
101 | 1 | tkerber | self.T = T
|
102 | 1 | tkerber | self.C = C
|
103 | 1 | tkerber | self.natoms = natoms
|
104 | 1 | tkerber | self.d = 2 * scale * radii |
105 | 1 | tkerber | |
106 | 1 | tkerber | def cell_to_lines(self, A): |
107 | 1 | tkerber | nlines = 0
|
108 | 1 | tkerber | nn = [] |
109 | 1 | tkerber | for c in range(3): |
110 | 1 | tkerber | d = sqrt((A[c]**2).sum())
|
111 | 1 | tkerber | n = max(2, int(d / 0.3)) |
112 | 1 | tkerber | nn.append(n) |
113 | 1 | tkerber | nlines += 4 * n
|
114 | 1 | tkerber | |
115 | 1 | tkerber | X = np.empty((nlines, 3))
|
116 | 1 | tkerber | T = np.empty(nlines, int)
|
117 | 1 | tkerber | D = np.zeros((3, 3)) |
118 | 1 | tkerber | |
119 | 1 | tkerber | n1 = 0
|
120 | 1 | tkerber | for c in range(3): |
121 | 1 | tkerber | n = nn[c] |
122 | 1 | tkerber | dd = A[c] / (4 * n - 2) |
123 | 1 | tkerber | D[c] = dd |
124 | 1 | tkerber | P = np.arange(1, 4 * n + 1, 4)[:, None] * dd |
125 | 1 | tkerber | T[n1:] = c |
126 | 1 | tkerber | for i, j in [(0, 0), (0, 1), (1, 0), (1, 1)]: |
127 | 1 | tkerber | n2 = n1 + n |
128 | 1 | tkerber | X[n1:n2] = P + i * A[(c + 1) % 3] + j * A[(c + 2) % 3] |
129 | 1 | tkerber | n1 = n2 |
130 | 1 | tkerber | |
131 | 1 | tkerber | return X, T, D
|
132 | 1 | tkerber | |
133 | 1 | tkerber | def write(self, filename): |
134 | 1 | tkerber | self.filename = filename
|
135 | 1 | tkerber | self.write_header()
|
136 | 1 | tkerber | self.write_body()
|
137 | 1 | tkerber | self.write_trailer()
|
138 | 1 | tkerber | |
139 | 1 | tkerber | def write_header(self): |
140 | 1 | tkerber | import matplotlib |
141 | 1 | tkerber | if matplotlib.__version__ <= '0.8': |
142 | 1 | tkerber | raise RuntimeError('Your version of matplotlib (%s) is too old' % |
143 | 1 | tkerber | matplotlib.__version__) |
144 | 1 | tkerber | |
145 | 1 | tkerber | from matplotlib.backends.backend_ps import RendererPS, \ |
146 | 1 | tkerber | GraphicsContextPS, psDefs |
147 | 1 | tkerber | |
148 | 1 | tkerber | self.fd = open(self.filename, 'w') |
149 | 1 | tkerber | self.fd.write('%!PS-Adobe-3.0 EPSF-3.0\n') |
150 | 1 | tkerber | self.fd.write('%%Creator: G2\n') |
151 | 1 | tkerber | self.fd.write('%%CreationDate: %s\n' % time.ctime(time.time())) |
152 | 1 | tkerber | self.fd.write('%%Orientation: portrait\n') |
153 | 1 | tkerber | bbox = (0, 0, self.w, self.h) |
154 | 1 | tkerber | self.fd.write('%%%%BoundingBox: %d %d %d %d\n' % bbox) |
155 | 1 | tkerber | self.fd.write('%%EndComments\n') |
156 | 1 | tkerber | |
157 | 1 | tkerber | Ndict = len(psDefs)
|
158 | 1 | tkerber | self.fd.write('%%BeginProlog\n') |
159 | 1 | tkerber | self.fd.write('/mpldict %d dict def\n' % Ndict) |
160 | 1 | tkerber | self.fd.write('mpldict begin\n') |
161 | 1 | tkerber | for d in psDefs: |
162 | 1 | tkerber | d = d.strip() |
163 | 1 | tkerber | for l in d.split('\n'): |
164 | 1 | tkerber | self.fd.write(l.strip() + '\n') |
165 | 1 | tkerber | self.fd.write('%%EndProlog\n') |
166 | 1 | tkerber | |
167 | 1 | tkerber | self.fd.write('mpldict begin\n') |
168 | 1 | tkerber | self.fd.write('%d %d 0 0 clipbox\n' % (self.w, self.h)) |
169 | 1 | tkerber | |
170 | 1 | tkerber | self.renderer = RendererPS(self.w, self.h, self.fd) |
171 | 1 | tkerber | |
172 | 1 | tkerber | def write_body(self): |
173 | 1 | tkerber | try:
|
174 | 1 | tkerber | from matplotlib.path import Path |
175 | 1 | tkerber | except ImportError: |
176 | 1 | tkerber | Path = None
|
177 | 1 | tkerber | from matplotlib.patches import Circle, Polygon |
178 | 1 | tkerber | else:
|
179 | 1 | tkerber | from matplotlib.patches import Circle, PathPatch |
180 | 1 | tkerber | |
181 | 1 | tkerber | indices = self.X[:, 2].argsort() |
182 | 1 | tkerber | for a in indices: |
183 | 1 | tkerber | xy = self.X[a, :2] |
184 | 1 | tkerber | if a < self.natoms: |
185 | 1 | tkerber | circle = Circle(xy, self.d[a] / 2, facecolor=self.colors[a]) |
186 | 1 | tkerber | circle.draw(self.renderer)
|
187 | 1 | tkerber | else:
|
188 | 1 | tkerber | a -= self.natoms
|
189 | 1 | tkerber | c = self.T[a]
|
190 | 1 | tkerber | if c != -1: |
191 | 1 | tkerber | hxy = self.D[c]
|
192 | 1 | tkerber | if Path is None: |
193 | 1 | tkerber | line = Polygon((xy + hxy, xy - hxy)) |
194 | 1 | tkerber | else:
|
195 | 1 | tkerber | line = PathPatch(Path((xy + hxy, xy - hxy))) |
196 | 1 | tkerber | line.draw(self.renderer)
|
197 | 1 | tkerber | |
198 | 1 | tkerber | def write_trailer(self): |
199 | 1 | tkerber | self.fd.write('end\n') |
200 | 1 | tkerber | self.fd.write('showpage\n') |
201 | 1 | tkerber | self.fd.close()
|
202 | 1 | tkerber | |
203 | 1 | tkerber | |
204 | 1 | tkerber | def write_eps(filename, atoms, **parameters): |
205 | 1 | tkerber | if isinstance(atoms, list): |
206 | 1 | tkerber | assert len(atoms) == 1 |
207 | 1 | tkerber | atoms = atoms[0]
|
208 | 1 | tkerber | EPS(atoms, **parameters).write(filename) |