def test_convert_attribute_to_xml(attr_value, types, results):
    """
    Test of the convert_xml_attribute function
    """
    from masci_tools.util.xml.converters import convert_attribute_to_xml

    expected_val, expected_suc = results
    if not expected_suc:
        with pytest.raises(ValueError):
            ret_val, suc = convert_attribute_to_xml(attr_value, types)
    else:
        ret_val, suc = convert_attribute_to_xml(attr_value, types)
        assert ret_val == expected_val
        assert suc == expected_suc
def test_convert_attribute_to_xml_warnings(caplog, attr_value, types, results, warnings):
    """
    Test of the convert_xml_attribute function
    """
    from masci_tools.util.xml.converters import convert_attribute_to_xml

    expected_val, expected_suc = results

    with caplog.at_level(logging.WARNING):
        ret_val, suc = convert_attribute_to_xml(attr_value, types, logger=LOGGER)
    assert ret_val == expected_val
    assert suc == expected_suc

    if len(warnings) == 0:
        assert caplog.text == ''
    else:
        for expected_warning in warnings:
            assert expected_warning in caplog.text
Ejemplo n.º 3
0
def set_kpointlist_max4(xmltree, schema_dict, kpoints, weights):
    """
    Explicitely create a kPointList from the given kpoints and weights. This
    routine is specific to input versions Max4 and before and will replace any
    existing kPointCount, kPointMesh, ... with the specified kPointList

    :param xmltree: xml tree that represents inp.xml
    :param schema_dict: InputSchemaDict containing all information about the structure of the input
    :param kpoints: list or array containing the **relative** coordinates of the kpoints
    :param weights: list or array containing the weights of the kpoints

    :returns: an xmltree of the inp.xml file with changes.
    """
    from masci_tools.util.schema_dict_util import eval_simple_xpath
    from masci_tools.util.xml.converters import convert_text_to_xml, convert_attribute_to_xml
    from lxml import etree
    import numpy as np

    if not isinstance(kpoints, (list, np.ndarray)) or not isinstance(weights, (list, np.ndarray)):
        raise ValueError('kPoints and weights have to be given as a list or array')

    if len(kpoints) != len(weights):
        raise ValueError('kPoints and weights do not have the same length')

    nkpts = len(kpoints)

    bzintegration_tag = eval_simple_xpath(xmltree, schema_dict, 'bzIntegration')

    for child in bzintegration_tag.iterchildren():
        if 'kPoint' in child.tag:
            bzintegration_tag.remove(child)

    new_kpo = etree.Element('kPointList', posScale='1.0', weightScale='1.0', count=f'{nkpts:d}')
    for kpoint, weight in zip(kpoints, weights):
        weight, _ = convert_attribute_to_xml(weight, ['float', 'float_expression'])
        new_k = etree.Element('kPoint', weight=weight)
        text, _ = convert_text_to_xml(kpoint, [{'type': ['float', 'float_expression'], 'length': 3}])
        new_k.text = text
        new_kpo.append(new_k)

    xmltree = create_tag(xmltree, schema_dict, new_kpo, not_contains='altKPoint')

    return xmltree
Ejemplo n.º 4
0
def xml_set_attrib_value(xmltree,
                         schema_dict,
                         xpath,
                         base_xpath,
                         attributename,
                         attribv,
                         occurrences=None,
                         create=False):
    """
    Sets an attribute in a xmltree to a given value. By default the attribute will be set
    on all nodes returned for the specified xpath.
    If there are no nodes under the specified xpath a tag can be created with `create=True`.
    The attribute values are converted automatically according to the types of the attribute
    with :py:func:`~masci_tools.util.xml.converters.convert_attribute_to_xml()` if they
    are not `str` already.

    :param xmltree: an xmltree that represents inp.xml
    :param schema_dict: InputSchemaDict containing all information about the structure of the input
    :param xpath: a path where to set the attributes
    :param base_xpath: path where to place a new tag without complex syntax ([] conditions and so on)
    :param attributename: the attribute name to set
    :param attribv: value or list of values to set
    :param occurrences: int or list of int. Which occurence of the node to set. By default all are set.
    :param create: bool optional (default False), if True the tag is created if is missing

    :raises ValueError: If the conversion to string failed
    :raises ValueError: If the tag is missing and `create=False`
    :raises ValueError: If the attributename is not allowed on the base_xpath

    :returns: xmltree with set attribute
    """

    from masci_tools.util.xml.xml_setters_basic import xml_set_attrib_value_no_create
    from masci_tools.util.xml.converters import convert_attribute_to_xml
    from masci_tools.util.xml.common_functions import check_complex_xpath, split_off_tag

    check_complex_xpath(xmltree, base_xpath, xpath)

    if create:
        nodes = eval_xpath_create(xmltree,
                                  schema_dict,
                                  xpath,
                                  base_xpath,
                                  create_parents=True,
                                  occurrences=occurrences,
                                  list_return=True)
    else:
        nodes = eval_xpath(xmltree, xpath, list_return=True)

    if len(nodes) == 0:
        raise ValueError(
            f"Could not set attribute '{attributename}' on path '{xpath}' "
            'because atleast one subtag is missing. '
            'Use create=True to create the subtags')

    _, tag_name = split_off_tag(base_xpath)

    attribs = schema_dict['tag_info'][base_xpath]['attribs']
    if attributename not in attribs:
        raise ValueError(
            f"The key '{attributename}' is not expected for this version of the input for the '{tag_name}' tag. "
            f'Allowed attributes are: {attribs.original_case.values()}')
    attributename = attribs.original_case[attributename]

    converted_attribv, suc = convert_attribute_to_xml(
        attribv, schema_dict['attrib_types'][attributename])

    if '/fleurInput/forceTheorem/' in base_xpath and attributename in (
            'theta', 'phi', 'ef_shift'):
        #Special case for theta and phi attributes on forceTheorem tags
        #In Max5/5.1 They are entered as FleurDouble but can be a list. Since
        #the attribute setting so far does not support this we convert the values explicitely
        #here
        if isinstance(converted_attribv, list):
            converted_attribv = ' '.join(converted_attribv)

    return xml_set_attrib_value_no_create(xmltree,
                                          xpath,
                                          attributename,
                                          converted_attribv,
                                          occurrences=occurrences)
