def create_outschema_dict(path, inpschema_dict):
    """
    Creates dictionary with information about the FleurOutputSchema.xsd.
    The functions, whose results are added to the schema_dict and the corresponding keys
    are defined in schema_actions

    :param path: str path to the folder containing the FleurOutputSchema.xsd file
    :param inp_path: str path to the FleurInputSchema.xsd file (defaults to the same folder as path)
    """

    #Add new functionality to this dictionary here
    schema_actions = {
        'input_tag': get_input_tag,
        'root_tag': get_root_tag,
        '_basic_types': get_basic_types,
        'attrib_types': extract_attribute_types,
        'simple_elements': get_basic_elements,
        'tag_paths': get_tag_paths,
        'iteration_tag_paths': get_tag_paths,
        'unique_attribs': get_unique_attribs,
        'unique_path_attribs': get_unique_path_attribs,
        'other_attribs': get_other_attribs,
        'iteration_unique_attribs': get_unique_attribs,
        'iteration_unique_path_attribs': get_unique_path_attribs,
        'iteration_other_attribs': get_other_attribs,
        'tag_info': get_tag_info,
        'iteration_tag_info': get_tag_info,
        'omitt_contained_tags': get_omittable_tags,
    }

    #print(f'processing: {path}/FleurOutputSchema.xsd')
    xmlschema = etree.parse(path)
    xmlschema, _ = clear_xml(xmlschema)

    namespaces = {'xsd': 'http://www.w3.org/2001/XMLSchema'}
    out_version = str(xmlschema.xpath('/xsd:schema/@version', namespaces=namespaces)[0])

    input_basic_types = inpschema_dict.get('_basic_types').get_unlocked()

    schema_dict = {}
    schema_dict['out_version'] = out_version
    for key, action in schema_actions.items():
        addargs = {'input_basic_types': input_basic_types}
        if key in ['unique_attribs', 'unique_path_attribs', 'other_attribs', 'tag_paths', 'tag_info']:
            addargs['stop_iteration'] = True
        elif key in [
                'iteration_unique_attribs', 'iteration_unique_path_attribs', 'iteration_other_attribs',
                'iteration_tag_paths', 'iteration_tag_info'
        ]:
            addargs['iteration_root'] = True
            addargs['iteration'] = True
        schema_dict[key] = action(xmlschema, namespaces, **schema_dict, **addargs)

    schema_dict['_input_basic_types'] = input_basic_types

    #We cannot do the conversion to CaseInsensitiveDict before since we need the correct case
    #For these attributes in the attrib_path functions
    schema_dict['simple_elements'] = CaseInsensitiveDict(schema_dict['simple_elements'])

    return schema_dict
示例#2
0
def get_nkpts(xmltree, schema_dict, logger=None):
    """
    Get the number of kpoints that will be used in the calculation specified in the given
    fleur XMl file.

    .. warning::
        For file versions before Max5 only kPointList or kPointCount tags will work. However,
        for kPointCount there is no real guarantee that for every occasion it will correspond
        to the number of kpoints. So a warning is written out

    :param xmltree: etree representing the fleur xml file
    :param schema_dict: schema dictionary corresponding to the file version
                        of the xmltree
    :param logger: logger object for logging warnings, errors

    :returns: int with the number of kpoints
    """
    from masci_tools.util.schema_dict_util import eval_simple_xpath
    from masci_tools.util.schema_dict_util import evaluate_attribute
    from masci_tools.util.xml.common_functions import clear_xml

    if isinstance(xmltree, etree._ElementTree):
        xmltree, _ = clear_xml(xmltree)
        root = xmltree.getroot()
    else:
        root = xmltree

    #Get the name of the current selected kPointSet
    list_name = evaluate_attribute(root,
                                   schema_dict,
                                   'listName',
                                   logger=logger)

    kpointlists = eval_simple_xpath(root,
                                    schema_dict,
                                    'kPointList',
                                    list_return=True,
                                    logger=logger)

    if len(kpointlists) == 0:
        raise ValueError('No Kpoint lists found in the given inp.xml')

    labels = [kpoint_set.attrib.get('name') for kpoint_set in kpointlists]
    if list_name not in labels:
        raise ValueError(
            f'Selected Kpoint list with the name: {list_name} does not exist'
            f'Available list names: {labels}')

    kpoint_index = labels.index(list_name)

    kpoint_set = kpointlists[kpoint_index]

    nkpts = evaluate_attribute(kpoint_set, schema_dict, 'count', logger=logger)

    return nkpts
示例#3
0
def create_inpschema_dict(path, apply_patches=True):
    """
    Creates dictionary with information about the FleurInputSchema.xsd.
    The functions, whose results are added to the schema_dict and the corresponding keys
    are defined in schema_actions

    :param path: str path to the folder containing the FleurInputSchema.xsd file
    :param apply_patches: bool if True (default) the registered patching functions are applied after creation

    """

    #Add new functionality to this dictionary here
    schema_actions = {
        'root_tag': get_root_tag,
        'tag_paths': get_tag_paths,
        '_basic_types': get_basic_types,
        'attrib_types': extract_attribute_types,
        'simple_elements': get_basic_elements,
        'unique_attribs': get_unique_attribs,
        'unique_path_attribs': get_unique_path_attribs,
        'other_attribs': get_other_attribs,
        'omitt_contained_tags': get_omittable_tags,
        'tag_info': get_tag_info,
    }
    schema_patches = [convert_string_to_float_expr, patch_simple_elements]

    #print(f'processing: {path}/FleurInputSchema.xsd')
    xmlschema = etree.parse(path)
    xmlschema, _ = clear_xml(xmlschema)

    namespaces = {'xsd': 'http://www.w3.org/2001/XMLSchema'}
    inp_version = str(
        xmlschema.xpath('/xsd:schema/@version', namespaces=namespaces)[0])
    inp_version_tuple = convert_str_version_number(inp_version)

    schema_dict = {}
    schema_dict['inp_version'] = inp_version
    for key, action in schema_actions.items():
        schema_dict[key] = action(xmlschema, namespaces, **schema_dict)

        if key == '_basic_types' and apply_patches:
            schema_dict[key] = patch_basic_types(schema_dict[key],
                                                 inp_version_tuple)

    #We cannot do the conversion to CaseInsensitiveDict before since we need the correct case
    #For these attributes in the attrib_path functions
    schema_dict['simple_elements'] = CaseInsensitiveDict(
        schema_dict['simple_elements'])

    if apply_patches:
        for patch_func in schema_patches:
            patch_func(schema_dict, inp_version_tuple)

    return schema_dict
