예제 #1
0
 def test_in_coord_list(self):
     coords = [[0, 0, 0], [0.5, 0.5, 0.5]]
     test_coord = [0.1, 0.1, 0.1]
     self.assertFalse(in_coord_list(coords, test_coord))
     self.assertTrue(in_coord_list(coords, test_coord, atol=0.15))
     self.assertFalse(in_coord_list([0.99, 0.99, 0.99], test_coord,
                                    atol=0.15))
예제 #2
0
    def get_center(self, lines):
        """
        Returns coordinates of center of a domain. Useful
        for labeling a Pourbaix plot.

        Args:
            lines:
                Lines corresponding to a domain
            limits:
                Limits of Pourbaix diagram

        Returns:
            center_x, center_y:
                x,y coordinate of center of domain. If domain lies
                outside limits, center will lie on the boundary.
        """
        center_x = 0.0
        center_y = 0.0
        coords = []
        count_center = 0.0
        for line in lines:
            for coord in np.array(line).T:
                if not in_coord_list(coords, coord):
                    coords.append(coord.tolist())
                    cx = coord[0]
                    cy = coord[1]
                    center_x += cx
                    center_y += cy
                    count_center += 1.0
        if count_center == 0.0:
            count_center = 1.0
        center_x /= count_center
        center_y /= count_center
        return center_x, center_y
예제 #3
0
    def set_miller_family(self):
        """
        get all miller indices for the given maximum index
        get the list of indices that correspond to the given family
        of indices
        """
        recp_structure = Structure(self.recp_lattice, ["H"], [[0, 0, 0]])
        analyzer = SpacegroupAnalyzer(recp_structure, symprec=0.001)
        symm_ops = analyzer.get_symmetry_operations()

        max_index = max(max(m) for m in self.hkl_family)
        r = list(range(-max_index, max_index + 1))
        r.reverse()
        miller_indices = []
        self.all_equiv_millers = []
        self.all_surface_energies = []
        for miller in itertools.product(r, r, r):
            if any([i != 0 for i in miller]):
                d = abs(reduce(gcd, miller))
                miller_index = tuple([int(i / d) for i in miller])
                for op in symm_ops:
                    for i, u_miller in enumerate(self.hkl_family):
                        if in_coord_list(u_miller, op.operate(miller_index)):
                            self.all_equiv_millers.append(miller_index)
                            self.all_surface_energies.append(
                                self.surface_energies[i])
예제 #4
0
    def get_center(self, lines):
        """
        Returns coordinates of center of a domain. Useful
        for labeling a Pourbaix plot.

        Args:
            lines:
                Lines corresponding to a domain
            limits:
                Limits of Pourbaix diagram

        Returns:
            center_x, center_y:
                x,y coordinate of center of domain. If domain lies
                outside limits, center will lie on the boundary.
        """
        center_x = 0.0
        center_y = 0.0
        coords = []
        count_center = 0.0
        for line in lines:
            for coord in np.array(line).T:
                if not in_coord_list(coords, coord):
                    coords.append(coord.tolist())
                    cx = coord[0]
                    cy = coord[1]
                    center_x += cx
                    center_y += cy
                    count_center += 1.0
        if count_center == 0.0:
            count_center = 1.0
        center_x /= count_center
        center_y /= count_center
        return center_x, center_y
예제 #5
0
    def set_miller_family(self):
        """
        get all miller indices for the given maximum index
        get the list of indices that correspond to the given family
        of indices
        """
        recp_structure = Structure(self.recp_lattice, ["H"], [[0, 0, 0]])
        analyzer = SpacegroupAnalyzer(recp_structure, symprec=0.001)
        symm_ops = analyzer.get_symmetry_operations()

        max_index = max(max(m) for m in self.hkl_family)
        r = list(range(-max_index, max_index + 1))
        r.reverse()
        miller_indices = []
        self.all_equiv_millers = []
        self.all_surface_energies = []
        for miller in itertools.product(r, r, r):
            if any([i != 0 for i in miller]):
                d = abs(reduce(gcd, miller))
                miller_index = tuple([int(i / d) for i in miller])
                for op in symm_ops:
                    for i, u_miller in enumerate(self.hkl_family):
                        if in_coord_list(u_miller, op.operate(miller_index)):
                            self.all_equiv_millers.append(miller_index)
                            self.all_surface_energies.append(self.surface_energies[i])
