Example #1
0
def determine_symmetry_positions(st, element):
    """
    determine non-equivalent positions for atoms of type *element*

    element (str) - name of element, for example Li

    return list of lists -  atom numbers for each non-equivalent position
    """

    from pymatgen.symmetry.analyzer import SpacegroupAnalyzer


    stp = st.convert2pymatgen()

    spg = SpacegroupAnalyzer(stp)

    info = spg.get_symmetry_dataset()

    positions = {}
    for i, (el, pos) in enumerate(zip(st.get_elements(), info['equivalent_atoms'])):
        
        if el == element and pos not in positions:
            positions[pos] = []

        if el == element:
            positions[pos].append(i)


    printlog('I have found ', len(positions), 'non-equivalent positions for', element, ':',positions.keys(), imp = 'y', end = '\n')
    printlog('Atom numbers: ', positions, imp = 'y')
    
    sorted_keys = sorted(list(positions.keys()))
    pos_lists = [positions[key] for key in sorted_keys ]

    return pos_lists
Example #2
0
def symmetry_reduce(tensors, structure, tol=1e-8, **kwargs):
    """
    Function that converts a list of tensors corresponding to a structure
    and returns a dictionary consisting of unique tensor keys with symmop
    values corresponding to transformations that will result in derivative
    tensors from the original list

    Args:
        tensors (list of tensors): list of Tensor objects to test for
            symmetrically-equivalent duplicates
        structure (Structure): structure from which to get symmetry
        tol (float): tolerance for tensor equivalence
        kwargs: keyword arguments for the SpacegroupAnalyzer

    returns:
        dictionary consisting of unique tensors with symmetry operations
        corresponding to those which will reconstruct the remaining
        tensors as values
    """
    sga = SpacegroupAnalyzer(structure, **kwargs)
    symmops = sga.get_symmetry_operations(cartesian=True)
    unique_tdict = {}
    for tensor in tensors:
        is_unique = True
        for unique_tensor, symmop in itertools.product(unique_tdict, symmops):
            if (np.abs(unique_tensor.transform(symmop) - tensor) < tol).all():
                unique_tdict[unique_tensor].append(symmop)
                is_unique = False
                break
        if is_unique:
            unique_tdict[tensor] = []
    return unique_tdict
Example #3
0
    def test_partial_disorder(self):
        s = Structure.from_file(filename=os.path.join(test_dir, "garnet.cif"))
        a = SpacegroupAnalyzer(s, 0.1)
        prim = a.find_primitive()
        s = prim.copy()
        s["Al3+"] = {"Al3+": 0.5, "Ga3+": 0.5}
        adaptor = EnumlibAdaptor(s, 1, 1, enum_precision_parameter=0.01)
        adaptor.run()
        structures = adaptor.structures
        self.assertEqual(len(structures), 7)
        for s in structures:
            self.assertEqual(s.formula, 'Ca12 Al4 Ga4 Si12 O48')
        s = prim.copy()
        s["Ca2+"] = {"Ca2+": 1/3, "Mg2+": 2/3}
        adaptor = EnumlibAdaptor(s, 1, 1, enum_precision_parameter=0.01)
        adaptor.run()
        structures = adaptor.structures
        self.assertEqual(len(structures), 20)
        for s in structures:
            self.assertEqual(s.formula, 'Ca4 Mg8 Al8 Si12 O48')

        s = prim.copy()
        s["Si4+"] = {"Si4+": 1/3, "Ge4+": 2/3}
        adaptor = EnumlibAdaptor(s, 1, 1, enum_precision_parameter=0.01)
        adaptor.run()
        structures = adaptor.structures
        self.assertEqual(len(structures), 18)
        for s in structures:
            self.assertEqual(s.formula, 'Ca12 Al8 Si4 Ge8 O48')
Example #4
0
    def multiplicity(self):
        """
        Returns the multiplicity of a defect site within the structure (needed for concentration analysis)
        """
        if self._multiplicity is None:
            # generate multiplicity based on space group symmetry operations performed on defect coordinates
            try:
                d_structure = create_saturated_interstitial_structure(self)
            except ValueError:
                logger.debug('WARNING! Multiplicity was not able to be calculated adequately '
                             'for interstitials...setting this to 1 and skipping for now...')
                return 1

            sga = SpacegroupAnalyzer(d_structure)
            periodic_struc = sga.get_symmetrized_structure()
            poss_deflist = sorted(
                periodic_struc.get_sites_in_sphere(self.site.coords, 2, include_index=True),
                key=lambda x: x[1])
            defindex = poss_deflist[0][2]

            equivalent_sites = periodic_struc.find_equivalent_sites(periodic_struc[defindex])
            return len(equivalent_sites)

        else:
            return self._multiplicity
Example #5
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
Example #6
0
    def test_structure_transform(self):
        # Test trivial case
        trivial = self.fit_r4.structure_transform(self.structure,
                                                  self.structure.copy())
        self.assertArrayAlmostEqual(trivial, self.fit_r4)

        # Test simple rotation
        rot_symm_op = SymmOp.from_axis_angle_and_translation([1, 1, 1], 55.5)
        rot_struct = self.structure.copy()
        rot_struct.apply_operation(rot_symm_op)
        rot_tensor = self.fit_r4.rotate(rot_symm_op.rotation_matrix)
        trans_tensor = self.fit_r4.structure_transform(self.structure, rot_struct)
        self.assertArrayAlmostEqual(rot_tensor, trans_tensor)

        # Test supercell
        bigcell = self.structure.copy()
        bigcell.make_supercell([2, 2, 3])
        trans_tensor = self.fit_r4.structure_transform(self.structure, bigcell)
        self.assertArrayAlmostEqual(self.fit_r4, trans_tensor)

        # Test rotated primitive to conventional for fcc structure
        sn = self.get_structure("Sn")
        sn_prim = SpacegroupAnalyzer(sn).get_primitive_standard_structure()
        sn_prim.apply_operation(rot_symm_op)
        rotated = self.fit_r4.rotate(rot_symm_op.rotation_matrix)
        transformed = self.fit_r4.structure_transform(sn, sn_prim)
        self.assertArrayAlmostEqual(rotated, transformed)
    def test_apply_transformation(self):
        trans = MagOrderingTransformation({"Fe": 5})
        p = Poscar.from_file(os.path.join(test_dir, 'POSCAR.LiFePO4'),
                             check_for_POTCAR=False)
        s = p.structure
        alls = trans.apply_transformation(s, 10)
        self.assertEqual(len(alls), 3)
        f = SpacegroupAnalyzer(alls[0]["structure"], 0.1)
        self.assertEqual(f.get_space_group_number(), 31)

        model = IsingModel(5, 5)
        trans = MagOrderingTransformation({"Fe": 5},
                                          energy_model=model)
        alls2 = trans.apply_transformation(s, 10)
        # Ising model with +J penalizes similar neighbor magmom.
        self.assertNotEqual(alls[0]["structure"], alls2[0]["structure"])
        self.assertEqual(alls[0]["structure"], alls2[2]["structure"])

        s = self.get_structure('Li2O')
        # Li2O doesn't have magnetism of course, but this is to test the
        # enumeration.
        trans = MagOrderingTransformation({"Li+": 1}, max_cell_size=3)
        alls = trans.apply_transformation(s, 100)
        # TODO: check this is correct, unclear what len(alls) should be
        self.assertEqual(len(alls), 12)

        trans = MagOrderingTransformation({"Ni": 5})
        alls = trans.apply_transformation(self.NiO.get_primitive_structure(),
                                          return_ranked_list=10)
        self.assertEqual(self.NiO_AFM_111.lattice, alls[0]["structure"].lattice)
        self.assertEqual(self.NiO_AFM_001.lattice, alls[1]["structure"].lattice)
Example #8
0
 def set_space_group_from_structure(self, structure):
     spga = SpacegroupAnalyzer(structure=structure)
     self.crystal_system = spga.get_crystal_system()
     self.hall = spga.get_hall()
     self.number = spga.get_space_group_number()
     self.source = "spglib"
     self.symbol = spga.get_space_group_symbol()
Example #9
0
def get_unique_site_indices(structure):
    sa = SpacegroupAnalyzer(structure)
    symm_data = sa.get_symmetry_dataset()
    # equivalency mapping for the structure
    # i'th site in the struct equivalent to eq_struct[i]'th site
    eq_atoms = symm_data["equivalent_atoms"]
    return np.unique(eq_atoms).tolist()
Example #10
0
    def symmetrize(self, structure):
        tensor = self._reduced_tensor

        if self._is_real_space:
            real_lattice = self._lattice
        else:
            real_lattice = self._lattice.reciprocal_lattice

        # I guess this is the reason why tensor.symmetrize (omega) is so slow!
        real_finder = SpacegroupAnalyzer(structure)

        real_symmops = real_finder.get_point_group_operations(cartesian=True)

        cartesian_tensor = self.cartesian_tensor

        sym_tensor = np.zeros((3,3))

        my_tensor = cartesian_tensor

        for real_sym in real_symmops:
            mat = real_sym.rotation_matrix
            prod_sym = np.dot(np.transpose(mat),np.dot(cartesian_tensor,mat))
            sym_tensor = sym_tensor + prod_sym

        sym_tensor = sym_tensor/len(real_symmops)

        self._reduced_tensor = from_cart_to_red(sym_tensor,self._lattice)
    def __init__(self, structure, min_cell_size=1, max_cell_size=1,
                 symm_prec=0.1, enum_precision_parameter=0.001,
                 refine_structure=False):
        """
        Initializes the adapter with a structure and some parameters.

        Args:
            structure: An input structure.
            min_cell_size (int): The minimum cell size wanted. Defaults to 1.
            max_cell_size (int): The maximum cell size wanted. Defaults to 1.
            symm_prec (float): Symmetry precision. Defaults to 0.1.
            enum_precision_parameter (float): Finite precision parameter for
                enumlib. Default of 0.001 is usually ok, but you might need to
                tweak it for certain cells.
            refine_structure (bool): If you are starting from a structure that
                has been relaxed via some electronic structure code,
                it is usually much better to start with symmetry determination
                and then obtain a refined structure. The refined structure have
                cell parameters and atomic positions shifted to the expected
                symmetry positions, which makes it much less sensitive precision
                issues in enumlib. If you are already starting from an
                experimental cif, refinement should have already been done and
                it is not necessary. Defaults to False.
        """
        if refine_structure:
            finder = SpacegroupAnalyzer(structure, symm_prec)
            self.structure = finder.get_refined_structure()
        else:
            self.structure = structure
        self.min_cell_size = min_cell_size
        self.max_cell_size = max_cell_size
        self.symm_prec = symm_prec
        self.enum_precision_parameter = enum_precision_parameter
Example #12
0
    def __init__(self, structure, element):
        """
        Initializes a Substitution Generator
        note: an Antisite is considered a type of substitution
        Args:
            structure(Structure): pymatgen structure object
            element (str or Element or Specie): element for the substitution
        """
        self.structure = structure
        self.element = element

        # Find equivalent site list
        sga = SpacegroupAnalyzer(self.structure)
        self.symm_structure = sga.get_symmetrized_structure()

        self.equiv_sub = []
        for equiv_site_set in list(self.symm_structure.equivalent_sites):
            vac_site = equiv_site_set[0]
            if isinstance(element, str):  # make sure you compare with specie symbol or Element type
                vac_specie = vac_site.specie.symbol
            else:
                vac_specie = vac_site.specie
            if element != vac_specie:
                defect_site = PeriodicSite(element, vac_site.coords, structure.lattice, coords_are_cartesian=True)
                sub = Substitution(structure, defect_site)
                self.equiv_sub.append(sub)
def print_spg(src="POSCAR"):
    srcpos = Poscar.from_file(src)
    finder = SpacegroupAnalyzer(srcpos.structure, symprec=5e-2, angle_tolerance=8)
    spg = finder.get_spacegroup_symbol()
    spg_num = finder.get_spacegroup_number()
    print(spg)
    print(spg_num)
Example #14
0
    def __init__(self, structure, element):
        """
        Initializes an Interstitial generator using Voronoi sites
        Args:
            structure (Structure): pymatgen structure object
            element (str or Element or Specie): element for the interstitial
        """
        self.structure = structure
        self.element = element

        framework = list(self.structure.symbol_set)
        get_voronoi = TopographyAnalyzer(self.structure, framework, [], check_volume=False)
        get_voronoi.cluster_nodes()
        get_voronoi.remove_collisions()

        # trim equivalent nodes with symmetry analysis
        struct_to_trim = self.structure.copy()
        for poss_inter in get_voronoi.vnodes:
            struct_to_trim.append(self.element, poss_inter.frac_coords, coords_are_cartesian=False)

        symmetry_finder = SpacegroupAnalyzer(struct_to_trim, symprec=1e-1)
        equiv_sites_list = symmetry_finder.get_symmetrized_structure().equivalent_sites

        self.equiv_site_seq = []
        for poss_site_list in equiv_sites_list:
            if poss_site_list[0] not in self.structure:
                self.equiv_site_seq.append(poss_site_list)

        self.count_def = 0  # for counting the index of the generated defect