def test_clear_xml():
    """
    Test of the clear_xml function
    """
    from lxml import etree
    from masci_tools.util.xml.common_functions import eval_xpath, clear_xml
    parser = etree.XMLParser(attribute_defaults=True, encoding='utf-8')
    xmltree = etree.parse(CLEAR_XML_TEST_FILE, parser)

    #Check that the file contains comments and includes
    root = xmltree.getroot()
    comments = eval_xpath(root, '//comment()', list_return=True)
    assert len(comments) == 3

    include_tags = eval_xpath(
        root,
        '//xi:include',
        namespaces={'xi': 'http://www.w3.org/2001/XInclude'},
        list_return=True)
    assert len(include_tags) == 2

    symmetry_tags = eval_xpath(root, '//symOp', list_return=True)
    assert len(symmetry_tags) == 0

    cleared_tree, all_include_tags = clear_xml(xmltree)
    cleared_root = cleared_tree.getroot()
    old_root = xmltree.getroot()

    assert all_include_tags == {'symmetryOperations'}
    #Make sure that the original tree was not modified
    comments = eval_xpath(old_root, '//comment()', list_return=True)
    assert len(comments) == 3

    #Check that the cleared tree is correct
    comments = eval_xpath(cleared_root, '//comment()', list_return=True)
    assert len(comments) == 0

    include_tags = eval_xpath(
        cleared_root,
        '//xi:include',
        namespaces={'xi': 'http://www.w3.org/2001/XInclude'},
        list_return=True)
    assert len(include_tags) == 0

    symmetry_tags = eval_xpath(cleared_root, '//symOp', list_return=True)
    assert len(symmetry_tags) == 16
def test_reverse_xinclude(load_inpxml):
    """
    Test of the reverse_xinclude function
    """
    from masci_tools.util.xml.common_functions import eval_xpath, reverse_xinclude, clear_xml

    xmltree, schema_dict = load_inpxml(CLEAR_XML_TEST_FILE)

    cleared_tree, all_include_tags = clear_xml(xmltree)
    cleared_root = cleared_tree.getroot()

    reexcluded_tree, included_trees = reverse_xinclude(cleared_tree,
                                                       schema_dict,
                                                       all_include_tags)
    reexcluded_root = reexcluded_tree.getroot()

    assert list(included_trees.keys()) == ['sym.xml']
    sym_root = included_trees['sym.xml'].getroot()

    include_tags = eval_xpath(
        cleared_root,
        '//xi:include',
        namespaces={'xi': 'http://www.w3.org/2001/XInclude'},
        list_return=True)
    assert len(include_tags) == 0

    include_tags = eval_xpath(
        reexcluded_root,
        '//xi:include',
        namespaces={'xi': 'http://www.w3.org/2001/XInclude'},
        list_return=True)
    assert len(include_tags) == 2
    assert [tag.attrib['href']
            for tag in include_tags] == ['sym.xml', 'relax.xml']

    symmetry_tags = eval_xpath(cleared_root, '//symOp', list_return=True)
    assert len(symmetry_tags) == 16

    symmetry_tags = eval_xpath(reexcluded_root, '//symOp', list_return=True)
    assert len(symmetry_tags) == 0

    symmetry_tags = eval_xpath(sym_root, 'symOp', list_return=True)
    assert len(symmetry_tags) == 16
示例#6
0
    def _include_files(self, xmltree):
        """
        Tries to insert all .xml, which are not inp.xml file into the etree since they are
        not naturally available for the parser (open vs self.open)

        Creates a NamedTemporaryFile for each one and replaces the name in the etree_string
        Then it is reparsed into a ElementTree and teh xi:include tags are executed
        """
        from masci_tools.util.xml.common_functions import clear_xml
        import tempfile

        xmltree_string = etree.tostring(xmltree)

        temp_files = []
        for file in self.files:
            if file.endswith('.xml') and file != 'inp.xml':

                #Get file content from node
                include_content = ''
                with self.open(path=file, mode='r') as include_file:
                    include_content = include_file.read()

                #Write content into temporary file
                with tempfile.NamedTemporaryFile(mode='w', delete=False) as fo:
                    fo.write(include_content)
                    temp_files.append(fo.name)
                    #If the include tag for the given file is not present nothing is replaced
                    xmltree_string = xmltree_string.replace(
                        bytes(file, 'utf-8'), bytes(fo.name, 'utf-8'))

        #Regenerate the tree with tempfile names
        xmltree_with_includes = etree.fromstring(xmltree_string).getroottree()

        #Performs the inclusions and remove comments
        cleared_tree, included_tags = clear_xml(xmltree_with_includes)

        #Remove temporary files
        for file in temp_files:
            os.remove(file)

        return cleared_tree, included_tags
def inpxml_parser(inpxmlfile,
                  version=None,
                  parser_info_out=None,
                  strict=False,
                  debug=False):
    """
    Parses the given inp.xml file to a python dictionary utilizing the schema
    defined by the version number to validate and corretly convert to the dictionary

    :param inpxmlfile: either path to the inp.xml file, opened file handle or a xml etree to be parsed
    :param version: version string to enforce that a given schema is used
    :param parser_info_out: dict, with warnings, info, errors, ...
    :param strict: bool if True  and no parser_info_out is provided any encountered error will immediately be raised

    :return: python dictionary with the parsed inp.xml

    :raises ValueError: If the validation against the schema failed, or an irrecoverable error
                        occured during parsing
    :raises FileNotFoundError: If no Schema file for the given version was found

    """

    __parser_version__ = '0.3.0'
    logger = logging.getLogger(__name__)

    parser_log_handler = None
    if parser_info_out is not None or not strict:
        if parser_info_out is None:
            parser_info_out = {}

        logging_level = logging.INFO
        if debug:
            logging_level = logging.DEBUG
        logger.setLevel(logging_level)

        parser_log_handler = DictHandler(parser_info_out,
                                         WARNING='parser_warnings',
                                         ERROR='parser_errors',
                                         INFO='parser_info',
                                         DEBUG='parser_debug',
                                         CRITICAL='parser_critical',
                                         ignore_unknown_levels=True,
                                         level=logging_level)

        logger.addHandler(parser_log_handler)

    if strict:
        logger = None

    if logger is not None:
        logger.info('Masci-Tools Fleur inp.xml Parser v%s', __parser_version__)

    if isinstance(inpxmlfile, etree._ElementTree):
        xmltree = inpxmlfile
    else:
        parser = etree.XMLParser(attribute_defaults=True, encoding='utf-8')
        try:
            xmltree = etree.parse(inpxmlfile, parser)
        except etree.XMLSyntaxError as msg:
            if logger is not None:
                logger.exception('Failed to parse input file')
            raise ValueError(f'Failed to parse input file: {msg}') from msg

    if version is None:
        version = eval_xpath(xmltree, '//@fleurInputVersion', logger=logger)
        version = str(version)
        if version is None:
            if logger is not None:
                logger.error('Failed to extract inputVersion')
            raise ValueError('Failed to extract inputVersion')

    if logger is not None:
        logger.info('Got Fleur input file with file version %s', version)
    schema_dict = InputSchemaDict.fromVersion(version, logger=logger)

    ignore_validation = schema_dict['inp_version'] != version

    xmltree, _ = clear_xml(xmltree)
    root = xmltree.getroot()

    constants = read_constants(root, schema_dict, logger=logger)

    try:
        validate_xml(
            xmltree,
            schema_dict.xmlschema,
            error_header='Input file does not validate against the schema')
    except etree.DocumentInvalid as err:
        errmsg = str(err)
        logger.warning(errmsg)
        if not ignore_validation:
            if logger is not None:
                logger.exception(errmsg)
            raise ValueError(errmsg) from err

    if schema_dict.xmlschema.validate(xmltree) or ignore_validation:
        inp_dict = inpxml_todict(root, schema_dict, constants, logger=logger)
    else:
        msg = 'Input file does not validate against the schema: Reason is unknown'
        if logger is not None:
            logger.warning(msg)
        if not ignore_validation:
            if logger is not None:
                logger.exception(msg)
            raise ValueError(msg)

    if parser_log_handler is not None:
        if logger is not None:
            logger.removeHandler(parser_log_handler)

    return inp_dict