예제 #6
0
    def test_generate_adsorption_structures(self):
        co = Molecule("CO", [[0, 0, 0], [0, 0, 1.23]])
        structures = self.asf_111.generate_adsorption_structures(
            co, repeat=[2, 2, 1])
        self.assertEqual(len(structures), 4)
        sites = self.asf_111.find_adsorption_sites()
        # Check repeat functionality
        self.assertEqual(
            len([
                site for site in structures[0]
                if site.properties['surface_properties'] != 'adsorbate'
            ]), 4 * len(self.asf_111.slab))
        for n, structure in enumerate(structures):
            self.assertArrayAlmostEqual(structure[-2].coords, sites['all'][n])
        find_args = {"positions": ["hollow"]}
        structures_hollow = self.asf_111.\
                generate_adsorption_structures(co, find_args=find_args)
        self.assertEqual(len(structures_hollow), len(sites['hollow']))
        for n, structure in enumerate(structures_hollow):
            self.assertTrue(
                in_coord_list(sites['hollow'], structure[-2].coords))

        # checks if top_surface boolean will properly
        # adsorb at the bottom surface when False
        o = Molecule("O", [[0, 0, 0]])
        adslabs = self.asf_111_bottom.generate_adsorption_structures(o)
        for adslab in adslabs:
            sites = sorted(adslab, key=lambda site: site.frac_coords[2])
            self.assertTrue(sites[0].species_string == "O")
예제 #7
0
    def symm_check(self, ucell, wulff_vertices):
        """
        # Checks if the point group of the Wulff shape matches
        # the point group of its conventional unit cell

        Args:
            ucell (string): Unit cell that the Wulff shape is based on.
            wulff_vertices (list): List of all vertices on the Wulff
                shape. Use wulff.wulff_pt_list to obtain the list
                (see wulff_generator.py).

        return (bool)
        """

        space_group_analyzer = SpacegroupAnalyzer(ucell)
        symm_ops = space_group_analyzer.get_point_group_operations(
            cartesian=True)
        for point in wulff_vertices:
            for op in symm_ops:
                symm_point = op.operate(point)
                if in_coord_list(wulff_vertices, symm_point):
                    continue
                else:
                    return False
        return True
예제 #8
0
 def test_generate_adsorption_structures(self):
     co = Molecule("CO", [[0, 0, 0], [0, 0, 1.23]])
     structures = self.asf_111.generate_adsorption_structures(co, repeat=[2, 2, 1])
     self.assertEqual(len(structures), 4)
     sites = self.asf_111.find_adsorption_sites()
     # Check repeat functionality
     self.assertEqual(len([site for site in structures[0] if 
                           site.properties['surface_properties'] != 'adsorbate']),
                      4*len(self.asf_111.slab))
     for n, structure in enumerate(structures):
         self.assertArrayAlmostEqual(structure[-2].coords, sites['all'][n])
     find_args = {"positions":["hollow"]}
     structures_hollow = self.asf_111.\
             generate_adsorption_structures(co, find_args=find_args)
     self.assertEqual(len(structures_hollow), len(sites['hollow']))
     for n, structure in enumerate(structures_hollow):
         self.assertTrue(in_coord_list(sites['hollow'], structure[-2].coords))
예제 #9
0
 def test_generate_adsorption_structures(self):
     co = Molecule("CO", [[0, 0, 0], [0, 0, 1.23]])
     structures = self.asf_111.generate_adsorption_structures(
         co, repeat=[2, 2, 1])
     self.assertEqual(len(structures), 4)
     sites = self.asf_111.find_adsorption_sites()
     # Check repeat functionality
     self.assertEqual(
         len([
             site for site in structures[0]
             if site.properties['surface_properties'] != 'adsorbate'
         ]), 4 * len(self.asf_111.slab))
     for n, structure in enumerate(structures):
         self.assertArrayAlmostEqual(structure[-2].coords, sites['all'][n])
     find_args = {"positions": ["hollow"]}
     structures_hollow = self.asf_111.\
             generate_adsorption_structures(co, find_args=find_args)
     self.assertEqual(len(structures_hollow), len(sites['hollow']))
     for n, structure in enumerate(structures_hollow):
         self.assertTrue(
             in_coord_list(sites['hollow'], structure[-2].coords))
