Esempio n. 1
0
def test_xml_set_first_attribv(inpxml_etree):
    from aiida_fleur.tools.xml_util import xml_set_first_attribv, eval_xpath
    etree = inpxml_etree(TEST_INP_XML_PATH)

    xml_set_first_attribv(etree, '/fleurInput/calculationSetup/cutoffs', 'Gmax', 11.00)
    assert float(eval_xpath(etree, '/fleurInput/calculationSetup/cutoffs/@Gmax')) == 11

    xml_set_first_attribv(etree, '/fleurInput/atomGroups/atomGroup', 'species', 'TEST-1')
    assert eval_xpath(etree, '/fleurInput/atomGroups/atomGroup/@species') == ['TEST-1', 'Pt-1']
def test_fleurinp_modifier2(create_fleurinp, inpxml_etree):
    """Tests if fleurinp_modifier with various other modifations methods,
    the detailed tests for method functionality is tested elsewhere."""
    from aiida_fleur.tools.xml_util import eval_xpath
    fleurinp_tmp = create_fleurinp(inpxmlfilefolder)
    etree = inpxml_etree(inpxmlfilefolder)

    fm = FleurinpModifier(fleurinp_tmp)

    actions = fm.get_avail_actions()
    assert isinstance(actions, dict)

    new_tag = eval_xpath(etree, '/fleurInput/calculationSetup/scfLoop')
    fm.delete_tag('/fleurInput/calculationSetup/scfLoop')
    fm.replace_tag('/fleurInput/calculationSetup/cutoffs', new_tag)
    fm.delete_att('/fleurInput/calculationSetup/soc', 'theta')
    fm.create_tag('/fleurInput/calculationSetup/soc', 'theta')
    fm.xml_set_all_text('/fleurInput/cell/symmetryOperations/symOp/row-1', 'test text')
    fm.xml_set_text_occ('/fleurInput/cell/symmetryOperations/symOp/row-1', 'test text')
    fm.xml_set_text('/fleurInput/cell/symmetryOperations/symOp/row-1', 'test text')
    fm.xml_set_all_attribv('/fleurInput/calculationSetup/soc', 'theta', 12)
    fm.xml_set_first_attribv('/fleurInput/calculationSetup/soc', 'theta', 12)
    fm.xml_set_attribv_occ('/fleurInput/calculationSetup/soc', 'theta', 12)
    fm.set_species_label('                 222', {'mtSphere': {'radius': 3.333}})
    fm.set_atomgr_att_label(attributedict={'force': [('relaxXYZ', 'FFF')]}, atom_label='                 222')
    fm.set_atomgr_att(attributedict={'force': [('relaxXYZ', 'TFF')]}, species='Fe-1')

    fm.set_nkpts(500, gamma='T')
    fm.set_kpath({'gamma': (0, 0, 0), 'L': (0.1, 0.1, 0.1)}, 300)
    fm.add_num_to_att('/fleurInput/calculationSetup/soc', 'theta', 4)
    #fm.set_species1
    fm.show()