示例#8
0
def get_relaxation_information(xmltree, schema_dict, logger=None):
    """
    Get the relaxation information from the given fleur XML file. This includes the current
    displacements, energy and posforce evolution

    :param xmltree: etree representing the fleur xml file
    :param schema_dict: schema dictionary corresponding to the file version
                        of the xmltree
    :param logger: logger object for logging warnings, errors

    :returns: dict with the relaxation information

    :raises ValueError: If no relaxation section is included in the xml tree
    """
    from masci_tools.util.schema_dict_util import tag_exists, read_constants, evaluate_text, eval_simple_xpath
    from masci_tools.util.schema_dict_util import evaluate_attribute
    from masci_tools.util.xml.common_functions import clear_xml

    if isinstance(xmltree, etree._ElementTree):
        xmltree, _ = clear_xml(xmltree)
        root = xmltree.getroot()
    else:
        root = xmltree
    constants = read_constants(root, schema_dict, logger=logger)

    if not tag_exists(root, schema_dict, 'relaxation', logger=logger):
        raise ValueError(
            'No relaxation information included in the given XML file')

    relax_tag = eval_simple_xpath(root,
                                  schema_dict,
                                  'relaxation',
                                  logger=logger)

    out_dict = {}
    out_dict['displacements'] = evaluate_text(relax_tag,
                                              schema_dict,
                                              'displace',
                                              list_return=True,
                                              constants=constants,
                                              logger=logger)

    out_dict['energies'] = evaluate_attribute(relax_tag,
                                              schema_dict,
                                              'energy',
                                              list_return=True,
                                              constants=constants,
                                              logger=logger)

    out_dict['posforces'] = []
    relax_iters = eval_simple_xpath(relax_tag,
                                    schema_dict,
                                    'step',
                                    list_return=True,
                                    logger=logger)
    for step in relax_iters:
        posforces = evaluate_text(step,
                                  schema_dict,
                                  'posforce',
                                  list_return=True,
                                  constants=constants,
                                  logger=logger)
        out_dict['posforces'].append(posforces)

    return out_dict
示例#9
0
def get_kpoints_data_max4(xmltree, schema_dict, logger=None):
    """
    Get the kpoint sets defined in the given fleur xml file.

    .. note::
        This function is specific to file version before and including the
        Max4 release of fleur

    :param xmltree: etree representing the fleur xml file
    :param schema_dict: schema dictionary corresponding to the file version
                        of the xmltree
    :param logger: logger object for logging warnings, errors

    :returns: tuple containing the kpoint information

    The tuple contains the following entries:

        1. :kpoints: list containing the coordinates of the kpoints
        2. :weights: list containing the weights of the kpoints
        3. :cell: numpy array, bravais matrix of the given system
        4. :pbc: list of booleans, determines in which directions periodic boundary conditions are applicable

    """
    from masci_tools.util.schema_dict_util import read_constants, eval_simple_xpath
    from masci_tools.util.schema_dict_util import evaluate_text, evaluate_attribute
    from masci_tools.util.xml.common_functions import clear_xml

    if isinstance(xmltree, etree._ElementTree):
        xmltree, _ = clear_xml(xmltree)
        root = xmltree.getroot()
    else:
        root = xmltree

    constants = read_constants(root, schema_dict, logger=logger)

    cell, pbc = get_cell(root, schema_dict, logger=logger)

    kpointlist = eval_simple_xpath(root,
                                   schema_dict,
                                   'kPointList',
                                   list_return=True,
                                   not_contains='altKPoint',
                                   logger=logger)

    if len(kpointlist) == 0:
        raise ValueError('No Kpoint lists found in the given inp.xml')

    kpointlist = kpointlist[0]

    kpoints = evaluate_text(kpointlist,
                            schema_dict,
                            'kPoint',
                            constants=constants,
                            not_contains='altKPoint',
                            list_return=True,
                            logger=logger)
    weights = evaluate_attribute(kpointlist,
                                 schema_dict,
                                 'weight',
                                 constants=constants,
                                 not_contains='altKPoint',
                                 list_return=True,
                                 logger=logger)

    return kpoints, weights, cell, pbc