예제 #10
0
파일: plotter.py 프로젝트: qimin/pymatgen
    def get_chempot_range_map_plot(self, elements):
        """
        Returns a plot of the chemical potential range map. Currently works
        only for 3-component PDs.

        Args:
            elements:
                Sequence of elements to be considered as independent variables.
                E.g., if you want to show the stability ranges of all Li-Co-O
                phases wrt to uLi and uO, you will supply
                [Element("Li"), Element("O")]
        Returns:
            A matplotlib plot object.
        """

        plt = get_publication_quality_plot(12, 8)
        analyzer = PDAnalyzer(self._pd)
        chempot_ranges = analyzer.get_chempot_range_map(elements)
        missing_lines = {}
        excluded_region = []
        for entry, lines in chempot_ranges.items():
            comp = entry.composition
            center_x = 0
            center_y = 0
            coords = []
            contain_zero = any([comp.get_atomic_fraction(el) == 0 for el in elements])
            is_boundary = (not contain_zero) and sum([comp.get_atomic_fraction(el) for el in elements]) == 1
            for line in lines:
                (x, y) = line.coords.transpose()
                plt.plot(x, y, "k-")

                for coord in line.coords:
                    if not in_coord_list(coords, coord):
                        coords.append(coord.tolist())
                        center_x += coord[0]
                        center_y += coord[1]
                if is_boundary:
                    excluded_region.extend(line.coords)

            if coords and contain_zero:
                missing_lines[entry] = coords
            else:
                xy = (center_x / len(coords), center_y / len(coords))
                plt.annotate(latexify(entry.name), xy, fontsize=22)

        ax = plt.gca()
        xlim = ax.get_xlim()
        ylim = ax.get_ylim()

        # Shade the forbidden chemical potential regions.
        excluded_region.append([xlim[1], ylim[1]])
        excluded_region = sorted(excluded_region, key=lambda c: c[0])
        (x, y) = np.transpose(excluded_region)
        plt.fill(x, y, "0.80")

        # The hull does not generate the missing horizontal and vertical lines.
        # The following code fixes this.
        el0 = elements[0]
        el1 = elements[1]
        for entry, coords in missing_lines.items():
            center_x = sum([c[0] for c in coords])
            center_y = sum([c[1] for c in coords])
            comp = entry.composition
            is_x = comp.get_atomic_fraction(el0) < 0.01
            is_y = comp.get_atomic_fraction(el1) < 0.01
            n = len(coords)
            if not (is_x and is_y):
                if is_x:
                    coords = sorted(coords, key=lambda c: c[1])
                    for i in [0, -1]:
                        x = [min(xlim), coords[i][0]]
                        y = [coords[i][1], coords[i][1]]
                        plt.plot(x, y, "k")
                        center_x += min(xlim)
                        center_y += coords[i][1]
                elif is_y:
                    coords = sorted(coords, key=lambda c: c[0])
                    for i in [0, -1]:
                        x = [coords[i][0], coords[i][0]]
                        y = [coords[i][1], min(ylim)]
                        plt.plot(x, y, "k")
                        center_x += coords[i][0]
                        center_y += min(ylim)
                xy = (center_x / (n + 2), center_y / (n + 2))
            else:
                center_x = sum(coord[0] for coord in coords) + xlim[0]
                center_y = sum(coord[1] for coord in coords) + ylim[0]
                xy = (center_x / (n + 1), center_y / (n + 1))

            plt.annotate(
                latexify(entry.name), xy, horizontalalignment="center", verticalalignment="center", fontsize=22
            )

        plt.xlabel("$\mu_{{{0}}} - \mu_{{{0}}}^0$ (eV)".format(el0.symbol))
        plt.ylabel("$\mu_{{{0}}} - \mu_{{{0}}}^0$ (eV)".format(el1.symbol))
        plt.tight_layout()
        return plt
