예제 #1
0
    def test_set_inpchanges(self, inpxml_etree, name, path):
        from aiida_fleur.tools.xml_util import set_inpchanges, eval_xpath2
        etree = inpxml_etree(TEST_INP_XML_PATH)

        skip_paths = ['atomSpecies', 'atomGroups', 'bzIntegration', 'kPointCount', 'bulkLattice', 'bravaisMatrix', 'a1']

        if any(x in path for x in skip_paths):
            pytest.skip('This attribute is not tested for FePt/inp.xml')
        elif name in self.xml_structure[11].keys():
            set_inpchanges(etree, change_dict={name: 'test'})
            if name not in ['relPos', 'absPos']:
                result = eval_xpath2(etree, path)[0]
                assert result.text == 'test'
        elif name in self.xml_structure[0]:
            set_inpchanges(etree, change_dict={name: 'T'})
            result = eval_xpath2(etree, path + '/@{}'.format(name))
            assert result[0] == 'T'
        elif name in self.xml_structure[4] or name in self.xml_structure[3]:
            set_inpchanges(etree, change_dict={name: 33})
            result = eval_xpath2(etree, path + '/@{}'.format(name))
            assert float(result[0]) == 33
        elif name in self.xml_structure[5]:
            set_inpchanges(etree, change_dict={name: 'test'})
            if name == 'xcFunctional':
                result = eval_xpath2(etree, path + '/@{}'.format('name'))
            else:
                result = eval_xpath2(etree, path + '/@{}'.format(name))
            assert result[0] == 'test'
        else:
            raise BaseException('A switch that you want to set is not one of the supported types.'
                                'Or you made a mistake during new switch registration')
예제 #2
0
def test_delete_tag(inpxml_etree):
    from aiida_fleur.tools.xml_util import delete_tag, eval_xpath2
    etree = inpxml_etree(TEST_INP_XML_PATH)

    assert eval_xpath2(etree, '/fleurInput/atomGroups/atomGroup/filmPos') != []

    delete_tag(etree, '/fleurInput/atomGroups/atomGroup/filmPos')
    assert eval_xpath2(etree, '/fleurInput/atomGroups/atomGroup/filmPos') == []
예제 #3
0
def test_delete_att(inpxml_etree):
    from aiida_fleur.tools.xml_util import delete_att, eval_xpath2
    etree = inpxml_etree(TEST_INP_XML_PATH)

    assert eval_xpath2(etree, '/fleurInput/atomGroups/atomGroup/filmPos/@label')[0] == '                 222'

    delete_att(etree, '/fleurInput/atomGroups/atomGroup/filmPos', 'label')
    assert eval_xpath2(etree, '/fleurInput/atomGroups/atomGroup/filmPos/@label') == []
예제 #4
0
def test_xml_set_text(inpxml_etree):
    from aiida_fleur.tools.xml_util import xml_set_text, eval_xpath2
    etree = inpxml_etree(TEST_INP_XML_PATH)

    second_text = eval_xpath2(etree, '/fleurInput/atomGroups/atomGroup/filmPos')[1].text

    xml_set_text(etree, '/fleurInput/atomGroups/atomGroup/filmPos', 'test_text')
    assert eval_xpath2(etree, '/fleurInput/atomGroups/atomGroup/filmPos')[0].text == 'test_text'
    assert eval_xpath2(etree, '/fleurInput/atomGroups/atomGroup/filmPos')[1].text == second_text
