From 17b70119c656382f6bc6116973ff325ba46971fe Mon Sep 17 00:00:00 2001 From: __sp__ Date: Fri, 2 Oct 2015 12:39:16 -0700 Subject: [PATCH] Use refined structure when using CifWriter with symprec. Fixes #241. --- pymatgen/io/cif.py | 10 +- pymatgen/io/tests/test_cif.py | 286 ++++++++++++++++++++++++++++++---- 2 files changed, 263 insertions(+), 33 deletions(-) diff --git a/pymatgen/io/cif.py b/pymatgen/io/cif.py index 7c3b2e56137..0091c702ce0 100644 --- a/pymatgen/io/cif.py +++ b/pymatgen/io/cif.py @@ -588,14 +588,18 @@ def __init__(self, struct, symprec=None): block = OrderedDict() loops = [] - latt = struct.lattice - comp = struct.composition - no_oxi_comp = comp.element_composition spacegroup = ("P 1", 1) if symprec is not None: sf = SpacegroupAnalyzer(struct, symprec) spacegroup = (sf.get_spacegroup_symbol(), sf.get_spacegroup_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( diff --git a/pymatgen/io/tests/test_cif.py b/pymatgen/io/tests/test_cif.py index 324e6e91764..eab4e059d9f 100644 --- a/pymatgen/io/tests/test_cif.py +++ b/pymatgen/io/tests/test_cif.py @@ -14,7 +14,7 @@ from pymatgen.io.vasp.inputs import Poscar from pymatgen import Element, Specie, Lattice, Structure, Composition, DummySpecie from pymatgen.analysis.structure_matcher import StructureMatcher - +from pymatgen.util.testing import PymatgenTest test_dir = os.path.join(os.path.dirname(__file__), "..", "..", "..", 'test_files') @@ -159,7 +159,7 @@ def test_long_loop(self): self.assertEqual(str(CifBlock(data, loops, 'test')), cif_str) -class CifIOTest(unittest.TestCase): +class CifIOTest(PymatgenTest): def test_CifParser(self): parser = CifParser(os.path.join(test_dir, 'LiFePO4.cif')) @@ -313,13 +313,11 @@ def test_CifWriter(self): _atom_site_fract_y _atom_site_fract_z _atom_site_occupancy - Fe Fe1 4 0.218728 0.750000 0.474867 1 - P P2 4 0.094613 0.250000 0.418243 1 - O O3 8 0.165710 0.046072 0.285384 1 - O O4 4 0.043372 0.750000 0.707138 1 - O O5 4 0.096642 0.250000 0.741320 1 - -""" + Fe Fe1 4 0.218728 0.250000 0.525133 1 + P P2 4 0.094613 0.750000 0.581757 1 + O O3 8 0.165710 0.546072 0.714616 1 + O O4 4 0.043372 0.250000 0.292862 1 + O O5 4 0.096642 0.750000 0.258680 1""" for l1, l2 in zip(str(writer).split("\n"), ans.split("\n")): self.assertEqual(l1.strip(), l2.strip()) @@ -360,37 +358,37 @@ def test_symmetrized(self): _atom_site_fract_y _atom_site_fract_z _atom_site_occupancy - Fe Fe1 4 0.218728 0.750000 0.474867 1 - P P2 4 0.094613 0.250000 0.418243 1 - O O3 8 0.165710 0.046072 0.285384 1 - O O4 4 0.043372 0.750000 0.707138 1 - O O5 4 0.096642 0.250000 0.741320 1""" + Fe Fe1 4 0.218728 0.250000 0.525133 1 + P P2 4 0.094613 0.750000 0.581757 1 + O O3 8 0.165710 0.546072 0.714616 1 + O O4 4 0.043372 0.250000 0.292862 1 + O O5 4 0.096642 0.750000 0.258680 1""" for l1, l2 in zip(str(writer).split("\n"), ans.split("\n")): self.assertEqual(l1.strip(), l2.strip()) ans = """# generated using pymatgen data_LiFePO4 _symmetry_space_group_name_H-M Pnma -_cell_length_a 4.74480000 +_cell_length_a 10.41037000 _cell_length_b 6.06577000 -_cell_length_c 10.41037000 -_cell_angle_alpha 90.50179000 -_cell_angle_beta 90.00019000 -_cell_angle_gamma 90.00362000 +_cell_length_c 4.74480000 +_cell_angle_alpha 90.00000000 +_cell_angle_beta 90.00000000 +_cell_angle_gamma 90.00000000 _symmetry_Int_Tables_number 62 _chemical_formula_structural LiFePO4 _chemical_formula_sum 'Li4 Fe4 P4 O16' -_cell_volume 299.607967711 +_cell_volume 299.619458734 _cell_formula_units_Z 4 loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz 1 'x, y, z' 2 '-x, -y, -z' - 3 'x+1/2, -y, -z+1/2' - 4 '-x+1/2, y, z+1/2' - 5 '-x+1/2, -y+1/2, z+1/2' - 6 'x+1/2, y+1/2, -z+1/2' + 3 '-x+1/2, -y, z+1/2' + 4 'x+1/2, y, -z+1/2' + 5 'x+1/2, -y+1/2, -z+1/2' + 6 '-x+1/2, y+1/2, z+1/2' 7 '-x, y+1/2, -z' 8 'x, -y+1/2, z' loop_ @@ -401,17 +399,245 @@ def test_symmetrized(self): _atom_site_fract_y _atom_site_fract_z _atom_site_occupancy - Li Li1 4 0.000010 0.500000 0.999990 1.0 - Fe Fe2 4 0.025030 0.746540 0.281160 1.0 - P P3 4 0.082060 0.248260 0.405570 1.0 - O O4 8 0.213420 0.043980 0.334230 1.0 - O O5 4 0.208430 0.251100 0.543180 1.0 - O O6 4 0.241480 0.750450 0.596220 1.0 + Li Li1 4 0.000000 0.000000 0.000000 1.0 + Fe Fe2 4 0.218845 0.750000 0.474910 1.0 + P P3 4 0.094445 0.250000 0.417920 1.0 + O O4 8 0.165815 0.044060 0.286540 1.0 + O O5 4 0.043155 0.750000 0.708460 1.0 + O O6 4 0.096215 0.250000 0.741480 1.0 """ s = Structure.from_file(os.path.join(test_dir, 'LiFePO4.cif')) writer = CifWriter(s, symprec=0.1) self.assertEqual(writer.__str__().strip(), ans.strip()) + s = self.get_structure("Li2O") + writer = CifWriter(s, symprec=0.1) + ans = """# generated using pymatgen +data_Li2O +_symmetry_space_group_name_H-M Fm-3m +_cell_length_a 4.61000000 +_cell_length_b 4.61000000 +_cell_length_c 4.61000000 +_cell_angle_alpha 90.00000000 +_cell_angle_beta 90.00000000 +_cell_angle_gamma 90.00000000 +_symmetry_Int_Tables_number 225 +_chemical_formula_structural Li2O +_chemical_formula_sum 'Li8 O4' +_cell_volume 97.972181 +_cell_formula_units_Z 4 +loop_ + _symmetry_equiv_pos_site_id + _symmetry_equiv_pos_as_xyz + 1 'x, y, z' + 2 '-x, -y, -z' + 3 'z, y, -x' + 4 '-z, -y, x' + 5 '-x, y, -z' + 6 'x, -y, z' + 7 '-z, y, x' + 8 'z, -y, -x' + 9 'x, -y, -z' + 10 '-x, y, z' + 11 'z, -y, x' + 12 '-z, y, -x' + 13 '-x, -y, z' + 14 'x, y, -z' + 15 '-z, -y, -x' + 16 'z, y, x' + 17 'y, -z, -x' + 18 '-y, z, x' + 19 'y, x, -z' + 20 '-y, -x, z' + 21 'y, z, x' + 22 '-y, -z, -x' + 23 'y, -x, z' + 24 '-y, x, -z' + 25 '-y, z, -x' + 26 'y, -z, x' + 27 '-y, -x, -z' + 28 'y, x, z' + 29 '-y, -z, x' + 30 'y, z, -x' + 31 '-y, x, z' + 32 'y, -x, -z' + 33 '-z, x, -y' + 34 'z, -x, y' + 35 'x, z, -y' + 36 '-x, -z, y' + 37 'z, -x, -y' + 38 '-z, x, y' + 39 '-x, -z, -y' + 40 'x, z, y' + 41 'z, x, y' + 42 '-z, -x, -y' + 43 '-x, z, y' + 44 'x, -z, -y' + 45 '-z, -x, y' + 46 'z, x, -y' + 47 'x, -z, y' + 48 '-x, z, -y' + 49 'x+1/2, y+1/2, z' + 50 '-x+1/2, -y+1/2, -z' + 51 'z+1/2, y+1/2, -x' + 52 '-z+1/2, -y+1/2, x' + 53 '-x+1/2, y+1/2, -z' + 54 'x+1/2, -y+1/2, z' + 55 '-z+1/2, y+1/2, x' + 56 'z+1/2, -y+1/2, -x' + 57 'x+1/2, -y+1/2, -z' + 58 '-x+1/2, y+1/2, z' + 59 'z+1/2, -y+1/2, x' + 60 '-z+1/2, y+1/2, -x' + 61 '-x+1/2, -y+1/2, z' + 62 'x+1/2, y+1/2, -z' + 63 '-z+1/2, -y+1/2, -x' + 64 'z+1/2, y+1/2, x' + 65 'y+1/2, -z+1/2, -x' + 66 '-y+1/2, z+1/2, x' + 67 'y+1/2, x+1/2, -z' + 68 '-y+1/2, -x+1/2, z' + 69 'y+1/2, z+1/2, x' + 70 '-y+1/2, -z+1/2, -x' + 71 'y+1/2, -x+1/2, z' + 72 '-y+1/2, x+1/2, -z' + 73 '-y+1/2, z+1/2, -x' + 74 'y+1/2, -z+1/2, x' + 75 '-y+1/2, -x+1/2, -z' + 76 'y+1/2, x+1/2, z' + 77 '-y+1/2, -z+1/2, x' + 78 'y+1/2, z+1/2, -x' + 79 '-y+1/2, x+1/2, z' + 80 'y+1/2, -x+1/2, -z' + 81 '-z+1/2, x+1/2, -y' + 82 'z+1/2, -x+1/2, y' + 83 'x+1/2, z+1/2, -y' + 84 '-x+1/2, -z+1/2, y' + 85 'z+1/2, -x+1/2, -y' + 86 '-z+1/2, x+1/2, y' + 87 '-x+1/2, -z+1/2, -y' + 88 'x+1/2, z+1/2, y' + 89 'z+1/2, x+1/2, y' + 90 '-z+1/2, -x+1/2, -y' + 91 '-x+1/2, z+1/2, y' + 92 'x+1/2, -z+1/2, -y' + 93 '-z+1/2, -x+1/2, y' + 94 'z+1/2, x+1/2, -y' + 95 'x+1/2, -z+1/2, y' + 96 '-x+1/2, z+1/2, -y' + 97 'x+1/2, y, z+1/2' + 98 '-x+1/2, -y, -z+1/2' + 99 'z+1/2, y, -x+1/2' + 100 '-z+1/2, -y, x+1/2' + 101 '-x+1/2, y, -z+1/2' + 102 'x+1/2, -y, z+1/2' + 103 '-z+1/2, y, x+1/2' + 104 'z+1/2, -y, -x+1/2' + 105 'x+1/2, -y, -z+1/2' + 106 '-x+1/2, y, z+1/2' + 107 'z+1/2, -y, x+1/2' + 108 '-z+1/2, y, -x+1/2' + 109 '-x+1/2, -y, z+1/2' + 110 'x+1/2, y, -z+1/2' + 111 '-z+1/2, -y, -x+1/2' + 112 'z+1/2, y, x+1/2' + 113 'y+1/2, -z, -x+1/2' + 114 '-y+1/2, z, x+1/2' + 115 'y+1/2, x, -z+1/2' + 116 '-y+1/2, -x, z+1/2' + 117 'y+1/2, z, x+1/2' + 118 '-y+1/2, -z, -x+1/2' + 119 'y+1/2, -x, z+1/2' + 120 '-y+1/2, x, -z+1/2' + 121 '-y+1/2, z, -x+1/2' + 122 'y+1/2, -z, x+1/2' + 123 '-y+1/2, -x, -z+1/2' + 124 'y+1/2, x, z+1/2' + 125 '-y+1/2, -z, x+1/2' + 126 'y+1/2, z, -x+1/2' + 127 '-y+1/2, x, z+1/2' + 128 'y+1/2, -x, -z+1/2' + 129 '-z+1/2, x, -y+1/2' + 130 'z+1/2, -x, y+1/2' + 131 'x+1/2, z, -y+1/2' + 132 '-x+1/2, -z, y+1/2' + 133 'z+1/2, -x, -y+1/2' + 134 '-z+1/2, x, y+1/2' + 135 '-x+1/2, -z, -y+1/2' + 136 'x+1/2, z, y+1/2' + 137 'z+1/2, x, y+1/2' + 138 '-z+1/2, -x, -y+1/2' + 139 '-x+1/2, z, y+1/2' + 140 'x+1/2, -z, -y+1/2' + 141 '-z+1/2, -x, y+1/2' + 142 'z+1/2, x, -y+1/2' + 143 'x+1/2, -z, y+1/2' + 144 '-x+1/2, z, -y+1/2' + 145 'x, y+1/2, z+1/2' + 146 '-x, -y+1/2, -z+1/2' + 147 'z, y+1/2, -x+1/2' + 148 '-z, -y+1/2, x+1/2' + 149 '-x, y+1/2, -z+1/2' + 150 'x, -y+1/2, z+1/2' + 151 '-z, y+1/2, x+1/2' + 152 'z, -y+1/2, -x+1/2' + 153 'x, -y+1/2, -z+1/2' + 154 '-x, y+1/2, z+1/2' + 155 'z, -y+1/2, x+1/2' + 156 '-z, y+1/2, -x+1/2' + 157 '-x, -y+1/2, z+1/2' + 158 'x, y+1/2, -z+1/2' + 159 '-z, -y+1/2, -x+1/2' + 160 'z, y+1/2, x+1/2' + 161 'y, -z+1/2, -x+1/2' + 162 '-y, z+1/2, x+1/2' + 163 'y, x+1/2, -z+1/2' + 164 '-y, -x+1/2, z+1/2' + 165 'y, z+1/2, x+1/2' + 166 '-y, -z+1/2, -x+1/2' + 167 'y, -x+1/2, z+1/2' + 168 '-y, x+1/2, -z+1/2' + 169 '-y, z+1/2, -x+1/2' + 170 'y, -z+1/2, x+1/2' + 171 '-y, -x+1/2, -z+1/2' + 172 'y, x+1/2, z+1/2' + 173 '-y, -z+1/2, x+1/2' + 174 'y, z+1/2, -x+1/2' + 175 '-y, x+1/2, z+1/2' + 176 'y, -x+1/2, -z+1/2' + 177 '-z, x+1/2, -y+1/2' + 178 'z, -x+1/2, y+1/2' + 179 'x, z+1/2, -y+1/2' + 180 '-x, -z+1/2, y+1/2' + 181 'z, -x+1/2, -y+1/2' + 182 '-z, x+1/2, y+1/2' + 183 '-x, -z+1/2, -y+1/2' + 184 'x, z+1/2, y+1/2' + 185 'z, x+1/2, y+1/2' + 186 '-z, -x+1/2, -y+1/2' + 187 '-x, z+1/2, y+1/2' + 188 'x, -z+1/2, -y+1/2' + 189 '-z, -x+1/2, y+1/2' + 190 'z, x+1/2, -y+1/2' + 191 'x, -z+1/2, y+1/2' + 192 '-x, z+1/2, -y+1/2' +loop_ + _atom_type_symbol + _atom_type_oxidation_number + Li+ 1.0 + O2- -2.0 +loop_ + _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 + Li+ Li1 8 0.250000 0.250000 0.250000 1.0 + O2- O2 4 0.000000 0.000000 0.000000 1.0""" + self.assertEqual(writer.__str__().strip(), ans.strip()) + def test_disordered(self): si = Element("Si") n = Element("N")