示例#10
0
def outxml_parser(outxmlfile,
                  version=None,
                  parser_info_out=None,
                  iteration_to_parse=None,
                  strict=False,
                  debug=False,
                  **kwargs):
    """
    Parses the out.xml file to a dictionary based on the version and the given tasks

    :param outxmlfile: either path to the out.xml file, opened file handle or a xml etree to be parsed
    :param version: version string to enforce that a given schema is used
    :param parser_info_out: dict, with warnings, info, errors, ...
    :param iteration_to_parse: either str or int, (optional, default 'last')
                               determines which iteration should be parsed.
                               Accepted are 'all', 'first', 'last' or an index for the iteration
    :param strict: bool if True  and no parser_info_out is provided any encountered error will immediately be raised
    :param debug: bool if True additional information is printed out in the logs

    Kwargs:
        :param ignore_validation: bool, if True schema validation errors are only logged
        :param minimal_mode: bool, if True only total Energy, iteration number and distances are parsed
        :param list_return: bool, if True one-item lists in the output dict are not converted to simple values
        :param additional_tasks: dict to define custom parsing tasks. For detailed explanation
                                 See :py:mod:`~masci_tools.io.parsers.fleur.default_parse_tasks`.
        :param overwrite: bool, if True and keys in additional_tasks collide with defaults
                          The defaults will be overwritten
        :param append: bool, if True and keys in additional_tasks collide with defaults
                       The inner tasks will be written into the dict. If inner keys collide
                       they are overwritten

    :return: python dictionary with the information parsed from the out.xml

    :raises ValueError: If the validation against the schema failed, or an irrecoverable error
                        occured during parsing
    :raises FileNotFoundError: If no Schema file for the given version was found
    :raises KeyError: If an unknown task is encountered

    """

    __parser_version__ = '0.5.0'

    logger = logging.getLogger(__name__)

    parser_log_handler = None
    if parser_info_out is not None or not strict:
        if parser_info_out is None:
            parser_info_out = {}

        logging_level = logging.INFO
        if debug:
            logging_level = logging.DEBUG
        logger.setLevel(logging_level)

        parser_log_handler = DictHandler(parser_info_out,
                                         WARNING='parser_warnings',
                                         ERROR='parser_errors',
                                         INFO='parser_info',
                                         DEBUG='parser_debug',
                                         CRITICAL='parser_critical',
                                         ignore_unknown_levels=True,
                                         level=logging_level)

        logger.addHandler(parser_log_handler)

    if strict:
        logger = None

    if logger is not None:
        logger.info('Masci-Tools Fleur out.xml Parser v%s', __parser_version__)

    outfile_broken = False

    if isinstance(outxmlfile, etree._ElementTree):
        xmltree = outxmlfile
    else:
        parser = etree.XMLParser(attribute_defaults=True,
                                 recover=False,
                                 encoding='utf-8')

        try:
            xmltree = etree.parse(outxmlfile, parser)
        except etree.XMLSyntaxError:
            outfile_broken = True
            if logger is None:
                warnings.warn('The out.xml file is broken I try to repair it.')
            else:
                logger.warning(
                    'The out.xml file is broken I try to repair it.')

        if outfile_broken:
            # repair xmlfile and try to parse what is possible.
            parser = etree.XMLParser(attribute_defaults=True,
                                     recover=True,
                                     encoding='utf-8')
            try:
                xmltree = etree.parse(outxmlfile, parser)
            except etree.XMLSyntaxError:
                if logger is None:
                    raise
                else:
                    logger.exception('Skipping the parsing of the xml file. '
                                     'Repairing was not possible.')
                    return {}

    if version is None:
        out_version = eval_xpath(xmltree,
                                 '//@fleurOutputVersion',
                                 logger=logger)
        out_version = str(out_version)
        if out_version is None:
            logger.error('Failed to extract outputVersion')
            raise ValueError('Failed to extract outputVersion')
    else:
        out_version = version

    if out_version == '0.27':
        program_version = eval_xpath(xmltree,
                                     '//programVersion/@version',
                                     logger=logger)
        if program_version == 'fleur 32':
            #Max5 release (before bugfix)
            out_version = '0.33'
            inp_version = '0.33'
            ignore_validation = True
            if logger is not None:
                logger.warning(
                    "Ignoring '0.27' outputVersion for MaX5.0 release")
            else:
                warnings.warn(
                    "Ignoring '0.27' outputVersion for MaX5.0 release")
        elif program_version == 'fleur 31':
            #Max4 release
            out_version = '0.31'
            inp_version = '0.31'
            ignore_validation = True
            if logger is not None:
                logger.warning(
                    "Ignoring '0.27' outputVersion for MaX4.0 release")
            else:
                warnings.warn(
                    "Ignoring '0.27' outputVersion for MaX4.0 release")
        elif program_version == 'fleur 30':
            #Max3.1 release
            out_version = '0.30'
            inp_version = '0.30'
            ignore_validation = True
            if logger is not None:
                logger.warning(
                    "Ignoring '0.27' outputVersion for MaX3.1 release")
            else:
                warnings.warn(
                    "Ignoring '0.27' outputVersion for MaX3.1 release")
        elif program_version == 'fleur 27':
            #Max3.1 release
            out_version = '0.29'
            inp_version = '0.29'
            ignore_validation = True
            if logger is not None:
                logger.warning(
                    "Found version before MaX3.1 release falling back to file version '0.29'"
                )
            warnings.warn(
                'out.xml files before the MaX3.1 release are not explicitely supported.'
                ' No guarantee is given that the parser will work without error',
                UserWarning)
        else:
            if logger is not None:
                logger.error(
                    "Unknown fleur version: File-version '%s' Program-version '%s'",
                    out_version, program_version)
            raise ValueError(
                f"Unknown fleur version: File-version '{out_version}' Program-version '{program_version}'"
            )
    else:
        ignore_validation = False
        inp_version = eval_xpath(xmltree,
                                 '//@fleurInputVersion',
                                 logger=logger)
        inp_version = str(inp_version)
        if inp_version is None:
            if logger is not None:
                logger.error('Failed to extract inputVersion')
            raise ValueError('Failed to extract inputVersion')

    ignore_validation = kwargs.get('ignore_validation', ignore_validation)

    #Load schema_dict (inp and out)
    outschema_dict = OutputSchemaDict.fromVersion(out_version,
                                                  inp_version=inp_version,
                                                  logger=logger)

    if outschema_dict['out_version'] != out_version or \
       outschema_dict['inp_version'] != inp_version:
        ignore_validation = True
        out_version = outschema_dict['out_version']
        inp_version = outschema_dict['inp_version']

    if logger is not None:
        logger.info('Found fleur out file with the versions out: %s; inp: %s',
                    out_version, inp_version)

    xmltree, _ = clear_xml(xmltree)
    root = xmltree.getroot()

    errmsg = ''
    try:
        validate_xml(
            xmltree,
            outschema_dict.xmlschema,
            error_header='Output file does not validate against the schema')
    except etree.DocumentInvalid as err:
        errmsg = str(err)
        if logger is not None:
            logger.warning(errmsg)
        if not ignore_validation:
            if logger is not None:
                logger.exception(errmsg)
            raise ValueError(errmsg) from err

    if not outschema_dict.xmlschema.validate(xmltree) and errmsg == '':
        msg = 'Output file does not validate against the schema: Reason is unknown'
        if logger is not None:
            logger.warning(msg)
        if not ignore_validation:
            if logger is not None:
                logger.exception(msg)
            raise ValueError(msg)

    parser = ParseTasks(out_version)
    additional_tasks = kwargs.pop('additional_tasks', {})
    for task_name, task_definition in additional_tasks.items():
        parser.add_task(task_name, task_definition, **kwargs)

    out_dict, constants = parse_general_information(
        root,
        parser,
        outschema_dict,
        logger=logger,
        iteration_to_parse=iteration_to_parse,
        **kwargs)

    out_dict['input_file_version'] = outschema_dict['inp_version']
    # get all iterations in out.xml file
    iteration_nodes = eval_simple_xpath(root,
                                        outschema_dict,
                                        'iteration',
                                        logger=logger,
                                        list_return=True)
    n_iters = len(iteration_nodes)

    # parse only last stable interation
    # (if modes (dos and co) maybe parse anyway if broken?)
    if outfile_broken and (n_iters >= 2):
        iteration_nodes = iteration_nodes[:-2]
        if logger is not None:
            logger.info('The last parsed iteration is %s', n_iters - 2)
    elif outfile_broken and (n_iters == 1):
        iteration_nodes = [iteration_nodes[0]]
        if logger is not None:
            logger.info('The last parsed iteration is %s', n_iters)
    elif not outfile_broken and (n_iters >= 1):
        pass
    else:  # there was no iteration found.
        # only the starting charge density could be generated
        msg = 'There was no iteration found in the outfile, either just a ' \
              'starting density was generated or something went wrong.'
        if logger is None:
            raise ValueError(msg)
        else:
            logger.error(msg)

    if iteration_to_parse is None:
        iteration_to_parse = 'last'  #This is the default from the aiida_fleur parser

    if iteration_to_parse == 'last':
        iteration_nodes = iteration_nodes[-1]
    elif iteration_to_parse == 'first':
        iteration_nodes = iteration_nodes[0]
    elif iteration_to_parse == 'all':
        pass
    elif isinstance(iteration_to_parse, int):
        try:
            iteration_nodes = iteration_nodes[iteration_to_parse]
        except IndexError as exc:
            if logger is not None:
                logger.exception(exc)
            raise ValueError(
                f"Invalid value for iteration_to_parse: Got '{iteration_to_parse}'"
                f"; but only '{len(iteration_nodes)}' iterations are available"
            ) from exc
    else:
        if logger is not None:
            logger.error(
                "Invalid value for iteration_to_parse: Got '%s' "
                "Valid values are: 'first', 'last', 'all', or int",
                iteration_to_parse)
        raise ValueError(
            f"Invalid value for iteration_to_parse: Got '{iteration_to_parse}' "
            "Valid values are: 'first', 'last', 'all', or int")

    if not isinstance(iteration_nodes, list):
        iteration_nodes = [iteration_nodes]

    logger_info = {'iteration': 'unknown'}
    iteration_logger = OutParserLogAdapter(logger, logger_info)

    for node in iteration_nodes:
        iteration_number = evaluate_attribute(node,
                                              outschema_dict,
                                              'numberForCurrentRun',
                                              optional=True)

        if iteration_number is not None:
            logger_info['iteration'] = iteration_number

        out_dict = parse_iteration(node,
                                   parser,
                                   outschema_dict,
                                   out_dict,
                                   constants,
                                   logger=iteration_logger,
                                   **kwargs)

        logger_info['iteration'] = 'unknown'

    if not kwargs.get('list_return', False):
        #Convert one item lists to simple values
        for key, value in out_dict.items():
            if isinstance(value, list):
                if len(value) == 1:
                    out_dict[key] = value[0]
            elif isinstance(value, dict):
                for subkey, subvalue in value.items():
                    if isinstance(subvalue, list):
                        if len(subvalue) == 1:
                            out_dict[key][subkey] = subvalue[0]

    if parser_log_handler is not None:
        if logger is not None:
            logger.removeHandler(parser_log_handler)

    return out_dict
