Statistiques
| Révision :

root / ase / visualize / fieldplotter.py @ 3

Historique | Voir | Annoter | Télécharger (10,86 ko)

1 1 tkerber
"""plotting fields defined on atoms during a simulation."""
2 1 tkerber
3 1 tkerber
from ase.visualize.primiplotter import PostScriptFile, PnmFile, GifFile, JpegFile, X11Window
4 1 tkerber
from ase.visualize.primiplotter import PrimiPlotter as _PrimiPlotter
5 1 tkerber
import numpy
6 1 tkerber
import time
7 1 tkerber
8 1 tkerber
class FieldPlotter(_PrimiPlotter):
9 1 tkerber
    def __init__(self, atoms, datasource=None, verbose=0, timing=0,
10 1 tkerber
                 interval=1, initframe=0):
11 1 tkerber
        _PrimiPlotter.__init__(self, atoms, verbose=verbose, timing=timing,
12 1 tkerber
                               interval=interval, initframe=initframe)
13 1 tkerber
        self.datasource = datasource
14 1 tkerber
        self.dims = (100,100)
15 1 tkerber
        self.set_plot_plane("xy")
16 1 tkerber
        self.set_data_range("plot")
17 1 tkerber
        self.set_background(0.0)
18 1 tkerber
        self.set_red_yellow_colors()
19 1 tkerber
20 1 tkerber
    def set_plot_plane(self, plane):
21 1 tkerber
        """Set the plotting plane to xy, xz or yz (default: xy)"""
22 1 tkerber
        if plane in ("xy", "xz", "yz"):
23 1 tkerber
            self.plane = plane
24 1 tkerber
        else:
25 1 tkerber
            raise ValueError, "The argument to plotPlane must be 'xy', 'xz' or 'yz'."
26 1 tkerber
27 1 tkerber
    def set_data_range(self, range1, range2=None):
28 1 tkerber
        """Set the range of the data used when coloring.
29 1 tkerber

30 1 tkerber
        This function sets the range of data values mapped unto colors
31 1 tkerber
        in the final plot.
32 1 tkerber

33 1 tkerber
        Three possibilities:
34 1 tkerber

35 1 tkerber
        'data':        Autoscale using the data on visible atoms.
36 1 tkerber
                       The range goes from the lowest to the highest
37 1 tkerber
                       value present on the atoms.  If only a few atoms
38 1 tkerber
                       have extreme values, the entire color range may not
39 1 tkerber
                       be used on the plot, as many values may be averaged
40 1 tkerber
                       on each point in the plot.
41 1 tkerber

42 1 tkerber
        'plot':        Autoscale using the data on the plot.  Unlike 'data'
43 1 tkerber
                       this guarantees that the entire color range is used.
44 1 tkerber

45 1 tkerber
        min, max:      Use the range [min, max]
46 1 tkerber

47 1 tkerber
        """
48 1 tkerber
        if (range1 == "data" or range1 == "plot") and range2 == None:
49 1 tkerber
            self.autorange = range1
50 1 tkerber
        elif range2 != None:
51 1 tkerber
            self.autorange = None
52 1 tkerber
            self.range = (range1, range2)
53 1 tkerber
        else:
54 1 tkerber
            raise ValueError, "Illegal argument(s) to set_data_range"
55 1 tkerber
56 1 tkerber
    def set_background(self, value):
57 1 tkerber
        """Set the data value of the background.  See also set_background_color
58 1 tkerber

59 1 tkerber
        Set the value of the background (parts of the plot without atoms) to
60 1 tkerber
        a specific value, or to 'min' or 'max' representing the minimal or
61 1 tkerber
        maximal data values on the atoms.
62 1 tkerber

63 1 tkerber
        Calling set_background cancels previous calls to set_background_color.
64 1 tkerber
        """
65 1 tkerber
        self.background = value
66 1 tkerber
        self.backgroundcolor = None
67 1 tkerber
68 1 tkerber
    def set_background_color(self, color):
