def test_fleurinp_modifier_set_kpointsdata(create_fleurinp):
    """Test if setting a kpoints list to a fleurinp data node works"""
    from aiida.orm import KpointsData

    fleurinp_tmp = create_fleurinp(inpxmlfilefolder)
    fleurinp_tmp.store()  # needed?
    struc = fleurinp_tmp.get_structuredata_ncf()

    kps = KpointsData()
    kps.set_cell(struc.cell)
    kps.pbc = struc.pbc
    kpoints_pos = [[0.0, 0.0, 0.0], [0.0, 0.5, 0.0], [0.5, 0.0, 0.0], [0.5, 0.0, 0.5], [0.5, 0.5, 0.5], [1.0, 1.0, 1.0]]
    kpoints_weight = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
    # Fleur renormalizes
    kps.set_kpoints(kpoints_pos, cartesian=False, weights=kpoints_weight)

    kps.store()  # needed, because node has to be loaded...
    #print(fleurinp_tmp)
    fm = FleurinpModifier(fleurinp_tmp)
    fm.set_kpointsdata(kps)

    fm.show(validate=True, display=False)
    fm.freeze()

    # check if kpoint node is input into modification
    # uuid of node show also work
    fm = FleurinpModifier(fleurinp_tmp)
    fm.set_kpointsdata(kps.uuid)
    fm.freeze()
示例#2
0
def _legacy_get_explicit_kpoints_path(structure, **kwargs):
    """
    Call the get_explicit_kpoints_path of the legacy implementation

    :param structure: a StructureData node
    :param float kpoint_distance: parameter controlling the distance between kpoints. Distance is
        given in crystal coordinates, i.e. the distance is computed in the space of b1, b2, b3.
        The distance set will be the closest possible to this value, compatible with the requirement
        of putting equispaced points between two special points (since extrema are included).
    :param bool cartesian: if set to true, reads the coordinates eventually passed in value as cartesian coordinates
    :param float epsilon_length: threshold on lengths comparison, used to get the bravais lattice info
    :param float epsilon_angle: threshold on angles comparison, used to get the bravais lattice info
    """
    args_recognized = ['value', 'kpoint_distance', 'cartesian', 'epsilon_length', 'epsilon_angle']
    args_unknown = set(kwargs).difference(args_recognized)

    if args_unknown:
        raise ValueError('unknown arguments {}'.format(args_unknown))

    point_coords, path, bravais_info, explicit_kpoints, labels = legacy.get_explicit_kpoints_path(  # pylint: disable=unbalanced-tuple-unpacking
        cell=structure.cell, pbc=structure.pbc, **kwargs
    )

    kpoints = KpointsData()
    kpoints.set_cell(structure.cell)
    kpoints.set_kpoints(explicit_kpoints)
    kpoints.labels = labels

    parameters = {
        'bravais_info': bravais_info,
        'point_coords': point_coords,
        'path': path,
    }

    return {'parameters': Dict(dict=parameters), 'explicit_kpoints': kpoints}
示例#3
0
    def get_kpointsdata_ncf(self, name=None, index=None, only_used=False):
        """
        This routine returns an AiiDA :class:`~aiida.orm.KpointsData` type produced from the
        ``inp.xml`` file. This only works if the kpoints are listed in the in inpxml.
        This is NOT a calcfunction and does not keep the provenance!

        :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

        :returns: :class:`~aiida.orm.KpointsData` node
        """
        from aiida.orm import KpointsData
        from masci_tools.util.xml.xml_getters import get_kpoints_data

        # HINT, TODO:? in this routine, the 'cell' you might get in an other way
        # exp: StructureData.cell, but for this you have to make a structureData Node,
        # which might take more time for structures with lots of atoms.
        # then just parsing the cell from the inp.xml
        # as in the routine get_structureData

        xmltree, schema_dict = self.load_inpxml()

        if name is None and index is None:
            kpoints, weights, cell, pbc = get_kpoints_data(xmltree,
                                                           schema_dict,
                                                           only_used=only_used)
        else:
            kpoints, weights, cell, pbc = get_kpoints_data(xmltree,
                                                           schema_dict,
                                                           name=name,
                                                           index=index,
                                                           only_used=only_used)

        if isinstance(kpoints, dict):
            kpoints_data = {}
            for (label,
                 kpoints_set), weights_set in zip(kpoints.items(),
                                                  weights.values()):
                kps = KpointsData()
                kps.set_cell(cell)
                kps.pbc = pbc
                kps.set_kpoints(kpoints_set,
                                cartesian=False,
                                weights=weights_set)
                #kpoints_data.add_link_from(self, label='fleurinp.kpts', link_type=LinkType.CREATE)
                kps.label = 'fleurinp.kpts'
                kpoints_data[label] = kps
        else:
            kpoints_data = KpointsData()
            kpoints_data.set_cell(cell)
            kpoints_data.pbc = pbc
            kpoints_data.set_kpoints(kpoints, cartesian=False, weights=weights)
            #kpoints_data.add_link_from(self, label='fleurinp.kpts', link_type=LinkType.CREATE)
            kpoints_data.label = 'fleurinp.kpts'

        return kpoints_data
