Beispiel #1
0
    def test_bandsexport_single_kp(self):
        """
        Plot band for single k-point (issue #2462).
        """
        kpnts = KpointsData()
        kpnts.set_kpoints([[0., 0., 0.]])

        bands = BandsData()
        bands.set_kpointsdata(kpnts)
        bands.set_bands([[1.0, 2.0]])
        bands.store()

        # matplotlib
        options = [str(bands.id), '--format', 'mpl_singlefile']
        res = self.cli_runner.invoke(cmd_bands.bands_export,
                                     options,
                                     catch_exceptions=False)
        self.assertIn(
            b'p.scatter', res.stdout_bytes,
            'The string p.scatter was not found in the bands mpl export')

        # gnuplot
        with self.cli_runner.isolated_filesystem():
            options = [str(bands.id), '--format', 'gnuplot', '-o', 'bands.gnu']
            self.cli_runner.invoke(cmd_bands.bands_export,
                                   options,
                                   catch_exceptions=False)
            with open('bands.gnu', 'r') as gnu_file:
                res = gnu_file.read()
                self.assertIn(
                    'vectors nohead', res,
                    'The string "vectors nohead" was not found in the gnuplot script'
                )
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()
Beispiel #3
0
    def test_get_kpoints(self):
        """Test the `get_kpoints` method."""
        kpt = KpointsData()
        kpt.set_cell_from_structure(self.structure)

        kpoints = [
            [0., 0., 0.],
            [0.5, 0.5, 0.5],
        ]

        cartesian_kpoints = [
            [0., 0., 0.],
            [np.pi / self.alat, np.pi / self.alat, np.pi / self.alat],
        ]

        kpt.set_kpoints(kpoints)
        self.assertEqual(
            np.abs(kpt.get_kpoints() - np.array(kpoints)).sum(), 0.)
        self.assertEqual(
            np.abs(
                kpt.get_kpoints(cartesian=True) -
                np.array(cartesian_kpoints)).sum(), 0.)

        # Check also after storing
        kpt.store()
        kpt2 = load_node(kpt.pk)
        self.assertEqual(
            np.abs(kpt2.get_kpoints() - np.array(kpoints)).sum(), 0.)
        self.assertEqual(
            np.abs(
                kpt2.get_kpoints(cartesian=True) -
                np.array(cartesian_kpoints)).sum(), 0.)
Beispiel #4
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}
Beispiel #5
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
Beispiel #6
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
Beispiel #7
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
Beispiel #8
0
def get_explicit_kpoints_path(structure, parameters):
    """
    Return the kpoint path for band structure (in scaled and absolute
    coordinates), given a crystal structure,
    using the paths proposed in the various publications (see description
    of the 'recipe' input parameter). The parameters are the same
    as get get_explicit_k_path in __init__, but here all structures are
    input and returned as AiiDA structures rather than tuples, and similarly
    k-points-related information as a AiiDA KpointsData class.

    :param structure: The AiiDA StructureData for which we want to obtain
        the suggested path.

    :param parameters: A dictionary whose key-value pairs are passed as
        additional kwargs to the ``seekpath.get_explicit_k_path`` function.

    :return: A dictionary with four nodes:

        - ``explicit_kpoints``: a KpointsData with the (explicit) kpoints
          (with labels set).

        - ``parameters``: a Dict, whose content is
          the same dictionary as returned by the ``seekpath.get_explicit_k_path`` function
          (see `seekpath documentation <https://seekpath.readthedocs.io/>`_),
          except that:

          - ``conv_lattice``, ``conv_positions``, ``conv_types``
            are removed and replaced by the ``conv_structure`` output node

          - ``primitive_lattice``, ``primitive_positions``, ``primitive_types``
            are removed and replaced by the `primitive_structure` output node

          - ``reciprocal_primitive_lattice``, ``explicit_kpoints_abs``,
            ``explicit_kpoints_rel`` and ``explicit_kpoints_labels`` are removed
            and replaced by the ``explicit_kpoints`` output node

        - ``primitive_structure``: A StructureData with the primitive structure

        - ``conv_structure``: A StructureData with the primitive structure
    """
    # pylint: disable=too-many-locals
    from aiida.tools.data.structure import spglib_tuple_to_structure, structure_to_spglib_tuple

    structure_tuple, kind_info, kinds = structure_to_spglib_tuple(structure)

    result = {}
    rawdict = seekpath.get_explicit_k_path(structure=structure_tuple,
                                           **parameters)

    # Replace primitive structure with AiiDA StructureData
    primitive_lattice = rawdict.pop('primitive_lattice')
    primitive_positions = rawdict.pop('primitive_positions')
    primitive_types = rawdict.pop('primitive_types')
    primitive_tuple = (primitive_lattice, primitive_positions, primitive_types)
    primitive_structure = spglib_tuple_to_structure(primitive_tuple, kind_info,
                                                    kinds)

    # Replace conv structure with AiiDA StructureData
    conv_lattice = rawdict.pop('conv_lattice')
    conv_positions = rawdict.pop('conv_positions')
    conv_types = rawdict.pop('conv_types')
    conv_tuple = (conv_lattice, conv_positions, conv_types)
    conv_structure = spglib_tuple_to_structure(conv_tuple, kind_info, kinds)

    # Remove reciprocal_primitive_lattice, recalculated by kpoints class
    rawdict.pop('reciprocal_primitive_lattice')
    kpoints_abs = rawdict.pop('explicit_kpoints_abs')
    kpoints_labels = rawdict.pop('explicit_kpoints_labels')

    # set_kpoints expects labels like [[0,'X'],[34,'L'],...], so generate it here skipping empty labels
    labels = [[idx, label] for idx, label in enumerate(kpoints_labels)
              if label]
    kpoints = KpointsData()
    kpoints.set_cell_from_structure(primitive_structure)
    kpoints.set_kpoints(kpoints_abs, cartesian=True, labels=labels)

    result['parameters'] = Dict(dict=rawdict)
    result['explicit_kpoints'] = kpoints
    result['primitive_structure'] = primitive_structure
    result['conv_structure'] = conv_structure

    return result
