Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FHI-aims IO Parsers #3435

Merged
merged 35 commits into from
Nov 8, 2023
Merged
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
8c677be
Move FHI-aims io from atomate2 into pymatgen
tpurcell90 Oct 23, 2023
3b152d1
Initial aims input files
tpurcell90 Oct 26, 2023
e3d1daa
Add test for the aims parsers
tpurcell90 Oct 27, 2023
b311ac4
Add tests for AimsOutputs
tpurcell90 Oct 30, 2023
2088fc8
Add aims output refrence files
tpurcell90 Oct 30, 2023
ea95182
Add tests for AimsGeometryIn inputs
tpurcell90 Oct 30, 2023
41ac7bd
Add tests for AimsCube
tpurcell90 Oct 30, 2023
d9e3041
Add tests for aims_control_in
tpurcell90 Oct 30, 2023
9da0f6f
gzip all output files
tpurcell90 Oct 31, 2023
e633e6f
Gzip all refrence files
tpurcell90 Oct 31, 2023
4e390f6
Remove json dict comparision
tpurcell90 Oct 31, 2023
7d85afd
Add full type hinting for inputs.py and convert docstrings
tpurcell90 Nov 1, 2023
168baba
Convert all AimsOutput docstrings to google doc
tpurcell90 Nov 1, 2023
0406a95
Add type hining and google doc strings to parsers
tpurcell90 Nov 2, 2023
0d368cd
Fix tests
tpurcell90 Nov 3, 2023
ff1a7ff
Merge branch 'master' into aims_io
tpurcell90 Nov 5, 2023
ed4e09c
Requested changes to tests
tpurcell90 Nov 7, 2023
7f5c675
Merge branch 'aims_io' of github.com:tpurcell90/pymatgen into aims_io
tpurcell90 Nov 7, 2023
9c8b42c
Update pymatgen/io/aims/inputs.py
tpurcell90 Nov 7, 2023
a5823bb
pre-commit auto-fixes
pre-commit-ci[bot] Nov 7, 2023
6da5e9d
Make more changes requested
tpurcell90 Nov 7, 2023
90968cc
Merge branch 'master' into aims_io
tpurcell90 Nov 7, 2023
bc0b4d6
Rename io.aims.output to io.aims.outputs
tpurcell90 Nov 8, 2023
c82cd43
Add example for FHI-aims io
tpurcell90 Nov 8, 2023
0a36fef
Merge branch 'master' into aims_io
tpurcell90 Nov 8, 2023
3adc5cc
Make corrections suggested by @janosh
tpurcell90 Nov 8, 2023
5f37cff
Merge branch 'aims_io' of github.com:tpurcell90/pymatgen into aims_io
tpurcell90 Nov 8, 2023
7761e4a
add nbstripout to pre-commit hooks apply to FHI-aims-example.ipynb
janosh Nov 8, 2023
d457393
class AimsCube snake_case spin_state
janosh Nov 8, 2023
5c2e354
fix doc str
janosh Nov 8, 2023
ad24261
refactor AimsCube.from_dict
janosh Nov 8, 2023
2756467
fix typo
janosh Nov 8, 2023
b45b71f
fix tests
janosh Nov 8, 2023
1563c82
mv tests/io/aims/(aims_->'')input_files tests/io/aims/(aims_->'')outp…
janosh Nov 8, 2023
89c29a9
Correct refrence json files for aims_outputs
tpurcell90 Nov 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Move FHI-aims io from atomate2 into pymatgen
1) parsers and AimsOuput ojbects moved over
2) All ASE Atoms objects removed in favor of pymatgen structures
3) TO DO: Check name schemes
4) Create an AimsInputs object in the future
tpurcell90 committed Oct 23, 2023
commit 8c677bedd78660418e9b8c3d698c5055c3c4667b
1 change: 1 addition & 0 deletions pymatgen/io/aims/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""IO interface for FHI-aims."""
191 changes: 191 additions & 0 deletions pymatgen/io/aims/aims_output.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
"""A representation of FHI-aims output (based on ASE output parser)."""
from __future__ import annotations

from typing import TYPE_CHECKING, Any

import numpy as np
from atomate2.aims.io.parsers import read_aims_header_info, read_aims_output
from monty.json import MontyDecoder, MSONable

if TYPE_CHECKING:
from collections.abc import Sequence
from pathlib import Path

from emmet.core.math import Matrix3D, Vector3D

from pymatgen.core import Molecule, Structure


class AimsOutput(MSONable):
"""The main output file for FHI-aims."""

def __init__(
self,
results: Sequence[Molecule | Structure],
metadata: dict[str, Any],
structure_summary: dict[str, Any],
):
"""AimsOutput object constructor.