예제 #11
0
    def set_structure(self, structure, reset_camera=True):
        """
        Add a structure to the visualizer.

        Args:
            structure:
                structure to visualize
            reset_camera:
                Set to True to reset the camera to a default determined based
                on the structure.
        """
        self.ren.RemoveAllViewProps()

        has_lattice = hasattr(structure, "lattice")

        if has_lattice:
            s = Structure.from_sites(structure, to_unit_cell=True)
            s.make_supercell(self.supercell)
        else:
            s = structure

        inc_coords = []
        for site in s:
            self.add_site(site)
            inc_coords.append(site.coords)

        count = 0
        labels = ["a", "b", "c"]
        colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]

        if has_lattice:
            matrix = s.lattice.matrix

        if self.show_unit_cell and has_lattice:
            #matrix = s.lattice.matrix
            self.add_text([0, 0, 0], "o")
            for vec in matrix:
                self.add_line((0, 0, 0), vec, colors[count])
                self.add_text(vec, labels[count], colors[count])
                count += 1
            for (vec1, vec2) in itertools.permutations(matrix, 2):
                self.add_line(vec1, vec1 + vec2)
            for (vec1, vec2, vec3) in itertools.permutations(matrix, 3):
                self.add_line(vec1 + vec2, vec1 + vec2 + vec3)

        if self.show_bonds or self.show_polyhedron:
            elements = sorted(s.composition.elements, key=lambda a: a.X)
            anion = elements[-1]

            def contains_anion(site):
                for sp in site.species_and_occu.keys():
                    if sp.symbol == anion.symbol:
                        return True
                return False

            anion_radius = anion.average_ionic_radius
            for site in s:
                exclude = False
                max_radius = 0
                color = np.array([0, 0, 0])
                for sp, occu in site.species_and_occu.items():
                    if sp.symbol in self.excluded_bonding_elements \
                            or sp == anion:
                        exclude = True
                        break
                    max_radius = max(max_radius, sp.average_ionic_radius)
                    color = color + \
                        occu * np.array(self.el_color_mapping.get(sp.symbol,
                                                                  [0, 0, 0]))

                if not exclude:
                    max_radius = (1 + self.poly_radii_tol_factor) * \
                        (max_radius + anion_radius)
                    nn = structure.get_neighbors(site, max_radius)
                    nn_sites = []
                    for nnsite, dist in nn:
                        if contains_anion(nnsite):
                            nn_sites.append(nnsite)
                            if not in_coord_list(inc_coords, nnsite.coords):
                                self.add_site(nnsite)
                    if self.show_bonds:
                        self.add_bonds(nn_sites, site)
                    if self.show_polyhedron:
                        color = [i / 255 for i in color]
                        self.add_polyhedron(nn_sites, site, color)

        if self.show_help:
            self.helptxt_actor = vtk.vtkActor2D()
            self.helptxt_actor.VisibilityOn()
            self.helptxt_actor.SetMapper(self.helptxt_mapper)
            self.ren.AddActor(self.helptxt_actor)
            self.display_help()

        camera = self.ren.GetActiveCamera()
        if reset_camera:
            if has_lattice:
                #Adjust the camera for best viewing
                lengths = s.lattice.abc
                pos = (matrix[1] + matrix[2]) * 0.5 + \
                    matrix[0] * max(lengths) / lengths[0] * 3.5
                camera.SetPosition(pos)
                camera.SetViewUp(matrix[2])
                camera.SetFocalPoint((matrix[0] + matrix[1] + matrix[2]) * 0.5)
            else:
                origin = s.center_of_mass
                max_site = max(
                    s, key=lambda site: site.distance_from_point(origin))
                camera.SetPosition(origin + 5 * (max_site.coords - origin))
                camera.SetFocalPoint(s.center_of_mass)

        self.structure = structure
        self.title = s.composition.formula
예제 #12
0
 def is_already_analyzed(miller_index):
     for op in symm_ops:
         if in_coord_list(unique_millers, op.operate(miller_index)):
             return True
     return False
예제 #13
0
    def get_pourbaix_plot(self, limits=None, title="", label_domains=True):
        """
        Plot Pourbaix diagram.

        Args:
            limits: 2D list containing limits of the Pourbaix diagram
                of the form [[xlo, xhi], [ylo, yhi]]

        Returns:
            plt:
                matplotlib plot object
        """
#        plt = get_publication_quality_plot(24, 14.4)
        plt = get_publication_quality_plot(16)
        (stable, unstable) = self.pourbaix_plot_data(limits)
        if limits:
            xlim = limits[0]
            ylim = limits[1]
        else:
            xlim = self._analyzer.chempot_limits[0]
            ylim = self._analyzer.chempot_limits[1]

        h_line = np.transpose([[xlim[0], -xlim[0] * PREFAC],
                               [xlim[1], -xlim[1] * PREFAC]])
        o_line = np.transpose([[xlim[0], -xlim[0] * PREFAC + 1.23],
                               [xlim[1], -xlim[1] * PREFAC + 1.23]])
        neutral_line = np.transpose([[7, ylim[0]], [7, ylim[1]]])
        V0_line = np.transpose([[xlim[0], 0], [xlim[1], 0]])

        ax = plt.gca()
        ax.set_xlim(xlim)
        ax.set_ylim(ylim)
        lw = 3
        plt.plot(h_line[0], h_line[1], "r--", linewidth=lw)
        plt.plot(o_line[0], o_line[1], "r--", linewidth=lw)
        plt.plot(neutral_line[0], neutral_line[1], "k-.", linewidth=lw)
        plt.plot(V0_line[0], V0_line[1], "k-.", linewidth=lw)

        for entry, lines in stable.items():
            center_x = 0.0
            center_y = 0.0
            coords = []
            count_center = 0.0
            for line in lines:
                (x, y) = line
                plt.plot(x, y, "k-", linewidth=lw)
                for coord in np.array(line).T:
                    if not in_coord_list(coords, coord):
                        coords.append(coord.tolist())
                        cx = coord[0]
                        cy = coord[1]
                        center_x += cx
                        center_y += cy
                        count_center += 1.0
            if count_center == 0.0:
                count_center = 1.0
            center_x /= count_center
            center_y /= count_center
            if ((center_x <= xlim[0]) | (center_x >= xlim[1]) |
                    (center_y <= ylim[0]) | (center_y >= ylim[1])):
                continue
            xy = (center_x, center_y)
            if label_domains:
                plt.annotate(self.print_name(entry), xy, fontsize=20, color="b")

        plt.xlabel("pH")
        plt.ylabel("E (V)")
        plt.title(title, fontsize=20, fontweight='bold')
        return plt