示例#4
0
        def connect_structure_bands(strct):  # pylint: disable=unused-argument
            alat = 4.
            cell = np.array([
                [alat, 0., 0.],
                [0., alat, 0.],
                [0., 0., alat],
            ])

            kpnts = KpointsData()
            kpnts.set_cell(cell)
            kpnts.set_kpoints([[0., 0., 0.], [0.1, 0.1, 0.1]])

            bands = BandsData()
            bands.set_kpointsdata(kpnts)
            bands.set_bands([[1.0, 2.0], [3.0, 4.0]])
            return bands
示例#5
0
        def connect_structure_bands(structure):
            alat = 4.
            cell = np.array([
                [alat, 0., 0.],
                [0., alat, 0.],
                [0., 0., alat],
            ])

            k = KpointsData()
            k.set_cell(cell)
            k.set_kpoints([[0., 0., 0.], [0.1, 0.1, 0.1]])

            b = BandsData()
            b.set_kpointsdata(k)
            b.set_bands([[1.0, 2.0], [3.0, 4.0]])

            return b
示例#6
0
    def change_fleurinp(self):
        """
        create a new fleurinp from the old with certain parameters
        """
        # TODO allow change of kpoint mesh?, tria?
        wf_dict = self.ctx.wf_dict

        if self.ctx.scf_needed:
            try:
                fleurin = self.ctx.scf.outputs.fleurinp
            except NotExistent:
                error = 'Fleurinp generated in the SCF calculation is not found.'
                self.control_end_wc(error)
                return self.exit_codes.ERROR_SCF_CALCULATION_FAILED
        else:
            if 'fleurinp' not in self.inputs:
                fleurin = get_fleurinp_from_remote_data(self.inputs.remote)
            else:
                fleurin = self.inputs.fleurinp

        # how can the user say he want to use the given kpoint mesh, ZZ nkpts : False/0
        fleurmode = FleurinpModifier(fleurin)

        fchanges = wf_dict.get('inpxml_changes', [])
        # apply further user dependend changes
        if fchanges:
            try:
                fleurmode.add_task_list(fchanges)
            except (ValueError, TypeError) as exc:
                error = (
                    'ERROR: Changing the inp.xml file failed. Tried to apply inpxml_changes'
                    f', which failed with {exc}. I abort, good luck next time!'
                )
                self.control_end_wc(error)
                return self.exit_codes.ERROR_CHANGING_FLEURINPUT_FAILED

        kpath = wf_dict['kpath']
        explicit = wf_dict['kpoints_explicit']
        distance = wf_dict['kpoints_distance']
        nkpts = wf_dict['kpoints_number']
        listname = wf_dict['klistname']

        if explicit is not None:
            try:
                fleurmode.set_kpointlist(**explicit)
            except (ValueError, TypeError) as exc:
                error = (
                    'ERROR: Changing the inp.xml file failed. Tried to apply kpoints_explicit'
                    f', which failed with {exc}. I abort, good luck next time!'
                )
                self.control_end_wc(error)
                return self.exit_codes.ERROR_CHANGING_FLEURINPUT_FAILED

        if listname is None:
            if wf_dict.get('mode') == 'band':
                listname = 'path-2'

        if nkpts is None and distance is None:
            nkpts = 500

        if 'kpoints' in self.inputs:
            fleurmode.set_kpointsdata(self.inputs.kpoints, switch=True)

        if kpath == 'auto':
            if fleurin.inp_version >= '0.32' and listname is not None:
                fleurmode.switch_kpointset(listname)
        elif isinstance(kpath, dict):
            if fleurin.inp_version < '0.32':
                if distance is not None:
                    raise ValueError(
                        'set_kpath only supports specifying the number of points for the kpoints'
                    )
                fleurmode.set_kpath(kpath, nkpts)
            else:
                raise ValueError(
                    'set_kpath is only supported for inputs up to Max4')
        elif kpath == 'seek':
            #Use aiida functionality
            struc = fleurin.get_structuredata()

            if distance is not None:
                output = get_explicit_kpoints_path(struc,
                                                   reference_distance=distance)
            else:
                output = get_explicit_kpoints_path(struc)
            primitive_struc = output['primitive_structure']

            #check if primitive_structure and input structure are identical:
            maxdiff_cell = sum(
                abs(np.array(primitive_struc.cell) -
                    np.array(struc.cell))).max()

            if maxdiff_cell > 3e-9:
                self.report(f'Error in cell : {maxdiff_cell}')
                self.report(
                    'WARNING: The structure data from the fleurinp is not the primitive structure type, which is mandatory in some cases'
                )

            output['explicit_kpoints'].store()

            fleurmode.set_kpointsdata(output['explicit_kpoints'], switch=True)

        elif kpath == 'skip':
            return
        else:
            #Use ase
            struc = fleurin.get_structuredata()

            path = bandpath(kpath,
                            cell=struc.cell,
                            npoints=nkpts,
                            density=distance)

            special_points = path.special_points

            labels = []
            for label, special_kpoint in special_points.items():
                for index, kpoint in enumerate(path.kpts):
                    if sum(abs(np.array(special_kpoint) -
                               np.array(kpoint))).max() < 1e-12:
                        labels.append((index, label))
            labels = sorted(labels, key=lambda x: x[0])

            kpts = KpointsData()
            kpts.set_cell(struc.cell)
            kpts.pbc = struc.pbc
            weights = np.ones(len(path.kpts)) / len(path.kpts)
            kpts.set_kpoints(kpoints=path.kpts,
                             cartesian=False,
                             weights=weights,
                             labels=labels)

            kpts.store()
            fleurmode.set_kpointsdata(kpts, switch=True)

        sigma = wf_dict['sigma']
        emin = wf_dict['emin']
        emax = wf_dict['emax']

        if fleurin.inp_version < '0.32':
            if wf_dict.get('mode') == 'dos':
                fleurmode.set_inpchanges({'ndir': -1})

        if wf_dict.get('mode') == 'dos':
            change_dict = {
                'dos': True,
                'minEnergy': emin,
                'maxEnergy': emax,
                'sigma': sigma
            }
        else:
            change_dict = {
                'band': True,
                'minEnergy': emin,
                'maxEnergy': emax,
                'sigma': sigma
            }
        fleurmode.set_inpchanges(change_dict)

        try:
            fleurmode.show(display=False, validate=True)
        except etree.DocumentInvalid:
            error = (
                'ERROR: input, user wanted inp.xml changes did not validate')
            self.control_end_wc(error)
            return self.exit_codes.ERROR_INVALID_INPUT_FILE
        except ValueError as exc:
            error = (
                'ERROR: input, user wanted inp.xml changes could not be applied.'
                f'The following error was raised {exc}')
            self.control_end_wc(error)
            return self.exit_codes.ERROR_CHANGING_FLEURINPUT_FAILED

        fleurinp_new = fleurmode.freeze()
        self.ctx.fleurinp_banddos = fleurinp_new