示例#11
0
def get_structure_data(xmltree, schema_dict, logger=None):
    """
    Get the structure defined in the given fleur xml file.

    .. warning::
        Only the explicit definition of the Bravais matrix is supported.
        Old inputs containing the `latnam` definitions are not supported

    :param xmltree: etree representing the fleur xml file
    :param schema_dict: schema dictionary corresponding to the file version
                        of the xmltree
    :param logger: logger object for logging warnings, errors

    :returns: tuple containing the structure information

    The tuple contains the following entries:

        1. :atom_data: list of tuples containing the absolute positions and symbols of the atoms
        2. :cell: numpy array, bravais matrix of the given system
        3. :pbc: list of booleans, determines in which directions periodic boundary conditions are applicable

    """
    from masci_tools.util.schema_dict_util import read_constants, eval_simple_xpath
    from masci_tools.util.schema_dict_util import evaluate_text, evaluate_attribute
    from masci_tools.util.xml.common_functions import clear_xml
    from masci_tools.io.common_functions import rel_to_abs, rel_to_abs_f

    if isinstance(xmltree, etree._ElementTree):
        xmltree, _ = clear_xml(xmltree)
        root = xmltree.getroot()
    else:
        root = xmltree
    constants = read_constants(root, schema_dict, logger=logger)
    cell, pbc = get_cell(root, schema_dict, logger=logger)

    species_names = evaluate_attribute(root,
                                       schema_dict,
                                       'name',
                                       constants=constants,
                                       contains='species',
                                       logger=logger)
    species_elements = evaluate_attribute(root,
                                          schema_dict,
                                          'element',
                                          constants=constants,
                                          contains='species',
                                          logger=logger)

    if not isinstance(species_names, list):
        species_names = [species_names]
    if not isinstance(species_elements, list):
        species_elements = [species_elements]

    if len(species_names) != len(species_elements):
        raise ValueError(
            f'Failed to read in species names and elements. Got {len(species_names)} names and {len(species_elements)} elements'
        )

    species_dict = dict(zip(species_names, species_elements))

    atom_data = []
    atom_groups = eval_simple_xpath(root,
                                    schema_dict,
                                    'atomGroup',
                                    list_return=True,
                                    logger=logger)
    for group in atom_groups:

        group_species = evaluate_attribute(group,
                                           schema_dict,
                                           'species',
                                           constants=constants,
                                           logger=logger)

        atom_positions = []

        absolute_positions = evaluate_text(group,
                                           schema_dict,
                                           'absPos',
                                           constants=constants,
                                           list_return=True,
                                           logger=logger,
                                           optional=True)
        relative_positions = evaluate_text(group,
                                           schema_dict,
                                           'relPos',
                                           constants=constants,
                                           list_return=True,
                                           logger=logger,
                                           optional=True)
        film_positions = evaluate_text(group,
                                       schema_dict,
                                       'filmPos',
                                       constants=constants,
                                       list_return=True,
                                       logger=logger,
                                       optional=True)

        atom_positions = absolute_positions

        for rel_pos in relative_positions:
            atom_positions.append(rel_to_abs(rel_pos, cell))

        for film_pos in film_positions:
            atom_positions.append(rel_to_abs_f(film_pos, cell))

        if len(atom_positions) == 0:
            raise ValueError('Failed to read atom positions for group')

        atom_data.extend(
            (pos, species_dict[group_species]) for pos in atom_positions)

    return atom_data, cell, pbc
