AKFReader¶
The AKFReader Python class provides a convenient way to read annotated data from the binary KF files generated by AMS.
Below is an example demonstrating some of the AKFReader class’s functionality.
#!/usr/bin/env amspython
from scm.akfreader import AKFReader
# Load a kf file.
akf = AKFReader("test.results/dftb.rkf")
# Print a summary of the content in the kf file:
print(akf.table_of_content())
# Also print comments and extra info for all variables
print(akf.table_of_content(verbose=True))
# Read a specific variable from file.
coordinates = akf.read("Molecule%Coords")
print("Coordinates:")
print(coordinates)
# Coordinates:
# [[-1.65367945e+00 4.59827802e+00 -9.59515212e-09]
# ...
# [-2.21256221e+00 5.05007997e+00 -1.93285786e+00]]
# Retrieve the description, units, and additional information for a variable:
description_dict = akf.description("Molecule%Coords")
print("'Molecule%Coords' description:")
print(description_dict)
# 'Molecule%Coords' description:
# {'_type': 'float_array',
# '_shape': [3, 'nAtoms'],
# '_comment': 'Coordinates of the nuclei (x,y,z)',
# '_unit': 'bohr'}
# Read another variable, and do a unit conversion:
energy_in_eV = akf.read("AMSResults%Energy", units="eV")
print(f"Energy: {energy_in_eV} [eV]")
# Read all variables matching the pattern:
history_energies = akf.read("History%Energy(#)")
print(history_energies)
# [('History%Energy(1)', -5.758015498298242),
# ('History%Energy(2)', -5.765039556660788),
# ('History%Energy(3)', -5.766261662994689),
# ('History%Energy(4)', -5.766288141072665)]
Note
The KFFile Python class can also be used to read KF files. Key differences between the AKFReader and the KFFile:
The
AKFReadercan provide extra information about the content of the KF files: it can give descriptions of sections, variables, units, and automatically reshapes matrices to the proper size/shape.The
KFFilecan also be used to write KF files (while theAKFReadercan only read).
See also
A command-line utility $AMSBIN/akf (described here) offers an alternative way of using the AKFReader tool.
See also
The list of possible variables for the various kf files can be found in the respective user manuals: ams.rkf, adf.rkf, band.rkf, dftb.rkf
API documentation:
- class AKFReader(path: str | PathLike[str] | KFFile, kf_def_path=None, strict=False, verbose=False)¶
A python class for reading AMS binary KF files.
- Parameters:
path (str, os.PathLike or KFFile): the KF file (.rkf) to read, either its path, or an already open
scm.base.KFFile, which the reader then uses as it is. (The other optional constructor parameters are expert options and are best left untouched.)
Example:
from scm.akfreader import AKFReader akf = AKFReader("test.results/dftb.rkf") # <- path to ams .rkf result file print(akf.table_of_content()) coordinates = akf.read("Molecule%Coords") energy = akf.read("AMSResults%Energy", units="eV")
- read(name: str, units=None) Any¶
Read and return the value of a variable on file.
- Parameters:
name (str): The name of the variable to read. This should be of the form “SectionName%VariableName”, so for example akf.read(“Molecule%Coords”) means “read the variable ‘Coords’ from Section ‘Molecule’)
units (str): the desired output units. See the :Units: class for more info on avaiable units.
- Returns:
The content of the variable. The return type depends on the variable you are reading. So, if the variable is an integer, and int will be return. If it’s an array, a numpy array will be returned.
Example:
>>> energy = akf.read("AMSResults%Energy") >>> energy_in_eV = akf.read("AMSResults%Energy", units="eV")
Note: in case the variable is a “pattern” (i.e. the variable name contains “#” or “*” characters, the result will be a list of tuples of all variables matching the pattern. E.g.: ‘foo(#)’ will return [(‘foo(1)’, value1), (‘foo(2)’, value2)]
- find(name: str) list¶
Given the name of a variable with patterns, return the list of actual variables that match the query.
E.g. if name=’History%Energy(#)’, this might return: [‘History%Energy(1)’,’History%Energy(2)’]
- table_of_content(verbose=False) str¶
Returns the table of content of the KF file (i.e. the list of all sections and variables on file) in text format.
- Parameters:
verbose (bool): if verbose is True, the full description of all variables will be included
Example:
>>> print(akf.table_of_content()) Content for KF file: /test/dftb.rkf == AMSResults == - AMSResults%Energy - AMSResults%Gradients - AMSResults%DipoleMoment ... >>> print(akf.table_of_content(verbose=True)) Content for KF file: /test/dftb.rkf == AMSResults == comment : Generic results of the DFTB evaluation. type : section - AMSResults%Energy comment : The energy computed by the engine. type : float unit : hartree - AMSResults%Gradients comment : The nuclear gradients. shape : [3, 'Molecule%nAtoms'] type : float_array unit : hartree/bohr - AMSResults%DipoleMoment comment : Dipole moment vector (x,y,z) shape : [3] type : float_array unit : e*bohr ...
- variables(include_hidden=False) List[str]¶
Returns the list of all variables on the KF file (in the form “section%variable”).
Example:
>>> all_variables = akf.variables() >>> print(all_variables) ['AMSResults%Charges', 'AMSResults%DipoleMoment', ... ... 'Orbitals%Energies(#)' 'Orbitals%Occupations(#)']
- sections() List[str]¶
Returns the list of all sections on the KF file.
Example:
>>> print(akf.sections()) ['General', 'AMSResults', 'Molecule', 'Orbitals', ...]
- variables_in_section(section: str) List[str]¶
Returns the list of all variables in the specified section.
Example:
>>> print(akf.variables_in_section("Molecule")) ['Molecule%AtomMasses', 'Molecule%Coords', 'Molecule%AtomicNumbers', ...] >>> for v in akf.variables_in_section("Molecule"): >>> print(f"{v}: {akf.read(v)}")
- __contains__(name: str)¶
Whether or not ‘name’ is present in the KF file. This can either be a section (e.g. “Molecule”) or a variable (e.g. “Molecule%Coords”) Example:
if "Molecule%Coords" in akf: coords = akf.read("Molecule%Coords") else: print("Variable 'Molecule%Coords' not present of file") print("Is the 'Molecule' section present? ", "Molecule" in akf)
- description(name: str) Dict[str, Any]¶
Return the description (meta-data) of the variable as a dictionary.
- Parameters:
name (str): The name of the variable (this should be in the form “Section%Variable”)
- Returns:
dictionary containing the available meta-data for the entry. Note that not meta-data entries are defined for all variables. For example, if a variable does not have a unit, the “_unit” key will not be present in the resulting dictionary
Example:
>>> d = akf.description("Molecule%Coords") >>> print(type(d)) <class 'dict'> >>> print(d) {'_type': 'float_array', '_shape': [3, 'nAtoms'], '_comment': 'Coordinates of the nuclei (x,y,z)', '_unit': 'bohr'}
- str_description(name: str) str¶
Return the description of the variable as a string.
Example:
>>> print(akf.str_description("Molecule%Coords")) comment : Coordinates of the nuclei (x,y,z) shape : [3, 'nAtoms'] type : float_array unit : bohr
- units(name: str) str | None¶
Return the unit of measurement of the variable if specified, otherwise returns None.
- read_int(name: str) int¶
Read a single integer, e.g.
akf.read_int("Molecule%nAtoms").Raises a
KeyErrorif the variable is not on the file, and anAKFTypeErrorif it is not a single integer.
- read_real(name: str, units: str | None = None) float¶
Read a single real number, e.g.
akf.read_real("AMSResults%Energy", units="eV").unitsconverts the value from the units in its KF definition. Raises aKeyErrorif the variable is not on the file, and anAKFTypeErrorif it is not a single real number.
- read_logical(name: str) bool¶
Read a single logical, e.g.
akf.read_logical("NEB%climbing").Raises a
KeyErrorif the variable is not on the file, and anAKFTypeErrorif it is not a single logical.
- read_string(name: str) str¶
Read a single string, e.g.
akf.read_string("General%program").Raises a
KeyErrorif the variable is not on the file, and anAKFTypeErrorif it is not a single string.
- read_ints(name: str, *, ndim: Literal[1] = 1) np.ndarray[Tuple[int], np.dtype[np.int32]]¶
- read_ints(name: str, *, ndim: Literal[2]) np.ndarray[Tuple[int, int], np.dtype[np.int32]]
- read_ints(name: str, *, ndim: Literal[3]) np.ndarray[Tuple[int, int, int], np.dtype[np.int32]]
- read_ints(name: str, *, ndim: Literal[4]) np.ndarray[Tuple[int, int, int, int], np.dtype[np.int32]]
Read an array of integers, as a numpy array of
int32, the type in which KF files store them.The array has the shape in its KF definition, which must have
ndimdimensions. Variables without a shape in their definition are one-dimensional. Raises aKeyErrorif the variable is not on the file, and anAKFTypeErrorif it is not an array of integers withndimdimensions.Example:
akf.read_ints("Molecule%AtomicNumbers")
- read_reals(name: str, *, ndim: Literal[1] = 1, units: str | None = None) np.ndarray[Tuple[int], np.dtype[np.float64]]¶
- read_reals(name: str, *, ndim: Literal[2], units: str | None = None) np.ndarray[Tuple[int, int], np.dtype[np.float64]]
- read_reals(name: str, *, ndim: Literal[3], units: str | None = None) np.ndarray[Tuple[int, int, int], np.dtype[np.float64]]
- read_reals(name: str, *, ndim: Literal[4], units: str | None = None) np.ndarray[Tuple[int, int, int, int], np.dtype[np.float64]]
Read an array of real numbers, as a numpy array of
float64.The array has the shape in its KF definition, which must have
ndimdimensions. Variables without a shape in their definition are one-dimensional.unitsconverts the values from the units in the KF definition. Raises aKeyErrorif the variable is not on the file, and anAKFTypeErrorif it is not an array of real numbers withndimdimensions.Example:
akf.read_reals("Molecule%Coords", ndim=2, units="angstrom"), an nAtoms x 3 array
- read_logicals(name: str, *, ndim: Literal[1] = 1) np.ndarray[Tuple[int], np.dtype[np.bool_]]¶
- read_logicals(name: str, *, ndim: Literal[2]) np.ndarray[Tuple[int, int], np.dtype[np.bool_]]
- read_logicals(name: str, *, ndim: Literal[3]) np.ndarray[Tuple[int, int, int], np.dtype[np.bool_]]
- read_logicals(name: str, *, ndim: Literal[4]) np.ndarray[Tuple[int, int, int, int], np.dtype[np.bool_]]
Read an array of logicals, as a numpy array of
bool.The array has the shape in its KF definition, which must have
ndimdimensions. Variables without a shape in their definition are one-dimensional. Raises aKeyErrorif the variable is not on the file, and anAKFTypeErrorif it is not an array of logicals withndimdimensions.Example:
akf.read_logicals("NEB%fixed")
- read_strings(name: str) List[str]¶
Read an array of strings as a list, e.g.
akf.read_strings("Vibrations%IrReps").Raises a
KeyErrorif the variable is not on the file, and anAKFTypeErrorif it is not an array of strings.
Typed reading methods:
The generic read method returns whatever a variable holds, and can also read all variables matching a pattern.
The typed read methods return exactly the type in their name: Python scalars,
numpy arrays of int32, float64 or bool with the shape from the variable’s definition, or lists of strings.
If a variable holds anything else, they raise an AKFTypeError.
- exception AKFTypeError¶
A variable on a KF file does not have the type of value that was asked for.
When using the typed readers for arrays, the arrays rank needs to be specified with the ndim argument. This is necessary because the rank of the return type is deduced by static Python checkers from the value of the ndim argument, since numpy arrays of different ranks are considered separate types.
coordinates = akf.read_reals("Molecule%Coords", ndim=2)
print("Coordinates:")
print(coordinates)