69 1 tkerber
        """Set the background color.  See also set_background.
70 1 tkerber

71 1 tkerber
        Set the background color.  Use a single value in the range [0, 1[
72 1 tkerber
        for gray values, or a tuple of three such values as an RGB color.
73 1 tkerber

74 1 tkerber
        Calling set_background_color cancels previous calls to set_background.
75 1 tkerber
        """
76 1 tkerber
        self.background = None
77 1 tkerber
        self.backgroundcolor = color
78 1 tkerber
79 1 tkerber
    def set_red_yellow_colors(self, reverse=False):
80 1 tkerber
        """Set colors to Black-Red-Yellow-White (a.k.a. STM colors)"""
81 1 tkerber
        self.set_colors([(0.0, 0, 0, 0),
82 1 tkerber
                        (0.33, 1, 0, 0),
83 1 tkerber
                        (0.66, 1, 1, 0),
84 1 tkerber
                        (1.0, 1, 1, 1)],
85 1 tkerber
                       reverse)
86 1 tkerber
87 1 tkerber
    def set_black_white_colors(self, reverse=False):
88 1 tkerber
        """Set the color to Black-White (greyscale)"""
89 1 tkerber
        self.set_colors([(0.0, 0),  (1.0, 1)], reverse)
90 1 tkerber
91 1 tkerber
    def set_colors(self, colors, reverse=False):
92 1 tkerber
        colors = numpy.array(colors, numpy.float)
93 1 tkerber
        if len(colors.shape) != 2:
94 1 tkerber
            raise ValueError, "Colors must be a 2D array."
95 1 tkerber
        if reverse:
96 1 tkerber
            colors[:,0] = 1 - colors[:,0]
97 1 tkerber
            colors = numpy.array(colors[::-1,:])
98 1 tkerber
            #print colors
99 1 tkerber
        if colors[0,0] != 0.0 or colors[-1,0] != 1.0:
100 1 tkerber
            raise ValueError, "First row must define the value 0 and last row must define the value 1"
101 1 tkerber
        if colors.shape[1] == 2:
102 1 tkerber
            self.colormode = 1
103 1 tkerber
        elif colors.shape[1] == 4:
104 1 tkerber
            self.colormode = 3
105 1 tkerber
        else:
106 1 tkerber
            raise ValueError, "Color specification must be Nx2 (grey) or Nx4 (rgb) matrix."
107 1 tkerber
        self.colorfunction = InterpolatingFunction(colors[:,0], colors[:,1:])
108 1 tkerber
109 1 tkerber
    def plot(self, data=None):
110 1 tkerber
        """Create a plot now.  Does not respect the interval timer.
111 1 tkerber

112 1 tkerber
        This method makes a plot unconditionally.  It does not look at
113 1 tkerber
        the interval variable, nor is this plot taken into account in
114 1 tkerber
        the counting done by the update() method if an interval
115 1 tkerber
        variable was specified.
116 1 tkerber

117 1 tkerber
        If data is specified, it must be an array of numbers with the
118 1 tkerber
        same length as the atoms.  That data will then be plotted.  If
119 1 tkerber
        no data is given, the data source specified when creating the
120 1 tkerber
        plotter is used.
121 1 tkerber

122 1 tkerber
        """
123 1 tkerber
        if self.timing:
124 1 tkerber
            self._starttimer()
125 1 tkerber
        self.log("FieldPlotter: Starting plot at "
126 1 tkerber
                 + time.strftime("%a, %d %b %Y %H:%M:%S"))
127 1 tkerber
        if data is None:
128 1 tkerber
            data = self.datasource()
129 1 tkerber
        if len(data) != len(self.atoms):
130 1 tkerber
            raise ValueError, ("Data has wrong length: %d instead of %d."
131 1 tkerber
                               % (len(data), len(self.atoms)))
132 1 tkerber
133 1 tkerber
        invisible = self._getinvisible()
134 1 tkerber
        coords = self._rotate(self._getpositions())
135 1 tkerber
        radii = self._getradii()
136 1 tkerber
        if self.autoscale:
137 1 tkerber
            self._autoscale(coords,radii)
138 1 tkerber
        scale = self.scale * self.relativescale
139 1 tkerber
        coords = scale * coords