Beispiel #9
0
def test_inp_gen_cell(gen_instance, sto_calc_inputs):
    """
    Test generation of the inputs
    """
    gen_instance.inputs = sto_calc_inputs
    gen_instance.prepare_inputs()
    assert 'symmetry_generate' in gen_instance.cell_file
    assert "POSITIONS_ABS" in gen_instance.cell_file
    assert "LATTICE_CART" in gen_instance.cell_file
    assert isinstance(gen_instance.cell_file["cell_constraints"], list)
    assert 'C9' in gen_instance.cell_file['SPECIES_POT'][0]

    # Test extra-kpoints
    from aiida.orm import KpointsData
    kpn1 = KpointsData()
    kpn1.set_kpoints_mesh((4, 4, 4))
    gen_instance._include_extra_kpoints(kpn1, 'phonon', {
        'task': ('phonon', ),
        'need_weights': False
    })
    assert 'phonon_kpoint_mp_grid' in gen_instance.cell_file

    kpn1.set_kpoints_mesh((
        4,
        4,
        4,
    ), (0.25, 0.25, 0.25))
    gen_instance._include_extra_kpoints(kpn1, 'phonon', {
        'task': ('phonon', ),
        'need_weights': False
    })
    assert 'phonon_kpoint_mp_offset' in gen_instance.cell_file

    # Explicit kpoints, with/without the weights
    kpn2 = KpointsData()
    kpn_points = [[0, 0, 0], [0.5, 0.5, 0.5]]
    kpn_weights = [0.3, 0.6]
    kpn2.set_kpoints(kpn_points, weights=kpn_weights)
    gen_instance._include_extra_kpoints(kpn2, 'bs', {
        'task': ('bandstructure', ),
        'need_weights': True
    })
    assert len(gen_instance.cell_file['BS_KPOINT_LIST'][0].split()) == 4

    kpn2 = KpointsData()
    kpn_points = [[0, 0, 0], [0.5, 0.5, 0.5]]
    kpn2.set_kpoints(kpn_points)
    gen_instance._include_extra_kpoints(kpn2, 'bs', {
        'task': ('bandstructure', ),
        'need_weights': True
    })
    assert len(gen_instance.cell_file['BS_KPOINT_LIST'][0].split()) == 4
    assert float(gen_instance.cell_file['BS_KPOINT_LIST'][0].split()[3]) == 0.5

    # No weights
    gen_instance._include_extra_kpoints(kpn2, 'bs', {
        'task': ('bandstructure', ),
        'need_weights': False
    })
    assert len(gen_instance.cell_file['BS_KPOINT_LIST'][0].split()) == 3

    assert 'BS_KPOINT_LIST' in gen_instance.cell_file