Example #15
0
    def test_tensor(self):
        """Initialize Tensor"""

        lattice = Lattice.hexagonal(4,6)
        #rprimd = np.array([[0,0.5,0.5],[0.5,0,0.5],[0.5,0.5,0]])
        #rprimd = rprimd*10
        #lattice = Lattice(rprimd)
        structure = Structure(lattice, ["Ga", "As"],
                                      [[0, 0, 0], [0.5, 0.5, 0.5]])

        #finder = SymmetryFinder(structure)
        finder = SpacegroupAnalyzer(structure)

        spacegroup = finder.get_spacegroup()
        pointgroup = finder.get_point_group()

        cartesian_tensor = [[2,3,1.2],[3,4,1.0],[1.2,1.0,6]]

        tensor = Tensor.from_cartesian_tensor(cartesian_tensor,lattice.reciprocal_lattice,space="g")
        red_tensor = tensor.reduced_tensor
        tensor2 = Tensor(red_tensor,lattice.reciprocal_lattice,space="g")
        assert(((np.abs(tensor2.cartesian_tensor)-np.abs(cartesian_tensor)) < 1E-8).all())

        self.assertTrue(tensor==tensor2)
        print(tensor)

        #print("non-symmetrized cartesian_tensor = ",tensor2.cartesian_tensor)
        tensor2.symmetrize(structure)

        #print("symmetrized_cartesian_tensor = ",tensor2.cartesian_tensor)

        self.serialize_with_pickle(tensor)
Example #16
0
    def test_adsorb_both_surfaces(self):

        # Test out for monatomic adsorption
        o = Molecule("O", [[0, 0, 0]])
        adslabs = self.asf_100.adsorb_both_surfaces(o)
        adslabs_one = self.asf_100.generate_adsorption_structures(o)
        self.assertEqual(len(adslabs), len(adslabs_one))
        for adslab in adslabs:
            sg = SpacegroupAnalyzer(adslab)
            sites = sorted(adslab, key=lambda site: site.frac_coords[2])
            self.assertTrue(sites[0].species_string == "O")
            self.assertTrue(sites[-1].species_string == "O")
            self.assertTrue(sg.is_laue())

        # Test out for molecular adsorption
        oh = Molecule(["O", "H"], [[0, 0, 0], [0, 0, 1]])
        adslabs = self.asf_100.adsorb_both_surfaces(oh)
        adslabs_one = self.asf_100.generate_adsorption_structures(oh)
        self.assertEqual(len(adslabs), len(adslabs_one))
        for adslab in adslabs:
            sg = SpacegroupAnalyzer(adslab)
            sites = sorted(adslab, key=lambda site: site.frac_coords[2])
            self.assertTrue(sites[0].species_string in ["O", "H"])
            self.assertTrue(sites[-1].species_string in ["O", "H"])
            self.assertTrue(sg.is_laue())
Example #17
0
    def from_structure(cls, structure, has_timerev=True, symprec=1e-5, angle_tolerance=5):
        """
        Takes a :class:`Structure` object. Uses spglib to perform various symmetry finding operations.

        Args:
            structure: :class:`Structure` object
            has_timerev: True is time-reversal symmetry is included.
            symprec: Tolerance for symmetry finding
            angle_tolerance: Angle tolerance for symmetry finding.

        .. warning::

            AFM symmetries are not supported.
        """
        # Call spglib to get the list of symmetry operations.
        spga = SpacegroupAnalyzer(structure, symprec=symprec, angle_tolerance=angle_tolerance)
        data = spga.get_symmetry_dataset()

        return cls(
            spgid=data["number"],
            symrel=data["rotations"],
            tnons=data["translations"],
            symafm=len(symrel) * [1],
            has_timerev=has_timerev,
            inord="C",
        )
Example #18
0
    def get_sym_eq_kpoints(self, kpoint, cartesian=False, tol=1e-2):
        """
        Returns a list of unique symmetrically equivalent k-points.

        Args:
            kpoint (1x3 array): coordinate of the k-point
            cartesian (bool): kpoint is in cartesian or fractional coordinates
            tol (float): tolerance below which coordinates are considered equal

        Returns:
            ([1x3 array] or None): if structure is not available returns None
        """
        if not self.structure:
            return None
        sg = SpacegroupAnalyzer(self.structure)
        symmops = sg.get_point_group_operations(cartesian=cartesian)
        points = np.dot(kpoint, [m.rotation_matrix for m in symmops])
        rm_list = []
        # identify and remove duplicates from the list of equivalent k-points:
        for i in range(len(points) - 1):
            for j in range(i + 1, len(points)):
                if np.allclose(pbc_diff(points[i], points[j]), [0, 0, 0], tol):
                    rm_list.append(i)
                    break
        return np.delete(points, rm_list, axis=0)
Example #19
0
def unique_symmetry_operations_as_vectors_from_structure( structure, subset = None ):
    """
    Uses pymatgen symmetry analysis to find the minimum complete set of symmetry operations for the space group of a structure.

    Args:
        structure (pymatgen Structure): structure to be analysed.
        subset    (Optional [list]):    list of atom indices to be used for generating the symmetry operations

    Returns:
        a list of lists, containing the symmetry operations as vector mappings.
    """
    symmetry_analyzer = SpacegroupAnalyzer( structure )

    print( "The spacegroup for structure is {}".format(symmetry_analyzer.get_spacegroup_symbol()) )

    symmetry_operations = symmetry_analyzer.get_symmetry_operations()

    mappings = []
    if subset:
        species_subset = [ spec for i,spec in enumerate(structure.species) if i in subset]
        frac_coords_subset = [ coord for i, coord in enumerate( structure.frac_coords ) if i in subset ]
        mapping_structure = Structure( structure.lattice, species_subset, frac_coords_subset ) 
    else:
        mapping_structure = structure

    for symmop in symmetry_operations:
        new_structure = Structure( mapping_structure.lattice, mapping_structure.species, symmop.operate_multi( mapping_structure.frac_coords ) )
        new_mapping = [ x+1 for x in list( coord_list_mapping_pbc( new_structure.frac_coords, mapping_structure.frac_coords ) ) ]
        if new_mapping not in mappings:
            mappings.append( new_mapping )

    return mappings
Example #20
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])
Example #21
0
    def set_material_data_from_structure(self, structure, space_group=True, symprec=1e-3, angle_tolerance=5):
        """
        Sets the fields of the Document using a Structure and Spglib to determine the space group properties

        Args:
            structure: A |Structure|
            space_group: if True sets the spacegroup fields using spglib_.
            symprec (float): Tolerance for symmetry finding.
            angle_tolerance (float): Angle tolerance for symmetry finding.
        """

        comp = structure.composition
        el_amt = structure.composition.get_el_amt_dict()
        self.unit_cell_formula = comp.as_dict()
        self.reduced_cell_formula = comp.to_reduced_dict
        self.elements = list(el_amt.keys())
        self.nelements = len(el_amt)
        self.pretty_formula = comp.reduced_formula
        self.anonymous_formula = comp.anonymized_formula
        self.nsites = comp.num_atoms
        self.chemsys = "-".join(sorted(el_amt.keys()))
        if space_group:
            sym = SpacegroupAnalyzer(structure, symprec=symprec, angle_tolerance=angle_tolerance)
            self.spacegroup = SpaceGroupDocument(crystal_system=sym.get_crystal_system(), hall=sym.get_hall(),
                                                 number=sym.get_space_group_number(), point_group=sym.get_point_group_symbol(),
                                                 symbol=sym.get_space_group_symbol(), source="spglib")
Example #22
0
    def symm_reduce(self, coords_set, threshold=1e-6):
        """
        Reduces the set of adsorbate sites by finding removing
        symmetrically equivalent duplicates

        Args:
            coords_set: coordinate set in cartesian coordinates
            threshold: tolerance for distance equivalence, used
                as input to in_coord_list_pbc for dupl. checking
        """
        surf_sg = SpacegroupAnalyzer(self.slab, 0.1)
        symm_ops = surf_sg.get_symmetry_operations()
        unique_coords = []
        # Convert to fractional
        coords_set = [self.slab.lattice.get_fractional_coords(coords)
                      for coords in coords_set]
        for coords in coords_set:
            incoord = False
            for op in symm_ops:
                if in_coord_list_pbc(unique_coords, op.operate(coords),
                                     atol=threshold):
                    incoord = True
                    break
            if not incoord:
                unique_coords += [coords]
        # convert back to cartesian
        return [self.slab.lattice.get_cartesian_coords(coords)
                for coords in unique_coords]
Example #23
0
def quick_view(structure, bonds=True, conventional=False, transform=None, show_box=True, bond_tol=0.2, stick_radius=0.1):
    """
    A function to visualize pymatgen Structure objects in jupyter notebook using chemview package.

    Args:
        structure: pymatgen Structure
        bonds: (bool) visualize bonds. Bonds are found by comparing distances
                        to added covalent radii of pairs. Defaults to True.
        conventional: (bool) use conventional cell. Defaults to False.
        transform: (list) can be used to make supercells with pymatgen.Structure.make_supercell method
        show_box: (bool) unit cell is shown. Defaults to True.
        bond_tol: (float) used if bonds=True. Sets the extra distance tolerance when finding bonds.
        stick_radius: (float) radius of bonds.
    Returns:
        A chemview.MolecularViewer object
    """

    s = structure.copy()
    if conventional:
        s = SpacegroupAnalyzer(s).get_conventional_standard_structure()

    if transform:
        s.make_supercell(transform)
    atom_types = [i.symbol for i in s.species]

    if bonds:
        bonds = []
        for i in range(s.num_sites - 1):
            sym_i = s[i].specie.symbol
            for j in range(i + 1, s.num_sites):
                sym_j = s[j].specie.symbol
                max_d = CovalentRadius.radius[sym_i] + CovalentRadius.radius[sym_j] + bond_tol
                if s.get_distance(i, j, np.array([0,0,0])) < max_d:
                    bonds.append((i, j))
    bonds = bonds if bonds else None

    mv = MolecularViewer(s.cart_coords, topology={'atom_types': atom_types, 'bonds': bonds})

    if bonds:
        mv.ball_and_sticks(stick_radius=stick_radius)
    for i in s.sites:
        el = i.specie.symbol
        coord = i.coords
        r = CovalentRadius.radius[el]
        mv.add_representation('spheres', {'coordinates': coord.astype('float32'),
                                          'colors': [get_atom_color(el)],
                                          'radii': [r * 0.5],
                                          'opacity': 1.0})
    if show_box:
        o = np.array([0, 0, 0])
        a, b, c = s.lattice.matrix[0], s.lattice.matrix[1], s.lattice.matrix[2]
        starts = [o, o, o, a, a, b, b, c, c, a + b, a + c, b + c]
        ends = [a, b, c, a + b, a + c, b + a, b + c, c + a, c + b, a + b + c, a + b + c, a + b + c]
        colors = [0xffffff for i in range(12)]
        mv.add_representation('lines', {'startCoords': np.array(starts),
                                        'endCoords': np.array(ends),
                                        'startColors': colors,
                                        'endColors': colors})
    return mv
Example #24
0
def cif(src='POSCAR'):
    """
    cifファイルを作成
    """
    srcpos = Poscar.from_file(src)
    finder = SpacegroupAnalyzer(srcpos.structure)
    std_str = finder.get_conventional_standard_structure()
    cif_obj = CifWriter(std_str, symprec=0.1)
    cif_obj.write_file('poscar.cif')
Example #25
0
def main():
    args = parse_command_line_arguments()
    # initialise
    poscar = Poscar() # this doesn't really need vasppy. Could just use pymatgen to read the POSCAR
    # read POSCAR file
    poscar.read_from( args.poscar )
    structure = poscar.to_pymatgen_structure()
    symmetry_analyzer = SpacegroupAnalyzer( structure, symprec = args.symprec )
    print( symmetry_analyzer.get_space_group_symbol() )
def cif(src="POSCAR"):
    """
    cifファイルを作成
    """
    srcpos = Poscar.from_file(src)
    finder = SpacegroupAnalyzer(srcpos.structure)
    std = finder.get_conventional_standard_structure()
    cif = CifWriter(std, find_spacegroup=True, symprec=0.1)
    cif.write_file("poscar.cif")
Example #27
0
def cif(src):
    """
    cifファイルを作成
    """
    srcpos = Poscar.from_file(src)
    finder = SpacegroupAnalyzer(srcpos.structure)
    std_str = finder.get_conventional_standard_structure()
    std_cif = CifWriter(std_str, symprec=0.1)
    std_cif.write_file("poscar.cif")
Example #28
0
 def prim_cif(self, dst):
     """
     primitive cellでのcifフォーマットをgetする
     """
     finder = SpacegroupAnalyzer(self.structure)
     structure = finder.get_primitive_standard_structure()
     structure = finder.get_conventional_standard_structure()
     cif = CifWriter(structure, symprec=0.1)
     cif.write_file(dst)
Example #29
0
    def complete_ordering(self, structure, num_remove_dict):
        self.logger.debug("Performing complete ordering...")
        all_structures = []
        symprec = 0.2
        s = SpacegroupAnalyzer(structure, symprec=symprec)
        self.logger.debug("Symmetry of structure is determined to be {}."
                          .format(s.get_space_group_symbol()))
        sg = s.get_space_group_operations()
        tested_sites = []
        starttime = time.time()
        self.logger.debug("Performing initial ewald sum...")
        ewaldsum = EwaldSummation(structure)
        self.logger.debug("Ewald sum took {} seconds."
                          .format(time.time() - starttime))
        starttime = time.time()

        allcombis = []
        for ind, num in num_remove_dict.items():
            allcombis.append(itertools.combinations(ind, num))

        count = 0
        for allindices in itertools.product(*allcombis):
            sites_to_remove = []
            indices_list = []
            for indices in allindices:
                sites_to_remove.extend([structure[i] for i in indices])
                indices_list.extend(indices)
            s_new = structure.copy()
            s_new.remove_sites(indices_list)
            energy = ewaldsum.compute_partial_energy(indices_list)
            already_tested = False
            for i, tsites in enumerate(tested_sites):
                tenergy = all_structures[i]["energy"]
                if abs((energy - tenergy) / len(s_new)) < 1e-5 and \
                        sg.are_symmetrically_equivalent(sites_to_remove,
                                                        tsites,
                                                        symm_prec=symprec):
                    already_tested = True

            if not already_tested:
                tested_sites.append(sites_to_remove)
                all_structures.append({"structure": s_new, "energy": energy})

            count += 1
            if count % 10 == 0:
                timenow = time.time()
                self.logger.debug("{} structures, {:.2f} seconds."
                                  .format(count, timenow - starttime))
                self.logger.debug("Average time per combi = {} seconds"
                                  .format((timenow - starttime) / count))
                self.logger.debug("{} symmetrically distinct structures found."
                                  .format(len(all_structures)))

        self.logger.debug("Total symmetrically distinct structures found = {}"
                          .format(len(all_structures)))
        all_structures = sorted(all_structures, key=lambda s: s["energy"])
        return all_structures