예제 #14
0
    def get_chempot_range_map_plot(self, elements, referenced=True):
        """
        Returns a plot of the chemical potential range _map. Currently works
        only for 3-component PDs.

        Args:
            elements: Sequence of elements to be considered as independent
                variables. E.g., if you want to show the stability ranges of
                all Li-Co-O phases wrt to uLi and uO, you will supply
                [Element("Li"), Element("O")]
            referenced: if True, gives the results with a reference being the
                        energy of the elemental phase. If False, gives absolute values.

        Returns:
            A matplotlib plot object.
        """

        plt = get_publication_quality_plot(12, 8)
        analyzer = PDAnalyzer(self._pd)
        chempot_ranges = analyzer.get_chempot_range_map(elements,
                                                        referenced=referenced)
        missing_lines = {}
        excluded_region = []
        for entry, lines in chempot_ranges.items():
            comp = entry.composition
            center_x = 0
            center_y = 0
            coords = []
            contain_zero = any(
                [comp.get_atomic_fraction(el) == 0 for el in elements])
            is_boundary = (not contain_zero) and \
                sum([comp.get_atomic_fraction(el) for el in elements]) == 1
            for line in lines:
                (x, y) = line.coords.transpose()
                plt.plot(x, y, "k-")

                for coord in line.coords:
                    if not in_coord_list(coords, coord):
                        coords.append(coord.tolist())
                        center_x += coord[0]
                        center_y += coord[1]
                if is_boundary:
                    excluded_region.extend(line.coords)

            if coords and contain_zero:
                missing_lines[entry] = coords
            else:
                xy = (center_x / len(coords), center_y / len(coords))
                plt.annotate(latexify(entry.name), xy, fontsize=22)

        ax = plt.gca()
        xlim = ax.get_xlim()
        ylim = ax.get_ylim()

        #Shade the forbidden chemical potential regions.
        excluded_region.append([xlim[1], ylim[1]])
        excluded_region = sorted(excluded_region, key=lambda c: c[0])
        (x, y) = np.transpose(excluded_region)
        plt.fill(x, y, "0.80")

        #The hull does not generate the missing horizontal and vertical lines.
        #The following code fixes this.
        el0 = elements[0]
        el1 = elements[1]
        for entry, coords in missing_lines.items():
            center_x = sum([c[0] for c in coords])
            center_y = sum([c[1] for c in coords])
            comp = entry.composition
            is_x = comp.get_atomic_fraction(el0) < 0.01
            is_y = comp.get_atomic_fraction(el1) < 0.01
            n = len(coords)
            if not (is_x and is_y):
                if is_x:
                    coords = sorted(coords, key=lambda c: c[1])
                    for i in [0, -1]:
                        x = [min(xlim), coords[i][0]]
                        y = [coords[i][1], coords[i][1]]
                        plt.plot(x, y, "k")
                        center_x += min(xlim)
                        center_y += coords[i][1]
                elif is_y:
                    coords = sorted(coords, key=lambda c: c[0])
                    for i in [0, -1]:
                        x = [coords[i][0], coords[i][0]]
                        y = [coords[i][1], min(ylim)]
                        plt.plot(x, y, "k")
                        center_x += coords[i][0]
                        center_y += min(ylim)
                xy = (center_x / (n + 2), center_y / (n + 2))
            else:
                center_x = sum(coord[0] for coord in coords) + xlim[0]
                center_y = sum(coord[1] for coord in coords) + ylim[0]
                xy = (center_x / (n + 1), center_y / (n + 1))

            plt.annotate(latexify(entry.name),
                         xy,
                         horizontalalignment="center",
                         verticalalignment="center",
                         fontsize=22)

        plt.xlabel("$\mu_{{{0}}} - \mu_{{{0}}}^0$ (eV)".format(el0.symbol))
        plt.ylabel("$\mu_{{{0}}} - \mu_{{{0}}}^0$ (eV)".format(el1.symbol))
        plt.tight_layout()
        return plt