Parameters
----------
results: Sequence[.MSONableAtoms]
A list of all images in an output file
metadata: Dict[str, Any]
The metadata of the executable used to perform the calculation
structure_summary: Dict[str, Any]
The summary of the starting atomic structure
"""
self._results = results
self._metadata = metadata
self._structure_summary = structure_summary

def as_dict(self) -> dict[str, Any]:
"""Create a dict representation of the outputs for MSONable."""
d: dict[str, Any] = {
"@module": self.__class__.__module__,
"@class": self.__class__.__name__,
}

d["results"] = self._results
d["metadata"] = self._metadata
d["structure_summary"] = self._structure_summary
return d

@classmethod
def from_outfile(cls, outfile: str | Path):
"""Construct an AimsOutput from an output file.

Parameters
----------
outfile: str or Path
The aims.out file to parse
"""
metadata, structure_summary = read_aims_header_info(outfile)
results = read_aims_output(outfile, index=slice(0, None))

return cls(results, metadata, structure_summary)

@classmethod
def from_dict(cls, d: dict[str, Any]):
"""Construct an AimsOutput from a dictionary.

Parameters
----------
d: Dict[str, Any]
The dictionary used to create AimsOutput
"""
decoded = {k: MontyDecoder().process_decoded(v) for k, v in d.items() if not k.startswith("@")}
return cls(decoded["results"], decoded["metadata"], decoded["structure_summary"])

def get_results_for_image(self, image_ind: int) -> Structure | Molecule:
"""Get the results dictionary for a particular image or slice of images.

Parameters
----------
image_ind: int
The index of the image to get the results for

Returns
-------
The results for that image
"""
return self._results[image_ind]

@property
def structure_summary(self) -> dict[str, Any]:
"""The summary of the material/molecule that the calculations represent."""
return self._structure_summary

@property
def metadata(self) -> dict[str, Any]:
"""The system metadata."""
return self._metadata

@property
def n_images(self) -> int:
"""The number of images in results."""
return len(self._results)

@property
def initial_structure(self) -> Structure | Molecule:
"""The initial structure for the calculations."""
return self._structure_summary["initial_structure"]

@property
def final_structure(self) -> Structure | Molecule:
"""The final structure for the calculation."""
return self._results[-1]

@property
def structures(self) -> Sequence[Structure | Molecule]:
"""All images in the output file."""
return self._results

@property
def fermi_energy(self) -> float:
"""The Fermi energy for the final structure in the calculation."""
return self.get_results_for_image(-1).properties["fermi_energy"]

@property
def vbm(self) -> float:
"""The HOMO level for the final structure in the calculation."""
return self.get_results_for_image(-1).properties["vbm"]

@property
def cbm(self) -> float:
"""The LUMO level for the final structure in the calculation."""
return self.get_results_for_image(-1).properties["cbm"]

@property
def band_gap(self) -> float:
"""The band gap for the final structure in the calculation."""
return self.get_results_for_image(-1).properties["gap"]

@property
def direct_band_gap(self) -> float:
"""The direct band gap for the final structure in the calculation."""
return self.get_results_for_image(-1).properties["direct_gap"]

@property
def final_energy(self) -> float:
"""The total energy for the final structure in the calculation."""
return self.get_results_for_image(-1).properties["energy"]

@property
def completed(self) -> bool:
"""Did the calculation complete."""
return len(self._results) > 0

@property
def aims_version(self) -> str:
"""The version of FHI-aims used for the calculation."""
return self._metadata["version_number"]

@property
def forces(self) -> Sequence[Vector3D] | None:
"""The forces for the final image of the calculation."""
force_array = self.get_results_for_image(-1).site_properties.get("force", None)
if isinstance(force_array, np.ndarray):
return force_array.tolist()

return force_array

@property
def stress(self) -> Matrix3D:
"""The stress for the final image of the calculation."""
return self.get_results_for_image(-1).properties.get("stress", None)

@property
def stresses(self) -> Sequence[Matrix3D] | None:
"""The atomic virial stresses for the final image of the calculation."""
stresses_array = self.get_results_for_image(-1).site_properties.get("atomic_virial_stress", None)
if isinstance(stresses_array, np.ndarray):
return stresses_array.tolist()
return stresses_array

@property
def all_forces(self) -> list[list[Vector3D]]:
"""The forces for all images in the calculation."""
all_forces_array = [res.site_properties.get("force", None) for res in self._results]
return [af.tolist() if isinstance(af, np.ndarray) else af for af in all_forces_array]
1,071 changes: 1,071 additions & 0 deletions pymatgen/io/aims/parsers.py

Large diffs are not rendered by default.