예제 #5
0
파일: scf.py 프로젝트: chrinide/aiida-fleur
    def get_res(self):
        """
        Check how the last Fleur calculation went
        Parse some results.
        """
        # TODO maybe do this different
        # or if complexer output node exists take from there.

        xpath_energy = '/fleurOutput/scfLoop/iteration/totalEnergy/@value'
        xpath_distance = '/fleurOutput/scfLoop/iteration/densityConvergence/chargeDensity/@distance'  # be aware of magnetism
        #densityconvergence_xpath = 'densityConvergence'
        #chargedensity_xpath = 'densityConvergence/chargeDensity'
        #overallchargedensity_xpath = 'densityConvergence/overallChargeDensity'
        #spindensity_xpath = 'densityConvergence/spinDensity'
        if self.ctx.successful:
            #self.report('last calc successful = {}'.format(self.ctx.successful))
            last_calc = self.ctx.last_calc
            '''
            spin = get_xml_attribute(eval_xpath(root, magnetism_xpath), jspin_name)

                charge_densitys = eval_xpath(iteration_node, chargedensity_xpath)
                charge_density1 = get_xml_attribute(charge_densitys[0], distance_name)
                write_simple_outnode(
                    charge_density1, 'float', 'charge_density1', simple_data)

                charge_density2 = get_xml_attribute(charge_densitys[1], distance_name)
                write_simple_outnode(
                    charge_density2, 'float', 'charge_density2', simple_data)

                spin_density = get_xml_attribute(
                    eval_xpath(iteration_node, spindensity_xpath), distance_name)
                write_simple_outnode(
                    spin_density, 'float', 'spin_density', simple_data)

                overall_charge_density = get_xml_attribute(
                    eval_xpath(iteration_node, overallchargedensity_xpath), distance_name)
                write_simple_outnode(
                    overall_charge_density, 'float', 'overall_charge_density', simple_data)

            '''
            #TODO: dangerous, can fail, error catching
            outxmlfile = last_calc.out.output_parameters.dict.outputfile_path
            #outpara = last_calc.get('output_parameters', None)
            #outxmlfile = outpara.dict.outputfile_path
            tree = etree.parse(outxmlfile)
            root = tree.getroot()
            energies = eval_xpath2(root, xpath_energy)
            for energy in energies:
                self.ctx.total_energy.append(float(energy))

            distances = eval_xpath2(root, xpath_distance)
            for distance in distances:
                self.ctx.distance.append(float(distance))
        else:
            errormsg = 'ERROR: scf wc was not successful, check log for details'
            self.control_end_wc(errormsg)
            return  # otherwise this will lead to erros further down
예제 #6
0
    def test_shift_species_label(self, inpxml_etree, att_name, tag):
        from aiida_fleur.tools.xml_util import shift_value_species_label, eval_xpath2
        import math
        etree = inpxml_etree(TEST_INP_XML_PATH)
        path = '/fleurInput/atomSpecies/species[@name = "Fe-1"]/' + tag + '/@' + att_name
        old_result = eval_xpath2(etree, path)[0]

        shift_value_species_label(etree, '                 222', att_name, 3, mode='abs')
        result = eval_xpath2(etree, path)[0]

        assert math.isclose(float(result) - float(old_result), 3)
예제 #7
0
    def test_shift_species_label_all_rel(self, inpxml_etree, att_name, tag):
        from aiida_fleur.tools.xml_util import shift_value_species_label, eval_xpath2
        import numpy as np
        etree = inpxml_etree(TEST_INP_XML_PATH)
        path = '/fleurInput/atomSpecies/species/' + tag + '/@' + att_name
        old_result = np.array(eval_xpath2(etree, path)).astype('float')

        shift_value_species_label(etree, 'all', att_name, 2, mode='rel')
        result = np.array(eval_xpath2(etree, path)).astype('float')

        assert np.all(np.isclose(old_result * 2, result))
예제 #8
0
def test_replace_tag(inpxml_etree):
    from aiida_fleur.tools.xml_util import replace_tag, eval_xpath2
    etree = inpxml_etree(TEST_INP_XML_PATH)

    to_insert = eval_xpath2(etree, '/fleurInput/calculationSetup/cutoffs')[0]
    print(to_insert)
    print(eval_xpath2(etree, '/fleurInput/atomGroups/atomGroup/filmPos'))

    replace_tag(etree, '/fleurInput/atomGroups/atomGroup/filmPos', to_insert)

    assert eval_xpath2(etree, '/fleurInput/atomGroups/atomGroup/filmPos') == []
    assert eval_xpath2(etree, '/fleurInput/atomGroups/atomGroup/cutoffs')[0] == to_insert
예제 #9
0
    def test_add_num_to_att(self, inpxml_etree, attr_name):
        from aiida_fleur.tools.xml_util import add_num_to_att, eval_xpath2
        etree = inpxml_etree(TEST_INP_XML_PATH)

        path = self.xml_structure[12][attr_name]
        result_before = eval_xpath2(etree, path + '/@{}'.format(attr_name))

        if not result_before:
            if attr_name in ['nx', 'ny', 'nz', 'scale']:
                pytest.skip('This attribute is not tested for FePt/inp.xml')
            raise BaseException('Can not find attribute that should exist in FePt/inp.xml')
        else:
            result_before = result_before[0]
            add_num_to_att(etree, path, attr_name, 333)
            result = eval_xpath2(etree, path + '/@{}'.format(attr_name))[0]

            assert float(result) - float(result_before) == 333