示例#12
0
def get_parameter_data(xmltree,
                       schema_dict,
                       inpgen_ready=True,
                       write_ids=True,
                       logger=None):
    """
    This routine returns an python dictionary produced from the inp.xml
    file, which contains all the parameters needed to setup a new inp.xml from a inpgen
    input file to produce the same input (for parameters that the inpgen can control)

    :param xmltree: etree representing the fleur xml file
    :param schema_dict: schema dictionary corresponding to the file version
                        of the xmltree
    :param inpgen_ready: Bool, return a dict which can be inputed into inpgen while setting atoms
    :param write_ids: Bool, if True the atom ids are added to the atom namelists
    :param logger: logger object for logging warnings, errors

    :returns: dict, which will lead to the same inp.xml (in case if other defaults,
              which can not be controlled by input for inpgen, were changed)

    """
    from masci_tools.util.schema_dict_util import read_constants, eval_simple_xpath
    from masci_tools.util.schema_dict_util import evaluate_attribute, evaluate_text
    from masci_tools.util.xml.common_functions import clear_xml
    from masci_tools.util.xml.converters import convert_fleur_lo
    from masci_tools.io.common_functions import filter_out_empty_dict_entries

    # TODO: convert econfig
    # TODO: parse kpoints, somehow count is bad (if symmetry changes), mesh is not known, path cannot be specified

    ########
    parameters = {}
    if isinstance(xmltree, etree._ElementTree):
        xmltree, _ = clear_xml(xmltree)
        root = xmltree.getroot()
    else:
        root = xmltree
    constants = read_constants(root, schema_dict, logger=logger)

    # Create the cards

    # &input # most things are not needed for AiiDA here. or we ignor them for now.
    # film is set by the plugin depended on the structure
    # symor per default = False? to avoid input which fleur can't take

    # &comp
    comp_dict = {}
    comp_dict['jspins'] = evaluate_attribute(root,
                                             schema_dict,
                                             'jspins',
                                             constants=constants,
                                             logger=logger)
    comp_dict['frcor'] = evaluate_attribute(root,
                                            schema_dict,
                                            'frcor',
                                            constants=constants,
                                            logger=logger,
                                            optional=True)
    comp_dict['ctail'] = evaluate_attribute(root,
                                            schema_dict,
                                            'ctail',
                                            constants=constants,
                                            logger=logger)
    comp_dict['kcrel'] = evaluate_attribute(root,
                                            schema_dict,
                                            'kcrel',
                                            constants=constants,
                                            logger=logger,
                                            optional=True)
    comp_dict['gmax'] = evaluate_attribute(root,
                                           schema_dict,
                                           'gmax',
                                           constants=constants,
                                           logger=logger)
    comp_dict['gmaxxc'] = evaluate_attribute(root,
                                             schema_dict,
                                             'gmaxxc',
                                             constants=constants,
                                             logger=logger)
    comp_dict['kmax'] = evaluate_attribute(root,
                                           schema_dict,
                                           'kmax',
                                           constants=constants,
                                           logger=logger)
    parameters['comp'] = filter_out_empty_dict_entries(comp_dict)

    # &atoms
    species_list = eval_simple_xpath(root,
                                     schema_dict,
                                     'species',
                                     list_return=True,
                                     logger=logger)
    species_several = {}
    # first we see if there are several species with the same atomic number
    for species in species_list:
        atom_z = evaluate_attribute(species,
                                    schema_dict,
                                    'atomicNumber',
                                    constants,
                                    logger=logger)
        species_several[atom_z] = species_several.get(atom_z, 0) + 1

    species_count = {}
    for indx, species in enumerate(species_list):
        atom_dict = {}
        atoms_name = f'atom{indx}'
        atom_z = evaluate_attribute(species,
                                    schema_dict,
                                    'atomicNumber',
                                    constants=constants,
                                    logger=logger)
        if not inpgen_ready:
            atom_dict['z'] = atom_z
        species_count[atom_z] = species_count.get(atom_z, 0) + 1
        atom_id = f'{atom_z}.{species_count[atom_z]}'
        if write_ids:
            if species_several[atom_z] > 1:
                atom_dict['id'] = atom_id

        if schema_dict.inp_version <= (0, 31):
            atom_dict['ncst'] = evaluate_attribute(species,
                                                   schema_dict,
                                                   'coreStates',
                                                   constants,
                                                   logger=logger)
        atom_dict['rmt'] = evaluate_attribute(species,
                                              schema_dict,
                                              'radius',
                                              constants=constants,
                                              logger=logger)
        atom_dict['dx'] = evaluate_attribute(species,
                                             schema_dict,
                                             'logIncrement',
                                             constants=constants,
                                             logger=logger)
        atom_dict['jri'] = evaluate_attribute(species,
                                              schema_dict,
                                              'gridPoints',
                                              constants=constants,
                                              logger=logger)
        atom_dict['lmax'] = evaluate_attribute(species,
                                               schema_dict,
                                               'lmax',
                                               constants=constants,
                                               logger=logger)
        atom_dict['lnonsph'] = evaluate_attribute(species,
                                                  schema_dict,
                                                  'lnonsphr',
                                                  constants=constants,
                                                  logger=logger)
        atom_dict['bmu'] = evaluate_attribute(species,
                                              schema_dict,
                                              'magMom',
                                              constants,
                                              logger=logger,
                                              optional=True)

        atom_dict['element'] = evaluate_attribute(species,
                                                  schema_dict,
                                                  'element',
                                                  constants=constants,
                                                  logger=logger)

        #atom_econfig = eval_simple_xpath(species, schema_dict, 'electronConfig')
        atom_lo = eval_simple_xpath(species,
                                    schema_dict,
                                    'lo',
                                    list_return=True,
                                    logger=logger)
        #atom_econfig = eval_simple_xpath(species, schema_dict, 'electronConfig')

        if len(atom_lo) != 0:
            atom_dict['lo'] = convert_fleur_lo(atom_lo)
        parameters[atoms_name] = filter_out_empty_dict_entries(atom_dict)

    # &soc
    soc = evaluate_attribute(root,
                             schema_dict,
                             'l_soc',
                             constants=constants,
                             logger=logger,
                             optional=True)
    theta = evaluate_attribute(root,
                               schema_dict,
                               'theta',
                               constants=constants,
                               contains='soc',
                               logger=logger,
                               optional=True)
    phi = evaluate_attribute(root,
                             schema_dict,
                             'phi',
                             constants=constants,
                             contains='soc',
                             logger=logger,
                             optional=True)
    if soc is not None and soc:
        parameters['soc'] = {'theta': theta, 'phi': phi}

    # &kpt
    #attrib = convert_from_fortran_bool(eval_xpath(root, l_soc_xpath))
    #theta = eval_xpath(root, theta_xpath)
    #phi = eval_xpath(root, phi_xpath)
    # if kpt:
    #    new_parameters['kpt'] = {'theta' : theta, 'phi' : phi}
    #    # ['nkpt', 'kpts', 'div1', 'div2', 'div3',                         'tkb', 'tria'],

    # title
    title = evaluate_text(root,
                          schema_dict,
                          'comment',
                          constants=constants,
                          logger=logger,
                          optional=True)
    if title:
        parameters['title'] = title.replace('\n', '').strip()

    # &exco
    #TODO, easy
    exco_dict = {}
    exco_dict['xctyp'] = evaluate_attribute(root,
                                            schema_dict,
                                            'name',
                                            constants,
                                            contains='xcFunctional',
                                            logger=logger)
    # 'exco' : ['xctyp', 'relxc'],
    parameters['exco'] = filter_out_empty_dict_entries(exco_dict)
    # &film
    # TODO

    # &qss
    # TODO

    # lattice, not supported?

    return parameters
示例#13
0
def get_cell(xmltree, schema_dict, logger=None):
    """
    Get the Bravais matrix from the given fleur xml file. In addition a list
    determining in, which directions there are periodic boundary conditions
    in the system.

    .. warning::
        Only the explicit definition of the Bravais matrix is supported.
        Old inputs containing the `latnam` definitions are not supported

    :param xmltree: etree representing the fleur xml file
    :param schema_dict: schema dictionary corresponding to the file version
                        of the xmltree
    :param logger: logger object for logging warnings, errors

    :returns: numpy array of the bravais matrix and list of boolean values for
              periodic boundary conditions
    """
    from masci_tools.util.schema_dict_util import read_constants, eval_simple_xpath
    from masci_tools.util.schema_dict_util import evaluate_text, tag_exists
    from masci_tools.util.xml.common_functions import clear_xml
    from masci_tools.util.constants import BOHR_A
    import numpy as np

    if isinstance(xmltree, etree._ElementTree):
        xmltree, _ = clear_xml(xmltree)
        root = xmltree.getroot()
    else:
        root = xmltree
    constants = read_constants(root, schema_dict, logger=logger)

    cell = None
    lattice_tag = None
    if tag_exists(root, schema_dict, 'bulkLattice', logger=logger):
        lattice_tag = eval_simple_xpath(root,
                                        schema_dict,
                                        'bulkLattice',
                                        logger=logger)
        pbc = [True, True, True]
    elif tag_exists(root, schema_dict, 'filmLattice', logger=logger):
        lattice_tag = eval_simple_xpath(root,
                                        schema_dict,
                                        'filmLattice',
                                        logger=logger)
        pbc = [True, True, False]

    if lattice_tag is not None:
        row1 = evaluate_text(lattice_tag,
                             schema_dict,
                             'row-1',
                             constants=constants,
                             contains='bravaisMatrix',
                             logger=logger,
                             optional=True)
        row2 = evaluate_text(lattice_tag,
                             schema_dict,
                             'row-2',
                             constants=constants,
                             contains='bravaisMatrix',
                             logger=logger,
                             optional=True)
        row3 = evaluate_text(lattice_tag,
                             schema_dict,
                             'row-3',
                             constants=constants,
                             contains='bravaisMatrix',
                             logger=logger,
                             optional=True)

        if all(x is not None and x != [] for x in [row1, row2, row3]):
            cell = np.array([row1, row2, row3]) * BOHR_A

    if cell is None:
        raise ValueError(
            'Could not extract Bravais matrix out of inp.xml. Is the '
            'Bravais matrix explicitly given? i.e Latnam definition '
            'not supported.')

    return cell, pbc
