# Using the Fleur input/output parsers ```{contents} ``` ```{eval-rst} .. currentmodule:: masci_tools.io.parsers.fleur ``` ## 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 {py:func}`inpxml_parser()` is implemented. The usage is shown below. The input file is parsed recursively and all information is put into the dictionary. ```python 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 {py:func}`outxml_parser()` is defined a lot more selectively. But the usage is almost completely identical to the input file. ```python 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 {ref}`devguidefleurxml`. 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 | ````{admonition} Using File handles Both the {py:func}`inpxml_parser()` and {py:func}`outxml_parser()` can also be used with file handles like shown below. ```python 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 {py:mod}`~masci_tools.util.xml.xml_getters` module. The following are available: ```{eval-rst} .. currentmodule:: masci_tools.util.xml.xml_getters ``` - {py:func}`get_fleur_modes()`: Get information about the mode of the fleur calculation - {py:func}`get_nkpts()`: Get the (for older versions approximate if not `kPointList` is used) number of kpoints to be used in the calculation - {py:func}`get_cell()`: Get the Bravais matrix of the system - {py:func}`get_parameterdata()`: Get the information about the calculation parameters needed to reproduce a calculation starting from the inpgen - {py:func}`get_structuredata()`: Get the structure from the xml file (atom positions + unit cell) - {py:func}`get_kpointsdata()`: Get the defined kpoint sets (single/multiple) from the xml file (kpoints + weights + unit cell) - {py:func}`get_relaxation_information()`: Get the relaxation history and current displacements - {py:func}`get_symmetry_information()`: Get the symmetry operations used in the calculation All of these are used in the same way ```python 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 {py:mod}`~masci_tools.util.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. ```python 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 {py:func}`~masci_tools.io.fleur_xml.FleurXMLContext()` is available to write the same code as above more concisely. ```python 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')) ```