Example #30
0
def analyze_symmetry(args):
    tolerance = args.symmetry
    t = []
    for filename in args.filenames:
        s = Structure.from_file(filename, primitive=False)
        finder = SpacegroupAnalyzer(s, tolerance)
        dataset = finder.get_symmetry_dataset()
        t.append([filename, dataset["international"], dataset["number"],
                  dataset["hall"]])
    print(tabulate(t, headers=["Filename", "Int Symbol", "Int number", "Hall"]))
Example #31
0
    def get_ieee_rotation(structure, refine_rotation=True):
        """
        Given a structure associated with a tensor, determines
        the rotation matrix for IEEE conversion according to
        the 1987 IEEE standards.

        Args:
            structure (Structure): a structure associated with the
                tensor to be converted to the IEEE standard
            refine_rotation (bool): whether to refine the rotation
                using SquareTensor.refine_rotation
        """
        # Check conventional setting:
        sga = SpacegroupAnalyzer(structure)
        dataset = sga.get_symmetry_dataset()
        trans_mat = dataset["transformation_matrix"]
        conv_latt = Lattice(
            np.transpose(
                np.dot(np.transpose(structure.lattice.matrix),
                       np.linalg.inv(trans_mat))))
        xtal_sys = sga.get_crystal_system()

        vecs = conv_latt.matrix
        lengths = np.array(conv_latt.abc)
        angles = np.array(conv_latt.angles)
        rotation = np.zeros((3, 3))

        # IEEE rules: a,b,c || x1,x2,x3
        if xtal_sys == "cubic":
            rotation = [vecs[i] / lengths[i] for i in range(3)]

        # IEEE rules: a=b in length; c,a || x3, x1
        elif xtal_sys == "tetragonal":
            rotation = np.array([
                vec / mag
                for (mag,
                     vec) in sorted(zip(lengths, vecs), key=lambda x: x[0])
            ])
            if abs(lengths[2] - lengths[1]) < abs(lengths[1] - lengths[0]):
                rotation[0], rotation[2] = rotation[2], rotation[0].copy()
            rotation[1] = get_uvec(np.cross(rotation[2], rotation[0]))

        # IEEE rules: c<a<b; c,a || x3,x1
        elif xtal_sys == "orthorhombic":
            rotation = [vec / mag for (mag, vec) in sorted(zip(lengths, vecs))]
            rotation = np.roll(rotation, 2, axis=0)

        # IEEE rules: c,a || x3,x1, c is threefold axis
        # Note this also includes rhombohedral crystal systems
        elif xtal_sys in ("trigonal", "hexagonal"):
            # find threefold axis:
            tf_index = np.argmin(abs(angles - 120.0))
            non_tf_mask = np.logical_not(angles == angles[tf_index])
            rotation[2] = get_uvec(vecs[tf_index])
            rotation[0] = get_uvec(vecs[non_tf_mask][0])
            rotation[1] = get_uvec(np.cross(rotation[2], rotation[0]))

        # IEEE rules: b,c || x2,x3; alpha=beta=90, c<a
        elif xtal_sys == "monoclinic":
            # Find unique axis
            u_index = np.argmax(abs(angles - 90.0))
            n_umask = np.logical_not(angles == angles[u_index])
            rotation[1] = get_uvec(vecs[u_index])
            # Shorter of remaining lattice vectors for c axis
            c = [
                vec / mag
                for (mag, vec) in sorted(zip(lengths[n_umask], vecs[n_umask]))
            ][0]
            rotation[2] = np.array(c)
            rotation[0] = np.cross(rotation[1], rotation[2])

        # IEEE rules: c || x3, x2 normal to ac plane
        elif xtal_sys == "triclinic":
            rotation = [vec / mag for (mag, vec) in sorted(zip(lengths, vecs))]
            rotation[1] = get_uvec(np.cross(rotation[2], rotation[0]))
            rotation[0] = np.cross(rotation[1], rotation[2])

        rotation = SquareTensor(rotation)
        if refine_rotation:
            rotation = rotation.refine_rotation()

        return rotation
Example #32
0
 def test_primitive(self):
     s = Structure.from_spacegroup("Fm-3m",
                                   np.eye(3) * 3, ["Cu"], [[0, 0, 0]])
     a = SpacegroupAnalyzer(s)
     self.assertEqual(len(s), 4)
     self.assertEqual(len(a.find_primitive()), 1)
Example #33
0
 def test_tricky_structure(self):
     # for some reason this structure kills spglib1.9
     # 1.7 can't find symmetry either, but at least doesn't kill python
     s = Structure.from_file(test_dir / 'POSCAR.tricky_symmetry')
     sa = SpacegroupAnalyzer(s, 0.1)
     sa.get_space_group_symbol()
     sa.get_space_group_number()
     sa.get_point_group_symbol()
     sa.get_crystal_system()
     sa.get_hall()
    def get_shortest_equiv_pairs(self):
        self._struct.make_supercell([2, 2, 2])
        moving_cation = []

        #Get symmetric equivalent sites
        analyzed_struct = SpacegroupAnalyzer(self._struct)
        analyzed_struct = analyzed_struct.get_symmetrized_structure()
        equivalent_sites = analyzed_struct.equivalent_sites
        #Debug
        #print len(equivalent_sites)

        for site in self._struct.sites:
            if site.specie == self._specie:
                moving_cation.append(site)
        #Debug
        #print len(moving_cation)

        distance = 100 * np.ones(
            (len(moving_cation), len(moving_cation)), dtype=float)
        for i in range(len(moving_cation)):
            for j in range(i):
                distance[i][j] = moving_cation[i].distance(moving_cation[j])

        min_distance = np.amin(distance)
        min_distance_pairs = []

        for i in range(len(moving_cation)):
            for j in range(i):
                if distance[i][j] < min_distance * 1.20:
                    min_distance_pairs.append([i, j])
        #Debug
        #print min_distance_pairs
        #print len(min_distance_pairs)

        cation_group_num = []
        for group in range(len(equivalent_sites)):
            if equivalent_sites[group][0].specie == self._specie:
                cation_group_num.append(group)

        group_pair = defaultdict(lambda: [])

        for pair in min_distance_pairs:
            for group in range(len(equivalent_sites)):
                if moving_cation[pair[0]] in equivalent_sites[group]:
                    group_i = group
                if moving_cation[pair[1]] in equivalent_sites[group]:
                    group_j = group

            if group_i == group_j:
                group_pair[(group_i, group_j)].append(
                    [moving_cation[pair[0]], moving_cation[pair[1]]])

        end_point_pair = []
        for pairs in group_pair.values():
            if pairs:
                selected_pair = pairs[0]
                coordin_sum = 10
                for pair in pairs:
                    if np.sum(pair[0].frac_coords) + np.sum(
                            pair[1].frac_coords) < coordin_sum:
                        selected_pair = pair
                        coordin_sum = np.sum(pair[0].frac_coords) + np.sum(
                            pair[1].frac_coords)
                end_point_pair.append(selected_pair)

        return end_point_pair
Example #35
0
 def test_is_laue(self):
     s = Structure.from_spacegroup("Fm-3m",
                                   np.eye(3) * 3, ["Cu"], [[0, 0, 0]])
     a = SpacegroupAnalyzer(s)
     self.assertTrue(a.is_laue())
Example #36
0
    def _generate_transformations(
            self,
            structure: Structure) -> Dict[str, MagOrderingTransformation]:
        """The central problem with trying to enumerate magnetic orderings is
        that we have to enumerate orderings that might plausibly be magnetic
        ground states, while not enumerating orderings that are physically
        implausible. The problem is that it is not always obvious by e.g.
        symmetry arguments alone which orderings to prefer. Here, we use a
        variety of strategies (heuristics) to enumerate plausible orderings,
        and later discard any duplicates that might be found by multiple
        strategies. This approach is not ideal, but has been found to be
        relatively robust over a wide range of magnetic structures.

        Args:
          structure: A sanitized input structure (_sanitize_input_structure)
        Returns: A dict of a transformation class instance (values) and name of
        enumeration strategy (keys)

        Returns: dict of Transformations keyed by strategy

        """

        formula = structure.composition.reduced_formula
        transformations: Dict[str, MagOrderingTransformation] = {}

        # analyzer is used to obtain information on sanitized input
        analyzer = CollinearMagneticStructureAnalyzer(
            structure,
            default_magmoms=self.default_magmoms,
            overwrite_magmom_mode="replace_all",
        )

        if not analyzer.is_magnetic:
            raise ValueError(
                "Not detected as magnetic, add a new default magmom for the "
                "element you believe may be magnetic?")

        # now we can begin to generate our magnetic orderings
        self.logger.info(
            "Generating magnetic orderings for {}".format(formula))

        mag_species_spin = analyzer.magnetic_species_and_magmoms
        types_mag_species = sorted(
            analyzer.types_of_magnetic_specie,
            key=lambda sp: analyzer.default_magmoms.get(str(sp), 0),
            reverse=True,
        )
        num_mag_sites = analyzer.number_of_magnetic_sites
        num_unique_sites = analyzer.number_of_unique_magnetic_sites()

        # enumerations become too slow as number of unique sites (and thus
        # permutations) increase, 8 is a soft limit, this can be increased
        # but do so with care
        if num_unique_sites > self.max_unique_sites:
            raise ValueError(
                "Too many magnetic sites to sensibly perform enumeration.")

        # maximum cell size to consider: as a rule of thumb, if the primitive cell
        # contains a large number of magnetic sites, perhaps we only need to enumerate
        # within one cell, whereas on the other extreme if the primitive cell only
        # contains a single magnetic site, we have to create larger supercells
        if "max_cell_size" not in self.transformation_kwargs:
            # TODO: change to 8 / num_mag_sites ?
            self.transformation_kwargs["max_cell_size"] = max(
                1, int(4 / num_mag_sites))
        self.logger.info("Max cell size set to {}".format(
            self.transformation_kwargs["max_cell_size"]))

        # when enumerating ferrimagnetic structures, it's useful to detect
        # symmetrically distinct magnetic sites, since different
        # local environments can result in different magnetic order
        # (e.g. inverse spinels)
        # initially, this was done by co-ordination number, but is
        # now done by a full symmetry analysis
        sga = SpacegroupAnalyzer(structure)
        structure_sym = sga.get_symmetrized_structure()
        wyckoff = ["n/a"] * len(structure)
        for indices, symbol in zip(structure_sym.equivalent_indices,
                                   structure_sym.wyckoff_symbols):
            for index in indices:
                wyckoff[index] = symbol
        is_magnetic_sites = [
            True if site.specie in types_mag_species else False
            for site in structure
        ]
        # we're not interested in sites that we don't think are magnetic,
        # set these symbols to None to filter them out later
        wyckoff = [
            symbol if is_magnetic_site else "n/a"
            for symbol, is_magnetic_site in zip(wyckoff, is_magnetic_sites)
        ]
        structure.add_site_property("wyckoff", wyckoff)
        wyckoff_symbols = set(wyckoff) - {"n/a"}

        # if user doesn't specifically request ferrimagnetic orderings,
        # we apply a heuristic as to whether to attempt them or not
        if self.automatic:
            if ("ferrimagnetic_by_motif" not in self.strategies
                    and len(wyckoff_symbols) > 1
                    and len(types_mag_species) == 1):
                self.strategies += ["ferrimagnetic_by_motif"]

            if ("antiferromagnetic_by_motif" not in self.strategies
                    and len(wyckoff_symbols) > 1
                    and len(types_mag_species) == 1):
                self.strategies += ["antiferromagnetic_by_motif"]

            if ("ferrimagnetic_by_species" not in self.strategies
                    and len(types_mag_species) > 1):
                self.strategies += ["ferrimagnetic_by_species"]

        # we start with a ferromagnetic ordering
        if "ferromagnetic" in self.strategies:
            # TODO: remove 0 spins !

            fm_structure = analyzer.get_ferromagnetic_structure()
            # store magmom as spin property, to be consistent with output from
            # other transformations
            fm_structure.add_spin_by_site(
                fm_structure.site_properties["magmom"])
            fm_structure.remove_site_property("magmom")

            # we now have our first magnetic ordering...
            self.ordered_structures.append(fm_structure)
            self.ordered_structure_origins.append("fm")

        # we store constraint(s) for each strategy first,
        # and then use each to perform a transformation later
        all_constraints: Dict[str, Any] = {}

        # ...to which we can add simple AFM cases first...
        if "antiferromagnetic" in self.strategies:

            constraint = MagOrderParameterConstraint(
                0.5,
                # TODO: update MagOrderParameterConstraint in
                # pymatgen to take types_mag_species directly
                species_constraints=list(map(str, types_mag_species)),
            )
            all_constraints["afm"] = [constraint]

            # allows for non-magnetic sublattices
            if len(types_mag_species) > 1:
                for sp in types_mag_species:
                    constraints = [
                        MagOrderParameterConstraint(
                            0.5, species_constraints=str(sp))
                    ]

                    all_constraints["afm_by_{}".format(sp)] = constraints

        # ...and then we also try ferrimagnetic orderings by motif if a
        # single magnetic species is present...
        if "ferrimagnetic_by_motif" in self.strategies and len(
                wyckoff_symbols) > 1:

            # these orderings are AFM on one local environment, and FM on the rest
            for symbol in wyckoff_symbols:
                constraints = [
                    MagOrderParameterConstraint(0.5,
                                                site_constraint_name="wyckoff",
                                                site_constraints=symbol),
                    MagOrderParameterConstraint(
                        1.0,
                        site_constraint_name="wyckoff",
                        site_constraints=list(wyckoff_symbols - {symbol}),
                    ),
                ]

                all_constraints["ferri_by_motif_{}".format(
                    symbol)] = constraints

        # and also try ferrimagnetic when there are multiple magnetic species
        if "ferrimagnetic_by_species" in self.strategies:

            sp_list = [str(site.specie) for site in structure]
            num_sp = {sp: sp_list.count(str(sp)) for sp in types_mag_species}
            total_mag_sites = sum(num_sp.values())

            for sp in types_mag_species:
                # attempt via a global order parameter
                all_constraints["ferri_by_{}".format(
                    sp)] = num_sp[sp] / total_mag_sites

                # attempt via afm on sp, fm on remaining species

                constraints = [
                    MagOrderParameterConstraint(0.5,
                                                species_constraints=str(sp)),
                    MagOrderParameterConstraint(
                        1.0,
                        species_constraints=list(
                            map(str,
                                set(types_mag_species) - {sp})),
                    ),
                ]

                all_constraints["ferri_by_{}_afm".format(sp)] = constraints

        # ...and finally, we can try orderings that are AFM on one local
        # environment, and non-magnetic on the rest -- this is less common
        # but unless explicitly attempted, these states are unlikely to be found
        if "antiferromagnetic_by_motif" in self.strategies:

            for symbol in wyckoff_symbols:
                constraints = [
                    MagOrderParameterConstraint(0.5,
                                                site_constraint_name="wyckoff",
                                                site_constraints=symbol)
                ]

                all_constraints["afm_by_motif_{}".format(symbol)] = constraints

        # and now construct all our transformations for each strategy
        transformations = {}
        for name, constraints in all_constraints.items():
            trans = MagOrderingTransformation(mag_species_spin,
                                              order_parameter=constraints,
                                              **self.transformation_kwargs)

            transformations[name] = trans

        return transformations
