Пример #1
0
    def find_unique_ions(self):
        """ Generate a unique set of the ions, fix duplicates """
        ions = dict()

        to_remove = set()

        for ion1 in self.ions:
            if ion1 not in to_remove:
                for ion2 in self.ions:
                    if ion1 != ion2:
                        dr, _ = self.ions.least_mirror(ion1.position,
                                                       ion2.position)

                        if dr < 0.01:
                            print ion1, ion2
                            to_remove.add(ion2)

        return AtomsView([atom for atom in self.ions if atom not in to_remove],
                         self.ions.lattice)
Пример #2
0
    def parse_ions(self):
        self.ions_type = None

        if 'POSITIONS_ABS' in self.blocks:
          self.ions_type = 'POSITIONS_ABS'
          self.basis = numpy.array([[1.0, 0.0, 0.0],
                                    [0.0, 1.0, 0.0],
                                    [0.0, 0.0, 1.0]])
        elif 'POSITIONS_FRAC' in self.blocks:
          self.ions_type = 'POSITIONS_FRAC'
          self.basis = self.lattice

        if self.ions_type is None:
          return

        convert = False # Dont convert frac to cart
        if self.ions_type == 'POSITIONS_FRAC':
          convert = True

        atoms = []

        index_counter = Counter()

        self.ions_units = None
        for line in self.blocks[self.ions_type]: # Include positions frac
          lsplit = line.split()

          if len(lsplit) == 4:
            s, x, y, z = lsplit
            position = (float(x), float(y), float(z))

            sl = s.split(":")

            species = sl[0]

            # Atoms are 1-indexed to match castep.
            index_counter[species] += 1
            index = index_counter[species]

            if len(sl) > 1:
              label = sl[1]
            else:
              label = species

            if convert:
              position = numpy.dot(self.basis.T, position)

            atoms.append(Atom(species, index, position, label))

          elif len(lsplit) == 1:
            self.ions_units = lsplit[0]

        if self.ions_units is None:
          self.ions_units = 'ang'

        # If we've converted, change the basis
        if convert:
          self.ions_type = 'POSITIONS_ABS'
          self.basis = numpy.array([[1.0, 0.0, 0.0],
                                    [0.0, 1.0, 0.0],
                                    [0.0, 0.0, 1.0]])

        self.ions = AtomsView(atoms, self.lattice)
