Using the Fleur input/output parsers

Parser for the Fleur inp.xml file

The fleur inp.xml contains all the information about the setup of a fleur calculation. To use this information in external scripts or aiida-fleur, the information needs to be parsed from the .xml format somehow.

For this purpose the inpxml_parser() is implemented. The usage is shown below. The input file is parsed recursively and all information is put into the dictionary.

from masci_tools.io.parsers.fleur import inpxml_parser

input_dict = inpxml_parser('/path/to/random/inp.xml')

#The call below will output warnings about failed conversions in the warnings dictionary
warnings = {'parser_warnings': []}
input_dict = inpxml_parser('/path/to/random/inp.xml', parser_info_out=warnings)

The conversion of each attribute or text is done according to the FleurInputSchema for the same version, which is stored in this repository for versions from 0.27 to 0.35. The following table shows the version compatibility of the input parser.

File Version

Compatible

0.27 - 0.36

Yes

0.37

Fallback to 0.36

Parser for the Fleur out.xml file

For the out.xml file a similar parser is implemented. However, since the output file contains a lot more information, which is not always useful the outxml_parser() is defined a lot more selectively. But the usage is almost completely identical to the input file.

from masci_tools.io.parsers.fleur import outxml_parser

#The default is that only the last stable iteration is parsed
output_dict = outxml_parser('/path/to/random/out.xml')

#Here all iterations are parsed
output_dict = outxml_parser('/path/to/random/out.xml', iteration_to_parse='all')

#Or the 5.
output_dict = outxml_parser('/path/to/random/out.xml', iteration_to_parse=5)

#The call below will output warnings about failed conversions in the warnings dictionary
warnings = {'parser_warnings': []}
output_dict = outxml_parser('/path/to/random/out.xml', parser_info_out=warnings)

For each iteration the parser decides based on the type of fleur calculation, what things should be parsed. For a more detailed explanation refer to the Updating or adapting the Fleur Parsers.

The following table shows the version compatibility of the output parser. For versions before 0.34 the file version corresponds to the input version, since the output version is 0.27 for all versions before this point.

File Version

Compatible

0.27 - 0.29

0.29 version is assumed (no XML validation)

0.30 - 0.31

Yes (no XML validation)

0.32

No (Does not exist for any release version of fleur)

0.33

Yes (no XML validation)

0.34 - 0.36

`Yes

0.37 -

Fallback to 0.36

Using File handles

Both the inpxml_parser() and outxml_parser() can also be used with file handles like shown below.

 from masci_tools.io.parsers.fleur import inpxml_parser

 with open('/path/to/random/inp.xml', 'rb') as file:
    input_dict = inpxml_parser(file)

Notice that the file has to be opened in binary mode.

XML getter functions

There are a number of functions for extracting specific parts of the XML files in the xml_getters module. The following are available:

  • get_fleur_modes(): Get information about the mode of the fleur calculation

  • get_nkpts(): Get the (for older versions approximate if not kPointList is used) number of kpoints to be used in the calculation

  • get_cell(): Get the Bravais matrix of the system

  • get_parameterdata(): Get the information about the calculation parameters needed to reproduce a calculation starting from the inpgen

  • get_structuredata(): Get the structure from the xml file (atom positions + unit cell)

  • get_kpointsdata(): Get the defined kpoint sets (single/multiple) from the xml file (kpoints + weights + unit cell)

  • get_relaxation_information(): Get the relaxation history and current displacements

  • get_symmetry_information(): Get the symmetry operations used in the calculation

All of these are used in the same way

from masci_tools.io.fleur_xml import load_inpxml
from masci_tools.util.xml.xml_getters import get_fleur_modes

xmltree, schema_dict = load_inpxml('/path/to/inp.xml')

fleur_modes = get_fleur_modes(xmltree, schema_dict)
print(fleur_modes)

Using the schema_dict_util functions

If only a small amount of information is required from the input or output files of fleur the full parsers might be overkill. But there are a number of utility functions allowing easy access to information from the .xml files without knowing the exact XPath expressions for each version of the input/output. A code example extracting information from a input file is given below.

from masci_tools.io.fleur_xml import load_inpxml
from masci_tools.util.schema_dict_util import evaluate_attribute, eval_simple_xpath

#First we create a xml-tree from the input file and load the desired input schema dictionary
xmltree, schema_dict = load_inpxml('/path/to/inp.xml')
root = xmltree.getroot()

#Here an example of extracting some attributes. The interface to all functions in
#schema_dict_util is the same

#Number of spins
spins = evaluate_attribute(root, schema_dict, 'jspins')

#Planewave cutoff (notice the names are case-insensitive, 'KMAX' would work as well)
kmax = evaluate_attribute(root, schema_dict, 'kmax')

#Some attributes need to be specified further for a distinct path
#`radius` exists both for atom species and atom groups so we give a phrase to distinguish them
mt_radii = evaluate_attribute(root, schema_dict, 'radius', contains='species')

#But we can also make implicit constraints
# 1. Get some element in the xml tree, where the path is more specified. In the example lets
#    get the element containing all species
# 2. If we evaluate the `radius` attribute now on the species elements, we do not need
#    the contains parameter, since from the point of the species element there is only one possibility
#    for the `radius` attribute

species = eval_simple_xpath(root, schema_dict, 'atomSpecies')
mt_radii = evaluate_attribute(species, schema_dict, 'radius')

To manage the context of these functions the FleurXMLContext() is available to write the same code as above more concisely.

from masci_tools.io.fleur_xml import load_inpxml, FleurXMLContext
xmltree, schema_dict = load_inpxml('/path/to/inp.xml')

with FleurXMLContext(xmltree, schema_dict) as root:
   spins = root.attribute('jspins')
   noco = root.attribute('l_noco', default=False)

   #Not nesting the context we need to specify which elements are meant
   mt_radii = root.attribute('radius', contains='species')

   #Nesting using find (the first element is return)
   with root.find('atomspecies') as all_species:
         mt_radii = all_species.attribute('radius')

   #Nesting using iter (each iteration returns a new context for the next element)
   mt_radii = []
   for species in root.iter('species'):
         mt_radii.append(species.attribute('radius'))