Esempio n. 3
0
def extract_corelevels(outxmlfile, options=None):
    """
    Extracts corelevels out of out.xml files

    :params outxmlfile: path to out.xml file

    :param options: A dict: 'iteration' : X/'all'
    :returns corelevels: A list of the form:

    .. code-block:: python

            [atomtypes][spin][dict={atomtype : '', corestates : list_of_corestates}]
            [atomtypeNumber][spin]['corestates'][corestate number][attribute]
            get corelevel energy of first atomtype, spin1, corelevels[0][0]['corestates'][i]['energy']

    :example of output:

    .. code-block:: python

                        [[{'atomtype': '     1',
                        'corestates': [{'energy': -3.6489930627,
                                        'j': ' 0.5',
                                        'l': ' 0',
                                        'n': ' 1',
                                        'weight': 2.0}],
                        'eigenvalue_sum': '     -7.2979861254',
                        'kin_energy': '     13.4757066163',
                        'spin': '1'}],
                        [{'atomtype': '     2',
                        'corestates': [{'energy': -3.6489930627,
                                        'j': ' 0.5',
                                        'l': ' 0',
                                        'n': ' 1',
                                        'weight': 2.0}],
                        'eigenvalue_sum': '     -7.2979861254',
                        'kin_energy': '     13.4757066163',
                        'spin': '1'}]]

    """
    ##########################################
    #1. read out.xml in etree

    #2. get all species
    #3. get number of atom types and their species

    #4 get corelevel dimension from atoms types.

    #5 init saving arrays:
    #list length number of atom types, which contains dictionaries:
    # in the form { 'species' : species, 'coresetup' : '', 'atom' : W , 'corelevels' : []} lists of corelevels from last iteration (Do i want all iterations, optional?) Or do I even want a dictionaries of corelevels? (but coresetup is in atom type info

    #6 parse corelevels:
    # get last iteration
    # fill corelevel list
    #######################################
    ########################
    #XPATHS to maintain

    species_xpath = '/fleurOutput/inputData/atomSpecies'
    iteration_xpath = '/fleurOutput/scfLoop/iteration'
    atomgroup_xpath = '/fleurOutput/inputData/atomGroups'
    coreconfig_xpath = 'electronConfig/coreConfig/text()'
    valenceconfig_xpath = 'electronConfig/valenceConfig/text()'
    state_occ_xpath = 'electronConfig/stateOccupation'

    relcoreStates_xpath = 'coreStates'
    relpos_xpath = 'relPos'
    abspos_xpath = 'absPos'
    filmpos_xpath = 'filmPos'
    #TODO all the attribute names...
    ######################

    #1. read out.xml in etree
    # TODO this should be common, moved somewhere else and importet
    parsed_data = {}
    outfile_broken = False
    parse_xml = True
    parser = etree.XMLParser(recover=False)  #, remove_blank_text=True)
    parser_info = {'parser_warnings': [], 'unparsed': []}

    try:
        tree = etree.parse(outxmlfile, parser)
    except etree.XMLSyntaxError:
        outfile_broken = True
        #print 'broken xml'
        parser_info['parser_warnings'].append(
            '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(recover=True)  #, remove_blank_text=True)
        try:
            tree = etree.parse(outxmlfile, parser)
        except etree.XMLSyntaxError:
            parser_info['parser_warnings'].append(
                'Skipping the parsing of the xml file. Repairing was not possible.'
            )
            parse_xml = False

    #if parse_xml:
    root = tree.getroot()

    # 2. get all species from input
    # get element, name, coreStates
    # TODO why can this not be eval_xpath2?
    species_nodes = eval_xpath(root, species_xpath, parser_info)
    species_atts = {}
    species_names = []
    for species in species_nodes:
        species_name = species.get('name')
        species_corestates = species.get('coreStates')
        species_element = species.get('element')
        species_atomicnumber = species.get('atomicNumber')
        species_magMom = species.get('magMom')
        #TODO sometimes not in inp.xml... what if it is not there
        coreconfig = eval_xpath(species, coreconfig_xpath, parser_info)
        valenceconfig = eval_xpath(species, valenceconfig_xpath, parser_info)
        state_occ = eval_xpath2(species, state_occ_xpath, parser_info)

        #parse state occ
        state_results = []
        for tag in state_occ:  #always a list?
            state = tag.get('state')
            spinUp = tag.get('spinUp')
            spinDown = tag.get('spinDown')
            state_results.append({state: [spinUp, spinDown]})

        species_atts[species_name] = {
            'name': species_name,
            'corestates': species_corestates,
            'element': species_element,
            'atomgroups': [],
            'mag_mom': species_magMom,
            'atomic_number': species_atomicnumber,
            'coreconfig': coreconfig,
            'valenceconfig': valenceconfig,
            'stateOccupation': state_results
        }
        species_names.append(species_name)

    #3. get number of atom types and their species from input
    atomtypes = []
    atomgroup_nodes = eval_xpath(root, atomgroup_xpath,
                                 parser_info)  #/fleurinp/
    # always a list?
    for atomgroup in atomgroup_nodes:
        types_dict = {}
        group_species = atomgroup.get('species')
        if group_species in species_names:
            species_atts[group_species]['atomgroups'].append(atomgroup)
            element = species_atts[group_species]['element']
            atomicnumber = int(species_atts[group_species]['atomic_number'])
            coreconf = species_atts[group_species]['coreconfig']
            valenceconf = species_atts[group_species]['valenceconfig']
            stateocc = species_atts[group_species]['stateOccupation']
            a = eval_xpath2(
                atomgroup, relpos_xpath, parser_info) + eval_xpath2(
                    atomgroup, abspos_xpath, parser_info) + eval_xpath2(
                        atomgroup, filmpos_xpath, parser_info)  # always list
            natoms = len(a)
            types_dict = {
                'species': group_species,
                'element': element,
                'atomic_number': atomicnumber,
                'coreconfig': coreconf,
                'valenceconfig': valenceconf,
                'stateOccupation': stateocc,
                'natoms': natoms
            }
        atomtypes.append(types_dict)

    #natomgroup = len(atomgroup_nodes)
    #print(natomgroup)
    corelevels = []

    #4 get corelevel dimension from atoms types.
    #5 init saving arrays:
    #6 parse corelevels:

    iteration_nodes = eval_xpath2(root, iteration_xpath, parser_info)
    nIteration = len(iteration_nodes)
    if nIteration >= 1:
        iteration_to_parse = iteration_nodes[-1]  #TODO:Optional all or other
        #print iteration_to_parse
        corestatescards = eval_xpath2(iteration_to_parse, relcoreStates_xpath,
                                      parser_info)
        # maybe does not return a list...
        for atype in atomtypes:  # spin=2 is already in there
            corelevels.append([])

        for corestatescard in corestatescards:
            corelv = parse_state_card(corestatescard, iteration_to_parse,
                                      parser_info)
            corelevels[int(corelv['atomtype']) - 1].append(
                corelv)  # is corelv['atomtype'] always an integer?

    #print parser_info
    #pprint(corelevels[0][1]['corestates'][2]['energy'])
    #corelevels[atomtypeNumber][spin]['corestates'][corestate number][attribute]
    return corelevels, atomtypes
Esempio n. 4
0
def set_nmmpmat(fleurinp_tree_copy, nmmp_lines_copy, species_name, orbital, spin,\
                occStates=None, denmat=None, phi=None, theta=None):
    """Routine sets the block in the n_mmp_mat file specified by species_name, orbital and spin
    to the desired density matrix

    :param fleurinp_tree_copy: an xmltree that represents inp.xml
    :param nmmp_lines_copy: list of lines in the n_mmp_mat file
    :param species_name: string, name of the species you want to change
    :param orbital: integer, orbital quantum number of the LDA+U procedure to be modified
    :param spin: integer, specifies which spin block should be modified
    :param occStates: list, sets the diagonal elements of the density matrix and everything
                      else to zero
    :param denmat: matrix, specify the density matrix explicitely
    :param phi: float, optional angle (radian), by which to rotate the density matrix before writing it
    :param theta: float, optional angle (radian), by which to rotate the density matrix before writing it

    :raises ValueError: If something in the input is wrong
    :raises KeyError: If no LDA+U procedure is found on a species
    """

    #All lda+U procedures have to be considered since we need to keep the order
    ldau_xpath = '/fleurInput/atomSpecies/species/ldaU'
    magnetism_xpath = '/fleurInput/calculationSetup/magnetism'

    if species_name == 'all':
        species_xpath = '/fleurInput/atomSpecies/species'
    elif species_name[:4] == 'all-':  #format all-<string>
        species_xpath = '/fleurInput/atomSpecies/species[contains(@name,"{}")]'.format(species_name[4:])
    else:
        species_xpath = '/fleurInput/atomSpecies/species[@name = "{}"]'.format(species_name)

    all_species = eval_xpath2(fleurinp_tree_copy, species_xpath)

    #Get number of spins (TODO for develop version also read l_mtnocoPot)
    mag_elem = eval_xpath(fleurinp_tree_copy, magnetism_xpath)
    nspins = convert_to_int(get_xml_attribute(mag_elem, 'jspins'), suc_return=False)

    if spin > nspins:
        raise ValueError(f'Invalid input: spin {spin} requested, but input has only {nspins} spins')

    all_ldau = eval_xpath2(fleurinp_tree_copy, ldau_xpath)
    numRows = nspins * 14 * len(all_ldau)

    #Check that numRows matches the number of lines in nmmp_lines_copy
    #If not either there was an n_mmp_mat file present in Fleurinp before and a lda+u calculation
    #was added or removed or the n_mmp_mat file was initialized and after the fact lda+u procedures were added
    #or removed. In both cases the resolution of this modification is very involved so we throw an error
    if nmmp_lines_copy is not None:
        #Remove blank lines
        while '' in nmmp_lines_copy:
            nmmp_lines_copy.remove('')
        if numRows != len(nmmp_lines_copy):
            raise ValueError('The number of lines in n_mmp_mat does not match the number expected from '+\
                             'the inp.xml file. Either remove the existing file before making modifications '+\
                             'and only use set_nmmpmat after all modifications to the inp.xml')

    if phi is not None or theta is not None:
        if phi is None:
            phi = 0.0
        if theta is None:
            theta = 0.0
        d_wigner = get_wigner_matrix(orbital, phi, theta)

    for species in all_species:
        current_name = get_xml_attribute(species, 'name')

        #Determine the place at which the given U procedure occurs
        ldau_index = None
        for index, ldau in enumerate(all_ldau):
            ldau_species = get_xml_attribute(ldau.getparent(), 'name')
            ldau_orbital = convert_to_int(get_xml_attribute(ldau, 'l'), suc_return=False)
            if current_name == ldau_species and ldau_orbital == orbital:
                ldau_index = index

        if ldau_index is None:
            raise KeyError(f'No LDA+U procedure found on species {current_name} with l={orbital}')

        if occStates is not None:
            #diagonal density matrix
            denmatpad = np.zeros((7, 7), dtype=complex)

            #Fill out the outer states with zero
            occStatespad = np.zeros(7, dtype=complex)
            occStatespad[3 - orbital:4 + orbital] = occStates[:]

            for i, occ in enumerate(occStatespad):
                denmatpad[i, i] = occ
        elif denmat is not None:
            #density matrix is completely specified
            denmatpad = np.zeros((7, 7), dtype=complex)
            denmatpad[3 - orbital:4 + orbital, 3 - orbital:4 + orbital] = denmat
        else:
            raise ValueError('Invalid definition of density matrix. Provide either occStates or denmat')

        if phi is not None and theta is not None:
            #Rotate the density matrix
            denmatpad = d_wigner.T.conj().dot(denmatpad.dot(d_wigner))

        #check if fleurinp has a specified n_mmp_mat file if not initialize it with 0
        if nmmp_lines_copy is None:
            nmmp_lines_copy = []
            for index in range(numRows):
                nmmp_lines_copy.append(''.join(map(str, [f'{0.0:20.13f}' for x in range(7)])))

        #Select the right block from n_mmp_mat and overwrite it with denmatpad
        startRow = ((spin - 1) * len(all_ldau) + ldau_index) * 14
        for index in range(startRow, startRow + 14):
            currentLine = index - startRow
            currentRow = currentLine // 2
            if currentLine % 2 == 0:
                #Line ends with a real part
                nmmp_lines_copy[index] = ''.join(map(str, [f'{x.real:20.13f}{x.imag:20.13f}'\
                                                           for x in denmatpad[currentRow, :3]])) +\
                                         f'{denmatpad[currentRow, 3].real:20.13f}'
            else:
                #Line begins with a imaginary part
                nmmp_lines_copy[index] = f'{denmatpad[currentRow, 3].imag:20.13f}' +\
                                         ''.join(map(str, [f'{x.real:20.13f}{x.imag:20.13f}'\
                                                           for x in denmatpad[currentRow, 4:]]))

    return nmmp_lines_copy
Esempio n. 5
0
def validate_nmmpmat(fleurinp_tree, nmmp_lines):
    """
    Checks that the given nmmp_lines is valid with the given fleurinp_tree

    Checks that the number of blocks is as expected from the inp.xml and each
    block does not contain non-zero elements outside their size given by the
    orbital quantum number in the inp.xml. Additionally the occupations, i.e.
    diagonal elements are checked that they are in between 0 and the maximum
    possible occupation

    :param fleurinp_tree_copy: an xmltree that represents inp.xml
    :param nmmp_lines_copy: list of lines in the n_mmp_mat file

    :raises ValueError: if any of the above checks are violated.
    """

    #First check the number of ldau procedures
    ldau_xpath = '/fleurInput/atomSpecies/species/ldaU'
    magnetism_xpath = '/fleurInput/calculationSetup/magnetism'

    #Get number of spins (TODO for develop version also read l_mtnocoPot)
    mag_elem = eval_xpath(fleurinp_tree, magnetism_xpath)
    nspins = convert_to_int(get_xml_attribute(mag_elem, 'jspins'), suc_return=False)

    all_ldau = eval_xpath2(fleurinp_tree, ldau_xpath)
    numRows = nspins * 14 * len(all_ldau)

    tol = 0.01
    if nspins > 1:
        maxOcc = 1.0
    else:
        maxOcc = 2.0

    #Check that numRows matches the number of lines in nmmp_lines
    if nmmp_lines is not None:
        #Remove blank lines
        while '' in nmmp_lines:
            nmmp_lines.remove('')
        if numRows != len(nmmp_lines):
            raise ValueError('The number of lines in n_mmp_mat does not match the number expected from '+\
                             'the inp.xml file.')
    else:
        return

    #Now check for each block if the numbers make sense
    #(no numbers outside the valid area and no nonsensical occupations)
    for ldau_index, ldau in enumerate(all_ldau):

        orbital = convert_to_int(get_xml_attribute(ldau, 'l'), suc_return=False)
        species_name = get_xml_attribute(ldau.getparent(), 'name')

        for spin in range(nspins):
            startRow = (spin * len(all_ldau) + ldau_index) * 14

            for index in range(startRow, startRow + 14):
                currentLine = index - startRow
                currentRow = currentLine // 2

                line = nmmp_lines[index].split('    ')
                while '' in line:
                    line.remove('')
                nmmp = np.array([float(x) for x in line])

                outside_val = False
                if abs(currentRow - 3) > orbital:
                    if any(np.abs(nmmp) > 1e-12):
                        outside_val = True

                if currentLine % 2 == 0:
                    #m=-3 to m=0 real part
                    if any(np.abs(nmmp[:(3 - orbital) * 2]) > 1e-12):
                        outside_val = True

                else:
                    #m=0 imag part to m=3
                    if any(np.abs(nmmp[orbital * 2 + 1:]) > 1e-12):
                        outside_val = True

                if outside_val:
                    raise ValueError(f'Found value outside of valid range in for species {species_name}, spin {spin+1}'
                                     f' and l={orbital}')

                invalid_diag = False
                if spin < 2:
                    if currentRow - 3 <= 0 and currentLine % 2 == 0:
                        if nmmp[currentRow * 2] < -tol or nmmp[currentRow * 2] > maxOcc + tol:
                            invalid_diag = True
                    else:
                        if nmmp[(currentRow - 3) * 2 - 1] < -tol or nmmp[(currentRow - 3) * 2 - 1] > maxOcc + tol:
                            invalid_diag = True

                if invalid_diag:
                    raise ValueError(f'Found invalid diagonal element for species {species_name}, spin {spin+1}'
                                     f' and l={orbital}')