Пример #3
0
class Cell:
    class LatticeNotImplemented(Exception): pass
    class LatticeWrongShape(Exception): pass

    def __init__(self, cell_file=None, **kwargs):
        self.blocks = {}
        self.otherdict = {}

        self.ions = None 

        if cell_file is not None:
          if type(cell_file) is str:
            if os.path.isfile(cell_file):
              self.parse_cell(open(cell_file).read())
            else:
              self.parse_cell(cell_file)

          elif type(cell_file) is file:
            self.parse_cell(cell_file.read())

          elif hasattr(cell_file, "ions"):
            new_ions = Atoms([a.copy() for a in cell_file.ions])
            new_ions.lattice = cell_file.lattice

            self.ions = new_ions
            self.lattice_units = cell_file.lattice_units
            self.lattice_type = cell_file.lattice_type
            self.ions_units = cell_file.ions_units
            self.ions_type = cell_file.ions_type
            self.basis = cell_file.basis


        if 'lattice' in kwargs:
          self.lattice_units = "ang"
          self.lattice_type = "LATTICE_CART"
          self.lattice = numpy.array(kwargs['lattice'])
          self.ions.lattice = self.lattice

          self.ions_units = "ang"
          self.ions_type = "POSITIONS_ABS"
          self.basis = numpy.array([[1.0, 0.0, 0.0],
                                    [0.0, 1.0, 0.0],
                                    [0.0, 0.0, 1.0]])

    def parse_cell(self, cell):
        block_re = re.compile(r"%block (.*?)\n(.*?\n{0,})%endblock (.*?)\n", re.I | re.S | re.M)

        # Fix any windows line endings
        cell = cell.replace("\r\n", "\n")
        blocks = block_re.findall(cell)
        
        for name, content, _ in blocks:
            unclean_lines = content.split('\n')
            lines = []
            for line in unclean_lines:
                line_clean = line.strip()
                if len(line_clean) > 0:
                    lines.append(line_clean)
            self.blocks[name.upper()] = lines

        cell_sans_blocks = block_re.sub("", cell)
        other = re.split("\n\s{0,}", cell_sans_blocks, re.S | re.M)
        for o in other:
            o_s = o.strip()
            if len(o_s) > 0:
                o_split = re.split("[\s:]+", o_s, maxsplit=1)

                if len(o_split) == 2:
                  self.otherdict[o_split[0]] = o_split[1]
                elif len(o_split) == 1:
                  self.otherdict[o_split[0]] = None
                else:
                  raise Exception("More than two columns for cell-other split")

        self.parse_lattice()
        self.parse_ions()

    def parse_lattice_cart(self, block):
      lattice = []
      units = "ang"

      for line in block: 
        lsplit = line.split()

        if len(lsplit) == 3:
          lattice.append((float(lsplit[0]),
                          float(lsplit[1]),
                          float(lsplit[2]),))
        elif len(lsplit) == 1:
          units = lsplit[0]

      return (units, lattice)

    def parse_lattice_abc(self, block):
      lattice = []
      units = None

      pi = numpy.pi
      sin = numpy.sin
      cos = numpy.cos
      sqrt = numpy.sqrt

      a = b = c = alpha = beta = gamma = None

      if len(block) == 3:
        units = block[0]
        a, b, c = map(float, block[1].split())
        alpha, beta, gamma = map(float, block[2].split())
      elif len(block) == 2:
        units = "ang"
        a, b, c = map(float, block[0].split())
        alpha, beta, gamma = map(float, block[1].split())

      alpha = alpha * pi / 180.0
      beta = beta * pi / 180.0
      gamma = gamma * pi / 180.0

      lattice.append([a, 0.0, 0.0])
      lattice.append([b*cos(gamma), b*sin(gamma), 0.0])
      lattice.append([c*cos(beta),
                      c*(cos(alpha) - cos(beta)*cos(gamma))/sin(gamma),
                      0.0])

      lattice[2][2] = sqrt(c**2 - lattice[2][0]**2 - lattice[2][1]**2)

      return (units, lattice)

    def parse_lattice(self):
        self.lattice_type = None
        for block_name in self.blocks:
          if 'LATTICE_' in block_name:
            self.lattice_type = block_name

        if self.lattice_type is None:
          return

        lattice = None
        units = None

        if self.lattice_type == "LATTICE_CART":
          units, lattice = self.parse_lattice_cart(self.blocks["LATTICE_CART"])
        elif self.lattice_type == "LATTICE_ABC":
          units, lattice = self.parse_lattice_abc(self.blocks["LATTICE_ABC"])
        else:
          raise self.LatticeNotImplemented("%s not implemented in parser" % self.lattice_type)

        self.lattice = numpy.array(lattice)
        self.lattice_units = units

        if self.lattice.shape != (3,3):
          raise self.LatticeWrongShape("Lattice vectors given not 3x3")

    def parse_ions(self):
        self.ions_type = None

        if 'POSITIONS_ABS' in self.blocks:
          self.ions_type = 'POSITIONS_ABS'
          self.basis = numpy.array([[1.0, 0.0, 0.0],
                                    [0.0, 1.0, 0.0],
                                    [0.0, 0.0, 1.0]])
        elif 'POSITIONS_FRAC' in self.blocks:
          self.ions_type = 'POSITIONS_FRAC'
          self.basis = self.lattice

        if self.ions_type is None:
          return

        convert = False # Dont convert frac to cart
        if self.ions_type == 'POSITIONS_FRAC':
          convert = True

        atoms = []

        index_counter = Counter()

        self.ions_units = None
        for line in self.blocks[self.ions_type]: # Include positions frac
          lsplit = line.split()

          if len(lsplit) == 4:
            s, x, y, z = lsplit
            position = (float(x), float(y), float(z))

            sl = s.split(":")

            species = sl[0]

            # Atoms are 1-indexed to match castep.
            index_counter[species] += 1
            index = index_counter[species]

            if len(sl) > 1:
              label = sl[1]
            else:
              label = species

            if convert:
              position = numpy.dot(self.basis.T, position)

            atoms.append(Atom(species, index, position, label))

          elif len(lsplit) == 1:
            self.ions_units = lsplit[0]

        if self.ions_units is None:
          self.ions_units = 'ang'

        # If we've converted, change the basis
        if convert:
          self.ions_type = 'POSITIONS_ABS'
          self.basis = numpy.array([[1.0, 0.0, 0.0],
                                    [0.0, 1.0, 0.0],
                                    [0.0, 0.0, 1.0]])

        self.ions = AtomsView(atoms, self.lattice)

    def regen_ion_block(self):
        for type in ['POSITIONS_ABS', 'POSITIONS_FRAC']: # Clear out any other ion blocks
          if type in self.blocks:
            del self.blocks[type]

        self.blocks[self.ions_type] = [self.ions_units] + ["{} {:f} {:f} {:f}".format(atom.species, atom.position[0], atom.position[1], atom.position[2]) for atom in self.ions]

    def regen_lattice_block(self):
        self.blocks[self.lattice_type] = [self.lattice_units] + ["{:f} {:f} {:f}".format(a,b,c) for a,b,c in self.ions.lattice]

    def find_unique_ions(self):
        """ Generate a unique set of the ions, fix duplicates """
        ions = dict()

        to_remove = set()

        for ion1 in self.ions:
          if ion1 not in to_remove:
            for ion2 in self.ions:
              if ion1 != ion2:
                dr, _ = self.ions.least_mirror(ion1.position, ion2.position)

                if dr < 0.01:
                  print ion1, ion2
                  to_remove.add(ion2)

        return AtomsView([atom for atom in self.ions if atom not in to_remove],
                         self.ions.lattice)
 
    def __str__(self):
        self.regen_ion_block()
        self.regen_lattice_block()
        
        out = []
        for name, lines in self.blocks.items():
            out.append("%block {}".format(name))
            out += lines
            out.append("%endblock {}".format(name))
            out.append("")

        for key, value in self.otherdict.items():
            if value is not None:
              out.append("{}: {}".format(key, value))
            else:
              out.append(key)

        return "\n".join(out)

    def supercell(self, N1, N2, N3):
        new_ions = []

        index = 0
        for ion in self.ions:
          for n1 in range(N1):
            for n2 in range(N2):
              for n3 in range(N3):
                R = numpy.dot(self.lattice, numpy.array([n1, n2, n3]))
                new_pos = ion.position + R

                new_ion = Atom(ion.species, index, new_pos)
                new_ions.append(new_ion)
                index += 1

        supercell = Cell(self)

        supercell.lattice = numpy.dot(numpy.diag([N1, N2, N3]), self.lattice)
        supercell.ions = Atoms(new_ions)
        supercell.ions.lattice = supercell.lattice

        return supercell