示例#14
0
def get_nkpts_max4(xmltree, schema_dict, logger=None):
    """
    Get the number of kpoints that will be used in the calculation specified in the given
    fleur XMl file. Version specific for Max4 versions or older

    .. warning::
        For file versions before Max5 only kPointList or kPointCount tags will work. However,
        for kPointCount there is no real guarantee that for every occasion it will correspond
        to the number of kpoints. So a warning is written out

    :param xmltree: etree representing the fleur xml file
    :param schema_dict: schema dictionary corresponding to the file version
                        of the xmltree
    :param logger: logger object for logging warnings, errors

    :returns: int with the number of kpoints
    """
    from masci_tools.util.schema_dict_util import evaluate_attribute, eval_simple_xpath
    from masci_tools.util.xml.common_functions import clear_xml
    import warnings

    if isinstance(xmltree, etree._ElementTree):
        xmltree, _ = clear_xml(xmltree)
        root = xmltree.getroot()
    else:
        root = xmltree

    modes = get_fleur_modes(root, schema_dict, logger=logger)

    alt_kpt_set = None
    if modes['band'] or modes['gw']:
        expected_mode = 'bands' if modes['band'] else 'gw'
        alt_kpts = eval_simple_xpath(root,
                                     schema_dict,
                                     'altKPointSet',
                                     list_return=True,
                                     logger=logger)
        for kpt_set in alt_kpts:
            if evaluate_attribute(kpt_set,
                                  schema_dict,
                                  'purpose',
                                  logger=logger) == expected_mode:
                alt_kpt_set = kpt_set
                break

    kpt_tag = None
    if alt_kpt_set is not None:
        kpt_tag = eval_simple_xpath(alt_kpt_set,
                                    schema_dict,
                                    'kPointList',
                                    list_return=True,
                                    logger=logger)
        if len(kpt_tag) == 0:
            kpt_tag = eval_simple_xpath(alt_kpt_set,
                                        schema_dict,
                                        'kPointCount',
                                        list_return=True,
                                        logger=logger)
            if len(kpt_tag) == 0:
                kpt_tag = None
            else:
                warnings.warn(
                    'kPointCount is not guaranteed to result in the given number of kpoints'
                )

    if kpt_tag is None:
        kpt_tag = eval_simple_xpath(root,
                                    schema_dict,
                                    'kPointList',
                                    not_contains='altKPointSet',
                                    list_return=True,
                                    logger=logger)
        if len(kpt_tag) == 0:
            kpt_tag = eval_simple_xpath(root,
                                        schema_dict,
                                        'kPointCount',
                                        not_contains='altKPointSet',
                                        list_return=True,
                                        logger=logger)
            if len(kpt_tag) == 0:
                raise ValueError('No kPointList or kPointCount found')
            else:
                warnings.warn(
                    'kPointCount is not guaranteed to result in the given number of kpoints'
                )

    kpt_tag = kpt_tag[0]

    nkpts = evaluate_attribute(kpt_tag, schema_dict, 'count', logger=logger)

    return nkpts
示例#15
0
def get_fleur_modes(xmltree, schema_dict, logger=None):
    """
    Determine the calculation modes of fleur for the given xml file. Calculation modes
    are things that change the produced files or output in the out.xml files

    :param xmltree: etree representing the fleur xml file
    :param schema_dict: schema dictionary corresponding to the file version
                        of the xmltree
    :param logger: logger object for logging warnings, errors

    :returns: dictionary with all the extracted calculation modes

    The following modes are inspected:

        - `jspin`: How many spins are considered in the calculation
        - `noco`: Is the calculation non-collinear?
        - `soc`: Is spin-orbit coupling included?
        - `relax`: Is the calculation a structure relaxation?
        - `gw`: Special mode for GW/Spex calculations
        - `force_theorem`: Is a Force theorem calculation performed?
        - `film`: Is the structure a film system
        - `ldau`: Is LDA+U included?
        - `dos`: Is it a density of states calculation?
        - `band`: Is it a bandstructure calculation?
        - `bz_integration`: How is the integration over the Brillouin-Zone performed?

    """
    from masci_tools.util.schema_dict_util import read_constants
    from masci_tools.util.schema_dict_util import evaluate_attribute, tag_exists
    from masci_tools.util.xml.common_functions import clear_xml

    if isinstance(xmltree, etree._ElementTree):
        xmltree, _ = clear_xml(xmltree)
        root = xmltree.getroot()
    else:
        root = xmltree
    constants = read_constants(root, schema_dict)

    fleur_modes = {}
    fleur_modes['jspin'] = evaluate_attribute(root,
                                              schema_dict,
                                              'jspins',
                                              logger=logger,
                                              constants=constants)

    noco = evaluate_attribute(root,
                              schema_dict,
                              'l_noco',
                              constants=constants,
                              logger=logger,
                              optional=True)
    if noco is None:
        noco = False
    fleur_modes['noco'] = noco

    soc = evaluate_attribute(root,
                             schema_dict,
                             'l_soc',
                             constants=constants,
                             logger=logger,
                             optional=True)
    if soc is None:
        soc = False
    fleur_modes['soc'] = soc

    relax = evaluate_attribute(root,
                               schema_dict,
                               'l_f',
                               constants=constants,
                               logger=logger,
                               optional=True)
    if relax is None:
        relax = False
    fleur_modes['relax'] = relax

    gw = evaluate_attribute(root,
                            schema_dict,
                            'gw',
                            constants=constants,
                            logger=logger,
                            optional=True)
    if gw is None:
        gw = False
    else:
        gw = gw != 0
    fleur_modes['gw'] = gw

    if schema_dict.inp_version > (0, 27):
        fleur_modes['force_theorem'] = tag_exists(root,
                                                  schema_dict,
                                                  'forceTheorem',
                                                  logger=logger)
    else:
        fleur_modes['force_theorem'] = False

    if schema_dict.inp_version >= (0, 33):
        if tag_exists(root, schema_dict, 'cFCoeffs', logger=logger):
            cf_coeff = any(
                evaluate_attribute(root,
                                   schema_dict,
                                   'potential',
                                   contains='cFCoeffs',
                                   logger=logger,
                                   list_return=True,
                                   optional=True))
            cf_coeff = cf_coeff or any(
                evaluate_attribute(root,
                                   schema_dict,
                                   'chargeDensity',
                                   contains='cFCoeffs',
                                   logger=logger,
                                   list_return=True,
                                   optional=True))
        else:
            cf_coeff = False
        fleur_modes['cf_coeff'] = cf_coeff
    else:
        fleur_modes['cf_coeff'] = False

    plot = None
    if tag_exists(root, schema_dict, 'plotting', logger=logger):
        plot = evaluate_attribute(root,
                                  schema_dict,
                                  'iplot',
                                  logger=logger,
                                  optional=True)

    if schema_dict.inp_version >= (0, 29) and plot is not None:
        plot = isinstance(plot, int) and plot != 0

    if plot is None:
        plot = False
    fleur_modes['plot'] = plot

    fleur_modes['film'] = tag_exists(root,
                                     schema_dict,
                                     'filmPos',
                                     logger=logger)
    fleur_modes['ldau'] = tag_exists(root,
                                     schema_dict,
                                     'ldaU',
                                     contains='species',
                                     logger=logger)
    fleur_modes['dos'] = evaluate_attribute(root,
                                            schema_dict,
                                            'dos',
                                            constants=constants,
                                            logger=logger)
    fleur_modes['band'] = evaluate_attribute(root,
                                             schema_dict,
                                             'band',
                                             constants=constants,
                                             logger=logger)
    fleur_modes['bz_integration'] = evaluate_attribute(
        root,
        schema_dict,
        'mode',
        constants=constants,
        tag_name='bzIntegration',
        logger=logger)

    greensf = False
    if schema_dict.inp_version >= (0, 32):
        #We make the assumption that the existence of a greensfCalculation
        #tag implies the existence of a greens function calculation
        greensf = tag_exists(root,
                             schema_dict,
                             'greensfCalculation',
                             contains='species',
                             logger=logger)
        greensf = greensf or tag_exists(root,
                                        schema_dict,
                                        'torgueCalculation',
                                        contains='species',
                                        logger=logger)
    fleur_modes['greensf'] = greensf

    ldahia = False
    if schema_dict.inp_version >= (0, 32):
        ldahia = tag_exists(root,
                            schema_dict,
                            'ldaHIA',
                            contains='species',
                            logger=logger)
    fleur_modes['ldahia'] = ldahia

    return fleur_modes