示例#7
0
    def get_kpointsdata_ncf(self):
        """
        This routine returns an AiiDA :class:`~aiida.orm.KpointsData` type produced from the
        ``inp.xml`` file. This only works if the kpoints are listed in the in inpxml.
        This is NOT a calcfunction and does not keep the provenance!

        :returns: :class:`~aiida.orm.KpointsData` node
        """
        from aiida.orm import KpointsData

        # HINT, TODO:? in this routine, the 'cell' you might get in an other way
        # exp: StructureData.cell, but for this you have to make a structureData Node,
        # which might take more time for structures with lots of atoms.
        # then just parsing the cell from the inp.xml
        # as in the routine get_structureData

        # Disclaimer: this routine needs some xpath expressions.
        # these are hardcoded here, therefore maintainance might be needed,
        # if you want to circumvent this, you have
        # to get all the paths from somewhere.

        #######
        # all hardcoded xpaths used and attributes names:
        bravaismatrix_bulk_xpath = '/fleurInput/cell/bulkLattice/bravaisMatrix/'
        bravaismatrix_film_xpath = '/fleurInput/cell/filmLattice/bravaisMatrix/'
        kpointlist_xpath = '/fleurInput/calculationSetup/bzIntegration/kPointList/'

        kpoint_tag = 'kPoint'
        kpointlist_attrib_posscale = 'posScale'
        kpointlist_attrib_weightscale = 'weightScale'
        #kpointlist_attrib_count = 'count'
        kpoint_attrib_weight = 'weight'
        row1_tag_name = 'row-1'
        row2_tag_name = 'row-2'
        row3_tag_name = 'row-3'
        ########

        if 'inp.xml' not in self.files:
            print(
                'cannot get a KpointsData because fleurinpdata has no inp.xml file yet'
            )
            # TODO what to do in this case?
            return False

        # else read in inpxml

        if self._schema_file_path:  # Schema there, parse with schema
            xmlschema_doc = etree.parse(self._schema_file_path)
            xmlschema = etree.XMLSchema(xmlschema_doc)
            parser = etree.XMLParser(attribute_defaults=True, encoding='utf-8')
            with self.open(path='inp.xml', mode='r') as inpxmlfile:
                tree = etree.parse(inpxmlfile, parser)
            tree.xinclude()
            # remove comments from inp.xml
            comments = tree.xpath('//comment()')
            for c in comments:
                p = c.getparent()
                p.remove(c)
            if not xmlschema.validate(tree):
                raise ValueError(
                    'Input file is not validated against the schema.')
        else:  # schema not there, parse without
            print('parsing inp.xml without XMLSchema')
            with self.open(path='inp.xml', mode='r') as inpxmlfile:
                tree = etree.parse(inpxmlfile)
            tree.xinclude()
            # remove comments from inp.xml
            comments = tree.xpath('//comment()')
            for c in comments:
                p = c.getparent()
                p.remove(c)
        root = tree.getroot()

        # get cell matrix from inp.xml
        cell = None
        row1 = root.xpath(bravaismatrix_bulk_xpath +
                          row1_tag_name)  # [0].text.split()

        if row1:  # bulk calculation
            row1 = row1[0].text.split()
            row2 = root.xpath(bravaismatrix_bulk_xpath +
                              row2_tag_name)[0].text.split()
            row3 = root.xpath(bravaismatrix_bulk_xpath +
                              row3_tag_name)[0].text.split()
            # TODO? allow math?
            for i, cor in enumerate(row1):
                row1[i] = float(cor) * BOHR_A
            for i, cor in enumerate(row2):
                row2[i] = float(cor) * BOHR_A
            for i, cor in enumerate(row3):
                row3[i] = float(cor) * BOHR_A

            cell = [row1, row2, row3]
            # set boundary conditions
            pbc1 = [True, True, True]

        elif root.xpath(bravaismatrix_film_xpath + row1_tag_name):
            # film calculation
            row1 = root.xpath(bravaismatrix_film_xpath +
                              row1_tag_name)[0].text.split()
            row2 = root.xpath(bravaismatrix_film_xpath +
                              row2_tag_name)[0].text.split()
            row3 = root.xpath(bravaismatrix_film_xpath +
                              row3_tag_name)[0].text.split()
            for i, cor in enumerate(row1):
                row1[i] = float(cor) * BOHR_A
            for i, cor in enumerate(row2):
                row2[i] = float(cor) * BOHR_A
            for i, cor in enumerate(row3):
                row3[i] = float(cor) * BOHR_A
            # row3 = [0, 0, 0]#? TODO:what has it to be in this case?
            cell = [row1, row2, row3]
            pbc1 = [True, True, False]

        if cell is None:
            print('Could not extract Bravias matrix out of inp.xml. Is the '
                  'Bravias matrix explicitly given? i.e Latnam definition '
                  'not supported.')
            return None
        # get kpoints only works if kpointlist in inp.xml
        kpoints = root.xpath(kpointlist_xpath + kpoint_tag)

        if kpoints:
            posscale = root.xpath(kpointlist_xpath + '@' +
                                  kpointlist_attrib_posscale)
            weightscale = root.xpath(kpointlist_xpath + '@' +
                                     kpointlist_attrib_weightscale)
            #count = root.xpath(kpointlist_xpath + '@' + kpointlist_attrib_count)

            kpoints_pos = []
            kpoints_weight = []

            for kpoint in kpoints:
                kpoint_pos = kpoint.text.split()
                for i, kval in enumerate(kpoint_pos):
                    kpoint_pos[i] = float(kval) / float(posscale[0])
                    kpoint_weight = float(
                        kpoint.get(kpoint_attrib_weight)) / float(
                            weightscale[0])
                kpoints_pos.append(kpoint_pos)
                kpoints_weight.append(kpoint_weight)
            totalw = 0
            for weight in kpoints_weight:
                totalw = totalw + weight
            kps = KpointsData()
            kps.set_cell(cell)
            kps.pbc = pbc1

            kps.set_kpoints(kpoints_pos,
                            cartesian=False,
                            weights=kpoints_weight)
            #kps.add_link_from(self, label='fleurinp.kpts', link_type=LinkType.CREATE)
            kps.label = 'fleurinp.kpts'
            # return {label: kps}
            return kps
        else:  # TODO parser other kpoints formats, if they fit in an AiiDA node
            print('No kpoint list in inp.xml')
            return None