예제 #1
0
 def structure_block(self):
     """ Retrieve which CIF block has the appropriate structural information """
     blocks = (self.file[key] for key in self.file.keys())
     for block in blocks:
         try:
             _, _ = get_number_with_esd(block["_cell_length_a"])
         except KeyError:
             continue
         else:
             return block
예제 #2
0
    def lattice_parameters(self):
        """ 
        Returns the lattice parameters associated to a CIF structure.

        Returns
        ----------
        a, b, c : float
            Lengths of lattice vectors [Angstroms]
        alpha, beta, gamma : float
            Angles of lattice vectors [degrees]. 
        """
        block = self.structure_block

        try:
            a_with_err = block["_cell_length_a"]
        except KeyError:
            raise ParseError(
                f"No lattice information is present in {self.filename}")

        # In case where b and c are not listed, we use the value of a
        a, _ = get_number_with_esd(a_with_err)
        b, _ = get_number_with_esd(block.get("_cell_length_b", a_with_err))
        c, _ = get_number_with_esd(block.get("_cell_length_c", a_with_err))

        alpha, _ = get_number_with_esd(block["_cell_angle_alpha"])
        beta, _ = get_number_with_esd(block["_cell_angle_beta"])
        gamma, _ = get_number_with_esd(block["_cell_angle_gamma"])

        return a, b, c, alpha, beta, gamma
예제 #3
0
    def lattice_parameters(self):
        """ 
        Returns the lattice parameters associated to a CIF structure.

        Returns
        ----------
        a, b, c : float
            Lengths of lattice vectors [Angstroms]
        alpha, beta, gamma : float
            Angles of lattice vectors [degrees]. 
        """
        block = self.structure_block

        try:
            a, _ = get_number_with_esd(block["_cell_length_a"])
            b, _ = get_number_with_esd(block["_cell_length_b"])
            c, _ = get_number_with_esd(block["_cell_length_c"])
            alpha, _ = get_number_with_esd(block["_cell_angle_alpha"])
            beta, _ = get_number_with_esd(block["_cell_angle_beta"])
            gamma, _ = get_number_with_esd(block["_cell_angle_gamma"])
        except:
            raise ParseError('Lattice vectors could not be determined.')
        else:
            return a, b, c, alpha, beta, gamma
예제 #4
0
    def atoms(self):
        """
        Asymmetric unit cell. Combine with CIFParser.symmetry_operators() for a full unit cell.

        Returns
        -------
        atoms : iterable of Atom instance
        """
        block = self.structure_block

        try:
            tmpdata = block.GetLoop("_atom_site_fract_x")
            cartesian = False
        except:
            try:
                tmpdata = block.GetLoop("_atom_site_Cartn_x")
                cartesian = True
            except:
                raise ParseError(
                    "Atomic positions could not be found or inferred.")

            t11 = block.get("_atom_sites_Cartn_tran_matrix_11")
            t12 = block.get("_atom_sites_Cartn_tran_matrix_12")
            t13 = block.get("_atom_sites_Cartn_tran_matrix_13")
            t21 = block.get("_atom_sites_Cartn_tran_matrix_21")
            t22 = block.get("_atom_sites_Cartn_tran_matrix_22")
            t23 = block.get("_atom_sites_Cartn_tran_matrix_23")
            t31 = block.get("_atom_sites_Cartn_tran_matrix_13")
            t32 = block.get("_atom_sites_Cartn_tran_matrix_23")
            t33 = block.get("_atom_sites_Cartn_tran_matrix_33")
            cart_trans_matrix_inv = np.array([
                [float(t11), float(t12), float(t13)],
                [float(t21), float(t22), float(t23)],
                [float(t31), float(t32), float(t33)],
            ])
            cart_trans_matrix = inv(cart_trans_matrix_inv)

            if not all([t11, t12, t13, t21, t22, t23, t31, t32, t33]):
                raise ParseError(
                    "Cartesian coordinates in CIF but no transformation matrix given"
                )

        if cartesian:
            xs = tmpdata.get("_atom_site_Cartn_x")
            ys = tmpdata.get("_atom_site_Cartn_y")
            zs = tmpdata.get("_atom_site_Cartn_z")
        else:
            xs = tmpdata.get("_atom_site_fract_x")
            ys = tmpdata.get("_atom_site_fract_y")
            zs = tmpdata.get("_atom_site_fract_z")
        # TODO: handle wildcards like '?', '.' in xs, ys, zs

        elements = tmpdata.get("_atom_site_type_symbol")
        if not elements:
            elements = tmpdata.get("_atom_site_label")
            if not elements:
                raise ParseError(
                    "Atom symbols could not be found or inferred.")
        elements = map(lambda s: s.strip(punctuation + digits).title(),
                       elements)

        atoms = list()
        for e, x, y, z in zip(elements, xs, ys, zs):
            coords = np.array([
                get_number_with_esd(x)[0],
                get_number_with_esd(y)[0],
                get_number_with_esd(z)[0],
            ])

            # We normalize atom position to be within the unit cell
            # Therefore we need the fractional coordinates
            if cartesian:
                coords = transform(cart_trans_matrix, coords)
                coords[:] = frac_coords(coords, self.lattice_vectors())

            atoms.append(Atom(element=e, coords=np.mod(coords, 1)))

        return atoms