140 1 tkerber
        center = self._getcenter(coords)
141 1 tkerber
        offset = numpy.array(self.dims + (0.0,))/2.0 - center
142 1 tkerber
        coords = coords + offset
143 1 tkerber
        radii = radii * scale
144 1 tkerber
        self.log("Scale is %f and size is (%d, %d)"
145 1 tkerber
                 % (scale, self.dims[0], self.dims[1]))
146 1 tkerber
        self.log("Physical size of plot is %f Angstrom times %f Angstrom"
147 1 tkerber
                 % (self.dims[0] / scale, self.dims[1] / scale))
148 1 tkerber
149 1 tkerber
        # Remove invisible atoms
150 1 tkerber
        selector = numpy.logical_not(invisible)
151 1 tkerber
        coords = numpy.compress(selector, coords, 0)
152 1 tkerber
        radii = numpy.compress(selector, radii)
153 1 tkerber
        data = numpy.compress(selector, data)
154 1 tkerber
155 1 tkerber
        self.log("plotting data in the range [%f,%f]" %
156 1 tkerber
                   (data.min(), data.max()))
157 1 tkerber
        # Now create the output array
158 1 tkerber
        sumarray = numpy.zeros(self.dims, numpy.float)
159 1 tkerber
        weight = numpy.zeros(self.dims)
160 1 tkerber
161 1 tkerber
        # Loop over all atoms, and plot them
162 1 tkerber
        nmiss = 0
163 1 tkerber
        if self.plane == "xy":
164 1 tkerber
            xy = coords[:,:2]
165 1 tkerber
        elif self.plane == "xz":
166 1 tkerber
            xy = coords[:,::2]
167 1 tkerber
        elif self.plane == "yz":
168 1 tkerber
            xy = coords[:,1:]
169 1 tkerber
        else:
170 1 tkerber
            raise RuntimeError, "self.plane is bogus: "+str(self.plane)
171 1 tkerber
        assert xy.shape[1] == 2
172 1 tkerber
173 1 tkerber
        self.log("plotting %d atoms on %d * %d (= %d) grid" %
174 1 tkerber
                   (len(xy), sumarray.shape[0], sumarray.shape[1],
175 1 tkerber
                    len(sumarray.flat)))
176 1 tkerber
177 1 tkerber
        xy = xy.astype(numpy.int)
178 1 tkerber
        for i in xrange(len(xy)):
179 1 tkerber
            (x, y) = xy[i]
180 1 tkerber
            d = data[i]
181 1 tkerber
            if (x >= 0 and x < self.dims[0] and y >= 0 and y < self.dims[1]):
182 1 tkerber
                sumarray[x,y] += d
183 1 tkerber
                weight[x,y] += 1
184 1 tkerber
            else:
185 1 tkerber
                nmiss += 1
186 1 tkerber
        print "... %d atoms fell outside plot." % (nmiss,)
187 1 tkerber
188 1 tkerber
        datamap = self._makedatamap(sumarray, weight, data.min(), data.max())
189 1 tkerber
        self.log("Range of data map: [%f, %f]" %
190 1 tkerber
                   (datamap.min(), datamap.max()))
191 1 tkerber
        plot = self._makeplotmap(datamap, weight)
192 1 tkerber
        #self.log("Range of plot: [%f, %f]" %
193 1 tkerber
        #           (min(plot.flat), max(plot.flat)))
194 1 tkerber
        examinplot = plot[:]
195 1 tkerber
        examinplot.shape = (plot.shape[0] * plot.shape[1],) + plot.shape[2:]
196 1 tkerber
        self.log("Range of plot: %s -> %s" %
197 1 tkerber
                 (str(examinplot.min(0)), str(examinplot.max(0))))
198 1 tkerber
        del examinplot
199 1 tkerber
        for device in self.outputdevice:
200 1 tkerber
            device.inform_about_scale(scale)
201 1 tkerber
            device.plotArray(self.n, numpy.swapaxes(plot,0,1))
202 1 tkerber
        self.n = self.n + 1
203 1 tkerber
        self.log("FieldPlotter: Finished plotting at "
204 1 tkerber
                 + time.strftime("%a, %d %b %Y %H:%M:%S"))