예제 #15
0
    def get_pourbaix_plot(self, limits=None, title="", label_domains=True):
        """
        Plot Pourbaix diagram.

        Args:
            limits: 2D list containing limits of the Pourbaix diagram
                of the form [[xlo, xhi], [ylo, yhi]]

        Returns:
            plt:
                matplotlib plot object
        """
        #        plt = get_publication_quality_plot(24, 14.4)
        plt = get_publication_quality_plot(16)
        (stable, unstable) = self.pourbaix_plot_data(limits)
        if limits:
            xlim = limits[0]
            ylim = limits[1]
        else:
            xlim = self._analyzer.chempot_limits[0]
            ylim = self._analyzer.chempot_limits[1]

        h_line = np.transpose([[xlim[0], -xlim[0] * PREFAC],
                               [xlim[1], -xlim[1] * PREFAC]])
        o_line = np.transpose([[xlim[0], -xlim[0] * PREFAC + 1.23],
                               [xlim[1], -xlim[1] * PREFAC + 1.23]])
        neutral_line = np.transpose([[7, ylim[0]], [7, ylim[1]]])
        V0_line = np.transpose([[xlim[0], 0], [xlim[1], 0]])

        ax = plt.gca()
        ax.set_xlim(xlim)
        ax.set_ylim(ylim)
        lw = 3
        plt.plot(h_line[0], h_line[1], "r--", linewidth=lw)
        plt.plot(o_line[0], o_line[1], "r--", linewidth=lw)
        plt.plot(neutral_line[0], neutral_line[1], "k-.", linewidth=lw)
        plt.plot(V0_line[0], V0_line[1], "k-.", linewidth=lw)

        for entry, lines in stable.items():
            center_x = 0.0
            center_y = 0.0
            coords = []
            count_center = 0.0
            for line in lines:
                (x, y) = line
                plt.plot(x, y, "k-", linewidth=lw)
                for coord in np.array(line).T:
                    if not in_coord_list(coords, coord):
                        coords.append(coord.tolist())
                        cx = coord[0]
                        cy = coord[1]
                        center_x += cx
                        center_y += cy
                        count_center += 1.0
            if count_center == 0.0:
                count_center = 1.0
            center_x /= count_center
            center_y /= count_center
            if ((center_x <= xlim[0]) | (center_x >= xlim[1]) |
                (center_y <= ylim[0]) | (center_y >= ylim[1])):
                continue
            xy = (center_x, center_y)
            if label_domains:
                plt.annotate(self.print_name(entry),
                             xy,
                             fontsize=20,
                             color="b")

        plt.xlabel("pH")
        plt.ylabel("E (V)")
        plt.title(title, fontsize=20, fontweight='bold')
        return plt
예제 #16
0
    def get_distribution_corrected_center(self,
                                          lines,
                                          h2o_h_line=None,
                                          h2o_o_line=None,
                                          radius=None):
        """
        Returns coordinates of distribution corrected center of a domain. Similar to get_center(), but
        considers the distance to the surronding lines that mostly affects the feeling of "center".
        This function will also try avoid overalapping the text babel with H2O stability line if H2O
        stability line is provided. Useful for labeling a Pourbaix plot.

        Args:
            lines:
                Lines corresponding to a domain
            limits:
                Limits of Pourbaix diagram
            h2o_h_line: Hydrogen line of H2O stability
            h2o_o_line: Oxygen line of H2O stablity
            radius: Half height of the text label.

        Returns:
            center_x, center_y:
                x,y coordinate of center of domain. If domain lies
                outside limits, center will lie on the boundary.
        """
        coords = []
        pts_x = []
        pts_y = []
        for line in lines:
            for coord in np.array(line).T:
                if not in_coord_list(coords, coord):
                    coords.append(coord.tolist())
                    cx = coord[0]
                    cy = coord[1]
                    pts_x.append(cx)
                    pts_y.append(cy)
        if len(pts_x) < 1:
            return 0.0, 0.0
        cx_1 = (max(pts_x) + min(pts_x)) / 2.0
        cy_1 = (max(pts_y) + min(pts_y)) / 2.0
        mid_x_list = []
        mid_y_list = []
        # move the center to the center of surrounding lines
        for line in lines:
            (x1, y1), (x2, y2) = np.array(line).T
            if (x1 - cx_1) * (x2 - cx_1) <= 0.0:
                # horizontal line
                mid_y = ((y2 - y1) / (x2 - x1)) * (cx_1 - x1) + y1
                assert (y2 - mid_y) * (y1 - mid_y) <= 0.0
                mid_y_list.append(mid_y)
            if (y1 - cy_1) * (y2 - cy_1) <= 0.0:
                # vertical line
                mid_x = ((x2 - x1) / (y2 - y1)) * (cy_1 - y1) + x1
                assert (x2 - mid_x) * (x1 - mid_x) <= 0.0
                mid_x_list.append(mid_x)
        upper_y = sorted([y for y in mid_y_list if y >= cy_1])[0]
        lower_y = sorted([y for y in mid_y_list if y < cy_1])[-1]
        left_x = sorted([x for x in mid_x_list if x <= cx_1])[-1]
        right_x = sorted([x for x in mid_x_list if x > cx_1])[0]
        center_x = (left_x + right_x) / 2.0
        center_y = (upper_y + lower_y) / 2.0
        if h2o_h_line is not None:
            (h2o_h_x1, h2o_h_y1), (h2o_h_x2, h2o_h_y2) = h2o_h_line.T
            h_slope = (h2o_h_y2 - h2o_h_y1) / (h2o_h_x2 - h2o_h_x1)
            (h2o_o_x1, h2o_o_y1), (h2o_o_x2, h2o_o_y2) = h2o_o_line.T
            o_slope = (h2o_o_y2 - h2o_o_y1) / (h2o_o_x2 - h2o_o_x1)
            h_y = h_slope * (cx_1 - h2o_h_x1) + h2o_h_y1
            o_y = o_slope * (cx_1 - h2o_o_x1) + h2o_o_y1
            h2o_y = None
            if abs(center_y - h_y) < radius:
                h2o_y = h_y
            elif abs(center_y - o_y) < radius:
                h2o_y = o_y
            if h2o_y is not None:
                if (upper_y - lower_y) / 2.0 > radius * 2.0:
                    # The space can hold the whole text (radius * 2.0)
                    if h2o_y > center_y:
                        center_y = h2o_y - radius
                    else:
                        center_y = h2o_y + radius
        return center_x, center_y