Пример #4
0
    def parse_ions(self):
        self.ions_type = None

        if 'POSITIONS_ABS' in self.blocks:
            self.ions_type = 'POSITIONS_ABS'
            self.basis = numpy.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0],
                                      [0.0, 0.0, 1.0]])
        elif 'POSITIONS_FRAC' in self.blocks:
            self.ions_type = 'POSITIONS_FRAC'
            self.basis = self.lattice

        if self.ions_type is None:
            return

        convert = False  # Dont convert frac to cart
        if self.ions_type == 'POSITIONS_FRAC':
            convert = True

        atoms = []

        index_counter = Counter()

        self.ions_units = None
        for line in self.blocks[self.ions_type]:  # Include positions frac
            lsplit = line.split()

            if len(lsplit) == 4:
                s, x, y, z = lsplit
                position = (float(x), float(y), float(z))

                sl = s.split(":")

                species = sl[0]

                # Atoms are 1-indexed to match castep.
                index_counter[species] += 1
                index = index_counter[species]

                if len(sl) > 1:
                    label = sl[1]
                else:
                    label = species

                if convert:
                    position = numpy.dot(self.basis.T, position)

                atoms.append(Atom(species, index, position, label))

            elif len(lsplit) == 1:
                self.ions_units = lsplit[0]

        if self.ions_units is None:
            self.ions_units = 'ang'

        # If we've converted, change the basis
        if convert:
            self.ions_type = 'POSITIONS_ABS'
            self.basis = numpy.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0],
                                      [0.0, 0.0, 1.0]])

        self.ions = AtomsView(atoms, self.lattice)