Example #37
0
 def get_sg_info(ss):
     finder = SpacegroupAnalyzer(Structure.from_sites(ss),
                                 self.symm_prec)
     sgnum = finder.get_spacegroup_number()
     return sgnum
Example #38
0
    def slab(self, miller_index_1, min_slab_size_1=8.0, min_vacuum_size_1=15):

        from pymatgen.analysis.adsorption import AdsorbateSiteFinder, plot_slab, reorient_z
        from pymatgen.core.surface import Slab, SlabGenerator, generate_all_slabs, Structure, Lattice, ReconstructionGenerator
        from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
        from pymatgen.core.structure import Structure
        from pymatgen.ext.matproj import MPRester
        from matplotlib import pyplot as plt
        from pymatgen.io.vasp.inputs import Poscar
        from pymatgen.io.vasp.sets import MVLSlabSet
        import shutil
        import os
        mpr = MPRester()  #密钥

        mp_id = self.mp_id  #通过mp_id来索引结构
        struct = mpr.get_structure_by_material_id(mp_id)
        #获取结构信息
        struct = SpacegroupAnalyzer(
            struct).get_conventional_standard_structure()
        #空间群分析
        need_miller_index = miller_index_1  #通过米勒指数,确定要切的晶面

        slab = SlabGenerator(struct, miller_index=need_miller_index, min_slab_size=min_slab_size_1,\
                             min_vacuum_size=min_vacuum_size_1, center_slab=True)
        #晶面生成器参数
        gh = str(miller_index_1).replace(" ", "")
        for n, slabs in enumerate(slab.get_slabs()):
            slabs_bak = slabs.copy()  #可能的晶面
            slabs.make_supercell(self.supercell)
            #晶胞扩充
            cc = slabs.surface_area
            os.chdir(r"F:\VASP practical\Input")
            print(os.getcwd())
            print(n)

            A = Poscar(slabs)  #将切面转换为Poscar
            relax = A.structure  #将Poscar 转换为结构信息
            custom_settings = {"NPAR": 4}  # 用户的INCAR 设置
            relax = MVLSlabSet(relax, user_incar_settings=custom_settings)
            #Vasp输入文件生成器

            fig = plt.figure()  #绘图--确立画布
            ax = fig.add_subplot(111)  #绘图--确立位置
            plot_slab(slabs, ax, adsorption_sites=False)  #绘图
            dire = str(mp_id) + "---" + str(gh) + '----' + str(n)

            #设置一个用作存储输入文件的名称
            plt.show()
            # plt.savefig(dire)#将该名称用于保存图片
            relax.write_input(str(gh) + '--' + str(n))  #将生成的VASP输入文件写入存储
            dire_1 = str(gh) + '--' + str(n)

            diree = os.chdir("./" + dire_1)
            fig.savefig('slab.png',
                        bbox_inches='tight',
                        transparent=True,
                        dpi=600,
                        format='png')
            #定义一个更改当前目录的变量
            dire2 = './vaspstd_sub'
            #确立脚本名称
            shutil.copy(r"C:\Users\41958\.spyder-py3\vaspstd_sub", dire2)
            #将脚本写入VASP输入文件所在文件夹
            with open('surface_area', 'w') as f:
                f.write(str(cc))
            print(cc)
        # os.chdir("../")
        #将当前目录改为默认目录

        os.chdir(r"D:\Desktop\VASP practical\workdir")
        print(os.getcwd())
        print('finished')
Example #39
0
    def fix_absorbed(self,
                     need_miller_index,
                     mole,
                     num,
                     selective_dynamic,
                     min_slab_size_1=8.0,
                     min_vacuum_size_1=15,
                     judge='fuchdi',
                     appendage=""):
        from pymatgen import Structure, Lattice, MPRester, Molecule
        import pymatgen.core.structure

        import pymatgen.core.sites
        from pymatgen.analysis.adsorption import AdsorbateSiteFinder, reorient_z, plot_slab
        from pymatgen.core.surface import generate_all_slabs
        from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
        from matplotlib import pyplot as plt
        from pymatgen.ext.matproj import MPRester
        from pymatgen.io.vasp.inputs import Poscar
        from pymatgen.io.vasp.sets import MVLSlabSet
        from pymatgen.io.cif import CifWriter
        import os
        import shutil
        from openbabel import openbabel
        from pymatgen.core.surface import Slab, SlabGenerator, generate_all_slabs, Structure, Lattice, ReconstructionGenerator
        mp_id = self.mp_id
        os.chdir(r"F:\VASP practical\Input")
        print(os.getcwd())

        # Note that you must provide your own API Key, which can
        # be accessed via the Dashboard at materialsproject.org
        mpr = MPRester()
        struct = mpr.get_structure_by_material_id(mp_id)
        struct = SpacegroupAnalyzer(
            struct).get_conventional_standard_structure()
        # fcc_ni = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3.5), ["Ni", "Ni"],
        # [[0, 0, 0], [0.5, 0.5, 0.5]])
        slab = SlabGenerator(struct,
                             miller_index=need_miller_index,
                             min_slab_size=min_slab_size_1,
                             min_vacuum_size=min_vacuum_size_1,
                             center_slab=True)

        for n, slabs in enumerate(slab.get_slabs()):
            if str(n) in str(num):
                slabs_bak = slabs.copy()  #可能的晶面
                slabs.make_supercell(self.supercell)
                print(n)
                #晶胞扩充

                asf_ni_111 = AdsorbateSiteFinder(
                    slabs, selective_dynamics=selective_dynamic)
                ads_sites = asf_ni_111.find_adsorption_sites()

                # print(ads_sites)
                assert len(ads_sites) == 4

                fig0 = plt.figure()
                ax = fig0.add_subplot(111)
                plot_slab(slabs, ax, adsorption_sites=False)

                fig1 = plt.figure()
                ax = fig1.add_subplot(111)
                os.chdir(r"D:\Desktop\VASP practical\Cif library")
                print(os.getcwd())
                obConversion = openbabel.OBConversion()
                obConversion.SetInAndOutFormats("pdb", "gjf")
                mol = openbabel.OBMol()
                print(mol)
                c = obConversion.ReadFile(mol, "CH3OH.pdb")
                obConversion.WriteFile(mol, "CH3OH.pdb" + '1.gjf')
                adsorbate = Molecule.from_file("CH3OH.pdb" + '.gjf')
                os.chdir(r"F:\VASP practical\Input")
                print(os.getcwd())

                print(adsorbate.sites)
                ads_structs = asf_ni_111.add_adsorbate(
                    adsorbate,
                    (20, 20, 20),
                    translate=False,
                )
                # ads_structs = asf_ni_111.generate_adsorption_structures(adsorbate,
                # repeat=[1, 1, 1])
                # A = Poscar(ads_structs[0])
                A = Poscar(reorient_z(ads_structs))  #将切面转换为Poscar
                open('POSCAR', 'w').write(str(A))
                p = Poscar.from_file('POSCAR')
                # w = CifWriter(A.struct)
                # w.write_file('mystructure.cif')
                path = r'F:\VASP practical\Input\POSCAR'  # 文件路径
                if os.path.exists(path):  # 如果文件存在
                    # 删除文件,可使用以下两种方法。
                    os.remove(path)
                #os.unlink(path)
                else:
                    print('no such file:%s' % my_file)  # 则返回文件不存在
                # w = CifWriter(A.struct)
                # w.write_file('mystructure.cif')

                relax = p.structure  #将Poscar 转换为结构信息
                custom_settings = {"NPAR": 4}  # 用户的INCAR 设置
                relaxs = MVLSlabSet(relax, user_incar_settings=custom_settings)
                # Vasp输入文件生成器
                dire = str(mp_id) + str(selective_dynamic) + str(mole) + str(
                    need_miller_index).replace(" ", "") + str(n)
                # print (relax)
                relaxs.write_input(dire)
                os.chdir("./" + dire)
                print(os.getcwd())
                fig0.savefig('slab.png',
                             bbox_inches='tight',
                             transparent=True,
                             dpi=600,
                             format='png')
                plot_slab(ads_structs, ax, adsorption_sites=False, decay=0.09)
                fig1.savefig('slab_adsobate.png',
                             bbox_inches='tight',
                             transparent=True,
                             dpi=600,
                             format='png')
                #定义一个更改当前目录的变量
                dire2 = './vaspstd_sub'
                #确立脚本名称
                shutil.copy(r"C:\Users\41958\.spyder-py3\vaspstd_sub", dire2)

                eb = appendage  #添加其他INCAR参数

                with open('INCAR', 'r') as f1:
                    lines = f1.readlines()

                with open('INCAR', 'w') as f2:
                    for line in lines:
                        if judge in line:
                            continue
                        f2.write(line)

                with open('INCAR', 'a') as f3:
                    f3.write(eb)

                # open('POSCAR001', 'w').write(str(Poscar(reorient_z(ads_structs[0]))))

                os.chdir(r"D:\Desktop\VASP practical\workdir")
                print(os.getcwd())
                print('finished')


# my_lattace = Lattace('mp-698074')#半水石膏
# # my_lattace.phase_out()#生成晶胞优化的输入文件
# go = my_lattace.phase_sol(66,judge='LWAVE',  appendage= '\nLWAVE = Ture')
# print('yoo')
Example #40
0
def get_dos_from_parabolic_bands(st, reclat_matrix, mesh, e_min, e_max, e_points, parabolic_bands, bandgap, width=0.1, SPB_DOS=False, all_values=False):
    """
    Args:
    st:       pmg object of crystal structure to calculate symmetries
    mesh:     list of integers defining the k-mesh on which the dos is required
    e_min:    starting energy (eV) of dos
    e_max:    ending energy (eV) of dos
    e_points: number of points of the get_dos
    width:    width in eV of the gaussians generated for each energy
    Returns:
    e_mesh:   energies in eV od the DOS
    dos:      density of states for each energy in e_mesh
    """
    height = 1.0 / (width * np.sqrt(2 * np.pi))
    e_mesh, step = np.linspace(e_min, e_max,num=e_points, endpoint=True, retstep=True)
    e_range = len(e_mesh)
    ir_kpts_n_weights = SpacegroupAnalyzer(st).get_ir_reciprocal_mesh(mesh)
    ir_kpts = [k[0] for k in ir_kpts_n_weights]
    weights = [k[1] for k in ir_kpts_n_weights]

    ir_kpts = [reclat_matrix.get_cartesian_coords(k)/A_to_nm for k in ir_kpts]

    w_sum = float(sum(weights))
    dos = np.zeros(e_range)

    if SPB_DOS:
        volume = st.volume
        for band in parabolic_bands:
            for valley in band:
                offset = valley[-1][0] # each valley has a list of k-points (valley[0]) and [offset, m*] (valley[1]) info
                m_eff = valley[-1][1]
                degeneracy = len(valley[0])
                for ie, energy in enumerate(e_mesh):
                    dos_temp = volume/(2*pi**2)*(2*m_e*m_eff/hbar**2)**1.5 * 1e-30/e**1.5
                    if energy <= -bandgap/2.0-offset:
                        # dos_temp *= (-energy-offset)**0.5
                        dos_temp *= (-energy+bandgap/2.0+offset)**0.5
                    elif energy >=bandgap/2.0+offset:
                        # dos_temp *= (energy-bandgap-offset)**0.5
                        dos_temp *= (energy-bandgap/2.0-offset)**0.5
                    else:
                        dos_temp = 0
                    dos[ie] += dos_temp * degeneracy
    else:
        all_energies = []
        all_ks = []
        for kpt,w in zip(ir_kpts,weights):
            for tp in ["n", "p"]:
                for ib in range(len(parabolic_bands)):
                    if all_values:
                        energy_list, k_dist = get_parabolic_energy(kpt, parabolic_bands, tp, ib=ib, bandgap=bandgap,
                                                           all_values=all_values)
                        all_energies += energy_list
                        all_ks += [k_dist]*len(energy_list)
                        for energy in energy_list:
                            g = height * np.exp(-((e_mesh - energy) / width) ** 2 / 2.)
                            dos += w/w_sum * g
                    else:
                        energy, v, m_eff = get_parabolic_energy(kpt, parabolic_bands, tp, ib=ib, bandgap=bandgap, all_values=all_values)
                        g = height * np.exp(-((e_mesh - energy) / width) ** 2 / 2.)
                        dos += w/w_sum * g
        if all_values:
            scatter(all_ks, all_energies)
            show()
    return e_mesh,dos