Beispiel #10
0
def launch_calculation(code, structure, pseudo_family, kpoints_mesh, ecutwfc,
                       ecutrho, hubbard_u, hubbard_v, hubbard_file_pk,
                       starting_magnetization, smearing, max_num_machines,
                       max_wallclock_seconds, with_mpi, daemon, parent_folder,
                       dry_run, mode, unfolded_kpoints):
    """Run a PwCalculation."""
    from aiida.orm import Dict, KpointsData
    from aiida.plugins import CalculationFactory

    from aiida_quantumespresso.utils.resources import get_default_options

    cutoff_wfc, cutoff_rho = pseudo_family.get_recommended_cutoffs(
        structure=structure, unit='Ry')

    parameters = {
        'CONTROL': {
            'calculation': mode,
        },
        'SYSTEM': {
            'ecutwfc': ecutwfc or cutoff_wfc,
            'ecutrho': ecutrho or cutoff_rho,
        }
    }

    if mode in CALCS_REQUIRING_PARENT and not parent_folder:
        raise click.BadParameter(
            f"calculation '{mode}' requires a parent folder",
            param_hint='--parent-folder')

    try:
        hubbard_file = validate.validate_hubbard_parameters(
            structure, parameters, hubbard_u, hubbard_v, hubbard_file_pk)
    except ValueError as exception:
        raise click.BadParameter(str(exception))

    try:
        validate.validate_starting_magnetization(structure, parameters,
                                                 starting_magnetization)
    except ValueError as exception:
        raise click.BadParameter(str(exception))

    try:
        validate.validate_smearing(parameters, smearing)
    except ValueError as exception:
        raise click.BadParameter(str(exception))

    if unfolded_kpoints:
        unfolded_list = kpoints_mesh.get_kpoints_mesh(print_list=True)
        kpoints_mesh = KpointsData()
        kpoints_mesh.set_kpoints(unfolded_list)

    inputs = {
        'code': code,
        'structure': structure,
        'pseudos': pseudo_family.get_pseudos(structure=structure),
        'kpoints': kpoints_mesh,
        'parameters': Dict(dict=parameters),
        'metadata': {
            'options':
            get_default_options(max_num_machines, max_wallclock_seconds,
                                with_mpi),
        }
    }

    if parent_folder:
        inputs['parent_folder'] = parent_folder

    if hubbard_file:
        inputs['hubbard_file'] = hubbard_file

    if dry_run:
        if daemon:
            # .submit() would forward to .run(), but it's better to stop here,
            # since it's a bit unexpected and the log messages output to screen
            # would be confusing ("Submitted PwCalculation<None> to the daemon")
            raise click.BadParameter(
                'cannot send to the daemon if in dry_run mode',
                param_hint='--daemon')
        inputs['metadata']['store_provenance'] = False
        inputs['metadata']['dry_run'] = True

    launch.launch_process(CalculationFactory('quantumespresso.pw'), daemon,
                          **inputs)
Beispiel #11
0
def get_explicit_kpoints(kpoints):
    """Convert from a mesh to an explicit list"""
    from aiida.orm import KpointsData
    kpt = KpointsData()
    kpt.set_kpoints(kpoints.get_kpoints_mesh(print_list=True))
    return kpt
Beispiel #12
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
Beispiel #13
0
def sto_spectral_inputs(sto_calc_inputs, db_test_app):
    kpoints = KpointsData()
    kpoints.set_kpoints([[0.0, 0.5, 0.5], [0.0, 0.0, 0.0]])
    sto_calc_inputs.spectral_kpoints = kpoints
    return sto_calc_inputs
