Statistiques
| Révision :

root / ase / io / pov.py

Historique | Voir | Annoter | Télécharger (8,99 ko)

1 1 tkerber
"""
2 1 tkerber
Module for povray file format support.
3 1 tkerber

4 1 tkerber
See http://www.povray.org/ for details on the format.
5 1 tkerber
"""
6 1 tkerber
import os
7 1 tkerber
8 1 tkerber
import numpy as np
9 1 tkerber
10 1 tkerber
from ase.io.eps import EPS
11 1 tkerber
from ase.data import chemical_symbols
12 1 tkerber
13 1 tkerber
14 1 tkerber
def pa(array):
15 1 tkerber
    """Povray array syntax"""
16 1 tkerber
    return '<% 6.2f, % 6.2f, % 6.2f>' % tuple(array)
17 1 tkerber
18 1 tkerber
19 1 tkerber
def pc(array):
20 1 tkerber
    """Povray color syntax"""
21 1 tkerber
    if type(array) == str:
22 1 tkerber
        return 'color ' + array
23 1 tkerber
    if type(array) == float:
24 1 tkerber
        return 'rgb <%.2f>*3' % array
25 1 tkerber
    if len(array) == 3:
26 1 tkerber
        return 'rgb <%.2f, %.2f, %.2f>' % tuple(array)
27 1 tkerber
    if len(array) == 4: # filter
28 1 tkerber
        return 'rgbf <%.2f, %.2f, %.2f, %.2f>' % tuple(array)
29 1 tkerber
    if len(array) == 5: # filter and transmit
30 1 tkerber
        return 'rgbft <%.2f, %.2f, %.2f, %.2f, %.2f>' % tuple(array)
31 1 tkerber
32 1 tkerber
33 1 tkerber
def get_bondpairs(atoms, radius=1.1):
34 1 tkerber
    """Get all pairs of bonding atoms
35 1 tkerber

36 1 tkerber
    Return all pairs of atoms which are closer than radius times the
37 1 tkerber
    sum of their respective covalent radii.  The pairs are returned as
38 1 tkerber
    tuples::
39 1 tkerber

40 1 tkerber
      (a, b, (i1, i2, i3))
41 1 tkerber

42 1 tkerber
    so that atoms a bonds to atom b displaced by the vector::
43 1 tkerber

44 1 tkerber
        _     _     _
45 1 tkerber
      i c + i c + i c ,
46 1 tkerber
       1 1   2 2   3 3
47 1 tkerber

48 1 tkerber
    where c1, c2 and c3 are the unit cell vectors and i1, i2, i3 are
49 1 tkerber
    integers."""
50 1 tkerber
51 1 tkerber
    from ase.data import covalent_radii
52 1 tkerber
    from ase.calculators.neighborlist import NeighborList
53 1 tkerber
    cutoffs = radius * covalent_radii[atoms.numbers]
54 1 tkerber
    nl = NeighborList(cutoffs=cutoffs, self_interaction=False)
55 1 tkerber
    nl.update(atoms)
56 1 tkerber
    bondpairs = []
57 1 tkerber
    for a in range(len(atoms)):
58 1 tkerber
        indices, offsets = nl.get_neighbors(a)
59 1 tkerber
        bondpairs.extend([(a, a2, offset)
60 1 tkerber
                          for a2, offset in zip(indices, offsets)])
61 1 tkerber
    return bondpairs
62 1 tkerber
63 1 tkerber
64 1 tkerber
class POVRAY(EPS):
65 1 tkerber
    default_settings = {
66 1 tkerber
        # x, y is the image plane, z is *out* of the screen
67 1 tkerber
        'display'      : True, # Display while rendering
68 1 tkerber
        'pause'        : True, # Pause when done rendering (only if display)
69 1 tkerber
        'transparent'  : True, # Transparent background
70 1 tkerber
        'canvas_width' : None, # Width of canvas in pixels
71 1 tkerber
        'canvas_height': None, # Height of canvas in pixels
72 1 tkerber
        'camera_dist'  : 50.,  # Distance from camera to front atom
73 1 tkerber
        'image_plane'  : None, # Distance from front atom to image plane
74 1 tkerber
        'camera_type'  : 'orthographic', # perspective, ultra_wide_angle
75 1 tkerber
        'point_lights' : [],             # [[loc1, color1], [loc2, color2],...]
76 1 tkerber
        'area_light'   : [(2., 3., 40.), # location
77 1 tkerber
                          'White',       # color
78 1 tkerber
                          .7, .7, 3, 3], # width, height, Nlamps_x, Nlamps_y
79 1 tkerber
        'background'   : 'White',        # color
80 1 tkerber
        'textures'     : None, # Length of atoms list of texture names
81 1 tkerber
        'celllinewidth': 0.05, # Radius of the cylinders representing the cell
82 1 tkerber
        'bondlinewidth': 0.10, # Radius of the cylinders representing the bonds
83 1 tkerber
        'bondatoms'    : [], # [[atom1, atom2], ...] pairs of bonding atoms
84 1 tkerber
        }
85 1 tkerber
86 1 tkerber
    def __init__(self, atoms, scale=1.0, **parameters):