Example #41
0
def calc_shiftk(structure, symprec=0.01, angle_tolerance=5):
    """
    Find the values of ``shiftk`` and ``nshiftk`` appropriated for the sampling of the Brillouin zone.

    When the primitive vectors of the lattice do NOT form a FCC or a BCC lattice,
    the usual (shifted) Monkhorst-Pack grids are formed by using nshiftk=1 and shiftk 0.5 0.5 0.5 .
    This is often the preferred k point sampling. For a non-shifted Monkhorst-Pack grid,
    use `nshiftk=1` and `shiftk 0.0 0.0 0.0`, but there is little reason to do that.

    When the primitive vectors of the lattice form a FCC lattice, with rprim::

            0.0 0.5 0.5
            0.5 0.0 0.5
            0.5 0.5 0.0

    the (very efficient) usual Monkhorst-Pack sampling will be generated by using nshiftk= 4 and shiftk::

        0.5 0.5 0.5
        0.5 0.0 0.0
        0.0 0.5 0.0
        0.0 0.0 0.5

    When the primitive vectors of the lattice form a BCC lattice, with rprim::

           -0.5  0.5  0.5
            0.5 -0.5  0.5
            0.5  0.5 -0.5

    the usual Monkhorst-Pack sampling will be generated by using nshiftk= 2 and shiftk::

            0.25  0.25  0.25
           -0.25 -0.25 -0.25

    However, the simple sampling nshiftk=1 and shiftk 0.5 0.5 0.5 is excellent.

    For hexagonal lattices with hexagonal axes, e.g. rprim::

            1.0  0.0       0.0
           -0.5  sqrt(3)/2 0.0
            0.0  0.0       1.0

    one can use nshiftk= 1 and shiftk 0.0 0.0 0.5
    In rhombohedral axes, e.g. using angdeg 3*60., this corresponds to shiftk 0.5 0.5 0.5,
    to keep the shift along the symmetry axis.

    Returns:
        Suggested value of shiftk.
    """
    # Find lattice type.
    from pymatgen.symmetry.analyzer import SpacegroupAnalyzer

    sym = SpacegroupAnalyzer(structure,
                             symprec=symprec,
                             angle_tolerance=angle_tolerance)
    lattice_type, spg_symbol = sym.get_lattice_type(
    ), sym.get_space_group_symbol()

    # Check if the cell is primitive
    is_primitive = len(sym.find_primitive()) == len(structure)

    # Generate the appropriate set of shifts.
    shiftk = None

    if is_primitive:
        if lattice_type == "cubic":
            if "F" in spg_symbol:
                # FCC
                shiftk = [
                    0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5
                ]

            elif "I" in spg_symbol:
                # BCC
                shiftk = [0.25, 0.25, 0.25, -0.25, -0.25, -0.25]
                # shiftk = [0.5, 0.5, 05])

        elif lattice_type == "hexagonal":
            # Find the hexagonal axis and set the shift along it.
            for i, angle in enumerate(structure.lattice.angles):
                if abs(angle - 120) < 1.0:
                    j = (i + 1) % 3
                    k = (i + 2) % 3
                    hex_ax = [ax for ax in range(3) if ax not in [j, k]][0]
                    break
            else:
                raise ValueError("Cannot find hexagonal axis")

            shiftk = [0.0, 0.0, 0.0]
            shiftk[hex_ax] = 0.5

        elif lattice_type == "tetragonal":
            if "I" in spg_symbol:
                # BCT
                shiftk = [0.25, 0.25, 0.25, -0.25, -0.25, -0.25]

    if shiftk is None:
        # Use default value.
        shiftk = [0.5, 0.5, 0.5]

    return np.reshape(shiftk, (-1, 3))
Example #42
0
def quick_view(structure,
               bonds=True,
               conventional=False,
               transform=None,
               show_box=True,
               bond_tol=0.2,
               stick_radius=0.1):
    """
    A function to visualize pymatgen Structure objects in jupyter notebook using chemview package.

    Args:
        structure: pymatgen Structure
        bonds: (bool) visualize bonds. Bonds are found by comparing distances
                        to added covalent radii of pairs. Defaults to True.
        conventional: (bool) use conventional cell. Defaults to False.
        transform: (list) can be used to make supercells with pymatgen.Structure.make_supercell method
        show_box: (bool) unit cell is shown. Defaults to True.
        bond_tol: (float) used if bonds=True. Sets the extra distance tolerance when finding bonds.
        stick_radius: (float) radius of bonds.
    Returns:
        A chemview.MolecularViewer object
    """

    s = structure.copy()
    if conventional:
        s = SpacegroupAnalyzer(s).get_conventional_standard_structure()

    if transform:
        s.make_supercell(transform)
    atom_types = [i.symbol for i in s.species]

    if bonds:
        bonds = []
        for i in range(s.num_sites - 1):
            sym_i = s[i].specie.symbol
            for j in range(i + 1, s.num_sites):
                sym_j = s[j].specie.symbol
                max_d = CovalentRadius.radius[sym_i] + CovalentRadius.radius[
                    sym_j] + bond_tol
                if s.get_distance(i, j, np.array([0, 0, 0])) < max_d:
                    bonds.append((i, j))
    bonds = bonds if bonds else None

    mv = MolecularViewer(s.cart_coords,
                         topology={
                             'atom_types': atom_types,
                             'bonds': bonds
                         })

    if bonds:
        mv.ball_and_sticks(stick_radius=stick_radius)
    for i in s.sites:
        el = i.specie.symbol
        coord = i.coords
        r = CovalentRadius.radius[el]
        mv.add_representation(
            'spheres', {
                'coordinates': coord.astype('float32'),
                'colors': [get_atom_color(el)],
                'radii': [r * 0.5],
                'opacity': 1.0
            })
    if show_box:
        o = np.array([0, 0, 0])
        a, b, c = s.lattice.matrix[0], s.lattice.matrix[1], s.lattice.matrix[2]
        starts = [o, o, o, a, a, b, b, c, c, a + b, a + c, b + c]
        ends = [
            a, b, c, a + b, a + c, b + a, b + c, c + a, c + b, a + b + c,
            a + b + c, a + b + c
        ]
        colors = [0xffffff for i in range(12)]
        mv.add_representation(
            'lines', {
                'startCoords': np.array(starts),
                'endCoords': np.array(ends),
                'startColors': colors,
                'endColors': colors
            })
    return mv
Example #43
0
# Download 3D material data from https://figshare.com/articles/jdft_3d-7-7-2018_json/6815699
# Download 2D material data from https://figshare.com/articles/jdft_2d-7-7-2018_json/6815705 
# Curating JARVIS-DFT data 

d=loadfn('jdft_3d-7-7-2018.json',cls=MontyDecoder)


count=0
for i in d:
 filname=str(i['jid'])+str('.xml')
 if  not os.path.exists(filname) :
   count=count+1
   energy=str(i['fin_en'])+str(',')+str(i['form_enp'])
   formula=str(i['final_str'].composition.reduced_formula)
   sgp= str(SpacegroupAnalyzer(i['final_str']).get_spacegroup_symbol())
   name=str(i['jid'])
   print (name)
   ref=str(i['mpid'])
   func=str('OptB88vdW')
   elem=''
   species=list(set(i['final_str'].species))
   for j in species:
     elem=str(elem)+str(j.symbol)+str('-')
   encut=str(i['encut'])
   kpoints=str(i['kpoints'].kpts[0][0])+str('x')+str(i['kpoints'].kpts[0][1])+str('x')+str(i['kpoints'].kpts[0][2])
   el_tens=str(i['elastic'])
   KV=str(i['kv'])
   GV=str(i['gv'])
   op_eg=str(i['op_gap'])
   mbj_eg=str(i['mbj_gap'])
Example #44
0
    def populate(self,
                 structure,
                 prec=1e-5,
                 maxiter=200,
                 verbose=False,
                 precond=True,
                 vsym=True):
        """
        Takes a partially populated tensor, and populates the non-zero
        entries according to the following procedure, iterated until
        the desired convergence (specified via prec) is achieved.

        1. Find non-zero entries
        2. Symmetrize the tensor with respect to crystal symmetry and
           (optionally) voigt symmetry
        3. Reset the non-zero entries of the original tensor

        Args:
            structure (structure object)
            prec (float): precision for determining a non-zero value
            maxiter (int): maximum iterations for populating the tensor
            verbose (bool): whether to populate verbosely
            precond (bool): whether to precondition by cycling through
                all symmops and storing new nonzero values, default True
            vsym (bool): whether to enforce voigt symmetry, defaults
                to True
        """
        if precond:
            # Generate the guess from populated
            sops = SpacegroupAnalyzer(structure).get_symmetry_operations()
            guess = Tensor(np.zeros(self.shape))
            mask = abs(self) > prec
            guess[mask] = self[mask]

            def merge(old, new):
                gmask = np.abs(old) > prec
                nmask = np.abs(new) > prec
                new_mask = np.logical_not(gmask) * nmask
                avg_mask = gmask * nmask
                old[avg_mask] = (old[avg_mask] + new[avg_mask]) / 2.0
                old[new_mask] = new[new_mask]

            if verbose:
                print(f"Preconditioning for {len(sops)} symmops")
            for sop in sops:
                rot = guess.transform(sop)
                # Store non-zero entries of new that weren't previously
                # in the guess in the guess
                merge(guess, rot)
            if verbose:
                print("Preconditioning for voigt symmetry")
            if vsym:
                v = guess.voigt
                perms = list(itertools.permutations(range(len(v.shape))))
                for perm in perms:
                    vtrans = np.transpose(v, perm)
                    merge(v, vtrans)
                guess = Tensor.from_voigt(v)
        else:
            guess = np.zeros(self.shape)

        assert guess.shape == self.shape, "Guess must have same shape"
        converged = False
        test_new, test_old = [guess.copy()] * 2
        for i in range(maxiter):
            test_new = test_old.fit_to_structure(structure)
            if vsym:
                test_new = test_new.voigt_symmetrized
            diff = np.abs(test_old - test_new)
            converged = (diff < prec).all()
            if converged:
                break
            test_new[mask] = self[mask]
            test_old = test_new
            if verbose:
                print(f"Iteration {i}: {np.max(diff)}")
        if not converged:
            max_diff = np.max(np.abs(self - test_new))
            warnings.warn(
                f"Warning, populated tensor is not converged with max diff of {max_diff}"
            )
        return self.__class__(test_new)
Example #45
0
 def is_centro(structure):
     sga = SpacegroupAnalyzer(structure)
     return SymmOp.inversion() in sga.get_symmetry_operations()
Example #46
0
    def sol(self,
            EB_K_2,
            miller_index_2,
            min_slab_size_2=8.0,
            min_vacuum_size_2=15):
        from pymatgen.analysis.adsorption import AdsorbateSiteFinder, plot_slab, reorient_z
        from pymatgen.core.surface import Slab, SlabGenerator, generate_all_slabs, Structure, Lattice, ReconstructionGenerator
        from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
        from pymatgen.core.structure import Structure
        from pymatgen.ext.matproj import MPRester
        from matplotlib import pyplot as plt
        from pymatgen.io.vasp.inputs import Poscar
        from pymatgen.io.vasp.sets import MVLSlabSet
        import shutil
        import os
        mpr = MPRester()  #密钥

        mp_id = self.mp_id  #通过mp_id来索引结构
        struct = mpr.get_structure_by_material_id(mp_id)
        #获取结构信息
        struct = SpacegroupAnalyzer(
            struct).get_conventional_standard_structure()
        #空间群分析
        need_miller_index = miller_index_2  #通过米勒指数,确定要切的晶面

        slab = SlabGenerator(struct, miller_index=need_miller_index, min_slab_size=min_slab_size_2,\
                             min_vacuum_size=min_vacuum_size_2, center_slab=True)
        #晶面生成器参数

        for n, slabs in enumerate(slab.get_slabs()):
            slabs_bak = slabs.copy()  #可能的晶面
            slabs.make_supercell(self.supercell)
            #晶胞扩充

            A = Poscar(slabs)  #将切面转换为Poscar
            relax = A.structure  #将Poscar 转换为结构信息
            custom_settings = {"NPAR": 4}  # 用户的INCAR 设置
            relax = MVLSlabSet(relax, user_incar_settings=custom_settings)
            #Vasp输入文件生成器

            fig = plt.figure()  #绘图--确立画布
            ax = fig.add_subplot(111)  #绘图--确立位置
            plot_slab(slabs, ax, adsorption_sites=False)  #绘图
            dire = str(mp_id) + "---" + "sol" + str(EB_K_2) + str(
                need_miller_index) + '----' + str(n)
            #设置一个用作存储输入文件的名称
            plt.savefig(dire)  #将该名称用于保存图片
            relax.write_input(dire)  #将生成的VASP输入文件写入存储

            os.chdir("./" + dire)
            #定义一个更改当前目录的变量
            dire2 = './vaspstd_sub'
            #确立脚本名称
            shutil.copy(r"C:\Users\41958\.spyder-py3\vaspstd_sub", dire2)
            #将脚本写入VASP输入文件所在文件夹

            eb = str(EB_K_2)
            ls = str('TURE')
            with open('INCAR', 'a') as file_object:
                file_object.write('LSOL = ' + ls + '\n' + 'EB_K = ' + eb)

            # os.chdir("../")
            #将当前目录改为默认目录
            os.chdir(r"D:\Desktop\VASP practical\workdir")
            print(os.getcwd())
            print('finished')
