pymatgen.io.xcrysden — pymatgen 2020.7.3 documentation

# Source code for pymatgen.io.xcrysden

    # coding: utf-8
    # Copyright (c) Pymatgen Development Team.
    # Distributed under the terms of the MIT License.

    """
    Support for reading XCrysDen files.
    """

    from pymatgen.core.periodic_table import Element

    __author__ = "Matteo Giantomassi"
    __copyright__ = "Copyright 2013, The Materials Project"
    __version__ = "0.1"
    __maintainer__ = "Matteo Giantomassi"

    class XSF:
        """
        Class for parsing XCrysden files.
        """

        def __init__(self, structure):
            """
            :param structure: Structure object.
            """
            self.structure = structure

        def to_string(self):
            """
            Returns a string with the structure in XSF format
            See http://www.xcrysden.org/doc/XSF.html
            """
            lines = []
            app = lines.append

            app("CRYSTAL")
            app("# Primitive lattice vectors in Angstrom")
            app("PRIMVEC")
            cell = self.structure.lattice.matrix
            for i in range(3):
                app(' %.14f %.14f %.14f' % tuple(cell[i]))

            cart_coords = self.structure.cart_coords
            app("# Cartesian coordinates in Angstrom.")
            app("PRIMCOORD")
            app(" %d 1" % len(cart_coords))

            for a in range(len(cart_coords)):
                sp = "%d" % self.structure.atomic_numbers[a]
                app(sp + ' %20.14f %20.14f %20.14f' % tuple(cart_coords[a]))

            return "\n".join(lines)

        @classmethod
        def from_string(cls, input_string, cls_=None):
            """
            Initialize a `Structure` object from a string with data in XSF format.

            Args:
                input_string: String with the structure in XSF format.
                    See http://www.xcrysden.org/doc/XSF.html
                cls_: Structure class to be created. default: pymatgen structure

            """
            # CRYSTAL                                        see (1)
            # these are primitive lattice vectors (in Angstroms)
            # PRIMVEC
            #    0.0000000    2.7100000    2.7100000         see (2)
            #    2.7100000    0.0000000    2.7100000
            #    2.7100000    2.7100000    0.0000000

            # these are conventional lattice vectors (in Angstroms)
            # CONVVEC
            #    5.4200000    0.0000000    0.0000000         see (3)
            #    0.0000000    5.4200000    0.0000000
            #    0.0000000    0.0000000    5.4200000

            # these are atomic coordinates in a primitive unit cell  (in Angstroms)
            # PRIMCOORD
            # 2 1                                            see (4)
            # 16      0.0000000     0.0000000     0.0000000  see (5)
            # 30      1.3550000    -1.3550000    -1.3550000

            lattice, coords, species = [], [], []
            lines = input_string.splitlines()

            for i in range(len(lines)):
                if "PRIMVEC" in lines[i]:
                    for j in range(i+1, i+4):
                        lattice.append([float(c) for c in lines[j].split()])

                if "PRIMCOORD" in lines[i]:
                    num_sites = int(lines[i+1].split()[0])

                    for j in range(i+2, i+2+num_sites):
                        tokens = lines[j].split()
                        if tokens[0].isalpha():
                            Z = Element(tokens[0]).Z
                        else:
                            Z = int(tokens[0])
                        species.append(Z)
                        coords.append([float(j) for j in tokens[1:4]])
                    break
            else:
                raise ValueError("Invalid XSF data")

            if cls_ is None:
                from pymatgen.core.structure import Structure
                cls_ = Structure

            s = cls_(lattice, species, coords, coords_are_cartesian=True)
            return XSF(s)