예제 #17
0
파일: surface.py 프로젝트: adozier/pymatgen
 def is_already_analyzed(miller_index):
     for op in symm_ops:
         if in_coord_list(unique_millers, op.operate(miller_index)):
             return True
     return False
예제 #18
0
    def get_distribution_corrected_center(self, lines, h2o_h_line=None, h2o_o_line=None, radius=None):
        """
        Returns coordinates of distribution corrected center of a domain. Similar to get_center(), but
        considers the distance to the surronding lines that mostly affects the feeling of "center".
        This function will also try avoid overalapping the text babel with H2O stability line if H2O
        stability line is provided. Useful for labeling a Pourbaix plot.

        Args:
            lines:
                Lines corresponding to a domain
            limits:
                Limits of Pourbaix diagram
            h2o_h_line: Hydrogen line of H2O stability
            h2o_o_line: Oxygen line of H2O stablity
            radius: Half height of the text label.

        Returns:
            center_x, center_y:
                x,y coordinate of center of domain. If domain lies
                outside limits, center will lie on the boundary.
        """
        coords = []
        pts_x = []
        pts_y = []
        for line in lines:
            for coord in np.array(line).T:
                if not in_coord_list(coords, coord):
                    coords.append(coord.tolist())
                    cx = coord[0]
                    cy = coord[1]
                    pts_x.append(cx)
                    pts_y.append(cy)
        if len(pts_x) < 1:
            return 0.0, 0.0
        cx_1 = (max(pts_x) + min(pts_x)) / 2.0
        cy_1 = (max(pts_y) + min(pts_y)) / 2.0
        mid_x_list = []
        mid_y_list = []
        # move the center to the center of surrounding lines
        for line in lines:
            (x1, y1), (x2, y2) = np.array(line).T
            if (x1 - cx_1) * (x2 - cx_1) <= 0.0:
                # horizontal line
                mid_y = ((y2 - y1) / (x2 - x1)) * (cx_1 - x1) + y1
                assert (y2 - mid_y) * (y1 - mid_y) <= 0.0
                mid_y_list.append(mid_y)
            if (y1 - cy_1) * (y2 - cy_1) <= 0.0:
                # vertical line
                mid_x = ((x2 - x1) / (y2 - y1)) * (cy_1 - y1) + x1
                assert (x2 - mid_x) * (x1 - mid_x) <= 0.0
                mid_x_list.append(mid_x)
        upper_y = sorted([y for y in mid_y_list if y >= cy_1])[0]
        lower_y = sorted([y for y in mid_y_list if y < cy_1])[-1]
        left_x = sorted([x for x in mid_x_list if x <= cx_1])[-1]
        right_x = sorted([x for x in mid_x_list if x > cx_1])[0]
        center_x = (left_x + right_x) / 2.0
        center_y = (upper_y + lower_y) / 2.0
        if h2o_h_line is not None:
            (h2o_h_x1, h2o_h_y1), (h2o_h_x2, h2o_h_y2) = h2o_h_line.T
            h_slope = (h2o_h_y2 - h2o_h_y1) / (h2o_h_x2 - h2o_h_x1)
            (h2o_o_x1, h2o_o_y1), (h2o_o_x2, h2o_o_y2) = h2o_o_line.T
            o_slope = (h2o_o_y2 - h2o_o_y1) / (h2o_o_x2 - h2o_o_x1)
            h_y = h_slope * (cx_1 - h2o_h_x1) + h2o_h_y1
            o_y = o_slope * (cx_1 - h2o_o_x1) + h2o_o_y1
            h2o_y = None
            if abs(center_y - h_y) < radius:
                h2o_y = h_y
            elif  abs(center_y - o_y) < radius:
                h2o_y = o_y
            if h2o_y is not None:
                if (upper_y - lower_y) / 2.0 > radius * 2.0:
                    # The space can hold the whole text (radius * 2.0)
                    if h2o_y > center_y:
                        center_y = h2o_y - radius
                    else:
                        center_y = h2o_y + radius
        return center_x, center_y