示例#16
0
def add_fleur_schema(path, overwrite=False):
    """
    Adds the FleurInput/OutputSchema from the specified path (folder containing the Schemas)
    to the folder with the correct version number and creates the schema_dicts

    :param path: path to the folder containing the schema files
    :param overwrite: bool, if True and the schema with the same version exists it will be
                      overwritten. Otherwise an error is raised
    """

    schema_path = os.path.join(path, 'FleurInputSchema.xsd')
    if os.path.isfile(schema_path):
        xmlschema = etree.parse(schema_path)
        xmlschema, _ = clear_xml(xmlschema)

        namespaces = {'xsd': 'http://www.w3.org/2001/XMLSchema'}
        inp_version = xmlschema.xpath('/xsd:schema/@version',
                                      namespaces=namespaces)[0]

        copy_schema_folder = os.path.abspath(
            os.path.join(PACKAGE_DIRECTORY, f'./{inp_version}'))
        copy_schema_file = os.path.abspath(
            os.path.join(copy_schema_folder, 'FleurInputSchema.xsd'))
        if os.path.isfile(copy_schema_file) and not overwrite:
            raise ValueError(
                f'Input Schema for version {inp_version} already exists. Use overwrite=True to replace the Schema'
            )

        os.makedirs(copy_schema_folder, exist_ok=True)
        if not os.path.isfile(
                os.path.abspath(os.path.join(copy_schema_folder,
                                             '__init__.py'))):
            with open(
                    os.path.abspath(
                        os.path.join(copy_schema_folder, '__init__.py')),
                    'w') as f:
                pass
        shutil.copy(schema_path, copy_schema_file)

    schema_path = os.path.join(path, 'FleurOutputSchema.xsd')
    if os.path.isfile(schema_path):
        xmlschema = etree.parse(schema_path)
        xmlschema, _ = clear_xml(xmlschema)

        namespaces = {'xsd': 'http://www.w3.org/2001/XMLSchema'}
        out_version = xmlschema.xpath('/xsd:schema/@version',
                                      namespaces=namespaces)[0]

        copy_schema_folder = os.path.abspath(
            os.path.join(PACKAGE_DIRECTORY, f'./{out_version}'))
        copy_schema_file = os.path.abspath(
            os.path.join(copy_schema_folder, 'FleurOutputSchema.xsd'))
        if os.path.isfile(copy_schema_file) and not overwrite:
            raise ValueError(
                f'Output Schema for version {out_version} already exists. Use overwrite=True to replace the Schema'
            )

        os.makedirs(copy_schema_folder, exist_ok=True)
        if not os.path.isfile(
                os.path.abspath(os.path.join(copy_schema_folder,
                                             '__init__.py'))):
            with open(
                    os.path.abspath(
                        os.path.join(copy_schema_folder, '__init__.py')),
                    'w') as f:
                pass
        shutil.copy(schema_path, copy_schema_file)
示例#17
0
def get_kpoints_data(xmltree, schema_dict, name=None, index=None, logger=None):
    """
    Get the kpoint sets defined in the given fleur xml file.

    .. warning::
        For file versions before Max5 the name argument is not valid

    :param xmltree: etree representing the fleur xml file
    :param schema_dict: schema dictionary corresponding to the file version
                        of the xmltree
    :param name: str, optional, if given only the kpoint set with the given name
                 is returned
    :param index: int, optional, if given only the kpoint set with the given index
                  is returned
    :param logger: logger object for logging warnings, errors

    :returns: tuple containing the kpoint information

    The tuple contains the following entries:

        1. :kpoints: dict or list (list if there is only one kpoint set),
                     containing the coordinates of the kpoints
        2. :weights: dict or list (list if there is only one kpoint set),
                     containing the weights of the kpoints
        3. :cell: numpy array, bravais matrix of the given system
        4. :pbc: list of booleans, determines in which directions periodic boundary conditions are applicable

    """
    from masci_tools.util.schema_dict_util import read_constants, eval_simple_xpath
    from masci_tools.util.schema_dict_util import evaluate_text, evaluate_attribute
    from masci_tools.util.xml.common_functions import clear_xml

    if name is not None and index is not None:
        raise ValueError(
            'Only provide one of index or name to select kpoint lists')

    if isinstance(xmltree, etree._ElementTree):
        xmltree, _ = clear_xml(xmltree)
        root = xmltree.getroot()
    else:
        root = xmltree

    constants = read_constants(root, schema_dict, logger=logger)

    cell, pbc = get_cell(root, schema_dict, logger=logger)

    kpointlists = eval_simple_xpath(root,
                                    schema_dict,
                                    'kPointList',
                                    list_return=True,
                                    logger=logger)

    if len(kpointlists) == 0:
        raise ValueError('No Kpoint lists found in the given inp.xml')

    labels = [kpoint_set.attrib.get('name') for kpoint_set in kpointlists]
    if name is not None and name not in labels:
        raise ValueError(f'Found no Kpoint list with the name: {name}'
                         f'Available list names: {labels}')

    if index is not None:
        try:
            kpointlists = [kpointlists[index]]
        except IndexError as exc:
            raise ValueError(f'No kPointList with index {index} found.'
                             f' Only {len(kpointlists)} available') from exc

    kpoints_data = {}
    weights_data = {}
    for kpointlist in kpointlists:

        label = evaluate_attribute(kpointlist,
                                   schema_dict,
                                   'name',
                                   logger=logger)

        if name is not None and name != label:
            continue

        kpoints = evaluate_text(kpointlist,
                                schema_dict,
                                'kPoint',
                                constants=constants,
                                list_return=True,
                                logger=logger)
        weights = evaluate_attribute(kpointlist,
                                     schema_dict,
                                     'weight',
                                     constants=constants,
                                     list_return=True,
                                     logger=logger)

        if not isinstance(kpoints[0], list):
            kpoints = [kpoints]
            weights = [weights]

        kpoints_data[label] = kpoints
        weights_data[label] = weights

    if len(kpoints_data) == 1:
        _, kpoints_data = kpoints_data.popitem()
        _, weights_data = weights_data.popitem()

    return kpoints_data, weights_data, cell, pbc