예제 #10
0
    def test_change_atomgr_att_position(inpxml_etree, attr_dict, correct_result, path):
        from aiida_fleur.tools.xml_util import change_atomgr_att, eval_xpath2
        etree = inpxml_etree(TEST_INP_XML_PATH)

        change_atomgr_att(etree, attributedict=attr_dict, position=1)

        result = eval_xpath2(etree, '/fleurInput/atomGroups/atomGroup/' + path)

        assert result[0] == correct_result
예제 #11
0
    def test_change_atomgr_att_label_all(inpxml_etree, attr_dict, correct_result, path):
        from aiida_fleur.tools.xml_util import change_atomgr_att_label, eval_xpath2
        etree = inpxml_etree(TEST_INP_XML_PATH)

        change_atomgr_att_label(etree, attributedict=attr_dict, at_label='all')

        result = eval_xpath2(etree, '/fleurInput/atomGroups/atomGroup/' + path)

        assert result == correct_result
예제 #12
0
    def test_change_atomgr_att_fail(self, inpxml_etree):
        from aiida_fleur.tools.xml_util import change_atomgr_att, eval_xpath2
        etree = inpxml_etree(TEST_INP_XML_PATH)

        change_atomgr_att(etree, attributedict=self.attdicts[0])

        result = eval_xpath2(etree, '/fleurInput/atomGroups/atomGroup[@species="Fe-1"]/' + self.paths[0])

        assert result[0] == 'TTT'
예제 #13
0
    def test_shift_value_rel(self, inpxml_etree, attr_name):
        import math
        from aiida_fleur.tools.xml_util import shift_value, eval_xpath2
        etree = inpxml_etree(TEST_INP_XML_PATH)

        path = self.xml_structure[12][attr_name]
        result_before = eval_xpath2(etree, path + '/@{}'.format(attr_name))

        if not result_before:
            if attr_name in ['scale']:
                pytest.skip('This attribute is not tested for FePt/inp.xml')
            raise BaseException('Can not find attribute that should exist in FePt/inp.xml')
        else:
            result_before = result_before[0]
            shift_value(etree, {attr_name: 1.2442}, mode='rel')
            result = eval_xpath2(etree, path + '/@{}'.format(attr_name))[0]

            if float(result_before) != 0:
                assert math.isclose(float(result) / float(result_before), 1.2442, rel_tol=1e-6)
            else:
                assert float(result) == 0
예제 #14
0
    def test_set_species_label_all(inpxml_etree, attr_dict, correct_result, path):
        from aiida_fleur.tools.xml_util import set_species_label, eval_xpath2
        etree = inpxml_etree(TEST_INP_XML_PATH)

        set_species_label(etree, 'all', attributedict=attr_dict)

        result = eval_xpath2(etree, '/fleurInput/atomSpecies/species/' + path)

        if 'coreConfig' in path:
            assert [x.text for x in result] == correct_result
        else:
            assert result == correct_result
예제 #15
0
    def test_set_species_all_string(inpxml_etree, attr_dict, correct_result, path):
        from aiida_fleur.tools.xml_util import set_species, eval_xpath2
        etree = inpxml_etree(TEST_INP_XML_PATH)

        set_species(etree, 'all-Fe', attributedict=attr_dict)

        result = eval_xpath2(etree, '/fleurInput/atomSpecies/species[@name="Fe-1"]/' + path)

        if isinstance(correct_result, str):
            if 'coreConfig' in path:
                assert result[0].text == correct_result
            else:
                assert result[0] == correct_result
        elif isinstance(correct_result, (float, int)):
            assert result[0] == correct_result
        else:
            assert correct_result == result
