Skip to content

Commit

Permalink
Aims input sets (#3482)
Browse files Browse the repository at this point in the history
* Add aims InputSets

move them from atomate2 to pymatgen as @utf requested

* Move input set and file tests from atomate2 to here

Also adjust the tests for not having all fixtures

* Initial setup to move all input generators to pymatgen

* Add AimsInputGenerator to aims/sets/base

Move default input set generator to pymatgen

* Move Core input sets from atomate2 into pymatgen

* Add bs sets from atomate2

* Correct sets import in core

forgot an io

* Move input generator tests into pymatgen

* BS and GW tests work

* All generator tests now work

* Add input generator refs from atomate2

* See if this fixes the windows path str errror

* This should fix the windows tests

json encoder did not use base string for path

* pre-commit auto-fixes

* Fix ruff error

pre-commit conflict resolved incorrectly

* fix error in species_dir

Somehow this was removed

* fix typo

* remove cwd context manager, use monty instead

* Make requested changes to the test sets

Monkeypatch cahnge env
Actually test check_bands

* Fix Bugs in modifications

1) InputSet remove_parameters error message became more verbose
2) Have to assert True not raise False

* pre-commit auto-fixes

* rename GWSetGenerator(user_parameters->user_params), simplify tests in tests/io/aims/test_sets/test_input_set.py

* del deepcopy method

* Test if `compare_files` in __init__.py works

I think my previous error was in the conftest file and not __init__

* Add test_sets __init__.py

* Create a helper module in tests for common aims test function removal

1) remove tests.__init__.py and similar files in io and io/aims
	this conflicts with a latex package that is a depdency that installs
	a "tests" directory into site-packages
2) creates a helpers and helpers/aims folder for what would be in tests/io/aims/__init__
3) Modify conftest and pytest ini in pyproject.toml to fix this

* Remove AimsInputFile

This class is not really needed

* Bug Fix: AimsControlIn Preamble write time

The content of the preamble should be made upon writing file
not generating content

* Remove uncessary files

* rm tests/helpers/__init__.py, add pymatgen/util/testing/aims.py instead

after moving pymatgen/util/(testing.py -> testing/__init__.py)

* Remove aims_sd_monkeypatch from tests

Make it once in conf tests

* refactor _set_aims_species_dir_env_var fixture

* 1) Remove seperate static_restart tests comp_system
2) Add more diverse docstrings to the testing.aims files

* Specify species_dir for windows tests

---------

