def test_write(self): cw_ref_string = """# generated using pymatgen data_GdB4 _symmetry_space_group_name_H-M 'P 1' _cell_length_a 7.13160000 _cell_length_b 7.13160000 _cell_length_c 4.05050000 _cell_angle_alpha 90.00000000 _cell_angle_beta 90.00000000 _cell_angle_gamma 90.00000000 _symmetry_Int_Tables_number 1 _chemical_formula_structural GdB4 _chemical_formula_sum 'Gd4 B16' _cell_volume 206.00729003 _cell_formula_units_Z 4 loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz 1 'x, y, z' 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 Gd Gd0 1 0.31746000 0.81746000 0.00000000 1.0 Gd Gd1 1 0.18254000 0.31746000 0.00000000 1.0 Gd Gd2 1 0.81746000 0.68254000 0.00000000 1.0 Gd Gd3 1 0.68254000 0.18254000 0.00000000 1.0 B B4 1 0.00000000 0.00000000 0.20290000 1.0 B B5 1 0.50000000 0.50000000 0.79710000 1.0 B B6 1 0.00000000 0.00000000 0.79710000 1.0 B B7 1 0.50000000 0.50000000 0.20290000 1.0 B B8 1 0.17590000 0.03800000 0.50000000 1.0 B B9 1 0.96200000 0.17590000 0.50000000 1.0 B B10 1 0.03800000 0.82410000 0.50000000 1.0 B B11 1 0.67590000 0.46200000 0.50000000 1.0 B B12 1 0.32410000 0.53800000 0.50000000 1.0 B B13 1 0.82410000 0.96200000 0.50000000 1.0 B B14 1 0.53800000 0.67590000 0.50000000 1.0 B B15 1 0.46200000 0.32410000 0.50000000 1.0 B B16 1 0.08670000 0.58670000 0.50000000 1.0 B B17 1 0.41330000 0.08670000 0.50000000 1.0 B B18 1 0.58670000 0.91330000 0.50000000 1.0 B B19 1 0.91330000 0.41330000 0.50000000 1.0 loop_ _atom_site_moment_label _atom_site_moment_crystalaxis_x _atom_site_moment_crystalaxis_y _atom_site_moment_crystalaxis_z Gd0 5.05000000 5.05000000 0.00000000 Gd1 -5.05000000 5.05000000 0.00000000 Gd2 5.05000000 -5.05000000 0.00000000 Gd3 -5.05000000 -5.05000000 0.00000000 """ s_ncl = self.mcif_ncl.get_structures(primitive=False)[0] cw = CifWriter(s_ncl, write_magmoms=True) self.assertEqual(cw.__str__(), cw_ref_string) # from list-type magmoms list_magmoms = [list(m) for m in s_ncl.site_properties['magmom']] # float magmoms (magnitude only) float_magmoms = [float(m) for m in s_ncl.site_properties['magmom']] s_ncl.add_site_property('magmom', list_magmoms) cw = CifWriter(s_ncl, write_magmoms=True) self.assertEqual(cw.__str__(), cw_ref_string) s_ncl.add_site_property('magmom', float_magmoms) cw = CifWriter(s_ncl, write_magmoms=True) cw_ref_string_magnitudes = """# generated using pymatgen data_GdB4 _symmetry_space_group_name_H-M 'P 1' _cell_length_a 7.13160000 _cell_length_b 7.13160000 _cell_length_c 4.05050000 _cell_angle_alpha 90.00000000 _cell_angle_beta 90.00000000 _cell_angle_gamma 90.00000000 _symmetry_Int_Tables_number 1 _chemical_formula_structural GdB4 _chemical_formula_sum 'Gd4 B16' _cell_volume 206.00729003 _cell_formula_units_Z 4 loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz 1 'x, y, z' 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 Gd Gd0 1 0.31746000 0.81746000 0.00000000 1.0 Gd Gd1 1 0.18254000 0.31746000 0.00000000 1.0 Gd Gd2 1 0.81746000 0.68254000 0.00000000 1.0 Gd Gd3 1 0.68254000 0.18254000 0.00000000 1.0 B B4 1 0.00000000 0.00000000 0.20290000 1.0 B B5 1 0.50000000 0.50000000 0.79710000 1.0 B B6 1 0.00000000 0.00000000 0.79710000 1.0 B B7 1 0.50000000 0.50000000 0.20290000 1.0 B B8 1 0.17590000 0.03800000 0.50000000 1.0 B B9 1 0.96200000 0.17590000 0.50000000 1.0 B B10 1 0.03800000 0.82410000 0.50000000 1.0 B B11 1 0.67590000 0.46200000 0.50000000 1.0 B B12 1 0.32410000 0.53800000 0.50000000 1.0 B B13 1 0.82410000 0.96200000 0.50000000 1.0 B B14 1 0.53800000 0.67590000 0.50000000 1.0 B B15 1 0.46200000 0.32410000 0.50000000 1.0 B B16 1 0.08670000 0.58670000 0.50000000 1.0 B B17 1 0.41330000 0.08670000 0.50000000 1.0 B B18 1 0.58670000 0.91330000 0.50000000 1.0 B B19 1 0.91330000 0.41330000 0.50000000 1.0 loop_ _atom_site_moment_label _atom_site_moment_crystalaxis_x _atom_site_moment_crystalaxis_y _atom_site_moment_crystalaxis_z Gd0 0.00000000 0.00000000 7.14177849 Gd1 0.00000000 0.00000000 7.14177849 Gd2 0.00000000 0.00000000 -7.14177849 Gd3 0.00000000 0.00000000 -7.14177849 """ self.assertEqual(cw.__str__().strip(), cw_ref_string_magnitudes.strip()) # test we're getting correct magmoms in ncl case s_ncl2 = self.mcif_ncl2.get_structures()[0] list_magmoms = [list(m) for m in s_ncl2.site_properties['magmom']] self.assertEqual(list_magmoms[0][0], 0.0) self.assertAlmostEqual(list_magmoms[0][1], 5.9160793408726366) self.assertAlmostEqual(list_magmoms[1][0], -5.1234749999999991) self.assertAlmostEqual(list_magmoms[1][1], 2.9580396704363183) # test creating an structure without oxidation state doesn't raise errors s_manual = Structure(Lattice.cubic(4.2), ["Cs", "Cl"], [[0, 0, 0], [0.5, 0.5, 0.5]]) s_manual.add_spin_by_site([1, -1]) cw = CifWriter(s_manual, write_magmoms=True) # check oxidation state cw_manual_oxi_string = """# generated using pymatgen data_CsCl _symmetry_space_group_name_H-M 'P 1' _cell_length_a 4.20000000 _cell_length_b 4.20000000 _cell_length_c 4.20000000 _cell_angle_alpha 90.00000000 _cell_angle_beta 90.00000000 _cell_angle_gamma 90.00000000 _symmetry_Int_Tables_number 1 _chemical_formula_structural CsCl _chemical_formula_sum 'Cs1 Cl1' _cell_volume 74.08800000 _cell_formula_units_Z 1 loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz 1 'x, y, z' loop_ _atom_type_symbol _atom_type_oxidation_number Cs+ 1.0 Cl+ 1.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 Cs+ Cs0 1 0.00000000 0.00000000 0.00000000 1 Cl+ Cl1 1 0.50000000 0.50000000 0.50000000 1 loop_ _atom_site_moment_label _atom_site_moment_crystalaxis_x _atom_site_moment_crystalaxis_y _atom_site_moment_crystalaxis_z """ s_manual.add_oxidation_state_by_site([1, 1]) cw = CifWriter(s_manual, write_magmoms=True) self.assertEqual(cw.__str__(), cw_manual_oxi_string)
def test_write(self): cw_ref_string = """# generated using pymatgen data_GdB4 _symmetry_space_group_name_H-M 'P 1' _cell_length_a 7.13160000 _cell_length_b 7.13160000 _cell_length_c 4.05050000 _cell_angle_alpha 90.00000000 _cell_angle_beta 90.00000000 _cell_angle_gamma 90.00000000 _symmetry_Int_Tables_number 1 _chemical_formula_structural GdB4 _chemical_formula_sum 'Gd4 B16' _cell_volume 206.00729003 _cell_formula_units_Z 4 loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz 1 'x, y, z' 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 Gd Gd0 1 0.317460 0.817460 0.000000 1.0 Gd Gd1 1 0.182540 0.317460 0.000000 1.0 Gd Gd2 1 0.817460 0.682540 0.000000 1.0 Gd Gd3 1 0.682540 0.182540 0.000000 1.0 B B4 1 0.000000 0.000000 0.202900 1.0 B B5 1 0.500000 0.500000 0.797100 1.0 B B6 1 0.000000 0.000000 0.797100 1.0 B B7 1 0.500000 0.500000 0.202900 1.0 B B8 1 0.175900 0.038000 0.500000 1.0 B B9 1 0.962000 0.175900 0.500000 1.0 B B10 1 0.038000 0.824100 0.500000 1.0 B B11 1 0.675900 0.462000 0.500000 1.0 B B12 1 0.324100 0.538000 0.500000 1.0 B B13 1 0.824100 0.962000 0.500000 1.0 B B14 1 0.538000 0.675900 0.500000 1.0 B B15 1 0.462000 0.324100 0.500000 1.0 B B16 1 0.086700 0.586700 0.500000 1.0 B B17 1 0.413300 0.086700 0.500000 1.0 B B18 1 0.586700 0.913300 0.500000 1.0 B B19 1 0.913300 0.413300 0.500000 1.0 loop_ _atom_site_moment_label _atom_site_moment_crystalaxis_x _atom_site_moment_crystalaxis_y _atom_site_moment_crystalaxis_z Gd0 5.05000 5.05000 0.00000 Gd1 -5.05000 5.05000 0.00000 Gd2 5.05000 -5.05000 0.00000 Gd3 -5.05000 -5.05000 0.00000 """ s_ncl = self.mcif_ncl.get_structures(primitive=False)[0] cw = CifWriter(s_ncl, write_magmoms=True) self.assertEqual(cw.__str__(), cw_ref_string) # from list-type magmoms list_magmoms = [list(m) for m in s_ncl.site_properties['magmom']] # float magmoms (magnitude only) float_magmoms = [float(m) for m in s_ncl.site_properties['magmom']] s_ncl.add_site_property('magmom', list_magmoms) cw = CifWriter(s_ncl, write_magmoms=True) self.assertEqual(cw.__str__(), cw_ref_string) s_ncl.add_site_property('magmom', float_magmoms) cw = CifWriter(s_ncl, write_magmoms=True) cw_ref_string_magnitudes = """# generated using pymatgen data_GdB4 _symmetry_space_group_name_H-M 'P 1' _cell_length_a 7.13160000 _cell_length_b 7.13160000 _cell_length_c 4.05050000 _cell_angle_alpha 90.00000000 _cell_angle_beta 90.00000000 _cell_angle_gamma 90.00000000 _symmetry_Int_Tables_number 1 _chemical_formula_structural GdB4 _chemical_formula_sum 'Gd4 B16' _cell_volume 206.00729003 _cell_formula_units_Z 4 loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz 1 'x, y, z' 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 Gd Gd0 1 0.317460 0.817460 0.000000 1.0 Gd Gd1 1 0.182540 0.317460 0.000000 1.0 Gd Gd2 1 0.817460 0.682540 0.000000 1.0 Gd Gd3 1 0.682540 0.182540 0.000000 1.0 B B4 1 0.000000 0.000000 0.202900 1.0 B B5 1 0.500000 0.500000 0.797100 1.0 B B6 1 0.000000 0.000000 0.797100 1.0 B B7 1 0.500000 0.500000 0.202900 1.0 B B8 1 0.175900 0.038000 0.500000 1.0 B B9 1 0.962000 0.175900 0.500000 1.0 B B10 1 0.038000 0.824100 0.500000 1.0 B B11 1 0.675900 0.462000 0.500000 1.0 B B12 1 0.324100 0.538000 0.500000 1.0 B B13 1 0.824100 0.962000 0.500000 1.0 B B14 1 0.538000 0.675900 0.500000 1.0 B B15 1 0.462000 0.324100 0.500000 1.0 B B16 1 0.086700 0.586700 0.500000 1.0 B B17 1 0.413300 0.086700 0.500000 1.0 B B18 1 0.586700 0.913300 0.500000 1.0 B B19 1 0.913300 0.413300 0.500000 1.0 loop_ _atom_site_moment_label _atom_site_moment_crystalaxis_x _atom_site_moment_crystalaxis_y _atom_site_moment_crystalaxis_z Gd0 0.00000 0.00000 7.14178 Gd1 0.00000 0.00000 7.14178 Gd2 0.00000 0.00000 -7.14178 Gd3 0.00000 0.00000 -7.14178 """ self.assertEqual(cw.__str__(), cw_ref_string_magnitudes) # test we're getting correct magmoms in ncl case s_ncl2 = self.mcif_ncl2.get_structures()[0] list_magmoms = [list(m) for m in s_ncl2.site_properties['magmom']] self.assertEqual(list_magmoms[0][0], 0.0) self.assertAlmostEqual(list_magmoms[0][1], 5.9160793408726366) self.assertAlmostEqual(list_magmoms[1][0], -5.1234749999999991) self.assertAlmostEqual(list_magmoms[1][1], 2.9580396704363183) # test creating an structure without oxidation state doesn't raise errors s_manual = Structure(Lattice.cubic(4.2), ["Cs", "Cl"],[[0, 0, 0], [0.5, 0.5, 0.5]]) s_manual.add_spin_by_site([1, -1]) cw = CifWriter(s_manual, write_magmoms=True) # check oxidation state cw_manual_oxi_string = """# generated using pymatgen data_CsCl _symmetry_space_group_name_H-M 'P 1' _cell_length_a 4.20000000 _cell_length_b 4.20000000 _cell_length_c 4.20000000 _cell_angle_alpha 90.00000000 _cell_angle_beta 90.00000000 _cell_angle_gamma 90.00000000 _symmetry_Int_Tables_number 1 _chemical_formula_structural CsCl _chemical_formula_sum 'Cs1 Cl1' _cell_volume 74.08800000 _cell_formula_units_Z 1 loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz 1 'x, y, z' loop_ _atom_type_symbol _atom_type_oxidation_number Cs+ 1.0 Cl+ 1.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 Cs+ Cs0 1 0.000000 0.000000 0.000000 1 Cl+ Cl1 1 0.500000 0.500000 0.500000 1 loop_ _atom_site_moment_label _atom_site_moment_crystalaxis_x _atom_site_moment_crystalaxis_y _atom_site_moment_crystalaxis_z """ s_manual.add_oxidation_state_by_site([1,1]) cw = CifWriter(s_manual, write_magmoms=True) self.assertEqual(cw.__str__(), cw_manual_oxi_string)
class MagOrderingTransformationTest(PymatgenTest): def setUp(self): latt = Lattice.cubic(4.17) species = ["Ni", "O"] coords = [[0, 0, 0], [0.5, 0.5, 0.5]] self.NiO = Structure.from_spacegroup(225, latt, species, coords) latt = Lattice([[2.085, 2.085, 0.0], [0.0, -2.085, -2.085], [-2.085, 2.085, -4.17]]) species = ["Ni", "Ni", "O", "O"] coords = [[0.5, 0, 0.5], [0, 0, 0], [0.25, 0.5, 0.25], [0.75, 0.5, 0.75]] self.NiO_AFM_111 = Structure(latt, species, coords) self.NiO_AFM_111.add_spin_by_site([-5, 5, 0, 0]) latt = Lattice([[2.085, 2.085, 0], [0, 0, -4.17], [-2.085, 2.085, 0]]) species = ["Ni", "Ni", "O", "O"] coords = [[0.5, 0.5, 0.5], [0, 0, 0], [0, 0.5, 0], [0.5, 0, 0.5]] self.NiO_AFM_001 = Structure(latt, species, coords) self.NiO_AFM_001.add_spin_by_site([-5, 5, 0, 0]) parser = CifParser(os.path.join(test_dir, 'Fe3O4.cif')) self.Fe3O4 = parser.get_structures()[0] trans = AutoOxiStateDecorationTransformation() self.Fe3O4_oxi = trans.apply_transformation(self.Fe3O4) parser = CifParser(os.path.join(test_dir, 'Li8Fe2NiCoO8.cif')) self.Li8Fe2NiCoO8 = parser.get_structures()[0] self.Li8Fe2NiCoO8.remove_oxidation_states() warnings.simplefilter("ignore") def tearDown(self): warnings.simplefilter("default") 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.assertArrayAlmostEqual(self.NiO_AFM_111.lattice.parameters, alls[0]["structure"].lattice.parameters) self.assertArrayAlmostEqual(self.NiO_AFM_001.lattice.parameters, alls[1]["structure"].lattice.parameters) def test_ferrimagnetic(self): trans = MagOrderingTransformation({"Fe": 5}, order_parameter=0.75, max_cell_size=1) p = Poscar.from_file(os.path.join(test_dir, 'POSCAR.LiFePO4'), check_for_POTCAR=False) s = p.structure a = SpacegroupAnalyzer(s, 0.1) s = a.get_refined_structure() alls = trans.apply_transformation(s, 10) self.assertEqual(len(alls), 1) def test_as_from_dict(self): trans = MagOrderingTransformation({"Fe": 5}, order_parameter=0.75) d = trans.as_dict() # Check json encodability s = json.dumps(d) trans = MagOrderingTransformation.from_dict(d) self.assertEqual(trans.mag_species_spin, {"Fe": 5}) from pymatgen.analysis.energy_models import SymmetryModel self.assertIsInstance(trans.energy_model, SymmetryModel) def test_zero_spin_case(self): # ensure that zero spin case maintains sites and formula s = self.get_structure('Li2O') trans = MagOrderingTransformation({"Li+": 0.0}, order_parameter=0.5) alls = trans.apply_transformation(s) Li_site = alls.indices_from_symbol('Li')[0] # Ensure s does not have a spin property self.assertFalse('spin' in s.sites[Li_site].specie._properties) # ensure sites are assigned a spin property in alls self.assertTrue('spin' in alls.sites[Li_site].specie._properties) self.assertEqual(alls.sites[Li_site].specie._properties['spin'], 0) def test_advanced_usage(self): # test spin on just one oxidation state magtypes = {"Fe2+": 5} trans = MagOrderingTransformation(magtypes) alls = trans.apply_transformation(self.Fe3O4_oxi) self.assertIsInstance(alls, Structure) self.assertEqual(str(alls[0].specie), "Fe2+,spin=5") self.assertEqual(str(alls[2].specie), "Fe3+") # test multiple order parameters # this should only order on Fe3+ site, but assign spin to both magtypes = {"Fe2+": 5, "Fe3+": 5} order_parameters = [ MagOrderParameterConstraint(1, species_constraints="Fe2+"), MagOrderParameterConstraint(0.5, species_constraints="Fe3+") ] trans = MagOrderingTransformation(magtypes, order_parameter=order_parameters) alls = trans.apply_transformation(self.Fe3O4_oxi) # using this 'sorted' syntax because exact order of sites in first # returned structure varies between machines: we just want to ensure # that the order parameter is accurate self.assertEqual(sorted([str(alls[idx].specie) for idx in range(0, 2)]), sorted(["Fe2+,spin=5", "Fe2+,spin=5"])) self.assertEqual(sorted([str(alls[idx].specie) for idx in range(2, 6)]), sorted(["Fe3+,spin=5", "Fe3+,spin=5", "Fe3+,spin=-5", "Fe3+,spin=-5"])) self.assertEqual(str(alls[0].specie), "Fe2+,spin=5") # this should give same results as previously # but with opposite sign on Fe2+ site magtypes = {"Fe2+": -5, "Fe3+": 5} order_parameters = [ MagOrderParameterConstraint(1, species_constraints="Fe2+"), MagOrderParameterConstraint(0.5, species_constraints="Fe3+") ] trans = MagOrderingTransformation(magtypes, order_parameter=order_parameters) alls = trans.apply_transformation(self.Fe3O4_oxi) self.assertEqual(sorted([str(alls[idx].specie) for idx in range(0, 2)]), sorted(["Fe2+,spin=-5", "Fe2+,spin=-5"])) self.assertEqual(sorted([str(alls[idx].specie) for idx in range(2, 6)]), sorted(["Fe3+,spin=5", "Fe3+,spin=5", "Fe3+,spin=-5", "Fe3+,spin=-5"])) # while this should order on both sites magtypes = {"Fe2+": 5, "Fe3+": 5} order_parameters = [ MagOrderParameterConstraint(0.5, species_constraints="Fe2+"), MagOrderParameterConstraint(0.25, species_constraints="Fe3+") ] trans = MagOrderingTransformation(magtypes, order_parameter=order_parameters) alls = trans.apply_transformation(self.Fe3O4_oxi) self.assertEqual(sorted([str(alls[idx].specie) for idx in range(0, 2)]), sorted(["Fe2+,spin=5", "Fe2+,spin=-5"])) self.assertEqual(sorted([str(alls[idx].specie) for idx in range(2, 6)]), sorted(["Fe3+,spin=5", "Fe3+,spin=-5", "Fe3+,spin=-5", "Fe3+,spin=-5"])) # add coordination numbers to our test case # don't really care what these are for the test case cns = [6, 6, 6, 6, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0] self.Fe3O4.add_site_property('cn', cns) # this should give FM ordering on cn=4 sites, and AFM ordering on cn=6 sites magtypes = {"Fe": 5} order_parameters = [ MagOrderParameterConstraint(0.5, species_constraints="Fe", site_constraint_name="cn", site_constraints=6), MagOrderParameterConstraint(1.0, species_constraints="Fe", site_constraint_name="cn", site_constraints=4) ] trans = MagOrderingTransformation(magtypes, order_parameter=order_parameters) alls = trans.apply_transformation(self.Fe3O4) alls.sort(key=lambda x: x.properties['cn'], reverse=True) self.assertEqual(sorted([str(alls[idx].specie) for idx in range(0, 4)]), sorted(["Fe,spin=-5", "Fe,spin=-5", "Fe,spin=5", "Fe,spin=5"])) self.assertEqual(sorted([str(alls[idx].specie) for idx in range(4, 6)]), sorted(["Fe,spin=5", "Fe,spin=5"])) # now ordering on both sites, equivalent to order_parameter = 0.5 magtypes = {"Fe2+": 5, "Fe3+": 5} order_parameters = [ MagOrderParameterConstraint(0.5, species_constraints="Fe2+"), MagOrderParameterConstraint(0.5, species_constraints="Fe3+") ] trans = MagOrderingTransformation(magtypes, order_parameter=order_parameters) alls = trans.apply_transformation(self.Fe3O4_oxi, return_ranked_list=10) struct = alls[0]["structure"] self.assertEqual(sorted([str(struct[idx].specie) for idx in range(0, 2)]), sorted(["Fe2+,spin=5", "Fe2+,spin=-5"])) self.assertEqual(sorted([str(struct[idx].specie) for idx in range(2, 6)]), sorted(["Fe3+,spin=5", "Fe3+,spin=-5", "Fe3+,spin=-5", "Fe3+,spin=5"])) self.assertEqual(len(alls), 4) # now mixed orderings where neither are equal or 1 magtypes = {"Fe2+": 5, "Fe3+": 5} order_parameters = [ MagOrderParameterConstraint(0.5, species_constraints="Fe2+"), MagOrderParameterConstraint(0.25, species_constraints="Fe3+") ] trans = MagOrderingTransformation(magtypes, order_parameter=order_parameters) alls = trans.apply_transformation(self.Fe3O4_oxi, return_ranked_list=100) struct = alls[0]["structure"] self.assertEqual(sorted([str(struct[idx].specie) for idx in range(0, 2)]), sorted(["Fe2+,spin=5", "Fe2+,spin=-5"])) self.assertEqual(sorted([str(struct[idx].specie) for idx in range(2, 6)]), sorted(["Fe3+,spin=5", "Fe3+,spin=-5", "Fe3+,spin=-5", "Fe3+,spin=-5"])) self.assertEqual(len(alls), 2) # now order on multiple species magtypes = {"Fe2+": 5, "Fe3+": 5} order_parameters = [ MagOrderParameterConstraint(0.5, species_constraints=["Fe2+", "Fe3+"]), ] trans = MagOrderingTransformation(magtypes, order_parameter=order_parameters) alls = trans.apply_transformation(self.Fe3O4_oxi, return_ranked_list=10) struct = alls[0]["structure"] self.assertEqual(sorted([str(struct[idx].specie) for idx in range(0, 2)]), sorted(["Fe2+,spin=5", "Fe2+,spin=-5"])) self.assertEqual(sorted([str(struct[idx].specie) for idx in range(2, 6)]), sorted(["Fe3+,spin=5", "Fe3+,spin=-5", "Fe3+,spin=-5", "Fe3+,spin=5"])) self.assertEqual(len(alls), 6)
class MagOrderingTransformationTest(PymatgenTest): def setUp(self): latt = Lattice.cubic(4.17) species = ["Ni", "O"] coords = [[0, 0, 0], [0.5, 0.5, 0.5]] self.NiO = Structure.from_spacegroup(225, latt, species, coords) latt = Lattice([[2.085, 2.085, 0.0], [0.0, -2.085, -2.085], [-2.085, 2.085, -4.17]]) species = ["Ni", "Ni", "O", "O"] coords = [[0.5, 0, 0.5], [0, 0, 0], [0.25, 0.5, 0.25], [0.75, 0.5, 0.75]] self.NiO_AFM_111 = Structure(latt, species, coords) self.NiO_AFM_111.add_spin_by_site([-5, 5, 0, 0]) latt = Lattice([[2.085, 2.085, 0], [0, 0, -4.17], [-2.085, 2.085, 0]]) species = ["Ni", "Ni", "O", "O"] coords = [[0.5, 0.5, 0.5], [0, 0, 0], [0, 0.5, 0], [0.5, 0, 0.5]] self.NiO_AFM_001 = Structure(latt, species, coords) self.NiO_AFM_001.add_spin_by_site([-5, 5, 0, 0]) parser = CifParser(os.path.join(test_dir, 'Fe3O4.cif')) self.Fe3O4 = parser.get_structures()[0] trans = AutoOxiStateDecorationTransformation() self.Fe3O4_oxi = trans.apply_transformation(self.Fe3O4) parser = CifParser(os.path.join(test_dir, 'Li8Fe2NiCoO8.cif')) self.Li8Fe2NiCoO8 = parser.get_structures()[0] self.Li8Fe2NiCoO8.remove_oxidation_states() warnings.simplefilter("ignore") def tearDown(self): warnings.resetwarnings() 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) def test_ferrimagnetic(self): trans = MagOrderingTransformation({"Fe": 5}, order_parameter=0.75, max_cell_size=1) 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), 2) def test_as_from_dict(self): trans = MagOrderingTransformation({"Fe": 5}, order_parameter=0.75) d = trans.as_dict() # Check json encodability s = json.dumps(d) trans = MagOrderingTransformation.from_dict(d) self.assertEqual(trans.mag_species_spin, {"Fe": 5}) from pymatgen.analysis.energy_models import SymmetryModel self.assertIsInstance(trans.energy_model, SymmetryModel) def test_zero_spin_case(self): # ensure that zero spin case maintains sites and formula s = self.get_structure('Li2O') trans = MagOrderingTransformation({"Li+": 0.0}, order_parameter=0.5) alls = trans.apply_transformation(s) Li_site = alls.indices_from_symbol('Li')[0] # Ensure s does not have a spin property self.assertFalse('spin' in s.sites[Li_site].specie._properties) # ensure sites are assigned a spin property in alls self.assertTrue('spin' in alls.sites[Li_site].specie._properties) self.assertEqual(alls.sites[Li_site].specie._properties['spin'], 0) def test_advanced_usage(self): # test spin on just one oxidation state magtypes = {"Fe2+": 5} trans = MagOrderingTransformation(magtypes) alls = trans.apply_transformation(self.Fe3O4_oxi) self.assertIsInstance(alls, Structure) self.assertEqual(str(alls[0].specie), "Fe2+,spin=5") self.assertEqual(str(alls[2].specie), "Fe3+") # test multiple order parameters # this should only order on Fe3+ site, but assign spin to both magtypes = {"Fe2+": 5, "Fe3+": 5} order_parameters = [ MagOrderParameterConstraint(1, species_constraints="Fe2+"), MagOrderParameterConstraint(0.5, species_constraints="Fe3+") ] trans = MagOrderingTransformation(magtypes, order_parameter=order_parameters) alls = trans.apply_transformation(self.Fe3O4_oxi) # using this 'sorted' syntax because exact order of sites in first # returned structure varies between machines: we just want to ensure # that the order parameter is accurate self.assertEqual(sorted([str(alls[idx].specie) for idx in range(0,2)]), sorted(["Fe2+,spin=5", "Fe2+,spin=5"])) self.assertEqual(sorted([str(alls[idx].specie) for idx in range(2, 6)]), sorted(["Fe3+,spin=5", "Fe3+,spin=5", "Fe3+,spin=-5", "Fe3+,spin=-5"])) self.assertEqual(str(alls[0].specie), "Fe2+,spin=5") # this should give same results as previously # but with opposite sign on Fe2+ site magtypes = {"Fe2+": -5, "Fe3+": 5} order_parameters = [ MagOrderParameterConstraint(1, species_constraints="Fe2+"), MagOrderParameterConstraint(0.5, species_constraints="Fe3+") ] trans = MagOrderingTransformation(magtypes, order_parameter=order_parameters) alls = trans.apply_transformation(self.Fe3O4_oxi) self.assertEqual(sorted([str(alls[idx].specie) for idx in range(0,2)]), sorted(["Fe2+,spin=-5", "Fe2+,spin=-5"])) self.assertEqual(sorted([str(alls[idx].specie) for idx in range(2, 6)]), sorted(["Fe3+,spin=5", "Fe3+,spin=5", "Fe3+,spin=-5", "Fe3+,spin=-5"])) # while this should order on both sites magtypes = {"Fe2+": 5, "Fe3+": 5} order_parameters = [ MagOrderParameterConstraint(0.5, species_constraints="Fe2+"), MagOrderParameterConstraint(0.25, species_constraints="Fe3+") ] trans = MagOrderingTransformation(magtypes, order_parameter=order_parameters) alls = trans.apply_transformation(self.Fe3O4_oxi) self.assertEqual(sorted([str(alls[idx].specie) for idx in range(0,2)]), sorted(["Fe2+,spin=5", "Fe2+,spin=-5"])) self.assertEqual(sorted([str(alls[idx].specie) for idx in range(2, 6)]), sorted(["Fe3+,spin=5", "Fe3+,spin=-5", "Fe3+,spin=-5", "Fe3+,spin=-5"])) # add coordination numbers to our test case # don't really care what these are for the test case cns = [6, 6, 6, 6, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0] self.Fe3O4.add_site_property('cn', cns) # this should give FM ordering on cn=4 sites, and AFM ordering on cn=6 sites magtypes = {"Fe": 5} order_parameters = [ MagOrderParameterConstraint(0.5, species_constraints="Fe", site_constraint_name="cn", site_constraints=6), MagOrderParameterConstraint(1.0, species_constraints="Fe", site_constraint_name="cn", site_constraints=4) ] trans = MagOrderingTransformation(magtypes, order_parameter=order_parameters) alls = trans.apply_transformation(self.Fe3O4) alls.sort(key=lambda x: x.properties['cn'], reverse=True) self.assertEqual(sorted([str(alls[idx].specie) for idx in range(0, 4)]), sorted(["Fe,spin=-5", "Fe,spin=-5", "Fe,spin=5", "Fe,spin=5"])) self.assertEqual(sorted([str(alls[idx].specie) for idx in range(4,6)]), sorted(["Fe,spin=5", "Fe,spin=5"])) # now ordering on both sites, equivalent to order_parameter = 0.5 magtypes = {"Fe2+": 5, "Fe3+": 5} order_parameters = [ MagOrderParameterConstraint(0.5, species_constraints="Fe2+"), MagOrderParameterConstraint(0.5, species_constraints="Fe3+") ] trans = MagOrderingTransformation(magtypes, order_parameter=order_parameters) alls = trans.apply_transformation(self.Fe3O4_oxi, return_ranked_list=10) struct = alls[0]["structure"] self.assertEqual(sorted([str(struct[idx].specie) for idx in range(0,2)]), sorted(["Fe2+,spin=5", "Fe2+,spin=-5"])) self.assertEqual(sorted([str(struct[idx].specie) for idx in range(2, 6)]), sorted(["Fe3+,spin=5", "Fe3+,spin=-5", "Fe3+,spin=-5", "Fe3+,spin=5"])) self.assertEqual(len(alls), 4) # now mixed orderings where neither are equal or 1 magtypes = {"Fe2+": 5, "Fe3+": 5} order_parameters = [ MagOrderParameterConstraint(0.5, species_constraints="Fe2+"), MagOrderParameterConstraint(0.25, species_constraints="Fe3+") ] trans = MagOrderingTransformation(magtypes, order_parameter=order_parameters) alls = trans.apply_transformation(self.Fe3O4_oxi, return_ranked_list=100) struct = alls[0]["structure"] self.assertEqual(sorted([str(struct[idx].specie) for idx in range(0,2)]), sorted(["Fe2+,spin=5", "Fe2+,spin=-5"])) self.assertEqual(sorted([str(struct[idx].specie) for idx in range(2, 6)]), sorted(["Fe3+,spin=5", "Fe3+,spin=-5", "Fe3+,spin=-5", "Fe3+,spin=-5"])) self.assertEqual(len(alls), 2) # now order on multiple species magtypes = {"Fe2+": 5, "Fe3+": 5} order_parameters = [ MagOrderParameterConstraint(0.5, species_constraints=["Fe2+", "Fe3+"]), ] trans = MagOrderingTransformation(magtypes, order_parameter=order_parameters) alls = trans.apply_transformation(self.Fe3O4_oxi, return_ranked_list=10) struct = alls[0]["structure"] self.assertEqual(sorted([str(struct[idx].specie) for idx in range(0,2)]), sorted(["Fe2+,spin=5", "Fe2+,spin=-5"])) self.assertEqual(sorted([str(struct[idx].specie) for idx in range(2, 6)]), sorted(["Fe3+,spin=5", "Fe3+,spin=-5", "Fe3+,spin=-5", "Fe3+,spin=5"])) self.assertEqual(len(alls), 6)