예제 #16
0
def compress_fleuroutxml(outxmlfilepath, dest_file_path=None, delete_eig=True, iterations_to_keep=None):
    """
    Compresses a fleur out.xml file by deleting certain things
    like eigenvalues tags and/or iterations from it

    :param outxmlfilepath: (absolut) file path
    :type outxmlfilepath: str
    :param dest_file_path: (absolut) for the compressed file to be saved, if no desitination file path is given the file is overriden in place (default)!
    :type dest_file_path: str, optional
    :param delete_eig:  if eigenvalues are deleted from file default is True
    :type delete_eig: boolean, optional
    :param iterations_to_keep: index of 'till' whihc iterations to be keep, i.e '-2' means only last two, '15' default (None) is keep all
    :type iterations_to_keep: int

     ###
     usage example:
     outxmldes = '/Users/broeder/test/FePt_out_test.xml'
     outxmlsrc = '/Users/broeder/test/FePt_out.xml'
     compress_fleuroutxml(outxmlsrc, dest_file_path=outxmldes, iterations_to_keep=14)
     compress_fleuroutxml(outxmlsrc, dest_file_path=outxmldes, iterations_to_keep=-1)


    """
    from aiida_fleur.tools.xml_util import delete_tag, eval_xpath2
    from lxml import etree

    xpath_eig = '/fleurOutput/scfLoop/iteration/eigenvalues'
    xpath_iter = '/fleurOutput/scfLoop/iteration'
    tree = None
    parser = etree.XMLParser(recover=False)
    outfile_broken = False
    try:
        tree = etree.parse(outxmlfilepath, parser)
    except etree.XMLSyntaxError:
        outfile_broken = True
        print('broken')

    if outfile_broken:
        # repair xmlfile and try to parse what is possible.
        parser = etree.XMLParser(recover=True)
        try:
            tree = etree.parse(outxmlfilepath, parser)
        except etree.XMLSyntaxError:
            parse_xml = False
            successful = False
            print('failed to parse broken file, I abort.')
            return

    if tree is None:
        print('xml tree is None, should not happen, ...')
        return

    # delete eigenvalues (all)
    if delete_eig:
        new_etree = delete_tag(tree, xpath_eig)

    # delete certain iterations
    if iterations_to_keep is not None:
        root = new_etree.getroot()
        iteration_nodes = eval_xpath2(root, xpath_iter)
        n_iters = len(iteration_nodes)
        print(n_iters)
        if iterations_to_keep < 0:
            # the first element has 1 (not 0) in xpath expresions
            position_keep = n_iters + iterations_to_keep + 1
            delete_xpath = xpath_iter + '[position()<{}]'.format(int(position_keep))
        else:
            delete_xpath = xpath_iter + '[position()>{}]'.format(int(iterations_to_keep))

        if abs(iterations_to_keep) > n_iters:
            print('Warning: iterations_to_keep is larger then the number of iterations'
                  ' in the given out.xml file, I keep all.')
        else:
            print(delete_xpath)
            new_etree = delete_tag(new_etree, delete_xpath)

    if dest_file_path is None:
        dest_file_path = outxmlfilepath  # overwrite file
    if new_etree.getroot() is not None:  #otherwise write fails
        new_etree.write(dest_file_path)
    else:
        print('new_etree has no root..., I cannot write to proper xml, skipping this now')
    return
예제 #17
0
파일: scf.py 프로젝트: sphuber/aiida-fleur
    def get_res(self):
        """
        Check how the last Fleur calculation went
        Parse some results.
        """
        self.report('INFO: get results FLEUR')

        xpath_energy = '/fleurOutput/scfLoop/iteration/totalEnergy/@value'
        xpath_iter = '/fleurOutput/scfLoop/iteration'
        xpath_force = 'totalForcesOnRepresentativeAtoms/forceTotal'

        # be aware of magnetism
        xpath_distance = '/fleurOutput/scfLoop/iteration/densityConvergence/chargeDensity/@distance'
        overallchargedensity_xpath = ('/fleurOutput/scfLoop/iteration/densityConvergence/'
                                      'overallChargeDensity/@distance')

        mode = self.ctx.wf_dict.get('mode')
        if self.ctx.parse_last:
            last_base_wc = self.ctx.last_base_wc
            fleur_calcjob = load_node(find_last_submitted_calcjob(last_base_wc))
            walltime = last_base_wc.outputs.output_parameters.dict.walltime
            if isinstance(walltime, int):
                self.ctx.total_wall_time = self.ctx.total_wall_time + walltime
            with fleur_calcjob.outputs.retrieved.open(fleur_calcjob.process_class._OUTXML_FILE_NAME,
                                                      'r') as outxmlfile_opened:
                tree = etree.parse(outxmlfile_opened)
            root = tree.getroot()

            energies = eval_xpath2(root, xpath_energy)
            for energy in energies:
                self.ctx.total_energy.append(float(energy))

            overall_distances = eval_xpath2(root, overallchargedensity_xpath)
            if not overall_distances:
                distances = eval_xpath2(root, xpath_distance)
                for distance in distances:
                    self.ctx.distance.append(float(distance))
            else:
                for distance in overall_distances:
                    self.ctx.distance.append(float(distance))

            if mode == 'force':
                iter_all = eval_xpath2(root, xpath_iter)
                for iteration in iter_all:
                    forces = eval_xpath2(iteration, xpath_force)
                    forces_in_iter = []
                    for force in forces:
                        force_x = float(get_xml_attribute(force, 'F_x'))
                        force_y = float(get_xml_attribute(force, 'F_y'))
                        force_z = float(get_xml_attribute(force, 'F_z'))

                        forces_in_iter.append(force_x)
                        forces_in_iter.append(force_y)
                        forces_in_iter.append(force_z)

                    self.ctx.all_forces.append(forces_in_iter)
        else:
            errormsg = 'ERROR: scf wc was not successful, check log for details'
            self.control_end_wc(errormsg)
            return self.exit_codes.ERROR_FLEUR_CALCULATION_FAILED

        if not self.ctx.distance:
            # if fleur relaxes an already converged crystal it stops directly
            if mode == 'force':
                self.report('INFO: System already force converged, could not extract distance.')
                self.ctx.last_charge_density = None
            else:
                errormsg = 'ERROR: did not manage to extract charge density from the calculation'
                self.control_end_wc(errormsg)
                return self.exit_codes.ERROR_FLEUR_CALCULATION_FAILED
        else:
            self.ctx.last_charge_density = self.ctx.distance[-1]