87 1 tkerber
        for k, v in self.default_settings.items():
88 1 tkerber
            setattr(self, k, parameters.pop(k, v))
89 1 tkerber
        EPS.__init__(self, atoms, scale=scale, **parameters)
90 1 tkerber
91 1 tkerber
    def cell_to_lines(self, A):
92 1 tkerber
        return np.empty((0, 3)), None, None
93 1 tkerber
94 1 tkerber
    def write(self, filename, **settings):
95 1 tkerber
        # Determine canvas width and height
96 1 tkerber
        ratio = float(self.w) / self.h
97 1 tkerber
        if self.canvas_width is None:
98 1 tkerber
            if self.canvas_height is None:
99 1 tkerber
                self.canvas_width = min(self.w * 15, 640)
100 1 tkerber
            else:
101 1 tkerber
                self.canvas_width = self.canvas_height * ratio
102 1 tkerber
        elif self.canvas_height is not None:
103 1 tkerber
            raise RuntimeError, "Can't set *both* width and height!"
104 1 tkerber
105 1 tkerber
        # Distance to image plane from camera
106 1 tkerber
        if self.image_plane is None:
107 1 tkerber
            if self.camera_type == 'orthographic':
108 1 tkerber
                self.image_plane = 1 - self.camera_dist
109 1 tkerber
            else:
110 1 tkerber
                self.image_plane = 0
111 1 tkerber
        self.image_plane += self.camera_dist
112 1 tkerber
113 1 tkerber
        # Produce the .ini file
114 1 tkerber
        if filename.endswith('.pov'):
115 1 tkerber
            ini = open(filename[:-4] + '.ini', 'w').write
116 1 tkerber
        else:
117 1 tkerber
            ini = open(filename + '.ini', 'w').write
118 1 tkerber
        ini('Input_File_Name=%s\n' % filename)
119 1 tkerber
        ini('Output_to_File=True\n')
120 1 tkerber
        ini('Output_File_Type=N\n')
121 1 tkerber
        ini('Output_Alpha=%s\n' % self.transparent)
122 1 tkerber
        ini('; if you adjust Height, and width, you must preserve the ratio\n')
123 1 tkerber
        ini('; Width / Height = %s\n' % repr(ratio))
124 1 tkerber
        ini('Width=%s\n' % self.canvas_width)
125 1 tkerber
        ini('Height=%s\n' % (self.canvas_width / ratio))
126 1 tkerber
        ini('Antialias=True\n')
127 1 tkerber
        ini('Antialias_Threshold=0.1\n')
128 1 tkerber
        ini('Display=%s\n' % self.display)
129 1 tkerber
        ini('Pause_When_Done=%s\n' % self.pause)
130 1 tkerber
        ini('Verbose=False\n')
131 1 tkerber
        del ini
132 1 tkerber
133 1 tkerber
        # Produce the .pov file
134 1 tkerber
        w = open(filename, 'w').write
135 1 tkerber
        w('#include "colors.inc"\n')
136 1 tkerber
        w('#include "finish.inc"\n')
137 1 tkerber
        w('\n')
138 1 tkerber
        w('global_settings {assumed_gamma 1 max_trace_level 6}\n')
139 1 tkerber
        w('background {%s}\n' % pc(self.background))
140 1 tkerber
        w('camera {%s\n' % self.camera_type)
141 1 tkerber
        w('  right -%.2f*x up %.2f*y\n' % (self.w, self.h))
142 1 tkerber
        w('  direction %.2f*z\n' % self.image_plane)
143 1 tkerber
        w('  location <0,0,%.2f> look_at <0,0,0>}\n' % self.camera_dist)
144 1 tkerber
        for loc, rgb in self.point_lights:
145 1 tkerber
            w('light_source {%s %s}\n' % (pa(loc), pc(rgb)))
146 1 tkerber
147 1 tkerber
        if self.area_light is not None:
148 1 tkerber
            loc, color, width, height, nx, ny = self.area_light
149 1 tkerber
            w('light_source {%s %s\n' % (pa(loc), pc(color)))
150 1 tkerber
            w('  area_light <%.2f, 0, 0>, <0, %.2f, 0>, %i, %i\n' % (
151 1 tkerber
                width, height, nx, ny))
152 1 tkerber
            w('  adaptive 1 jitter}\n')
153 1 tkerber
154 1 tkerber
        w('\n')
155 1 tkerber
        w('#declare simple = finish {phong 0.7}\n')
156 1 tkerber
        w('#declare vmd = finish {'
157 1 tkerber
          'ambient .0 '
158 1 tkerber
          'diffuse .65 '
159 1 tkerber
          'phong 0.1 '
160 1 tkerber
          'phong_size 40. '
161 1 tkerber
          'specular 0.500 }\n')
162 1 tkerber
        w('#declare jmol = finish {'
163 1 tkerber
          'ambient .2 '
164 1 tkerber
          'diffuse .6 '
165 1 tkerber
          'specular 1 '
166 1 tkerber
          'roughness .001 '
167 1 tkerber
          'metallic}\n')
