def test_species_order(): lattice = Lattice.orthorhombic(5, 6, 7) coords = [ [0.0, 0.0, 0.0], [0.5, 0.5, 0.0], [0.5, 0.0, 0.5], [0.0, 0.5, 0.5], [0.0, 0.0, 0.5], [0.0, 0.5, 0.0], [0.5, 0.0, 0.0], [0.5, 0.5, 0.5], ] structure = Structure(lattice=lattice, species=["H"] * 4 + ["He"] * 4, coords=coords) supercell = structure * [1, 1, 2] actual = [e.specie for e in StructureSymmetrizer(supercell).conventional] expected = [Element.H] * 4 + [Element.He] * 4 assert actual == expected
def __init__(self, primitive_structure: IStructure, matrix_to_conv_cell: Optional[List[List[int]]] = None, symprec: float = defaults.symmetry_length_tolerance, angle_tolerance: float = defaults.symmetry_angle_tolerance, raise_error: bool = True, **supercell_kwargs): self.primitive_structure = primitive_structure self.symmetrizer = StructureSymmetrizer( primitive_structure, symprec=symprec, angle_tolerance=angle_tolerance) if primitive_structure != self.symmetrizer.primitive: logger.warning( "The input structure is different from the primitive one," "which might be due to the difference of symprec used in" "the pydefect and unitcell conversion.") logger.warning("\n".join([ "Input lattice:", f"{primitive_structure.lattice}", "", "Primitive structure lattice:", f"{self.symmetrizer.primitive.lattice}", "", "Input structure:", f"{primitive_structure}", "", "Primitive structure:", f"{self.symmetrizer.primitive}" ])) if raise_error: raise NotPrimitiveError self.sg_symbol = self.symmetrizer.spglib_sym_data["international"] self.conv_structure = self.symmetrizer.conventional crystal_system, center = str(self.symmetrizer.bravais) centering = Centering(center) self.conv_multiplicity = centering.conv_multiplicity self.conv_trans_mat = centering.primitive_to_conv self._matrix = matrix_to_conv_cell self._supercell_kwargs = supercell_kwargs self._generate_supercell(crystal_system) self._generate_supercell_info()
def test_symmetrize_defect_structure(): structure = Structure.from_str(fmt="POSCAR", input_string="""Mg4 O3 1.00000000000000 5 0 0 0 5 0 0 0 5 Mg O 4 3 Direct 0.0051896248240553 0.9835077947659414 0.9945137498637422 0.0047282952713914 0.4827940046010823 0.4942929782542009 0.5040349492352973 0.9821499237428384 0.4944941755970405 0.5058945352747628 0.4828206016032297 0.9940420309511140 0.5045613848356609 0.4811103128264023 0.4933877756337353 0.0013796816599694 0.9829379087234287 0.4953360299212051 0.0083465288988691 0.4848714537370853 0.9941122597789658""") structure_symmetrizer = StructureSymmetrizer( structure, defaults.symmetry_length_tolerance, defaults.symmetry_angle_tolerance) actual = symmetrize_defect_structure(structure_symmetrizer, anchor_atom_idx=1, anchor_atom_coord=np.array( [0.0, 0.5, 0.5])) expected = Structure.from_str(fmt="POSCAR", input_string="""Mg4 O3 1.00000000000000 5 0 0 0 5 0 0 0 5 Mg O 4 3 Direct 0.0 0.0 0.0 0.0 0.5 0.5 0.5 0.0 0.5 0.5 0.5 0.0 0.5 0.5 0.5 0.0 0.0 0.5 0.0 0.5 0.0""") assert actual == expected
def test_symmetrize_defect_structure_wo_anchor(): structure = Structure.from_str(fmt="POSCAR", input_string="""Mg4 O3 1.00000000000000 5 0 0 0 5 0 0 0 5 Mg O 4 3 Direct 0.01 0.01 0.01 0.01 0.51 0.51 0.51 0.01 0.51 0.51 0.51 0.01 0.51 0.51 0.51 0.01 0.01 0.51 0.01 0.51 0.01""") structure_symmetrizer = StructureSymmetrizer(structure) actual = symmetrize_defect_structure( structure_symmetrizer=structure_symmetrizer) expected = Structure.from_str(fmt="POSCAR", input_string="""Mg4 O3 1.00000000000000 5 0 0 0 5 0 0 0 5 Mg O 4 3 Direct 0.01 0.01 0.01 0.01 0.51 0.51 0.51 0.01 0.51 0.51 0.51 0.01 0.51 0.51 0.51 0.01 0.01 0.51 0.01 0.51 0.01""") assert actual == expected
def _create_defect_structures( self, defect: SimpleDefect ) -> Tuple[IStructure, Coords, str, Optional[IStructure], Optional[Tuple[ PerturbedSite, ...]], Optional[str]]: structure = copy_to_structure(self.supercell_info.structure) if defect.out_atom[0] == "i": index = int(defect.out_atom[1:]) - 1 site = self.supercell_info.interstitials[index] cutoff = self.supercell_info.interstitial_coords(index).cutoff coords = self.supercell_info.interstitials[index].frac_coords else: site = self.supercell_info.sites[defect.out_atom] cutoff = self.supercell_info.coords(defect.out_atom).cutoff removed_site_index = site.equivalent_atoms[0] coords = structure.pop(removed_site_index).frac_coords if defaults.displace_distance: p_structure, p_sites = perturb_structure(structure, coords, cutoff) p_site_symmetry = StructureSymmetrizer( p_structure, defaults.symmetry_length_tolerance, defaults.symmetry_angle_tolerance).point_group if defect.in_atom: add_atom_to_structure(structure, defect.in_atom, coords) add_atom_to_structure(p_structure, defect.in_atom, coords) return (to_istructure(structure), tuple(coords), site.site_symmetry, to_istructure(p_structure), p_sites, p_site_symmetry) else: if defect.in_atom: add_atom_to_structure(structure, defect.in_atom, coords) return (to_istructure(structure), tuple(coords), site.site_symmetry, None, None, None)
def make_defect_entry(name: str, charge: int, perfect_structure: IStructure, defect_structure: IStructure): analyzer = DefectStructureComparator(perfect_structure, defect_structure) species = [] frac_coords = [] for d, p in enumerate(analyzer.p_to_d): if p is None: site = defect_structure[d] else: site = perfect_structure[p] species.append(site.specie) frac_coords.append(site.frac_coords) initial_structure = IStructure(perfect_structure.lattice, species, frac_coords) symmetrizer = StructureSymmetrizer(initial_structure) return DefectEntry(name=name, charge=charge, structure=initial_structure, site_symmetry=symmetrizer.point_group, defect_center=tuple(analyzer.defect_center_coord))
def append_interstitial(supercell_info: SupercellInfo, unitcell_structure: Union[Structure, IStructure], frac_coords: List[Union[List[float], Coords]], infos: List[str] ) -> SupercellInfo: """ inv_trans_mat must be multiplied with coords from the right as the trans_mat is multiplied to the unitcell lattice vector from the left. see __mul__ of IStructure in pymatgen. x_u, x_s means the frac coordinates in unitcell and supercell, while a, b, c are the unitcell lattice vector. (a_u, b_u, c_u) . (a, b, c) = (a_s, b_s, c_s) . trans_mat . (a, b, c) (a_u, b_u, c_u) = (a_s, b_s, c_s) . trans_mat so, (a_s, b_s, c_s) = (a_u, b_u, c_u) . inv_trans_ma """ if supercell_info.unitcell_structure and \ supercell_info.unitcell_structure != unitcell_structure: raise NotPrimitiveError if isinstance(frac_coords[0], float): frac_coords = [frac_coords] for fcoord, info in zip(frac_coords, infos): us = Structure.from_dict(unitcell_structure.as_dict()) us.append(species=Element.H, coords=fcoord) symmetrizer = StructureSymmetrizer(us) site_symm = symmetrizer.spglib_sym_data["site_symmetry_symbols"][-1] inv_matrix = inv(np.array(supercell_info.transformation_matrix)) new_coords = np.dot(fcoord, inv_matrix).tolist() supercell_info.interstitials.append( Interstitial(frac_coords=new_coords, site_symmetry=site_symm, info=info)) return supercell_info
def test_(): structure = Structure.from_str(""" Na2 Cu2 O4 1.0 1.8088488050 -5.4059198794 0.0000000000 1.8088488050 5.4059198794 0.0000000000 0.0000000000 0.0000000000 5.3190514901 Na Cu O 2 2 4 direct 0.7123738820 0.2876261180 0.2500000000 Na 0.2876261180 0.7123738820 0.7500000000 Na 0.9970663194 0.0029336806 0.2500000000 Cu 0.0029336806 0.9970663194 0.7500000000 Cu 0.1138815169 0.8861184831 0.4939795157 O 0.8861184831 0.1138815169 0.5060204843 O 0.1138815169 0.8861184831 0.0060204843 O 0.8861184831 0.1138815169 0.9939795157 O """, fmt="POSCAR") symmetrizer = StructureSymmetrizer(structure) print(symmetrizer.primitive) sstructure = Structure.from_str(""" Na24 Cu24 O48 1.0 10.853093 0.000000 0.000000 0.000000 10.811840 0.000000 0.000000 0.000000 10.638103 Na Cu O 24 24 48 direct 0.166667 -0.212374 0.125000 Na 0.166667 -0.212374 0.625000 Na 0.500000 -0.212374 0.125000 Na 0.500000 -0.212374 0.625000 Na 0.833333 -0.212374 0.125000 Na 0.833333 -0.212374 0.625000 Na 0.333333 0.287626 0.125000 Na 0.333333 0.287626 0.625000 Na 0.666667 0.287626 0.125000 Na 0.666667 0.287626 0.625000 Na 1.000000 0.287626 0.125000 Na 1.000000 0.287626 0.625000 Na 0.166667 0.212374 0.375000 Na 0.166667 0.212374 0.875000 Na 0.500000 0.212374 0.375000 Na 0.500000 0.212374 0.875000 Na 0.833333 0.212374 0.375000 Na 0.833333 0.212374 0.875000 Na 0.333333 0.712374 0.375000 Na 0.333333 0.712374 0.875000 Na 0.666667 0.712374 0.375000 Na 0.666667 0.712374 0.875000 Na 1.000000 0.712374 0.375000 Na 1.000000 0.712374 0.875000 Na 0.166667 -0.497066 0.125000 Cu 0.166667 -0.497066 0.625000 Cu 0.500000 -0.497066 0.125000 Cu 0.500000 -0.497066 0.625000 Cu 0.833333 -0.497066 0.125000 Cu 0.833333 -0.497066 0.625000 Cu 0.333333 0.002934 0.125000 Cu 0.333333 0.002934 0.625000 Cu 0.666667 0.002934 0.125000 Cu 0.666667 0.002934 0.625000 Cu 1.000000 0.002934 0.125000 Cu 1.000000 0.002934 0.625000 Cu 0.166667 0.497066 0.375000 Cu 0.166667 0.497066 0.875000 Cu 0.500000 0.497066 0.375000 Cu 0.500000 0.497066 0.875000 Cu 0.833333 0.497066 0.375000 Cu 0.833333 0.497066 0.875000 Cu 0.333333 0.997066 0.375000 Cu 0.333333 0.997066 0.875000 Cu 0.666667 0.997066 0.375000 Cu 0.666667 0.997066 0.875000 Cu 1.000000 0.997066 0.375000 Cu 1.000000 0.997066 0.875000 Cu 0.166667 0.386118 0.246990 O 0.166667 0.386118 0.746990 O 0.500000 0.386118 0.246990 O 0.500000 0.386118 0.746990 O 0.833333 0.386118 0.246990 O 0.833333 0.386118 0.746990 O 0.333333 0.886118 0.246990 O 0.333333 0.886118 0.746990 O 0.666667 0.886118 0.246990 O 0.666667 0.886118 0.746990 O 1.000000 0.886118 0.246990 O 1.000000 0.886118 0.746990 O 0.166667 -0.386118 0.253010 O 0.166667 -0.386118 0.753010 O 0.500000 -0.386118 0.253010 O 0.500000 -0.386118 0.753010 O 0.833333 -0.386118 0.253010 O 0.833333 -0.386118 0.753010 O 0.333333 0.113882 0.253010 O 0.333333 0.113882 0.753010 O 0.666667 0.113882 0.253010 O 0.666667 0.113882 0.753010 O 1.000000 0.113882 0.253010 O 1.000000 0.113882 0.753010 O 0.166667 0.386118 0.003010 O 0.166667 0.386118 0.503010 O 0.500000 0.386118 0.003010 O 0.500000 0.386118 0.503010 O 0.833333 0.386118 0.003010 O 0.833333 0.386118 0.503010 O 0.333333 0.886118 0.003010 O 0.333333 0.886118 0.503010 O 0.666667 0.886118 0.003010 O 0.666667 0.886118 0.503010 O 1.000000 0.886118 0.003010 O 1.000000 0.886118 0.503010 O 0.166667 -0.386118 0.496990 O 0.166667 -0.386118 0.996990 O 0.500000 -0.386118 0.496990 O 0.500000 -0.386118 0.996990 O 0.833333 -0.386118 0.496990 O 0.833333 -0.386118 0.996990 O 0.333333 0.113882 0.496990 O 0.333333 0.113882 0.996990 O 0.666667 0.113882 0.496990 O 0.666667 0.113882 0.996990 O 1.000000 0.113882 0.496990 O 1.000000 0.113882 0.996990 O""", fmt="POSCAR") symmetrizer = StructureSymmetrizer(sstructure) print(symmetrizer.primitive)
def test_symmetrize_defect_structure_2(): structure = Structure.from_str(fmt="POSCAR", input_string="""Mg48 N31 1.00000000000000 10.00 0.00 0.00 0.00 10.00 0.00 0.00 0.00 10.00 N 31 Direct 0.9998735951099533 0.9999339271342436 0.9998810782738516 0.4998325344890802 0.0000864604371742 0.0001093145892668 0.9999579188430090 0.5001853666498661 0.0001277381372233 0.2491639910909313 0.2182663238872422 0.4987861655656971 0.2808293379596023 0.4991743721150215 0.7498359204125151 0.5007987323114946 0.2498921962049820 0.2191539974347521 0.2186260754052398 0.4998463318536253 0.2504951842089369 0.5003683092799207 0.7505911171114192 0.2814698995089699 0.7491029691281099 0.2824156531954642 0.4998653178588484 0.2496769296641759 0.2810133141130393 0.0008972384265746 0.2179934993920654 0.0013328906653882 0.7491830895564036 0.9985995146190305 0.2494223137356002 0.2817274775328684 0.2819549960242611 0.0002510594995684 0.2492863143591961 0.9999066837513126 0.7494408251560003 0.2182162389686653 0.7503446162775589 0.2186089947761758 0.0001821657373426 0.5000178504783079 0.5000386610406409 0.9999895875233165 0.4999380720704565 0.5002342427150381 0.5000689317878368 0.0000976472392296 0.5000243131273407 0.5000777225283457 0.5001616481443207 0.0002089601314523 0.4998675396277079 0.7502599885437249 0.7191435719333086 0.9992528941462950 0.7820064323950149 0.9990033992670391 0.2509026823008185 0.0012722293791043 0.7506950871201497 0.7182763220765622 0.7176368346430237 0.9998582962107960 0.7509680009789932 0.0000228430868177 0.2509182464808006 0.7821761073165092 0.2495215811710665 0.7814963684974714 0.9998566240987685 0.7508300518084354 0.7818602560717594 0.5013867902350881 0.7190618878688895 0.5010405127949369 0.2502514755283229 0.4989978969018409 0.7502977850544852 0.7809492219327865 0.7814464623477875 0.5003886730650109 0.7494947707104060 0.4996606931909255 0.2496508616713697 0.7186036919929819 0.2506716727065808 0.7181216545822622 0.5001902272634595""") structure_symmetrizer = StructureSymmetrizer( structure, defaults.symmetry_length_tolerance, defaults.symmetry_angle_tolerance) actual = symmetrize_defect_structure(structure_symmetrizer, anchor_atom_idx=15, anchor_atom_coord=np.array([0.5, 0.5, 0.0])) expected = Structure.from_str(fmt="POSCAR", input_string="""Mg4 O3 1.00000000000000 10 0 0 0 10 0 0 0 10 N 31 Direct 0 0 0 0.5 0 0 0 0.5 0 0.249164 0.218235 0.498835 0.280829 0.499143 0.749885 0.500857 0.249885 0.219171 0.218626 0.499815 0.250544 0.500185 0.750544 0.281374 0.749103 0.282384 0.499914 0.249885 0.280829 0.000857 0.218235 0.001165 0.749164 0.998835 0.249164 0.281765 0.282384 8.6e-05 0.249103 0.999914 0.749103 0.217616 0.750544 0.218626 0.000185 0.5 0.5 0 0.5 0.5 0.5 0 0.5 0.5 0.5 1 0.5 0.750115 0.719171 0.999143 0.781765 0.998835 0.250836 0.001165 0.750836 0.718235 0.717616 0.999914 0.750897 8.6e-05 0.250897 0.782384 0.249456 0.781374 0.999815 0.750836 0.781765 0.501165 0.719171 0.500857 0.250115 0.499143 0.750115 0.780829 0.781374 0.500185 0.749456 0.499815 0.249456 0.718626 0.250897 0.717616 0.500086""") assert actual == expected
def test_f_centering(bcc): s = StructureSymmetrizer(bcc) primitive = s.primitive to_conventional = primitive * Centering.I.primitive_to_conv assert to_conventional == s.conventional assert Centering.I.conv_multiplicity == 2
def symmetrizer_bcc(): lattice = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]] coords = [[0.0, 0.0, 0.0], [0.5, 0.5, 0.5]] structure = Structure(lattice=lattice, species=["H", "H"], coords=coords) symmetrizer = StructureSymmetrizer(structure) return symmetrizer
def test_a_centering(a_centered_orthorhombic): s = StructureSymmetrizer(a_centered_orthorhombic) primitive = s.primitive to_conventional = primitive * Centering.A.primitive_to_conv assert to_conventional.lattice == s.conventional.lattice assert Centering.A.conv_multiplicity == 2
def group_by_non_equiv_sites(structure: Structure): symmetrizer = StructureSymmetrizer(structure) return symmetrizer.grouped_atom_indices()
def test_grouped_atom_indices(complex_monoclinic_structure): symmetrizer = StructureSymmetrizer(complex_monoclinic_structure) actual = symmetrizer.grouped_atom_indices() assert actual == {'H1_a': [0], 'He1_m': [1, 2], 'He2_m': [3, 4]}
def test_c_centering(c_centered_monoclinic): s = StructureSymmetrizer(c_centered_monoclinic) primitive = s.primitive to_conventional = primitive * Centering.C.primitive_to_conv assert to_conventional == s.conventional assert Centering.C.conv_multiplicity == 2
def symmetrizer_mc(): lattice = [[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [-2.0, 0.0, 10.0]] coords = [[0.0, 0.0, 0.0], [0.5, 0.5, 0.0]] structure = Structure(lattice=lattice, species=["H"] * 2, coords=coords) symmetrizer = StructureSymmetrizer(structure) return symmetrizer
def test_r_centering(rhombohedral): s = StructureSymmetrizer(rhombohedral) rhombohedral = s.primitive to_conventional = rhombohedral * Centering.R.primitive_to_conv assert to_conventional == s.conventional
def _unique_point_group(self, structure): symmetrizer = StructureSymmetrizer(structure, self.symprec) return unique_point_group(symmetrizer.point_group)
def mc_structure_conv(mc_structure): symmetrizer = StructureSymmetrizer(mc_structure) return symmetrizer.conventional