Пример #5
0
class Cell:
    class LatticeNotImplemented(Exception):
        pass

    class LatticeWrongShape(Exception):
        pass

    def __init__(self, cell_file=None, **kwargs):
        self.blocks = {}
        self.otherdict = {}

        self.ions = None

        if cell_file is not None:
            if type(cell_file) is str:
                if os.path.isfile(cell_file):
                    self.parse_cell(open(cell_file).read())
                else:
                    self.parse_cell(cell_file)

            elif type(cell_file) is file:
                self.parse_cell(cell_file.read())

            elif hasattr(cell_file, "ions"):
                new_ions = Atoms([a.copy() for a in cell_file.ions])
                new_ions.lattice = cell_file.lattice

                self.ions = new_ions
                self.lattice_units = cell_file.lattice_units
                self.lattice_type = cell_file.lattice_type
                self.ions_units = cell_file.ions_units
                self.ions_type = cell_file.ions_type
                self.basis = cell_file.basis

        if 'lattice' in kwargs:
            self.lattice_units = "ang"
            self.lattice_type = "LATTICE_CART"
            self.lattice = numpy.array(kwargs['lattice'])
            self.ions.lattice = self.lattice

            self.ions_units = "ang"
            self.ions_type = "POSITIONS_ABS"
            self.basis = numpy.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0],
                                      [0.0, 0.0, 1.0]])

    def parse_cell(self, cell):
        block_re = re.compile(r"%block (.*?)\n(.*?\n{0,})%endblock (.*?)\n",
                              re.I | re.S | re.M)

        # Fix any windows line endings
        cell = cell.replace("\r\n", "\n")
        blocks = block_re.findall(cell)

        for name, content, _ in blocks:
            unclean_lines = content.split('\n')
            lines = []
            for line in unclean_lines:
                line_clean = line.strip()
                if len(line_clean) > 0:
                    lines.append(line_clean)
            self.blocks[name.upper()] = lines

        cell_sans_blocks = block_re.sub("", cell)
        other = re.split("\n\s{0,}", cell_sans_blocks, re.S | re.M)
        for o in other:
            o_s = o.strip()
            if len(o_s) > 0:
                o_split = re.split("[\s:]+", o_s, maxsplit=1)

                if len(o_split) == 2:
                    self.otherdict[o_split[0]] = o_split[1]
                elif len(o_split) == 1:
                    self.otherdict[o_split[0]] = None
                else:
                    raise Exception(
                        "More than two columns for cell-other split")

        self.parse_lattice()
        self.parse_ions()

    def parse_lattice_cart(self, block):
        lattice = []
        units = "ang"

        for line in block:
            lsplit = line.split()

            if len(lsplit) == 3:
                lattice.append((
                    float(lsplit[0]),
                    float(lsplit[1]),
                    float(lsplit[2]),
                ))
            elif len(lsplit) == 1:
                units = lsplit[0]

        return (units, lattice)

    def parse_lattice_abc(self, block):
        lattice = []
        units = None

        pi = numpy.pi
        sin = numpy.sin
        cos = numpy.cos
        sqrt = numpy.sqrt

        a = b = c = alpha = beta = gamma = None

        if len(block) == 3:
            units = block[0]
            a, b, c = map(float, block[1].split())
            alpha, beta, gamma = map(float, block[2].split())
        elif len(block) == 2:
            units = "ang"
            a, b, c = map(float, block[0].split())
            alpha, beta, gamma = map(float, block[1].split())

        alpha = alpha * pi / 180.0
        beta = beta * pi / 180.0
        gamma = gamma * pi / 180.0

        lattice.append([a, 0.0, 0.0])
        lattice.append([b * cos(gamma), b * sin(gamma), 0.0])
        lattice.append([
            c * cos(beta),
            c * (cos(alpha) - cos(beta) * cos(gamma)) / sin(gamma), 0.0
        ])

        lattice[2][2] = sqrt(c**2 - lattice[2][0]**2 - lattice[2][1]**2)

        return (units, lattice)

    def parse_lattice(self):
        self.lattice_type = None
        for block_name in self.blocks:
            if 'LATTICE_' in block_name:
                self.lattice_type = block_name

        if self.lattice_type is None:
            return

        lattice = None
        units = None

        if self.lattice_type == "LATTICE_CART":
            units, lattice = self.parse_lattice_cart(
                self.blocks["LATTICE_CART"])
        elif self.lattice_type == "LATTICE_ABC":
            units, lattice = self.parse_lattice_abc(self.blocks["LATTICE_ABC"])
        else:
            raise self.LatticeNotImplemented("%s not implemented in parser" %
                                             self.lattice_type)

        self.lattice = numpy.array(lattice)
        self.lattice_units = units

        if self.lattice.shape != (3, 3):
            raise self.LatticeWrongShape("Lattice vectors given not 3x3")

    def parse_ions(self):
        self.ions_type = None

        if 'POSITIONS_ABS' in self.blocks:
            self.ions_type = 'POSITIONS_ABS'
            self.basis = numpy.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0],
                                      [0.0, 0.0, 1.0]])
        elif 'POSITIONS_FRAC' in self.blocks:
            self.ions_type = 'POSITIONS_FRAC'
            self.basis = self.lattice

        if self.ions_type is None:
            return

        convert = False  # Dont convert frac to cart
        if self.ions_type == 'POSITIONS_FRAC':
            convert = True

        atoms = []

        index_counter = Counter()

        self.ions_units = None
        for line in self.blocks[self.ions_type]:  # Include positions frac
            lsplit = line.split()

            if len(lsplit) == 4:
                s, x, y, z = lsplit
                position = (float(x), float(y), float(z))

                sl = s.split(":")

                species = sl[0]

                # Atoms are 1-indexed to match castep.
                index_counter[species] += 1
                index = index_counter[species]

                if len(sl) > 1:
                    label = sl[1]
                else:
                    label = species

                if convert:
                    position = numpy.dot(self.basis.T, position)

                atoms.append(Atom(species, index, position, label))

            elif len(lsplit) == 1:
                self.ions_units = lsplit[0]

        if self.ions_units is None:
            self.ions_units = 'ang'

        # If we've converted, change the basis
        if convert:
            self.ions_type = 'POSITIONS_ABS'
            self.basis = numpy.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0],
                                      [0.0, 0.0, 1.0]])

        self.ions = AtomsView(atoms, self.lattice)

    def regen_ion_block(self):
        for type in ['POSITIONS_ABS',
                     'POSITIONS_FRAC']:  # Clear out any other ion blocks
            if type in self.blocks:
                del self.blocks[type]

        self.blocks[self.ions_type] = [self.ions_units] + [
            "{} {:f} {:f} {:f}".format(atom.species, atom.position[0],
                                       atom.position[1], atom.position[2])
            for atom in self.ions
        ]

    def regen_lattice_block(self):
        self.blocks[self.lattice_type] = [self.lattice_units] + [
            "{:f} {:f} {:f}".format(a, b, c) for a, b, c in self.ions.lattice
        ]

    def find_unique_ions(self):
        """ Generate a unique set of the ions, fix duplicates """
        ions = dict()

        to_remove = set()

        for ion1 in self.ions:
            if ion1 not in to_remove:
                for ion2 in self.ions:
                    if ion1 != ion2:
                        dr, _ = self.ions.least_mirror(ion1.position,
                                                       ion2.position)

                        if dr < 0.01:
                            print ion1, ion2
                            to_remove.add(ion2)

        return AtomsView([atom for atom in self.ions if atom not in to_remove],
                         self.ions.lattice)

    def __str__(self):
        self.regen_ion_block()
        self.regen_lattice_block()

        out = []
        for name, lines in self.blocks.items():
            out.append("%block {}".format(name))
            out += lines
            out.append("%endblock {}".format(name))
            out.append("")

        for key, value in self.otherdict.items():
            if value is not None:
                out.append("{}: {}".format(key, value))
            else:
                out.append(key)

        return "\n".join(out)

    def supercell(self, N1, N2, N3):
        new_ions = []

        index = 0
        for ion in self.ions:
            for n1 in range(N1):
                for n2 in range(N2):
                    for n3 in range(N3):
                        R = numpy.dot(self.lattice, numpy.array([n1, n2, n3]))
                        new_pos = ion.position + R

                        new_ion = Atom(ion.species, index, new_pos)
                        new_ions.append(new_ion)
                        index += 1

        supercell = Cell(self)

        supercell.lattice = numpy.dot(numpy.diag([N1, N2, N3]), self.lattice)
        supercell.ions = Atoms(new_ions)
        supercell.ions.lattice = supercell.lattice

        return supercell