Beispiel #14
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
Beispiel #15
0
def band_parser_legacy(band_dat, band_kpt, special_points, structure):  # pylint: disable=too-many-locals
    """
    Parsers the bands output data, along with the special points retrieved
    from the input kpoints to construct a BandsData object which is then
    returned. Cannot handle discontinuities in the kpath, if two points are
    assigned to same spot only one will be passed. Used for wannier90 < 3.0
    :param band_dat: list of str with each str stores one line of aiida_band.dat file
    :param band_kpt: list of str with each str stores one line of aiida_band.kpt file
    :param special_points: special points to add labels to the bands a dictionary in
        the form expected in the input as described in the wannier90 documentation
    :return: BandsData object constructed from the input params,
        and a list contains warnings.
    """
    import numpy as np

    from aiida.orm import BandsData
    from aiida.orm import KpointsData

    warnings = []
    warnings.append((
        "Note: no file named SEEDNAME_band.labelinfo.dat found. "
        "You are probably using a version of Wannier90 before 3.0. "
        "There, the labels associated with each k-points were not printed in output "
        "and there were also cases in which points were not calculated "
        "(see issue #195 on the Wannier90 GitHub page). "
        "I will anyway try to do my best to assign labels, "
        "but the assignment might be wrong "
        "(especially if there are path discontinuities)."))

    # imports the data
    out_kpt = np.genfromtxt(band_kpt, skip_header=1, usecols=(0, 1, 2))
    out_dat = np.genfromtxt(band_dat, usecols=1)

    # reshaps the output bands
    out_dat = out_dat.reshape(len(out_kpt), (len(out_dat) // len(out_kpt)),
                              order="F")

    # finds expected points of discontinuity
    kpath = special_points['path']
    cont_break = [(i, (kpath[i - 1][1], kpath[i][0]))
                  for i in range(1, len(kpath))
                  if kpath[i - 1][1] != kpath[i][0]]

    # finds the special points
    special_points_dict = special_points['point_coords']
    # We set atol to 1e-5 because in the kpt file the coords are printed with fixed precision
    labels = [
        (i, k) for k in special_points_dict for i in range(len(out_kpt))
        if all(
            np.isclose(special_points_dict[k], out_kpt[i], rtol=0, atol=1.e-5))
    ]
    labels.sort()

    # Checks and appends labels if discontinuity
    appends = []
    for x in cont_break:
        # two cases the break is before or the break is after
        # if the break is before
        if labels[x[0]][1] != x[1][0]:
            # checks to see if the discontinuity was already there
            if labels[x[0] - 1] == x[1][0]:
                continue
            insert_point = x[0]
            new_label = x[1][0]
            kpoint = labels[x[0]][0] - 1
            appends += [[insert_point, new_label, kpoint]]
        # if the break is after
        if labels[x[0]][1] != x[1][1]:
            # checks to see if the discontinuity was already there
            if labels[x[0] + 1] == x[1][1]:
                continue
            insert_point = x[0] + 1
            new_label = x[1][1]
            kpoint = labels[x[0]][0] + 1
            appends += [[insert_point, new_label, kpoint]]
    appends.sort()

    for i, append in enumerate(appends):
        labels.insert(append[0] + i, (append[2], six.text_type(append[1])))
    bands = BandsData()
    k = KpointsData()
    k.set_cell_from_structure(structure)
    k.set_kpoints(out_kpt, cartesian=False)
    bands.set_kpointsdata(k)
    bands.set_bands(out_dat, units='eV')
    bands.labels = labels
    return bands, warnings
Beispiel #16
0
def band_parser(band_dat, band_kpt, band_labelinfo, structure):  # pylint: disable=too-many-locals
    """
    Parsers the bands output data to construct a BandsData object which is then
    returned. Used for wannier90 >= 3.0

    :param band_dat: list of str with each str stores one line of aiida_band.dat file
    :param band_kpt: list of str with each str stores one line of aiida_band.kpt file
    :param band_labelinfo: list of str with each str stores one line in aiida_band.labelinfo.dat file
    :return: BandsData object constructed from the input params
    """
    import numpy as np

    from aiida.orm import BandsData
    from aiida.orm import KpointsData

    warnings = []

    # imports the data
    out_kpt = np.genfromtxt(band_kpt, skip_header=1, usecols=(0, 1, 2))
    out_dat = np.genfromtxt(band_dat, usecols=1)

    # reshaps the output bands
    out_dat = out_dat.reshape(len(out_kpt), (len(out_dat) // len(out_kpt)),
                              order="F")

    labels_dict = {}
    for line_idx, line in enumerate(band_labelinfo, start=1):
        if not line.strip():
            continue
        try:
            # label, idx, xval, kx, ky, kz = line.split()
            label, idx, _, _, _, _ = line.split()
        except ValueError:
            warnings.append(
                ('Wrong number of items in line {} of the labelinfo file - '
                 'I will not assign that label')).format(line_idx)
            continue
        try:
            idx = int(idx)
        except ValueError:
            warnings.append((
                "Invalid value for the index in line {} of the labelinfo file, "
                "it's not an integer - I will not assign that label"
            )).format(line_idx)
            continue

        # I use a dictionary because there are cases in which there are
        # two lines for the same point (e.g. when I do a zero-length path,
        # from a point to the same point, just to have that value)
        # Note the -1 because in fortran indices are 1-based, in Python are
        # 0-based
        labels_dict[idx - 1] = label
    labels = [(key, labels_dict[key]) for key in sorted(labels_dict)]

    bands = BandsData()
    k = KpointsData()
    k.set_cell_from_structure(structure)
    k.set_kpoints(out_kpt, cartesian=False)
    bands.set_kpointsdata(k)
    bands.set_bands(out_dat, units='eV')
    bands.labels = labels
    return bands, warnings