Example #47
0
    def __init__(self, struct, symprec=None):
        format_str = "{:.8f}"

        block = OrderedDict()
        loops = []
        spacegroup = ("P 1", 1)
        if symprec is not None:
            sf = SpacegroupAnalyzer(struct, symprec)
            spacegroup = (sf.get_space_group_symbol(),
                          sf.get_space_group_number())
            # Needs the refined struture when using symprec. This converts
            # primitive to conventional structures, the standard for CIF.
            struct = sf.get_refined_structure()

        latt = struct.lattice
        comp = struct.composition
        no_oxi_comp = comp.element_composition
        block["_symmetry_space_group_name_H-M"] = spacegroup[0]
        for cell_attr in ['a', 'b', 'c']:
            block["_cell_length_" + cell_attr] = format_str.format(
                getattr(latt, cell_attr))
        for cell_attr in ['alpha', 'beta', 'gamma']:
            block["_cell_angle_" + cell_attr] = format_str.format(
                getattr(latt, cell_attr))
        block["_symmetry_Int_Tables_number"] = spacegroup[1]
        block["_chemical_formula_structural"] = no_oxi_comp.reduced_formula
        block["_chemical_formula_sum"] = no_oxi_comp.formula
        block["_cell_volume"] = latt.volume.__str__()

        reduced_comp, fu = no_oxi_comp.get_reduced_composition_and_factor()
        block["_cell_formula_units_Z"] = str(int(fu))

        if symprec is None:
            block["_symmetry_equiv_pos_site_id"] = ["1"]
            block["_symmetry_equiv_pos_as_xyz"] = ["x, y, z"]
        else:
            sf = SpacegroupAnalyzer(struct, symprec)

            symmops = []
            for op in sf.get_symmetry_operations():
                v = op.translation_vector
                symmops.append(SymmOp.from_rotation_and_translation(
                    op.rotation_matrix, v))

            ops = [op.as_xyz_string() for op in symmops]
            block["_symmetry_equiv_pos_site_id"] = \
                ["%d" % i for i in range(1, len(ops) + 1)]
            block["_symmetry_equiv_pos_as_xyz"] = ops

        loops.append(["_symmetry_equiv_pos_site_id",
                      "_symmetry_equiv_pos_as_xyz"])

        contains_oxidation = True
        try:
            symbol_to_oxinum = OrderedDict([
                                               (el.__str__(),
                                                float(el.oxi_state))
                                               for el in sorted(comp.elements)])
        except AttributeError:
            symbol_to_oxinum = OrderedDict([(el.symbol, 0) for el in
                                            sorted(comp.elements)])
            contains_oxidation = False
        if contains_oxidation:
            block["_atom_type_symbol"] = symbol_to_oxinum.keys()
            block["_atom_type_oxidation_number"] = symbol_to_oxinum.values()
            loops.append(["_atom_type_symbol", "_atom_type_oxidation_number"])

        atom_site_type_symbol = []
        atom_site_symmetry_multiplicity = []
        atom_site_fract_x = []
        atom_site_fract_y = []
        atom_site_fract_z = []
        atom_site_label = []
        atom_site_occupancy = []
        count = 1
        if symprec is None:
            for site in struct:
                for sp, occu in sorted(site.species_and_occu.items()):
                    atom_site_type_symbol.append(sp.__str__())
                    atom_site_symmetry_multiplicity.append("1")
                    atom_site_fract_x.append("{0:f}".format(site.a))
                    atom_site_fract_y.append("{0:f}".format(site.b))
                    atom_site_fract_z.append("{0:f}".format(site.c))
                    atom_site_label.append("{}{}".format(sp.symbol, count))
                    atom_site_occupancy.append(occu.__str__())
                    count += 1
        else:
            # The following just presents a deterministic ordering.
            unique_sites = [
                (sorted(sites, key=lambda s: tuple([abs(x) for x in
                                                    s.frac_coords]))[0],
                 len(sites))
                for sites in sf.get_symmetrized_structure().equivalent_sites
                ]
            for site, mult in sorted(
                    unique_sites,
                    key=lambda t: (t[0].species_and_occu.average_electroneg,
                                   -t[1], t[0].a, t[0].b, t[0].c)):
                for sp, occu in site.species_and_occu.items():
                    atom_site_type_symbol.append(sp.__str__())
                    atom_site_symmetry_multiplicity.append("%d" % mult)
                    atom_site_fract_x.append("{0:f}".format(site.a))
                    atom_site_fract_y.append("{0:f}".format(site.b))
                    atom_site_fract_z.append("{0:f}".format(site.c))
                    atom_site_label.append("{}{}".format(sp.symbol, count))
                    atom_site_occupancy.append(occu.__str__())
                    count += 1

        block["_atom_site_type_symbol"] = atom_site_type_symbol
        block["_atom_site_label"] = atom_site_label
        block["_atom_site_symmetry_multiplicity"] = \
            atom_site_symmetry_multiplicity
        block["_atom_site_fract_x"] = atom_site_fract_x
        block["_atom_site_fract_y"] = atom_site_fract_y
        block["_atom_site_fract_z"] = atom_site_fract_z
        block["_atom_site_occupancy"] = atom_site_occupancy
        loops.append(["_atom_site_type_symbol",
                      "_atom_site_label",
                      "_atom_site_symmetry_multiplicity",
                      "_atom_site_fract_x",
                      "_atom_site_fract_y",
                      "_atom_site_fract_z",
                      "_atom_site_occupancy"])
        d = OrderedDict()
        d[comp.reduced_formula] = CifBlock(block, loops, comp.reduced_formula)
        self._cf = CifFile(d)
# Note that Composition conveniently allows strings to be treated just
# like an Element object.
print(comp["Fe"])
print(comp.get_atomic_fraction("Fe"))
lattice = mg.Lattice.cubic(4.2)
structure = mg.Structure(lattice, ["Cs", "Cl"], [[0, 0, 0], [0.5, 0.5, 0.5]])
print(structure.volume)
print(structure[0])
# You can create a Structure using spacegroup symmetry as well.
li2o = mg.Structure.from_spacegroup("Fm-3m", mg.Lattice.cubic(3), ["Li", "O"],
                                    [[0.25, 0.25, 0.25], [0, 0, 0]])

# Integrated symmetry analysis tools from spglib.
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
finder = SpacegroupAnalyzer(structure)
# print(finder.get_spacegroup_symbol())

# Convenient IO to various formats. You can specify various formats.
# Without a filename, a string is returned. Otherwise,
# the output is written to the file. If only the filenmae is provided,
# the format is intelligently determined from a file.
# structure.to(fmt="poscar")
# structure.to(filename="POSCAR")
# structure.to(filename="CsCl.cif")

# Pythonic API for editing Structures and Molecules (v2.9.1 onwards)
# Changing the specie of a site.
structure[1] = "F"
print(structure)
import argparse
import pickle
# analyze space group of POSCAR using pymatgen
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer

if __name__ == '__main__':
    # ---------- argparse
    parser = argparse.ArgumentParser()
    parser.add_argument('-a', '--all_id', help='flag for all structures', action='store_true')
    parser.add_argument('-i', '--index', help='structure ID', type=int, nargs='*')
    parser.add_argument('-s', '--symmetrized', help='flag for symmetrized structure', action='store_true')
    parser.add_argument('infile', help='input file')
    args = parser.parse_args()

    # ---------- load struc_data
    with open(args.infile, 'rb') as f:
        struc_data = pickle.load(f)

    # ---------- write POSCAR
    if args.index:
        for cid in args.index:
            # print(struc_data[cid].to(fmt='poscar'))
            print(struc_data[cid])
            # print(SpacegroupAnalyzer(struc_data[cid], symprec=.1).get_space_group_symbol())
            # print(SpacegroupAnalyzer(struc_data[cid], 0.1).get_space_group_symbol())
            print(SpacegroupAnalyzer(struc_data[cid], 0.1).get_space_group_number())
            spg_no =  SpacegroupAnalyzer(struc_data[cid], 0.1).get_space_group_number()
            # struc_data[cid].to(fmt='cif', filename='{}.cif'.format(cid))
            struc_data[cid].to(fmt='POSCAR', filename='{}.vasp'.format(str(cid)+'_'+str(spg_no)))
        raise SystemExit()
Example #50
0
from pyxtal.lattice import cellsize

for G in range(1, 231):
    #for G in [90, 99, 105, 107, 203, 210, 224, 226, 227, 228]:
    g = Group(G)
    subs = g.get_max_t_subgroup()
    indices = subs['index']
    hs = subs['subgroup']
    relations = subs['relations']
    tran = subs['transformation']
    letter = str(g[0].multiplicity) + g[0].letter
    print(G)
    C1 = random_crystal(G, ['C'], [int(g[0].multiplicity / cellsize(g))],
                        sites=[[letter]])
    pmg_s1 = C1.to_pymatgen()
    sga1 = SpacegroupAnalyzer(pmg_s1).get_space_group_symbol()
    # each subgroup
    for i in range(len(relations)):
        C2 = C1.subgroup(eps=0, idx=[i], once=True)
        pmg_s2 = C2.to_pymatgen()
        try:
            sga2 = SpacegroupAnalyzer(pmg_s2,
                                      symprec=1e-4).get_space_group_symbol()
        except:
            #print("unable to find the space group")
            sga2 = None
        print(G, hs[i], g.symbol, sga1, Group(hs[i]).symbol, sga2, i)
        if not sm.StructureMatcher().fit(pmg_s1, pmg_s2):
            print('WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW')
            print(C1)
            print(C2)
Example #51
0
    def _gen_input_file(self):
        """
        Generate the necessary struct_enum.in file for enumlib. See enumlib
        documentation for details.
        """
        coord_format = "{:.6f} {:.6f} {:.6f}"

        # Using symmetry finder, get the symmetrically distinct sites.
        fitter = SpacegroupAnalyzer(self.structure, self.symm_prec)
        symmetrized_structure = fitter.get_symmetrized_structure()
        logger.debug("Spacegroup {} ({}) with {} distinct sites".format(
            fitter.get_spacegroup_symbol(), fitter.get_spacegroup_number(),
            len(symmetrized_structure.equivalent_sites)))
        """
        Enumlib doesn"t work when the number of species get too large. To
        simplify matters, we generate the input file only with disordered sites
        and exclude the ordered sites from the enumeration. The fact that
        different disordered sites with the exact same species may belong to
        different equivalent sites is dealt with by having determined the
        spacegroup earlier and labelling the species differently.
        """

        # index_species and index_amounts store mappings between the indices
        # used in the enum input file, and the actual species and amounts.
        index_species = []
        index_amounts = []

        #Stores the ordered sites, which are not enumerated.
        ordered_sites = []
        disordered_sites = []
        coord_str = []
        for sites in symmetrized_structure.equivalent_sites:
            if sites[0].is_ordered:
                ordered_sites.append(sites)
            else:
                sp_label = []
                species = {k: v for k, v in sites[0].species_and_occu.items()}
                if sum(species.values()) < 1 - EnumlibAdaptor.amount_tol:
                    #Let us first make add a dummy element for every single
                    #site whose total occupancies don't sum to 1.
                    species[DummySpecie("X")] = 1 - sum(species.values())
                for sp in species.keys():
                    if sp not in index_species:
                        index_species.append(sp)
                        sp_label.append(len(index_species) - 1)
                        index_amounts.append(species[sp] * len(sites))
                    else:
                        ind = index_species.index(sp)
                        sp_label.append(ind)
                        index_amounts[ind] += species[sp] * len(sites)
                sp_label = "/".join(["{}".format(i) for i in sorted(sp_label)])
                for site in sites:
                    coord_str.append("{} {}".format(
                        coord_format.format(*site.coords), sp_label))
                disordered_sites.append(sites)

        def get_sg_info(ss):
            finder = SpacegroupAnalyzer(Structure.from_sites(ss),
                                        self.symm_prec)
            sgnum = finder.get_spacegroup_number()
            return sgnum

        curr_sites = list(itertools.chain.from_iterable(disordered_sites))
        min_sgnum = get_sg_info(curr_sites)
        logger.debug("Disorderd sites has sgnum %d" % (min_sgnum))
        #It could be that some of the ordered sites has a lower symmetry than
        #the disordered sites.  So we consider the lowest symmetry sites as
        #disordered in our enumeration.
        self.ordered_sites = []
        to_add = []

        if self.check_ordered_symmetry:
            for sites in ordered_sites:
                temp_sites = list(curr_sites) + sites
                sgnum = get_sg_info(temp_sites)
                if sgnum < min_sgnum:
                    logger.debug("Adding {} to sites to be ordered. "
                                 "New sgnum {}".format(sites, sgnum))
                    to_add = sites
                    min_sgnum = sgnum

        for sites in ordered_sites:
            if sites == to_add:
                index_species.append(sites[0].specie)
                index_amounts.append(len(sites))
                sp_label = len(index_species) - 1
                logger.debug(
                    "Lowest symmetry {} sites are included in enum.".format(
                        sites[0].specie))
                for site in sites:
                    coord_str.append("{} {}".format(
                        coord_format.format(*site.coords), sp_label))
                disordered_sites.append(sites)
            else:
                self.ordered_sites.extend(sites)

        self.index_species = index_species

        lattice = self.structure.lattice

        output = [self.structure.formula, "bulk"]
        for vec in lattice.matrix:
            output.append(coord_format.format(*vec))
        output.append("{}".format(len(index_species)))
        output.append("{}".format(len(coord_str)))
        output.extend(coord_str)

        output.append("{} {}".format(self.min_cell_size, self.max_cell_size))
        output.append(str(self.enum_precision_parameter))
        output.append("partial")

        ndisordered = sum([len(s) for s in disordered_sites])
        base = ndisordered  #10 ** int(math.ceil(math.log10(ndisordered)))
        #To get a reasonable number of structures, we fix concentrations to the
        #range expected in the original structure.
        total_amounts = sum(index_amounts)
        for amt in index_amounts:
            conc = amt / total_amounts
            if abs(conc * base - round(conc * base)) < 1e-5:
                output.append("{} {} {}".format(int(round(conc * base)),
                                                int(round(conc * base)), base))
            else:
                min_conc = int(math.floor(conc * base))
                output.append("{} {} {}".format(min_conc - 1, min_conc + 1,
                                                base))
        output.append("")
        logger.debug("Generated input file:\n{}".format("\n".join(output)))
        with open("struct_enum.in", "w") as f:
            f.write("\n".join(output))