예제 #19
0
    def set_structure(self, structure, reset_camera=True):
        """
        Add a structure to the visualizer.

        Args:
            structure:
                structure to visualize
            reset_camera:
                Set to True to reset the camera to a default determined based
                on the structure.
        """
        self.ren.RemoveAllViewProps()

        has_lattice = hasattr(structure, "lattice")

        if has_lattice:
            s = Structure.from_sites(structure, to_unit_cell=True)
            s.make_supercell(self.supercell)
        else:
            s = structure

        inc_coords = []
        for site in s:
            self.add_site(site)
            inc_coords.append(site.coords)

        count = 0
        labels = ["a", "b", "c"]
        colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]

        if has_lattice:
            matrix = s.lattice.matrix

        if self.show_unit_cell and has_lattice:
            #matrix = s.lattice.matrix
            self.add_text([0, 0, 0], "o")
            for vec in matrix:
                self.add_line((0, 0, 0), vec, colors[count])
                self.add_text(vec, labels[count], colors[count])
                count += 1
            for (vec1, vec2) in itertools.permutations(matrix, 2):
                self.add_line(vec1, vec1 + vec2)
            for (vec1, vec2, vec3) in itertools.permutations(matrix, 3):
                self.add_line(vec1 + vec2, vec1 + vec2 + vec3)

        if self.show_bonds or self.show_polyhedron:
            elements = sorted(s.composition.elements, key=lambda a: a.X)
            anion = elements[-1]

            def contains_anion(site):
                for sp in site.species_and_occu.keys():
                    if sp.symbol == anion.symbol:
                        return True
                return False

            anion_radius = anion.average_ionic_radius
            for site in s:
                exclude = False
                max_radius = 0
                color = np.array([0, 0, 0])
                for sp, occu in site.species_and_occu.items():
                    if sp.symbol in self.excluded_bonding_elements \
                            or sp == anion:
                        exclude = True
                        break
                    max_radius = max(max_radius, sp.average_ionic_radius)
                    color = color + \
                        occu * np.array(self.el_color_mapping.get(sp.symbol,
                                                                  [0, 0, 0]))

                if not exclude:
                    max_radius = (1 + self.poly_radii_tol_factor) * \
                        (max_radius + anion_radius)
                    nn = structure.get_neighbors(site, max_radius)
                    nn_sites = []
                    for nnsite, dist in nn:
                        if contains_anion(nnsite):
                            nn_sites.append(nnsite)
                            if not in_coord_list(inc_coords, nnsite.coords):
                                self.add_site(nnsite)
                    if self.show_bonds:
                        self.add_bonds(nn_sites, site)
                    if self.show_polyhedron:
                        color = [i / 255 for i in color]
                        self.add_polyhedron(nn_sites, site, color)

        if self.show_help:
            self.helptxt_actor = vtk.vtkActor2D()
            self.helptxt_actor.VisibilityOn()
            self.helptxt_actor.SetMapper(self.helptxt_mapper)
            self.ren.AddActor(self.helptxt_actor)
            self.display_help()

        camera = self.ren.GetActiveCamera()
        if reset_camera:
            if has_lattice:
                #Adjust the camera for best viewing
                lengths = s.lattice.abc
                pos = (matrix[1] + matrix[2]) * 0.5 + \
                    matrix[0] * max(lengths) / lengths[0] * 3.5
                camera.SetPosition(pos)
                camera.SetViewUp(matrix[2])
                camera.SetFocalPoint((matrix[0] + matrix[1] + matrix[2]) * 0.5)
            else:
                origin = s.center_of_mass
                max_site = max(
                    s, key=lambda site: site.distance_from_point(origin))
                camera.SetPosition(origin + 5 * (max_site.coords - origin))
                camera.SetFocalPoint(s.center_of_mass)

        self.structure = structure
        self.title = s.composition.formula