Ejemplo n.º 5
0
def set_kpointlist(xmltree,
                   schema_dict,
                   kpoints,
                   weights,
                   name=None,
                   kpoint_type='path',
                   special_labels=None,
                   switch=False,
                   overwrite=False):
    """
    Explicitely create a kPointList from the given kpoints and weights. This routine will add the
    specified kPointList with the given name.

    .. warning::
        For input versions Max4 and older **all** keyword arguments are not valid (`name`, `kpoint_type`,
        `special_labels`, `switch` and `overwrite`)

    :param xmltree: xml tree that represents inp.xml
    :param schema_dict: InputSchemaDict containing all information about the structure of the input
    :param kpoints: list or array containing the **relative** coordinates of the kpoints
    :param weights: list or array containing the weights of the kpoints
    :param name: str for the name of the list, if not given a default name is generated
    :param kpoint_type: str specifying the type of the kPointList ('path', 'mesh', 'spex', 'tria', ...)
    :param special_labels: dict mapping indices to labels. The labels will be inserted for the kpoints
                           corresponding to the given index
    :param switch: bool, if True the kPointlist will be used by Fleur when starting the next calculation
    :param overwrite: bool, if True and a kPointlist with the given name already exists it will be overwritten

    :returns: an xmltree of the inp.xml file with changes.
    """
    from masci_tools.util.schema_dict_util import evaluate_attribute
    from masci_tools.util.xml.converters import convert_text_to_xml, convert_attribute_to_xml
    from masci_tools.util.xml.xml_setters_basic import xml_delete_tag
    from lxml import etree
    import numpy as np

    if not isinstance(kpoints, (list, np.ndarray)) or not isinstance(weights, (list, np.ndarray)):
        raise ValueError('kPoints and weights have to be given as a list or array')

    if len(kpoints) != len(weights):
        raise ValueError('kPoints and weights do not have the same length')

    kpointlist_xpath = get_tag_xpath(schema_dict, 'kPointList')
    nkpts = len(kpoints)

    if special_labels is None:
        special_labels = {}

    existing_labels = evaluate_attribute(xmltree, schema_dict, 'name', contains='kPointList', list_return=True)

    if name is None:
        name = f'default-{len(existing_labels)+1}'

    if name in existing_labels:
        if not overwrite:
            raise ValueError(f'kPointList named {name} already exists. Use overwrite=True to ignore')

        xmltree = xml_delete_tag(xmltree, f"{kpointlist_xpath}[@name='{name}']")

    new_kpo = etree.Element('kPointList', name=name, count=f'{nkpts:d}', type=kpoint_type)
    for indx, (kpoint, weight) in enumerate(zip(kpoints, weights)):
        weight, _ = convert_attribute_to_xml(weight, ['float', 'float_expression'])
        if indx in special_labels:
            new_k = etree.Element('kPoint', weight=weight, label=special_labels[indx])
        else:
            new_k = etree.Element('kPoint', weight=weight)
        text, _ = convert_text_to_xml(kpoint, [{'type': ['float', 'float_expression'], 'length': 3}])
        new_k.text = text
        new_kpo.append(new_k)

    xmltree = create_tag(xmltree, schema_dict, new_kpo)

    if switch:
        xmltree = switch_kpointset(xmltree, schema_dict, name)

    return xmltree