Example #52
0
    def get_pattern(self, structure, scaled=True, two_theta_range=(0, 90)):
        """
        Calculates the powder neutron diffraction pattern for a structure.

        Args:
            structure (Structure): Input structure
            scaled (bool): Whether to return scaled intensities. The maximum
                peak is set to a value of 100. Defaults to True. Use False if
                you need the absolute values to combine ND plots.
            two_theta_range ([float of length 2]): Tuple for range of
                two_thetas to calculate in degrees. Defaults to (0, 90). Set to
                None if you want all diffracted beams within the limiting
                sphere of radius 2 / wavelength.

        Returns:
            (NDPattern)
        """
        if self.symprec:
            finder = SpacegroupAnalyzer(structure, symprec=self.symprec)
            structure = finder.get_refined_structure()

        wavelength = self.wavelength
        latt = structure.lattice
        is_hex = latt.is_hexagonal()

        # Obtained from Bragg condition. Note that reciprocal lattice
        # vector length is 1 / d_hkl.
        min_r, max_r = (0, 2 / wavelength) if two_theta_range is None else \
            [2 * sin(radians(t / 2)) / wavelength for t in two_theta_range]

        # Obtain crystallographic reciprocal lattice points within range
        recip_latt = latt.reciprocal_lattice_crystallographic
        recip_pts = recip_latt.get_points_in_sphere(
            [[0, 0, 0]], [0, 0, 0], max_r)
        if min_r:
            recip_pts = [pt for pt in recip_pts if pt[1] >= min_r]

        # Create a flattened array of coeffs, fcoords and occus. This is
        # used to perform vectorized computation of atomic scattering factors
        # later. Note that these are not necessarily the same size as the
        # structure as each partially occupied specie occupies its own
        # position in the flattened array.
        coeffs = []
        fcoords = []
        occus = []
        dwfactors = []

        for site in structure:
            for sp, occu in site.species.items():
                try:
                    c = ATOMIC_SCATTERING_LEN[sp.symbol]
                except KeyError:
                    raise ValueError("Unable to calculate ND pattern as "
                                     "there is no scattering coefficients for"
                                     " %s." % sp.symbol)
                coeffs.append(c)
                dwfactors.append(self.debye_waller_factors.get(sp.symbol, 0))
                fcoords.append(site.frac_coords)
                occus.append(occu)

        coeffs = np.array(coeffs)
        fcoords = np.array(fcoords)
        occus = np.array(occus)
        dwfactors = np.array(dwfactors)
        peaks = {}
        two_thetas = []

        for hkl, g_hkl, ind, _ in sorted(
                recip_pts, key=lambda i: (i[1], -i[0][0], -i[0][1], -i[0][2])):
            # Force miller indices to be integers.
            hkl = [int(round(i)) for i in hkl]
            if g_hkl != 0:

                d_hkl = 1 / g_hkl

                # Bragg condition
                theta = asin(wavelength * g_hkl / 2)

                # s = sin(theta) / wavelength = 1 / 2d = |ghkl| / 2 (d =
                # 1/|ghkl|)
                s = g_hkl / 2

                # Calculate Debye-Waller factor
                dw_correction = np.exp(-dwfactors * (s**2))

                # Vectorized computation of g.r for all fractional coords and
                # hkl.
                g_dot_r = np.dot(fcoords, np.transpose([hkl])).T[0]

                # Structure factor = sum of atomic scattering factors (with
                # position factor exp(2j * pi * g.r and occupancies).
                # Vectorized computation.
                f_hkl = np.sum(coeffs * occus * np.exp(2j * pi * g_dot_r)
                               * dw_correction)

                # Lorentz polarization correction for hkl
                lorentz_factor = 1 / (sin(theta) ** 2 * cos(theta))

                # Intensity for hkl is modulus square of structure factor.
                i_hkl = (f_hkl * f_hkl.conjugate()).real

                two_theta = degrees(2 * theta)

                if is_hex:
                    # Use Miller-Bravais indices for hexagonal lattices.
                    hkl = (hkl[0], hkl[1], - hkl[0] - hkl[1], hkl[2])
                # Deal with floating point precision issues.
                ind = np.where(np.abs(np.subtract(two_thetas, two_theta)) <
                               self.TWO_THETA_TOL)
                if len(ind[0]) > 0:
                    peaks[two_thetas[ind[0][0]]][0] += i_hkl * lorentz_factor
                    peaks[two_thetas[ind[0][0]]][1].append(tuple(hkl))
                else:
                    peaks[two_theta] = [i_hkl * lorentz_factor, [tuple(hkl)],
                                        d_hkl]
                    two_thetas.append(two_theta)

        # Scale intensities so that the max intensity is 100.
        max_intensity = max([v[0] for v in peaks.values()])
        x = []
        y = []
        hkls = []
        d_hkls = []
        for k in sorted(peaks.keys()):
            v = peaks[k]
            fam = get_unique_families(v[1])
            if v[0] / max_intensity * 100 > self.SCALED_INTENSITY_TOL:
                x.append(k)
                y.append(v[0])
                hkls.append(fam)
                d_hkls.append(v[2])
        nd = DiffractionPattern(x, y, hkls, d_hkls)
        if scaled:
            nd.normalize(mode="max", value=100)
        return nd
    def get_end_point_pairs(self):
        """
        will change self._struct into supercell structure if necessary
        the distinct sites in list should be less than 4.
        :return: a list of end points pairs for diffusion
        """
        self._struct.make_supercell([2, 2, 2])
        moving_cation = []

        #Get symmetric equivalent sites
        analyzed_struct = SpacegroupAnalyzer(self._struct)
        analyzed_struct = analyzed_struct.get_symmetrized_structure()
        equivalent_sites = analyzed_struct.equivalent_sites
        #Debug
        #print len(equivalent_sites)

        for site in self._struct.sites:
            if site.specie == self._specie:
                moving_cation.append(site)
        #Debug
        #print len(moving_cation)

        distance = 100 * np.ones(
            (len(moving_cation), len(moving_cation)), dtype=float)
        for i in range(len(moving_cation)):
            for j in range(i):
                distance[i][j] = moving_cation[i].distance(moving_cation[j])

        min_distance = np.amin(distance)
        min_distance_pairs = []

        for i in range(len(moving_cation)):
            for j in range(i):
                if distance[i][j] < min_distance * 1.15:
                    min_distance_pairs.append([i, j])
        #Debug
        #print min_distance_pairs
        #print len(min_distance_pairs)

        cation_group_num = []
        for group in range(len(equivalent_sites)):
            if equivalent_sites[group][0].specie == self._specie:
                cation_group_num.append(group)

        group_pair = {}
        for i in range(len(cation_group_num)):
            for j in range(i + 1):
                group_pair[(cation_group_num[i], cation_group_num[j])] = []

        for pair in min_distance_pairs:
            for group in range(len(equivalent_sites)):
                if moving_cation[pair[0]] in equivalent_sites[group]:
                    group_i = group
                if moving_cation[pair[1]] in equivalent_sites[group]:
                    group_j = group
            (group_i, group_j) = EndPointFinder._reorder(group_i, group_j)

            if moving_cation[pair[0]] in equivalent_sites[group_i]:
                group_pair[(group_i, group_j)].append(
                    [moving_cation[pair[0]], moving_cation[pair[1]]])
            else:
                group_pair[(group_i, group_j)].append(
                    [moving_cation[pair[1]], moving_cation[pair[0]]])

        end_point_pair = []
        for pairs in group_pair.values():
            if pairs:
                selected_pair = pairs[0]
                coordin_sum = 10
                for pair in pairs:
                    if np.sum(pair[0].frac_coords) + np.sum(
                            pair[1].frac_coords) < coordin_sum:
                        selected_pair = pair
                        coordin_sum = np.sum(pair[0].frac_coords) + np.sum(
                            pair[1].frac_coords)
                end_point_pair.append(selected_pair)

        return end_point_pair
Example #54
0
    def generate_doc(self, dir_name, vasprun_files, outcar_files):
        """
        Adapted from matgendb.creator.generate_doc
        """
        try:
            # basic properties, incl. calcs_reversed and run_stats
            fullpath = os.path.abspath(dir_name)
            d = {k: v for k, v in self.additional_fields.items()}
            d["schema"] = {"code": "atomate", "version": VaspDrone.__version__}
            d["dir_name"] = fullpath
            d["calcs_reversed"] = [self.process_vasprun(dir_name, taskname, filename)
                                   for taskname, filename in vasprun_files.items()]
            outcar_data = [Outcar(os.path.join(dir_name, filename)).as_dict()
                           for taskname, filename in outcar_files.items()]
            run_stats = {}
            for i, d_calc in enumerate(d["calcs_reversed"]):
                run_stats[d_calc["task"]["name"]] = outcar_data[i].pop("run_stats")
                if d_calc.get("output"):
                    d_calc["output"].update({"outcar": outcar_data[i]})
                else:
                    d_calc["output"] = {"outcar": outcar_data[i]}
            try:
                overall_run_stats = {}
                for key in ["Total CPU time used (sec)", "User time (sec)", "System time (sec)",
                            "Elapsed time (sec)"]:
                    overall_run_stats[key] = sum([v[key] for v in run_stats.values()])
                run_stats["overall"] = overall_run_stats
            except:
                logger.error("Bad run stats for {}.".format(fullpath))
            d["run_stats"] = run_stats

            # reverse the calculations data order so newest calc is first
            d["calcs_reversed"].reverse()

            # set root formula/composition keys based on initial and final calcs
            d_calc_init = d["calcs_reversed"][-1]
            d_calc_final = d["calcs_reversed"][0]
            d["chemsys"] = "-".join(sorted(d_calc_final["elements"]))
            comp = Composition(d_calc_final["composition_unit_cell"])
            d["formula_anonymous"] = comp.anonymized_formula
            d["formula_reduced_abc"] = comp.reduced_composition.alphabetical_formula
            for root_key in ["completed_at", "nsites", "composition_unit_cell",
                             "composition_reduced", "formula_pretty", "elements", "nelements"]:
                d[root_key] = d_calc_final[root_key]

            # store the input key based on initial calc
            # store any overrides to the exchange correlation functional
            xc = d_calc_init["input"]["incar"].get("GGA")
            if xc:
                xc = xc.upper()
            p = d_calc_init["input"]["potcar_type"][0].split("_")
            pot_type = p[0]
            functional = "lda" if len(pot_type) == 1 else "_".join(p[1:])
            d["input"] = {"structure": d_calc_init["input"]["structure"],
                          "is_hubbard": d_calc_init.pop("is_hubbard"),
                          "hubbards": d_calc_init.pop("hubbards"),
                          "is_lasph": d_calc_init["input"]["incar"].get("LASPH", False),
                          "potcar_spec": d_calc_init["input"].get("potcar_spec"),
                          "xc_override": xc,
                          "pseudo_potential": {"functional": functional.lower(),
                                               "pot_type": pot_type.lower(),
                                               "labels": d_calc_init["input"]["potcar"]},
                          "parameters": d_calc_init["input"]["parameters"],
                          "incar": d_calc_init["input"]["incar"]
                          }

            # store the output key based on final calc
            d["output"] = {
                "structure": d_calc_final["output"]["structure"],
                "density": d_calc_final.pop("density"),
                "energy": d_calc_final["output"]["energy"],
                "energy_per_atom": d_calc_final["output"]["energy_per_atom"]}

            # patch calculated magnetic moments into final structure
            if len(d_calc_final["output"]["outcar"]["magnetization"]) != 0:
                magmoms = [m["tot"] for m in d_calc_final["output"]["outcar"]["magnetization"]]
                s = Structure.from_dict(d["output"]["structure"])
                s.add_site_property('magmom', magmoms)
                d["output"]["structure"] = s.as_dict()

            calc = d["calcs_reversed"][0]

            try:
                d["output"].update({"bandgap": calc["output"]["bandgap"],
                                    "cbm": calc["output"]["cbm"],
                                    "vbm": calc["output"]["vbm"],
                                    "is_gap_direct": calc["output"]["is_gap_direct"],
                                    "is_metal": calc["output"]["is_metal"]})
            except Exception:
                if self.bandstructure_mode is True:
                    import traceback
                    logger.error(traceback.format_exc())
                    logger.error("Error in " + os.path.abspath(dir_name) + ".\n" + traceback.format_exc())
                    raise

            sg = SpacegroupAnalyzer(Structure.from_dict(d_calc_final["output"]["structure"]), 0.1)
            if not sg.get_symmetry_dataset():
                sg = SpacegroupAnalyzer(Structure.from_dict(d_calc_final["output"]["structure"]),
                                        1e-3, 1)
            d["output"]["spacegroup"] = {
                "source": "spglib",
                "symbol": sg.get_space_group_symbol(),
                "number": sg.get_space_group_number(),
                "point_group": sg.get_point_group_symbol(),
                "crystal_system": sg.get_crystal_system(),
                "hall": sg.get_hall()}
            if d["input"]["parameters"].get("LEPSILON"):
                for k in ['epsilon_static', 'epsilon_static_wolfe', 'epsilon_ionic']:
                    d["output"][k] = d_calc_final["output"][k]
                if SymmOp.inversion() not in sg.get_symmetry_operations():
                    for k in ["piezo_ionic_tensor", "piezo_tensor"]:
                        d["output"][k] = d_calc_final["output"]["outcar"][k]

            d["state"] = "successful" if d_calc["has_vasp_completed"] else "unsuccessful"

            self.set_analysis(d)

            d["last_updated"] = datetime.datetime.today()
            return d

        except Exception:
            import traceback
            logger.error(traceback.format_exc())
            logger.error("Error in " + os.path.abspath(dir_name) + ".\n" + traceback.format_exc())
            raise