예제 #18
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
예제 #19
0
def parse_state_card(corestateNode, iteration_node, parser_info=None):
    """
    Parses the ONE core state card

    :params corestateNode: an etree element (node), of a fleur output corestate card
    :params iteration_node: an etree element, iteration node
    :params jspin: integer 1 or 2

    :returns: a pythondict of type:

    .. code-block:: python

            {'eigenvalue_sum' : eigenvalueSum,
             'corestates': states,
             'spin' : spin,
             'kin_energy' : kinEnergy,
             'atomtype' : atomtype}

    """
    ##### all xpath of density convergence card (maintain) ########
    coreStates_xpath = 'coreStates'
    state_xpath = 'state'

    units_name = 'units'
    value_name = 'value'
    distance_name = 'distance'

    n_name = 'n'
    j_name = 'j'
    l_name = 'l'
    energy_name = 'energy'
    weight_name = 'weight'
    spin_name = 'spin'
    kinEnergy_name = 'kinEnergy'
    eigenvalueSum_name = 'eigValSum'
    lostElectrons_name = 'lostElectrons'
    atomtype_name = 'atomType'
    #######
    if parser_info is None:
        parser_info = {'parser_warnings': []}

    atomtype = get_xml_attribute(corestateNode, atomtype_name, parser_info)

    kinEnergy = get_xml_attribute(corestateNode, kinEnergy_name, parser_info)
    vE2, suc = convert_to_float(kinEnergy, parser_info)
    eigenvalueSum = get_xml_attribute(corestateNode, eigenvalueSum_name,
                                      parser_info)
    vE2, suc = convert_to_float(eigenvalueSum, parser_info)

    spin = get_xml_attribute(corestateNode, spin_name, parser_info)
    #print('spin {}'.format(spin))
    #states = corestateNode.xpath(
    #for state in states:

    # get all corestate tags, (atomtypes * spin)
    #corestateNodes = eval_xpath(iteration_node, coreStates_xpath, parser_info)
    # for every corestate tag parse the attributes

    # some only the first interation, then get all state tags of the corestate tag (atom depended)
    # parse each core state #Attention to spin
    states = []
    corestates = eval_xpath2(corestateNode, state_xpath)  #, parser_info)

    for corestate in corestates:  # be careful that corestates is a list
        state_dict = {}
        n_state = get_xml_attribute(corestate, n_name, parser_info)
        l_state = get_xml_attribute(corestate, l_name, parser_info)
        j_state = get_xml_attribute(corestate, j_name, parser_info)
        energy, suc = convert_to_float(
            get_xml_attribute(corestate, energy_name, parser_info),
            parser_info)
        weight, suc = convert_to_float(
            get_xml_attribute(corestate, weight_name, parser_info),
            parser_info)
        state_dict = {
            'n': n_state,
            'l': l_state,
            'j': j_state,
            'energy': energy,
            'weight': weight
        }
        states.append(state_dict)

    core_states = {
        'eigenvalue_sum': eigenvalueSum,
        'corestates': states,
        'spin': spin,
        'kin_energy': kinEnergy,
        'atomtype': atomtype
    }
    return core_states