205 1 tkerber
        self.log("\n\n")
206 1 tkerber
207 1 tkerber
208 1 tkerber
    def _makedatamap(self, sumarray, weight, minimum, maximum):
209 1 tkerber
        background = numpy.equal(weight, 0)
210 1 tkerber
        print "Number of background points:", sum(background.flat)
211 1 tkerber
        datamap = sumarray / numpy.where(background, 1, weight)
212 1 tkerber
213 1 tkerber
        if self.background is not None:
214 1 tkerber
            if self.background == "min":
215 1 tkerber
                bg = minimum
216 1 tkerber
            elif self.background == "max":
217 1 tkerber
                bg = maximum
218 1 tkerber
            else:
219 1 tkerber
                bg = self.background
220 1 tkerber
            datamap = numpy.where(background, bg, datamap)
221 1 tkerber
222 1 tkerber
        if self.autorange == "data":
223 1 tkerber
            datamap = (datamap - minimum) / (maximum - minimum)
224 1 tkerber
            self.log("Autorange using data.  Data range is [%f, %f]"
225 1 tkerber
                     % (minimum, maximum))
226 1 tkerber
        elif self.autorange == "plot":
227 1 tkerber
            ma = numpy.where(background, minimum, datamap).max()
228 1 tkerber
            mi = numpy.where(background, maximum, datamap).min()
229 1 tkerber
            datamap = (datamap - mi) / (ma - mi)
230 1 tkerber
            self.log("Autorange using plot.  Data range is [%f, %f]"
231 1 tkerber
                     % (mi, ma))
232 1 tkerber
        else:
233 1 tkerber
            assert self.autorange == None
234 1 tkerber
            datamap = (datamap - self.range[0]) / (self.range[1]
235 1 tkerber
                                                   - self.range[0])
236 1 tkerber
            datamap = numpy.clip(datamap, 0.0, 1.0)
237 1 tkerber
            self.log("Data range specified by user: [%f, %f]" % self.range)
238 1 tkerber
        datamap = numpy.where(background, bg, datamap)
239 1 tkerber
        assert datamap.min() >= 0 and datamap.max() <= 1.0
240 1 tkerber
241 1 tkerber
        return datamap
242 1 tkerber
243 1 tkerber
    def _makeplotmap(self, datamap, weight):
244 1 tkerber
        plot = numpy.zeros(self.dims + (self.colormode,), numpy.float)
245 1 tkerber
        for i in range(self.dims[0]):
246 1 tkerber
            for j in range(self.dims[1]):
247 1 tkerber
                if self.backgroundcolor is not None and weight[i,j] == 0:
248 1 tkerber
                    plot[i,j,:] = self.backgroundcolor
249 1 tkerber
                else:
250 1 tkerber
                    x = datamap[i,j]
251 1 tkerber
                    plot[i,j,:] = self.colorfunction(x)
252 1 tkerber
        return plot
253 1 tkerber
254 1 tkerber
class InterpolatingFunction:
255 1 tkerber
    def __init__(self, xpoints, ypoints):
256 1 tkerber
        if len(xpoints) != len(ypoints):
257 1 tkerber
            raise ValueError, "Length of x and y arrays should be the same."
258 1 tkerber
        idx = xpoints.argsort()
259 1 tkerber
        self.xpoints = xpoints[idx]
260 1 tkerber
        self.ypoints = ypoints[idx]
261 1 tkerber
    def __call__(self, x):
262 1 tkerber
        n = self.xpoints.searchsorted(x)
263 1 tkerber
        if n == 0:
264 1 tkerber
            return self.ypoints[0]
265 1 tkerber
        if n == len(self.xpoints):
266 1 tkerber
            return self.xpoints[-1]
267 1 tkerber
        x0 = self.xpoints[n-1]
268 1 tkerber
        x1 = self.xpoints[n]
269 1 tkerber
        y0 = self.ypoints[n-1]
270 1 tkerber
        y1 = self.ypoints[n]
271 1 tkerber
        return y0 + (y1 - y0) / (x1 - x0) * (x - x0)