168 1 tkerber
        w('#declare ase2 = finish {'
169 1 tkerber
          'ambient 0.05 '
170 1 tkerber
          'brilliance 3 '
171 1 tkerber
          'diffuse 0.6 '
172 1 tkerber
          'metallic '
173 1 tkerber
          'specular 0.70 '
174 1 tkerber
          'roughness 0.04 '
175 1 tkerber
          'reflection 0.15}\n')
176 1 tkerber
        w('#declare ase3 = finish {'
177 1 tkerber
          'ambient .15 '
178 1 tkerber
          'brilliance 2 '
179 1 tkerber
          'diffuse .6 '
180 1 tkerber
          'metallic '
181 1 tkerber
          'specular 1. '
182 1 tkerber
          'roughness .001 '
183 1 tkerber
          'reflection .0}\n')
184 1 tkerber
        w('#declare glass = finish {' # Use filter 0.7
185 1 tkerber
          'ambient .05 '
186 1 tkerber
          'diffuse .3 '
187 1 tkerber
          'specular 1. '
188 1 tkerber
          'roughness .001}\n')
189 1 tkerber
        w('#declare Rcell = %.3f;\n' % self.celllinewidth)
190 1 tkerber
        w('#declare Rbond = %.3f;\n' % self.bondlinewidth)
191 1 tkerber
        w('\n')
192 1 tkerber
        w('#macro atom(LOC, R, COL, FIN)\n')
193 1 tkerber
        w('  sphere{LOC, R texture{pigment{COL} finish{FIN}}}\n')
194 1 tkerber
        w('#end\n')
195 1 tkerber
        w('\n')
196 1 tkerber
197 1 tkerber
        z0 = self.X[:, 2].max()
198 1 tkerber
        self.X -= (self.w / 2, self.h / 2, z0)
199 1 tkerber
200 1 tkerber
        # Draw unit cell
201 1 tkerber
        if self.C is not None:
202 1 tkerber
            self.C -= (self.w / 2, self.h / 2, z0)
203 1 tkerber
            self.C.shape = (2, 2, 2, 3)
204 1 tkerber
            for c in range(3):
205 1 tkerber
                for j in ([0, 0], [1, 0], [1, 1], [0, 1]):
206 1 tkerber
                    w('cylinder {')
207 1 tkerber
                    for i in range(2):
208 1 tkerber
                        j.insert(c, i)
209 1 tkerber
                        w(pa(self.C[tuple(j)]) + ', ')
210 1 tkerber
                        del j[c]
211 1 tkerber
                    w('Rcell pigment {Black}}\n')
212 1 tkerber
213 1 tkerber
        # Draw atoms
214 1 tkerber
        a = 0
215 1 tkerber
        for loc, dia, color in zip(self.X, self.d, self.colors):
216 1 tkerber
            tex = 'ase3'
217 1 tkerber
            if self.textures is not None:
218 1 tkerber
                tex = self.textures[a]
219 1 tkerber
            w('atom(%s, %.2f, %s, %s) // #%i \n' % (
220 1 tkerber
                pa(loc), dia / 2., pc(color), tex, a))
221 1 tkerber
            a += 1
222 1 tkerber
223 1 tkerber
        # Draw atom bonds
224 1 tkerber
        for pair in self.bondatoms:
225 1 tkerber
            if len(pair) == 2:
226 1 tkerber
                a, b = pair
227 1 tkerber
                offset = (0, 0, 0)
228 1 tkerber
            else:
229 1 tkerber
                a, b, offset = pair
230 1 tkerber
            R = np.dot(offset, self.A)
231 1 tkerber
            mida = 0.5 * (self.X[a] + self.X[b] + R)
232 1 tkerber
            midb = 0.5 * (self.X[a] + self.X[b] - R)
233 1 tkerber
            if self.textures is not None:
234 1 tkerber
                texa = self.textures[a]
235 1 tkerber
                texb = self.textures[b]
236 1 tkerber
            else:
237 1 tkerber
                texa = texb = 'ase3'
238 1 tkerber
            w('cylinder {%s, %s, Rbond texture{pigment {%s} finish{%s}}}\n' % (
239 1 tkerber
                pa(self.X[a]), pa(mida), pc(self.colors[a]), texa))
240 1 tkerber
            w('cylinder {%s, %s, Rbond texture{pigment {%s} finish{%s}}}\n' % (
241 1 tkerber
                pa(self.X[b]), pa(midb), pc(self.colors[b]), texb))
242 1 tkerber
243 1 tkerber
244 1 tkerber
def write_pov(filename, atoms, run_povray=False, **parameters):
245 1 tkerber
    if isinstance(atoms, list):
246 1 tkerber
        assert len(atoms) == 1
247 1 tkerber
        atoms = atoms[0]
248 1 tkerber
    assert 'scale' not in parameters
249 1 tkerber
    POVRAY(atoms, **parameters).write(filename)
250 1 tkerber
    if run_povray:
251 1 tkerber
        errcode = os.system('povray %s.ini 2> /dev/null' % filename[:-4])
252 1 tkerber
        if errcode != 0:
253 1 tkerber
            raise OSError('Povray failed with error code %d' % errcode)