예제 #20
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}')
예제 #21
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
예제 #22
0
def create_corehole_fleurinp(fleurinp, species, stateocc, pos=[], coreconfig='same', valenceconfig='same'):
    """
    Removes an electron from the core and adds it to the valence band of the kind
    given econfig as in inp.xml [Kr] (5s1/2) (4d3/2) (4d5/2) (4f5/2) (4f7/2)
    if position(pos) is given the electronConfig for the specifed position will be set.
    (or todo? econfig, either [Kr] 5s2 4d10 4f13 | 5p6 5d4 6s2 or
    [Kr] 2(5s1/2) 4(4d3/2) 6(4d5/2) 6(4f5/2) 8(4f7/2) |2(5p1/2) 4(5p3/2) 2(6s1/2) 2(5d3/2) 2(5d5/2))
    occ tags already there will be untouched, unless the state is the same as given

    :param fleurinp:, an unstored! changes are done on this fleurinp fleurinpdata object # TODO alternatively stored?
    :param species:, string with species name
    :param stateocc: dict state tuples (spinup, spindown), exp: {'(5d3/2)' : (2.5, 0.0), '(4f7/2)' : (3.5 , 4.0)}
    :param pos: list of tuples of 3, pos=[(0.0, 0.0, 0.0), ...]
    :param coreconfig: string, e.g: [Kr] (5s1/2) (4d3/2) (4d5/2) (4f5/2) (4f7/2), default='same' (same as current in inp.xml)
    :param valenceconfig, string, e.g.: (5p1/2) (5p3/2) (6s1/2) (5d3/2) (5d5/2)

    :return: the changes fleurinpData object
    """
    '''
         <electronConfig>
            <coreConfig>[Kr] (5s1/2) (4d3/2) (4d5/2) (4f5/2) (4f7/2)</coreConfig>
            <valenceConfig>(5p1/2) (5p3/2) (6s1/2) (5d3/2) (5d5/2)</valenceConfig>
            <stateOccupation state="(5d3/2)" spinUp="2.00000000" spinDown=".00000000"/>
            <stateOccupation state="(5d5/2)" spinUp="2.00000000" spinDown=".00000000"/>
         </electronConfig>
    '''
    from aiida_fleur.tools.xml_util import eval_xpath2, get_xml_attribute
    #from aiida_fleur.data.fleurinpmodifier import FleurinpModifier
    # or from fleurinp?

    FleurinpData = DataFactory('fleur.fleurinp')
    ########### all xpath maintain ########### ? needed?
    electronConfig_xpath =  '/fleurInput/atomSpecies/species/electronConfig'
    species_xpath = '/fleurInput/atomSpecies/species'
    #####################

    # test input, if something wrong return/ throw error
    # get electronConfig tag from fleurinp
    # create new tag from old tag and method input
    # return new fleurinp data
    # Best use fleurinp functions
    # Do it with xml or rather

    new_core = False
    new_valence = False

    # test input.
    if not isinstance(fleurinp, FleurinpData):
        print 'No fleurinp Data given to "create_valence_corehole"'
        return None # TODO throw error?

    if coreconfig != 'same':
        new_core = True

    if valenceconfig != 'same':
        new_valence = True
    #print stateocc

    species_tags = fleurinp.get_tag(species_xpath)
    #print species_tags
    for speci in species_tags:
        if get_xml_attribute(speci, 'name') == species:
            # change
            econfig = eval_xpath2(speci, 'electronConfig')[0]
            coreconfig = eval_xpath2(econfig, 'coreConfig')
            valenceconfig = eval_xpath2(econfig, 'valenceConfig')
            occupations = eval_xpath2(econfig, 'stateOccupation')

            for key, val in stateocc.iteritems():
                #print key
                added = False
                for occ in occupations:
                    name = get_xml_attribute(occ, 'state')
                    #print name
                    if name == key:
                        added = True
                        # override and break (can occur only once)
                        occ.set('spinUp', str(val[0]))
                        occ.set('spinDown', str(val[0]))
                        break
                if not added:
                    pass


    #st_inpchanges(change_dict)


    #alternative
    change_dict = {'coreConfig' : '', 'valenceConfig': ''}
    change_dict2 = {'state' : '', 'spinUp' : '', 'spinDown' : ''}
    change_dict3 = {'valenceElectrons' : ''}




    return fleurinp