Example #55
0
    def test_get_kpoint_weights(self):
        for name in ["SrTiO3", "LiFePO4", "Graphite"]:
            s = PymatgenTest.get_structure(name)
            a = SpacegroupAnalyzer(s)
            ir_mesh = a.get_ir_reciprocal_mesh((4, 4, 4))
            weights = [i[1] for i in ir_mesh]
            weights = np.array(weights) / sum(weights)
            for i, w in zip(weights,
                            a.get_kpoint_weights([i[0] for i in ir_mesh])):
                self.assertAlmostEqual(i, w)

        for name in ["SrTiO3", "LiFePO4", "Graphite"]:
            s = PymatgenTest.get_structure(name)
            a = SpacegroupAnalyzer(s)
            ir_mesh = a.get_ir_reciprocal_mesh((1, 2, 3))
            weights = [i[1] for i in ir_mesh]
            weights = np.array(weights) / sum(weights)
            for i, w in zip(weights,
                            a.get_kpoint_weights([i[0] for i in ir_mesh])):
                self.assertAlmostEqual(i, w)

        v = Vasprun(test_dir / "vasprun.xml")
        a = SpacegroupAnalyzer(v.final_structure)
        wts = a.get_kpoint_weights(v.actual_kpoints)

        for w1, w2 in zip(v.actual_kpoints_weights, wts):
            self.assertAlmostEqual(w1, w2)

        kpts = [[0, 0, 0], [0.15, 0.15, 0.15], [0.2, 0.2, 0.2]]
        self.assertRaises(ValueError, a.get_kpoint_weights, kpts)
Example #56
0
 def get_plot_2d_concise(self, structure: Structure) -> go.Figure:
     """
     Generates the concise 2D diffraction pattern of the input structure of a smaller size and without layout.
     Does not display.
     Args:
         structure (Structure): The input structure.
     Returns:
         Figure
     """
     if self.symprec:
         finder = SpacegroupAnalyzer(structure, symprec=self.symprec)
         structure = finder.get_refined_structure()
     points = self.generate_points(-10, 11)
     tem_dots = self.tem_dots(structure, points)
     xs = []
     ys = []
     hkls = []
     intensities = []
     for dot in tem_dots:
         if dot.hkl != (0, 0, 0):
             xs.append(dot.position[0])
             ys.append(dot.position[1])
             hkls.append(dot.hkl)
             intensities.append(dot.intensity)
     data = [
         go.Scatter(x=xs,
                    y=ys,
                    text=hkls,
                    mode='markers',
                    hoverinfo='skip',
                    marker=dict(size=4,
                                cmax=1,
                                cmin=0,
                                color=intensities,
                                colorscale=[[0, 'black'], [1.0, 'white']]),
                    showlegend=False)
     ]
     layout = go.Layout(
         xaxis=dict(autorange=True,
                    showgrid=False,
                    zeroline=False,
                    showline=False,
                    ticks='',
                    showticklabels=False),
         yaxis=dict(
             autorange=True,
             showgrid=False,
             zeroline=False,
             showline=False,
             ticks='',
             showticklabels=False,
         ),
         plot_bgcolor='black',
         margin={
             'l': 0,
             'r': 0,
             't': 0,
             'b': 0
         },
         width=121,
         height=121,
     )
     fig = go.Figure(data=data, layout=layout)
     fig.layout.update(showlegend=False)
     return fig
Example #57
0
 def setUp(self):
     p = Poscar.from_file(str(test_dir / 'POSCAR'))
     self.structure = p.structure
     self.sg1 = SpacegroupAnalyzer(self.structure,
                                   0.001).get_space_group_operations()
Example #58
0
 def get_plot_2d(self, structure: Structure) -> go.Figure:
     """
     Generates the 2D diffraction pattern of the input structure.
     Args:
         structure (Structure): The input structure.
     Returns:
         Figure
     """
     if self.symprec:
         finder = SpacegroupAnalyzer(structure, symprec=self.symprec)
         structure = finder.get_refined_structure()
     points = self.generate_points(-10, 11)
     tem_dots = self.tem_dots(structure, points)
     xs = []
     ys = []
     hkls = []
     intensities = []
     for dot in tem_dots:
         xs.append(dot.position[0])
         ys.append(dot.position[1])
         hkls.append(str(dot.hkl))
         intensities.append(dot.intensity)
     hkls = list(
         map(unicodeify_spacegroup, list(map(latexify_spacegroup, hkls))))
     data = [
         go.Scatter(
             x=xs,
             y=ys,
             text=hkls,
             hoverinfo='text',
             mode='markers',
             marker=dict(size=8,
                         cmax=1,
                         cmin=0,
                         color=intensities,
                         colorscale=[[0, 'black'], [1.0, 'white']]),
             showlegend=False,
         ),
         go.Scatter(
             x=[0],
             y=[0],
             text="(0, 0, 0): Direct beam",
             hoverinfo='text',
             mode='markers',
             marker=dict(size=14, cmax=1, cmin=0, color='white'),
             showlegend=False,
         )
     ]
     layout = go.Layout(
         title='2D Diffraction Pattern<br>Beam Direction: ' +
         ''.join(str(e) for e in self.beam_direction),
         font=dict(size=14, color='#7f7f7f'),
         hovermode='closest',
         xaxis=dict(range=[-5.5, 5.5],
                    showgrid=False,
                    zeroline=False,
                    showline=False,
                    ticks='',
                    showticklabels=False),
         yaxis=dict(
             range=[-5.5, 5.5],
             showgrid=False,
             zeroline=False,
             showline=False,
             ticks='',
             showticklabels=False,
         ),
         width=550,
         height=550,
         paper_bgcolor='rgba(100,110,110,0.5)',
         plot_bgcolor='black',
     )
     fig = go.Figure(data=data, layout=layout)
     return fig
Example #59
0
    def EV_find(self):
        hit = []
        count = []
        phases = []
        volumes = []
        ITEMS = []
        for i in self.items:
            try:
                mm = i['metadata']['tag']
            except:
                continue
            if mm in hit:
                volume = i['output']['structure']['lattice']['volume']
                if volume not in volumes[hit.index(mm)]:
                    volumes[hit.index(mm)].append(volume)
                    count[hit.index(mm)] += 1
                #if mm=='5252ccc3-e8da-499f-bb9e-9cf7eb1c5370': print("eeeeeeeee",mm, pot)
            else:
                ITEMS.append(i)
                hit.append(mm)
                count.append(1)
                volumes.append([i['output']['structure']['lattice']['volume']])

                pot = i['input']['pseudo_potential']['functional'].upper()
                #if mm=='5252ccc3-e8da-499f-bb9e-9cf7eb1c5370': print("eeeeeeeee",mm, pot)
                if pot == "":
                    pot = i['orig_inputs']['potcar']['functional'].upper()
                    if pot == 'Perdew-Zunger81'.upper(): pot = "LDA"

                try:
                    pot += "+" + i['input']['GGA']
                except:
                    pass

                if i['input']['is_hubbard']: pot += '+U'
                try:
                    if i['input']['incar']['LSORBIT']: potsoc = pot + "SOC"
                except:
                    potsoc = pot

                structure = Structure.from_dict(i['output']['structure'])
                natoms = len(structure.sites)
                formula_pretty = structure.composition.reduced_formula
                try:
                    formula2composition(formula_pretty)
                except:
                    formula_pretty = reduced_formula(
                        structure.composition.alphabetical_formula)
                sa = SpacegroupAnalyzer(structure)
                phasename = formula_pretty+'_'\
                    + sa.get_space_group_symbol().replace('/','.')+'_'+str(sa.get_space_group_number())+potsoc

                if phasename in phases:
                    for jj in range(10000):
                        nphasename = phasename + "#" + str(jj)
                        if nphasename in phases: continue
                        phasename = nphasename
                        break
                phases.append(phasename)

        for i, m in enumerate(hit):
            if count[i] < self.nV: continue
            if self.skipby(phases[i]): continue
            sys.stdout.write('{}, static: {:>2}, {}\n'.format(
                m, count[i], phases[i]))
            EV, POSCAR, INCAR = get_rec_from_metatag(self.vasp_db, m)

            evdir = './E-V/'
            if not os.path.exists(evdir): os.mkdir(evdir)
            folder = evdir + phases[i]
            if not os.path.exists(folder): os.mkdir(folder)
            with open(folder + '/POSCAR', 'w') as fp:
                fp.write(POSCAR)
            readme = {}
            readme['E-V'] = EV
            readme['INCAR'] = INCAR
            readme['POSCAR'] = POSCAR
            with open(folder + '/readme', 'w') as fp:
                myjsonout(readme, fp, indent="", comma="")

            thermoplot(folder, "0 K total energies (eV/atom)", EV['volumes'],
                       EV['energies'])
    def from_structure(cls, structure, equivalent_wyckoff_sites=None):
        """

        Parameters
        ----------
        structure : pymatgen.Structure
        equivalent_wyckoff_sites : list of lists
            List of Wyckoff sites that are treated as the same sublattice, e.g. [['b', 'f']] will
            give combine Wyckoff site 'b' and Wyckoff site 'f' into one sublattice. Putting the same
            Wyckoff site in multiple equivalent groups will produce undefined results.

        Returns
        -------
        PRLStructure
        """
        struct = PRLStructure.from_dict(structure.as_dict())
        # normalize the input structure to a pure element to get Wyckoff sites
        structure = Structure.from_dict(structure.as_dict())
        structure.replace_species({sp.name: "H" for sp in structure.species})
        sga = SpacegroupAnalyzer(structure)
        wyckoff_sites = sga.get_symmetry_dataset()['wyckoffs']
        true_sublattices = sorted(set(wyckoff_sites))
        if equivalent_wyckoff_sites is not None:
            # transform the true sublattices by combining equivalent sites
            combined_sublattices = [
                ''.join(sorted(sites)) for sites in equivalent_wyckoff_sites
            ]

            def match_subl(candidate):
                for subl in combined_sublattices:
                    # if the candidate site is in the combined sublattice, return the combined sublattice
                    if candidate in subl:
                        return subl
                # no match found
                return candidate

            new_subl_model = sorted(
                set([match_subl(subl) for subl in true_sublattices]))
        else:
            new_subl_model = true_sublattices

        #ratios = [sum([1 if site in subl else 0 for site in wyckoff_sites]) for subl in new_subl_model]
        config = []
        occ = []
        ratios = []
        for subl in new_subl_model:
            species_frequency_dict = {}
            for site, wyckoff_site in zip(struct.sites, wyckoff_sites):
                if wyckoff_site in subl:
                    species = site.specie.name
                    species_frequency_dict[
                        species] = species_frequency_dict.get(species, 0) + 1
            total_subl_occupation = sum(species_frequency_dict.values())
            subl_species = sorted(set(species_frequency_dict.keys()))
            subl_occpancy = [
                species_frequency_dict[sp] / total_subl_occupation
                for sp in subl_species
            ]
            config.append(subl_species)
            occ.append(subl_occpancy)
            ratios.append(total_subl_occupation)
        #config = [sorted(set([site.specie.name for site, wyckoff in  if wyckoff in subl])) for subl in new_subl_model]

        struct.sublattice_configuration = config
        struct.sublattice_occupancies = occ
        struct.sublattice_site_ratios = ratios
        return struct