Skip to content

Commit

Permalink
Merge branch 'master' into test-sdist-whl-before-release
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielYang59 authored Oct 13, 2024
2 parents 46df4ce + 668f1aa commit 7491c62
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/pymatgen/core/ion.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ def get_reduced_formula_and_factor(
elif formula == "HCOO":
formula = "HCO2"
# oxalate
elif formula == "CO2":
elif formula == "CO2" and self.charge == -2:
formula = "C2O4"
factor /= 2
# diatomic gases
Expand Down
21 changes: 19 additions & 2 deletions src/pymatgen/core/structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@

from pymatgen.util.typing import CompositionLike, MillerIndex, PathLike, PbcLike, SpeciesLike

FileFormats = Literal["cif", "poscar", "cssr", "json", "yaml", "yml", "xsf", "mcsqs", "res", "pwmat", ""]
FileFormats = Literal["cif", "poscar", "cssr", "json", "yaml", "yml", "xsf", "mcsqs", "res", "pwmat", "aims", ""]
StructureSources = Literal["Materials Project", "COD"]


Expand Down Expand Up @@ -2847,7 +2847,8 @@ def to(self, filename: PathLike = "", fmt: FileFormats = "", **kwargs) -> str:
fmt (str): Format to output to. Defaults to JSON unless filename
is provided. If fmt is specifies, it overrides whatever the
filename is. Options include "cif", "poscar", "cssr", "json",
"xsf", "mcsqs", "prismatic", "yaml", "yml", "fleur-inpgen", "pwmat".
"xsf", "mcsqs", "prismatic", "yaml", "yml", "fleur-inpgen", "pwmat",
"aims".
Non-case sensitive.
**kwargs: Kwargs passthru to relevant methods. e.g. This allows
the passing of parameters like symprec to the
Expand Down Expand Up @@ -2915,6 +2916,16 @@ def to(self, filename: PathLike = "", fmt: FileFormats = "", **kwargs) -> str:
with zopen(filename, mode="wt") as file:
file.write(yaml_str)
return yaml_str
elif fmt == "aims" or fnmatch(filename, "geometry.in"):
from pymatgen.io.aims.inputs import AimsGeometryIn

geom_in = AimsGeometryIn.from_structure(self)
if filename:
with zopen(filename, mode="w") as file:
file.write(geom_in.get_header(filename))
file.write(geom_in.content)
file.write("\n")
return geom_in.content
# fleur support implemented in external namespace pkg https://github.com/JuDFTteam/pymatgen-io-fleur
elif fmt == "fleur-inpgen" or fnmatch(filename, "*.in*"):
from pymatgen.io.fleur import FleurInput
Expand Down Expand Up @@ -3021,6 +3032,10 @@ def from_str(
from pymatgen.io.atat import Mcsqs

struct = Mcsqs.structure_from_str(input_string, **kwargs)
elif fmt == "aims":
from pymatgen.io.aims.inputs import AimsGeometryIn

struct = AimsGeometryIn.from_str(input_string).structure
# fleur support implemented in external namespace pkg https://github.com/JuDFTteam/pymatgen-io-fleur
elif fmt == "fleur-inpgen":
from pymatgen.io.fleur import FleurInput
Expand Down Expand Up @@ -3117,6 +3132,8 @@ def from_file(
from pymatgen.io.lmto import LMTOCtrl

return LMTOCtrl.from_file(filename=filename, **kwargs).structure
elif fnmatch(fname, "geometry.in*"):
return cls.from_str(contents, fmt="aims", primitive=primitive, sort=sort, merge_tol=merge_tol, **kwargs)
elif fnmatch(fname, "inp*.xml") or fnmatch(fname, "*.in*") or fnmatch(fname, "inp_*"):
from pymatgen.io.fleur import FleurInput

Expand Down
24 changes: 18 additions & 6 deletions src/pymatgen/io/aims/inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import os
import re
import textwrap
import time
from copy import deepcopy
from dataclasses import dataclass, field
Expand Down Expand Up @@ -183,6 +184,20 @@ def content(self) -> str:
"""Access the contents of the file."""
return self._content

def get_header(self, filename: str) -> str:
"""A header of geometry.in file
Args:
filename (str): A name of the file for the header
"""
return textwrap.dedent(f"""\
#{'=' * 72}
# FHI-aims geometry file: {filename}
# File generated from pymatgen
# {time.asctime()}
#{'=' * 72}
""")

def write_file(self, directory: str | Path | None = None, overwrite: bool = False) -> None:
"""Write the geometry.in file.
Expand All @@ -191,16 +206,13 @@ def write_file(self, directory: str | Path | None = None, overwrite: bool = Fals
overwrite (bool): If True allow to overwrite existing files
"""
directory = directory or Path.cwd()
file_name = Path(directory) / "geometry.in"

if not overwrite and (Path(directory) / "geometry.in").exists():
if not overwrite and file_name.exists():
raise ValueError(f"geometry.in file exists in {directory}")

with open(f"{directory}/geometry.in", mode="w") as file:
file.write(f"#{'=' * 72}\n")
file.write(f"# FHI-aims geometry file: {directory}/geometry.in\n")
file.write("# File generated from pymatgen\n")
file.write(f"# {time.asctime()}\n")
file.write(f"#{'=' * 72}\n")
file.write(self.get_header(file_name.as_posix()))
file.write(self.content)
file.write("\n")

Expand Down
6 changes: 5 additions & 1 deletion tests/core/test_ion.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ def test_charge_from_formula(self):
assert Ion.from_formula("Ca++").charge == 2
assert Ion.from_formula("Ca[++]").charge == 2
assert Ion.from_formula("Ca2+").charge == 1
assert Ion.from_formula("C2O4-2").charge == -2
assert Ion.from_formula("CO2").charge == 0

assert Ion.from_formula("Cl-").charge == -1
assert Ion.from_formula("Cl[-]").charge == -1
Expand Down Expand Up @@ -70,7 +72,9 @@ def test_special_formulas(self):
("CH3COOH", "CH3COOH(aq)"),
("CH3OH", "CH3OH(aq)"),
("H4CO", "CH3OH(aq)"),
("CO2-", "C2O4[-2]"),
("C2O4--", "C2O4[-2]"),
("CO2", "CO2(aq)"),
("CO3--", "CO3[-2]"),
("CH4", "CH4(aq)"),
("NH4+", "NH4[+1]"),
("NH3", "NH3(aq)"),
Expand Down
6 changes: 6 additions & 0 deletions tests/io/aims/test_inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ def test_read_write_si_in(tmp_path: Path):

compare_files(TEST_DIR / "geometry.in.si.ref", f"{tmp_path}/geometry.in")

si.structure.to(tmp_path / "si.in", fmt="aims")
compare_files(TEST_DIR / "geometry.in.si.ref", f"{tmp_path}/si.in")

si_from_file = Structure.from_file(f"{tmp_path}/geometry.in")
assert all(sp.symbol == "Si" for sp in si_from_file.species)

with gzip.open(f"{TEST_DIR}/si_ref.json.gz", mode="rt") as si_ref_json:
si_from_dct = json.load(si_ref_json, cls=MontyDecoder)

Expand Down

0 comments on commit 7491c62

Please sign in to comment.