From fdac209631a36e42de9e39ca0d3052026933bff0 Mon Sep 17 00:00:00 2001 From: matthewkuner Date: Wed, 16 Aug 2023 16:32:17 -0700 Subject: [PATCH 1/5] fix auto kpoints mesh style selection --- pymatgen/io/vasp/inputs.py | 9 +++--- tests/files/POSCAR_bcc | 11 +++++++ tests/files/POSCAR_fcc | 17 +++++++++++ tests/files/POSCAR_hcp | 11 +++++++ tests/io/vasp/test_inputs.py | 58 ++++++++++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 tests/files/POSCAR_bcc create mode 100644 tests/files/POSCAR_fcc create mode 100644 tests/files/POSCAR_hcp diff --git a/pymatgen/io/vasp/inputs.py b/pymatgen/io/vasp/inputs.py index c7025aa5b7c..54e9e415825 100644 --- a/pymatgen/io/vasp/inputs.py +++ b/pymatgen/io/vasp/inputs.py @@ -1192,7 +1192,7 @@ def monkhorst_automatic(kpts: tuple[int, int, int] = (2, 2, 2), shift: Vector3D def automatic_density(structure: Structure, kppa: float, force_gamma: bool = False): """ Returns an automatic Kpoint object based on a structure and a kpoint - density. Uses Gamma centered meshes for hexagonal cells and + density. Uses Gamma centered meshes for hexagonal cells and face-centered cells, Monkhorst-Pack grids otherwise. Algorithm: @@ -1219,9 +1219,9 @@ def automatic_density(structure: Structure, kppa: float, force_gamma: bool = Fal num_div = [int(math.floor(max(mult / length, 1))) for length in lengths] is_hexagonal = latt.is_hexagonal() - + is_face_centered = structure.get_space_group_info()[0][0] == "F" has_odd = any(i % 2 == 1 for i in num_div) - if has_odd or is_hexagonal or force_gamma: + if has_odd or is_hexagonal or is_face_centered or force_gamma: style = Kpoints.supported_modes.Gamma else: style = Kpoints.supported_modes.Monkhorst @@ -1310,8 +1310,9 @@ def automatic_density_by_lengths( abc = lattice.abc num_div = [np.ceil(ld / abc[idx]) for idx, ld in enumerate(length_densities)] is_hexagonal = lattice.is_hexagonal() + is_face_centered = structure.get_space_group_info()[0][0] == "F" has_odd = any(idx % 2 == 1 for idx in num_div) - if has_odd or is_hexagonal or force_gamma: + if has_odd or is_hexagonal or is_face_centered or force_gamma: style = Kpoints.supported_modes.Gamma else: style = Kpoints.supported_modes.Monkhorst diff --git a/tests/files/POSCAR_bcc b/tests/files/POSCAR_bcc new file mode 100644 index 00000000000..4426b2ea0b0 --- /dev/null +++ b/tests/files/POSCAR_bcc @@ -0,0 +1,11 @@ +H2 +1.0 + 1.0000000000000000 0.0000000000000000 0.0000000000000000 + 0.0000000000000000 1.0000000000000000 0.0000000000000000 + 0.0000000000000000 0.0000000000000000 1.0000000000000000 +H +2 +direct + 0.0000000000000000 0.0000000000000000 0.0000000000000000 H + 0.5000000000000000 0.5000000000000000 0.5000000000000000 H + diff --git a/tests/files/POSCAR_fcc b/tests/files/POSCAR_fcc new file mode 100644 index 00000000000..6eb675c42ec --- /dev/null +++ b/tests/files/POSCAR_fcc @@ -0,0 +1,17 @@ +H8 +1.0 + 0.0000000000000000 1.0000000000000000 1.0000000000000000 + 1.0000000000000000 0.0000000000000000 1.0000000000000000 + 1.0000000000000000 1.0000000000000000 0.0000000000000000 +H +8 +direct + 0.0000000000000000 0.0000000000000000 0.0000000000000000 H + 0.0000000000000000 0.0000000000000000 0.5000000000000000 H + 0.0000000000000000 0.5000000000000000 0.0000000000000000 H + 0.0000000000000000 0.5000000000000000 0.5000000000000000 H + 0.5000000000000000 0.0000000000000000 0.0000000000000000 H + 0.5000000000000000 0.0000000000000000 0.5000000000000000 H + 0.5000000000000000 0.5000000000000000 0.0000000000000000 H + 0.5000000000000000 0.5000000000000000 0.5000000000000000 H + diff --git a/tests/files/POSCAR_hcp b/tests/files/POSCAR_hcp new file mode 100644 index 00000000000..13306c18126 --- /dev/null +++ b/tests/files/POSCAR_hcp @@ -0,0 +1,11 @@ +H2 +1.0 + 0.5000000000000000 -0.8660254037844390 0.0000000000000000 + 0.5000000000000000 0.8660254037844390 0.0000000000000000 + 0.0000000000000000 0.0000000000000000 1.6329931618554521 +H +2 +direct + 0.0000000000000000 0.0000000000000000 0.0000000000000000 H + 0.3333333333333330 -0.3333333333333330 0.5000000000000000 H + diff --git a/tests/io/vasp/test_inputs.py b/tests/io/vasp/test_inputs.py index 5375e0c1073..b9bcb24d3b7 100644 --- a/tests/io/vasp/test_inputs.py +++ b/tests/io/vasp/test_inputs.py @@ -880,6 +880,64 @@ def test_automatic_density_by_lengths(self): assert kpoints.style == expected_style + def test_automatic_monkhorst_vs_gamma_style_selection(self): + # bcc structures should allow *both* Monkhorst and Gamma. + filepath = f"{PymatgenTest.TEST_FILES_DIR}/POSCAR_bcc" + bcc_struct = Structure.from_file(filepath) + + filepath = f"{PymatgenTest.TEST_FILES_DIR}/POSCAR_fcc" + fcc_struct = Structure.from_file(filepath) + + filepath = f"{PymatgenTest.TEST_FILES_DIR}/POSCAR_hcp" + hcp_struct = Structure.from_file(filepath) + + ### Kpoints.automatic_density + # bcc structures should allow both Monkhorst and Gamma + kpoints = Kpoints.automatic_density(bcc_struct, 500) + assert kpoints.style == Kpoints.supported_modes.Monkhorst + kpoints = Kpoints.automatic_density(bcc_struct, 600) + assert kpoints.style == Kpoints.supported_modes.Monkhorst + kpoints = Kpoints.automatic_density(bcc_struct, 700) + assert kpoints.style == Kpoints.supported_modes.Gamma + + # face-centered structures should allow only Gamma + kpoints = Kpoints.automatic_density(fcc_struct, 500) + assert kpoints.style == Kpoints.supported_modes.Gamma + kpoints = Kpoints.automatic_density(fcc_struct, 600) + assert kpoints.style == Kpoints.supported_modes.Gamma + kpoints = Kpoints.automatic_density(fcc_struct, 700) + assert kpoints.style == Kpoints.supported_modes.Gamma + + # hcp structures should allow only Gamma + kpoints = Kpoints.automatic_density(hcp_struct, 500) + assert kpoints.style == Kpoints.supported_modes.Gamma + kpoints = Kpoints.automatic_density(hcp_struct, 600) + assert kpoints.style == Kpoints.supported_modes.Gamma + kpoints = Kpoints.automatic_density(hcp_struct, 700) + assert kpoints.style == Kpoints.supported_modes.Gamma + + ### Kpoints.automatic_density_by_lengths + # bcc structures should allow both Monkhorst and Gamma + kpoints = Kpoints.automatic_density_by_lengths(bcc_struct, [50,50,50]) + assert kpoints.style == Kpoints.supported_modes.Monkhorst + kpoints = Kpoints.automatic_density_by_lengths(bcc_struct, [53,53,53]) + assert kpoints.style == Kpoints.supported_modes.Gamma + kpoints = Kpoints.automatic_density_by_lengths(bcc_struct, [56,56,56]) + assert kpoints.style == Kpoints.supported_modes.Monkhorst + + # Overkill test to make sure these methods never set the style to + # anything except for Gamma + for length_density in range(1,50): + # face-centered structures should allow only Gamma + kpoints = Kpoints.automatic_density_by_lengths( + fcc_struct, [length_density,length_density,length_density]) + assert kpoints.style == Kpoints.supported_modes.Gamma + + # hcp structures should allow only Gamma + kpoints = Kpoints.automatic_density_by_lengths( + hcp_struct, [length_density,length_density,length_density]) + assert kpoints.style == Kpoints.supported_modes.Gamma + class TestPotcarSingle: _multiprocess_shared_ = True From 891cc9046ec19466cc085f2f49d74180f1804418 Mon Sep 17 00:00:00 2001 From: matthewkuner Date: Wed, 16 Aug 2023 16:41:04 -0700 Subject: [PATCH 2/5] linting --- tests/io/vasp/test_inputs.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/tests/io/vasp/test_inputs.py b/tests/io/vasp/test_inputs.py index b9bcb24d3b7..54f1c968357 100644 --- a/tests/io/vasp/test_inputs.py +++ b/tests/io/vasp/test_inputs.py @@ -882,13 +882,13 @@ def test_automatic_density_by_lengths(self): def test_automatic_monkhorst_vs_gamma_style_selection(self): # bcc structures should allow *both* Monkhorst and Gamma. - filepath = f"{PymatgenTest.TEST_FILES_DIR}/POSCAR_bcc" + filepath = f"{TEST_FILES_DIR}/POSCAR_bcc" bcc_struct = Structure.from_file(filepath) - filepath = f"{PymatgenTest.TEST_FILES_DIR}/POSCAR_fcc" + filepath = f"{TEST_FILES_DIR}/POSCAR_fcc" fcc_struct = Structure.from_file(filepath) - filepath = f"{PymatgenTest.TEST_FILES_DIR}/POSCAR_hcp" + filepath = f"{TEST_FILES_DIR}/POSCAR_hcp" hcp_struct = Structure.from_file(filepath) ### Kpoints.automatic_density @@ -918,24 +918,22 @@ def test_automatic_monkhorst_vs_gamma_style_selection(self): ### Kpoints.automatic_density_by_lengths # bcc structures should allow both Monkhorst and Gamma - kpoints = Kpoints.automatic_density_by_lengths(bcc_struct, [50,50,50]) + kpoints = Kpoints.automatic_density_by_lengths(bcc_struct, [50, 50, 50]) assert kpoints.style == Kpoints.supported_modes.Monkhorst - kpoints = Kpoints.automatic_density_by_lengths(bcc_struct, [53,53,53]) + kpoints = Kpoints.automatic_density_by_lengths(bcc_struct, [53, 53, 53]) assert kpoints.style == Kpoints.supported_modes.Gamma - kpoints = Kpoints.automatic_density_by_lengths(bcc_struct, [56,56,56]) + kpoints = Kpoints.automatic_density_by_lengths(bcc_struct, [56, 56, 56]) assert kpoints.style == Kpoints.supported_modes.Monkhorst - # Overkill test to make sure these methods never set the style to + # Overkill test to make sure these methods never set the style to # anything except for Gamma - for length_density in range(1,50): + for length_density in range(1, 50): # face-centered structures should allow only Gamma - kpoints = Kpoints.automatic_density_by_lengths( - fcc_struct, [length_density,length_density,length_density]) + kpoints = Kpoints.automatic_density_by_lengths(fcc_struct, [length_density, length_density, length_density]) assert kpoints.style == Kpoints.supported_modes.Gamma # hcp structures should allow only Gamma - kpoints = Kpoints.automatic_density_by_lengths( - hcp_struct, [length_density,length_density,length_density]) + kpoints = Kpoints.automatic_density_by_lengths(hcp_struct, [length_density, length_density, length_density]) assert kpoints.style == Kpoints.supported_modes.Gamma From c335e43b5f1454786dcbfcdf20b47fd677132665 Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Thu, 17 Aug 2023 07:15:55 -0700 Subject: [PATCH 3/5] fix TypeError: unhashable type: 'list' from magmoms being tuple[list[float]] > self._space_group_data = _get_symmetry_dataset(self._cell, symprec, angle_tolerance) --- pymatgen/symmetry/analyzer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymatgen/symmetry/analyzer.py b/pymatgen/symmetry/analyzer.py index 581875458fa..0a8fa2da94a 100644 --- a/pymatgen/symmetry/analyzer.py +++ b/pymatgen/symmetry/analyzer.py @@ -105,7 +105,7 @@ def __init__(self, structure: Structure, symprec: float | None = 0.01, angle_tol tuple(map(tuple, structure.lattice.matrix.tolist())), tuple(map(tuple, structure.frac_coords.tolist())), tuple(zs), - tuple(magmoms), + tuple(map(tuple, magmoms)), ) else: # if no magmoms given do not add to cell self._cell = ( From 694436d25d49e8d95c1269ac4376e3c7b30a624d Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Thu, 17 Aug 2023 07:26:29 -0700 Subject: [PATCH 4/5] clean up tests --- tests/io/vasp/test_inputs.py | 76 ++++++++++++------------------------ 1 file changed, 24 insertions(+), 52 deletions(-) diff --git a/tests/io/vasp/test_inputs.py b/tests/io/vasp/test_inputs.py index 54f1c968357..18dc23ac27d 100644 --- a/tests/io/vasp/test_inputs.py +++ b/tests/io/vasp/test_inputs.py @@ -881,60 +881,32 @@ def test_automatic_density_by_lengths(self): assert kpoints.style == expected_style def test_automatic_monkhorst_vs_gamma_style_selection(self): - # bcc structures should allow *both* Monkhorst and Gamma. - filepath = f"{TEST_FILES_DIR}/POSCAR_bcc" - bcc_struct = Structure.from_file(filepath) + structs = {key: Structure.from_file(f"{TEST_FILES_DIR}/POSCAR_{key}") for key in ("bcc", "fcc", "hcp")} - filepath = f"{TEST_FILES_DIR}/POSCAR_fcc" - fcc_struct = Structure.from_file(filepath) - - filepath = f"{TEST_FILES_DIR}/POSCAR_hcp" - hcp_struct = Structure.from_file(filepath) - - ### Kpoints.automatic_density - # bcc structures should allow both Monkhorst and Gamma - kpoints = Kpoints.automatic_density(bcc_struct, 500) - assert kpoints.style == Kpoints.supported_modes.Monkhorst - kpoints = Kpoints.automatic_density(bcc_struct, 600) - assert kpoints.style == Kpoints.supported_modes.Monkhorst - kpoints = Kpoints.automatic_density(bcc_struct, 700) - assert kpoints.style == Kpoints.supported_modes.Gamma - - # face-centered structures should allow only Gamma - kpoints = Kpoints.automatic_density(fcc_struct, 500) - assert kpoints.style == Kpoints.supported_modes.Gamma - kpoints = Kpoints.automatic_density(fcc_struct, 600) - assert kpoints.style == Kpoints.supported_modes.Gamma - kpoints = Kpoints.automatic_density(fcc_struct, 700) - assert kpoints.style == Kpoints.supported_modes.Gamma - - # hcp structures should allow only Gamma - kpoints = Kpoints.automatic_density(hcp_struct, 500) - assert kpoints.style == Kpoints.supported_modes.Gamma - kpoints = Kpoints.automatic_density(hcp_struct, 600) - assert kpoints.style == Kpoints.supported_modes.Gamma - kpoints = Kpoints.automatic_density(hcp_struct, 700) - assert kpoints.style == Kpoints.supported_modes.Gamma - - ### Kpoints.automatic_density_by_lengths # bcc structures should allow both Monkhorst and Gamma - kpoints = Kpoints.automatic_density_by_lengths(bcc_struct, [50, 50, 50]) - assert kpoints.style == Kpoints.supported_modes.Monkhorst - kpoints = Kpoints.automatic_density_by_lengths(bcc_struct, [53, 53, 53]) - assert kpoints.style == Kpoints.supported_modes.Gamma - kpoints = Kpoints.automatic_density_by_lengths(bcc_struct, [56, 56, 56]) - assert kpoints.style == Kpoints.supported_modes.Monkhorst - - # Overkill test to make sure these methods never set the style to - # anything except for Gamma - for length_density in range(1, 50): - # face-centered structures should allow only Gamma - kpoints = Kpoints.automatic_density_by_lengths(fcc_struct, [length_density, length_density, length_density]) - assert kpoints.style == Kpoints.supported_modes.Gamma - - # hcp structures should allow only Gamma - kpoints = Kpoints.automatic_density_by_lengths(hcp_struct, [length_density, length_density, length_density]) - assert kpoints.style == Kpoints.supported_modes.Gamma + for struct_type, struct in structs.items(): + for density in (500, 600, 700): + kpoints = Kpoints.automatic_density(struct, density) + if struct_type == "bcc" and density in (500, 600): + assert kpoints.style == Kpoints.supported_modes.Monkhorst + else: + assert kpoints.style == Kpoints.supported_modes.Gamma + + # Kpoints.automatic_density_by_lengths + for struct_type, struct in structs.items(): + for lengths in [50, 50, 50], [53, 53, 53], [56, 56, 56]: + kpoints = Kpoints.automatic_density_by_lengths(struct, lengths) + if struct_type == "bcc" and all(length % 2 == 0 for length in lengths): + assert kpoints.style == Kpoints.supported_modes.Monkhorst + else: + assert kpoints.style == Kpoints.supported_modes.Gamma + + # Overkill test to make sure these methods always set the style to Gamma + for len_density in range(1, 50): + for struct_type, struct in structs.items(): + if struct_type != "bcc": + kpoints = Kpoints.automatic_density_by_lengths(struct, [len_density] * 3) + assert kpoints.style == Kpoints.supported_modes.Gamma class TestPotcarSingle: From 646b3be6ee372944a3926a4a504ee690eee0ff81 Mon Sep 17 00:00:00 2001 From: Janosh Riebesell Date: Thu, 17 Aug 2023 12:42:53 -0700 Subject: [PATCH 5/5] fix TypeError: 'float' object is not iterable if len(magmoms) > 0: self._cell: tuple[Any, ...] = ( tuple(map(tuple, structure.lattice.matrix.tolist())), tuple(map(tuple, structure.frac_coords.tolist())), tuple(zs), > tuple(map(tuple, magmoms)), ) --- .../analysis/chemenv/utils/scripts_utils.py | 4 +-- pymatgen/cli/pmg_query.py | 36 +++++++++---------- pymatgen/symmetry/analyzer.py | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pymatgen/analysis/chemenv/utils/scripts_utils.py b/pymatgen/analysis/chemenv/utils/scripts_utils.py index 20fb3e8b3f6..0e8d8e5f4df 100644 --- a/pymatgen/analysis/chemenv/utils/scripts_utils.py +++ b/pymatgen/analysis/chemenv/utils/scripts_utils.py @@ -245,8 +245,8 @@ def compute_environments(chemenv_configuration): input_source = input('Enter materials project id (e.g. "mp-1902") : ') from pymatgen.ext.matproj import MPRester - mpr = MPRester() - structure = mpr.get_structure_by_material_id(input_source) + with MPRester() as mpr: + structure = mpr.get_structure_by_material_id(input_source) lgf.setup_structure(structure) print(f"Computing environments for {structure.composition.reduced_formula} ... ") se = lgf.compute_structure_environments(maximum_distance_factor=max_dist_factor) diff --git a/pymatgen/cli/pmg_query.py b/pymatgen/cli/pmg_query.py index dda89f88e69..b71b216db3c 100644 --- a/pymatgen/cli/pmg_query.py +++ b/pymatgen/cli/pmg_query.py @@ -21,44 +21,44 @@ def do_query(args): """ from pymatgen.ext.matproj import MPRester - m = MPRester() + mpr = MPRester() try: criteria = json.loads(args.criteria) except json.decoder.JSONDecodeError: criteria = args.criteria if args.structure: count = 0 - for d in m.query(criteria, properties=["structure", "task_id"]): - struct = d["structure"] + for dct in mpr.query(criteria, properties=["structure", "task_id"]): + struct = dct["structure"] formula = re.sub(r"\s+", "", struct.formula) if args.structure == "poscar": - fname = f"POSCAR.{d['task_id']}_{formula}" + fname = f"POSCAR.{dct['task_id']}_{formula}" else: - fname = f"{d['task_id']}-{formula}.{args.structure}" + fname = f"{dct['task_id']}-{formula}.{args.structure}" struct.to(filename=fname) count += 1 print(f"{count} structures written!") elif args.entries: - entries = m.get_entries(criteria) + entries = mpr.get_entries(criteria) dumpfn(entries, args.entries) print(f"{len(entries)} entries written to {args.entries}!") else: props = ["e_above_hull", "spacegroup"] props += args.data - entries = m.get_entries(criteria, property_data=props) - t = [] + entries = mpr.get_entries(criteria, property_data=props) + table = [] headers = ["mp-id", "Formula", "Spacegroup", "E/atom (eV)", "E above hull (eV)", *args.data] - for e in entries: + for entry in entries: row = [ - e.entry_id, - e.composition.reduced_formula, - e.data["spacegroup"]["symbol"], - e.energy_per_atom, - e.data["e_above_hull"], + entry.entry_id, + entry.composition.reduced_formula, + entry.data["spacegroup"]["symbol"], + entry.energy_per_atom, + entry.data["e_above_hull"], ] - row += [e.data[s] for s in args.data] + row += [entry.data[s] for s in args.data] - t.append(row) + table.append(row) - t = sorted(t, key=lambda x: x[headers.index("E above hull (eV)")]) - print(tabulate(t, headers=headers, tablefmt="pipe", floatfmt=".3f")) + table = sorted(table, key=lambda x: x[headers.index("E above hull (eV)")]) + print(tabulate(table, headers=headers, tablefmt="pipe", floatfmt=".3f")) diff --git a/pymatgen/symmetry/analyzer.py b/pymatgen/symmetry/analyzer.py index 0a8fa2da94a..fc98f6b6e00 100644 --- a/pymatgen/symmetry/analyzer.py +++ b/pymatgen/symmetry/analyzer.py @@ -105,7 +105,7 @@ def __init__(self, structure: Structure, symprec: float | None = 0.01, angle_tol tuple(map(tuple, structure.lattice.matrix.tolist())), tuple(map(tuple, structure.frac_coords.tolist())), tuple(zs), - tuple(map(tuple, magmoms)), + tuple(map(tuple, magmoms) if isinstance(magmoms[0], Sequence) else magmoms), ) else: # if no magmoms given do not add to cell self._cell = (