Signed-off-by: Thomas Purcell <tpurcell90@users.noreply.github.com>
Co-authored-by: Thomas Purcell <purcellt@arizona.edu>
Co-authored-by: Janosh Riebesell <janosh.riebesell@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
4 people authored Jan 29, 2024
1 parent d677a0a commit b40ce6e
Show file tree
Hide file tree
Showing 60 changed files with 1,668 additions and 74 deletions.
130 changes: 77 additions & 53 deletions pymatgen/io/aims/inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,81 @@ def get_aims_control_parameter_str(self, key: str, value: Any, fmt: str) -> str:
"""
return f"{key:35s}{fmt % value}\n"

def get_content(
self, structure: Structure | Molecule, verbose_header: bool = False, directory: str | Path | None = None
) -> str:
"""Get the content of the file
Args:
structure (Structure or Molecule): The structure to write the input
file for
verbose_header (bool): If True print the input option dictionary
directory: str | Path | None = The directory for the calculation,
Returns:
str: The content of the file for a given structure
"""
parameters = deepcopy(self._parameters)

if directory is None:
directory = ""

lim = "#" + "=" * 79
content = ""

if parameters["xc"] == "LDA":
parameters["xc"] = "pw-lda"

cubes = parameters.pop("cubes", None)

if verbose_header:
content += "# \n# List of parameters used to initialize the calculator:"
for param, val in parameters.items():
s = f"# {param}:{val}\n"
content += s
content += lim + "\n"

assert not ("smearing" in parameters and "occupation_type" in parameters)

for key, value in parameters.items():
if key in ["species_dir", "plus_u"]:
continue
if key == "smearing":
name = parameters["smearing"][0].lower()
if name == "fermi-dirac":
name = "fermi"
width = parameters["smearing"][1]
if name == "methfessel-paxton":
order = parameters["smearing"][2]
order = " %d" % order
else:
order = ""

content += self.get_aims_control_parameter_str("occupation_type", (name, width, order), "%s %f%s")
elif key == "output":
for output_type in value:
content += self.get_aims_control_parameter_str(key, output_type, "%s")
elif key == "vdw_correction_hirshfeld" and value:
content += self.get_aims_control_parameter_str(key, "", "%s")
elif isinstance(value, bool):
content += self.get_aims_control_parameter_str(key, str(value).lower(), ".%s.")
elif isinstance(value, (tuple, list)):
content += self.get_aims_control_parameter_str(key, " ".join([str(x) for x in value]), "%s")
elif isinstance(value, str):
content += self.get_aims_control_parameter_str(key, value, "%s")
else:
content += self.get_aims_control_parameter_str(key, value, "%r")

if cubes:
for cube in cubes:
content += cube.control_block

content += lim + "\n\n"
species_dir = self._parameters.get("species_dir", os.environ.get("AIMS_SPECIES_DIR"))
content += self.get_species_block(structure, species_dir)

return content

def write_file(
self,
structure: Structure | Molecule,
Expand All @@ -507,14 +582,12 @@ def write_file(
if (Path(directory) / "control.in").exists() and not overwrite:
raise ValueError(f"control.in file already in {directory}")

lim = "#" + "=" * 79

if isinstance(structure, Structure) and (
"k_grid" not in self._parameters and "k_grid_density" not in self._parameters
):
raise ValueError("k-grid must be defined for periodic systems")

parameters = deepcopy(self._parameters)
content = self.get_content(structure, verbose_header)

with open(f"{directory}/control.in", mode="w") as file:
file.write(f"#{'=' * 72}\n")
Expand All @@ -523,56 +596,7 @@ def write_file(
file.write(f"# {time.asctime()}\n")
file.write(f"#{'=' * 72}\n")

if parameters["xc"] == "LDA":
parameters["xc"] = "pw-lda"

cubes = parameters.pop("cubes", None)

if verbose_header:
file.write("# \n# List of parameters used to initialize the calculator:")
for param, val in parameters.items():
s = f"# {param}:{val}\n"
file.write(s)
file.write(lim + "\n")

assert not ("smearing" in parameters and "occupation_type" in parameters)

for key, value in parameters.items():
if key in ["species_dir", "plus_u"]:
continue
if key == "smearing":
name = parameters["smearing"][0].lower()
if name == "fermi-dirac":
name = "fermi"
width = parameters["smearing"][1]
if name == "methfessel-paxton":
order = parameters["smearing"][2]
order = " %d" % order
else:
order = ""

file.write(self.get_aims_control_parameter_str("occupation_type", (name, width, order), "%s %f%s"))
elif key == "output":
for output_type in value:
file.write(self.get_aims_control_parameter_str(key, output_type, "%s"))
elif key == "vdw_correction_hirshfeld" and value:
file.write(self.get_aims_control_parameter_str(key, "", "%s"))
elif isinstance(value, bool):
file.write(self.get_aims_control_parameter_str(key, str(value).lower(), ".%s."))
elif isinstance(value, (tuple, list)):
file.write(self.get_aims_control_parameter_str(key, " ".join([str(x) for x in value]), "%s"))
elif isinstance(value, str):
file.write(self.get_aims_control_parameter_str(key, value, "%s"))
else:
file.write(self.get_aims_control_parameter_str(key, value, "%r"))

if cubes:
for cube in cubes:
file.write(cube.control_block)

file.write(lim + "\n\n")
species_dir = self._parameters.get("species_dir", os.environ.get("AIMS_SPECIES_DIR"))
file.write(self.get_species_block(structure, species_dir))
file.write(content)

def get_species_block(self, structure: Structure | Molecule, species_dir: str | Path) -> str:
"""Get the basis set information for a structure
Expand Down
3 changes: 3 additions & 0 deletions pymatgen/io/aims/sets/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from __future__ import annotations

from pymatgen.io.aims.sets.base import AimsInputSet
Loading

0 comments on commit b40ce6e

Please sign in to comment.