Esempio n. 1
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.)
Esempio n. 2
0
def create_kpoints_from_distance(structure, distance, force_parity):
    """Generate a uniformly spaced kpoint mesh for a given structure.

    The spacing between kpoints in reciprocal space is guaranteed to be at least the defined distance.

    :param structure: the StructureData to which the mesh should apply
    :param distance: a Float with the desired distance between kpoints in reciprocal space
    :param force_parity: a Bool to specify whether the generated mesh should maintain parity
    :returns: a KpointsData with the generated mesh
    """
    from numpy import linalg
    from aiida.orm import KpointsData

    epsilon = 1E-5

    kpoints = KpointsData()
    kpoints.set_cell_from_structure(structure)
    kpoints.set_kpoints_mesh_from_density(distance.value, force_parity=force_parity.value)

    lengths_vector = [linalg.norm(vector) for vector in structure.cell]
    lengths_kpoint = kpoints.get_kpoints_mesh()[0]

    is_symmetric_cell = all(abs(length - lengths_vector[0]) < epsilon for length in lengths_vector)
    is_symmetric_mesh = all(length == lengths_kpoint[0] for length in lengths_kpoint)

    # If the vectors of the cell all have the same length, the kpoint mesh should be isotropic as well
    if is_symmetric_cell and not is_symmetric_mesh:
        nkpoints = max(lengths_kpoint)
        kpoints.set_kpoints_mesh([nkpoints, nkpoints, nkpoints])

    return kpoints
Esempio n. 3
0
def example_dft(code, pseudo_family):
    """Run simple silicon DFT calculation."""

    print('Testing Abinit Total energy on Silicon using AbinitCalculation')

    thisdir = os.path.dirname(os.path.realpath(__file__))
    structure = StructureData(pymatgen=mg.core.Structure.from_file(
        os.path.join(thisdir, 'files', 'Si.cif')))
    pseudo_family = Group.objects.get(label=pseudo_family)
    pseudos = pseudo_family.get_pseudos(structure=structure)

    kpoints = KpointsData()
    kpoints.set_cell_from_structure(structure)
    kpoints.set_kpoints_mesh([2, 2, 2])
    # kpoints.set_kpoints_mesh_from_density(2.0)

    parameters_dict = {
        'code':
        code,
        'structure':
        structure,
        'pseudos':
        pseudos,
        'kpoints':
        kpoints,
        'parameters':
        Dict(
            dict={
                'ecut':
                8.0,  # Maximal kinetic energy cut-off, in Hartree
                'nshiftk':
                4,  # of the reciprocal space (that form a BCC lattice !)
                'shiftk': [[0.5, 0.5, 0.5], [0.5, 0.0, 0.0], [0.0, 0.5, 0.0],
                           [0.0, 0.0, 0.5]],
                'nstep':
                20,  # Maximal number of SCF cycles
                'toldfe':
                1.0e-6,  # Will stop when, twice in a row, the difference
                # between two consecutive evaluations of total energy
                # differ by less than toldfe (in Hartree)
            }),
        'metadata': {
            'options': {
                'withmpi': True,
                'max_wallclock_seconds': 2 * 60,
                'resources': {
                    'num_machines': 1,
                    'num_mpiprocs_per_machine': 4,
                }
            }
        }
    }

    print('Running calculation...')
    run(AbinitCalculation, **parameters_dict)
Esempio n. 4
0
def get_distance_from_kmesh(calc):
    mesh = calc.inputs.kpoints.get_kpoints_mesh()[0]
    k = KpointsData()
    k.set_cell_from_structure(
        calc.inputs.structure
    )  #these take trace of PBC...if set in the inputs.!!
    for i in range(4, 400):
        k.set_kpoints_mesh_from_density(1 / (i * 0.25))
        if k.get_kpoints_mesh()[0] == mesh:
            print('ok, {} is the density'.format(i * 0.25))
            print(k.get_kpoints_mesh()[0], mesh)
            return i * 0.25
Esempio n. 5
0
    def setup_kpoints(self):
        """
        Define the k-point mesh for the relax and scf calculations.
        """

        kpoints_mesh = KpointsData()
        kpoints_mesh.set_cell_from_structure(
            self.ctx.structure_initial_primitive)
        kpoints_mesh.set_kpoints_mesh_from_density(
            distance=self.ctx.protocol['kpoints_mesh_density'],
            offset=self.ctx.protocol['kpoints_mesh_offset'])

        self.ctx.kpoints_mesh = kpoints_mesh
Esempio n. 6
0
    def test_reciprocal_cell(self):
        """
        Test the `reciprocal_cell` method.

        This is a regression test for #2749.
        """
        kpt = KpointsData()
        kpt.set_cell_from_structure(self.structure)

        self.assertEqual(np.abs(kpt.reciprocal_cell - self.expected_reciprocal_cell).sum(), 0.)

        # Check also after storing
        kpt.store()
        kpt2 = load_node(kpt.pk)
        self.assertEqual(np.abs(kpt2.reciprocal_cell - self.expected_reciprocal_cell).sum(), 0.)
Esempio n. 7
0
    def _get_kpoints(self, key, structure):
        from aiida.orm import KpointsData
        if "kpoints" in self._protocols[key]:
            kpoints_mesh = KpointsData()
            kpoints_mesh.set_cell_from_structure(structure)
            kp_dict = self._protocols[key]["kpoints"]
            if "offset" in kp_dict:
                kpoints_mesh.set_kpoints_mesh_from_density(
                    distance=kp_dict["distance"], offset=kp_dict["offset"])
            else:
                kpoints_mesh.set_kpoints_mesh_from_density(
                    distance=kp_dict["distance"])
        else:
            kpoints_mesh = None

        return kpoints_mesh
Esempio n. 8
0
    def run_scf_and_ldos(self):
        """
        Run the SiestaBaseWorkChain in scf+ldos mode on the primitive cell of the relaxed input structure
        """

        try:
            structure = self.ctx.workchain_relax.outputs.output_structure
        except:
            return self.exit_codes.ERROR_RELAXED_STRUCTURE_NOT_AVAILABLE

        # Do we need further refinement by Seekpath on this=? (eventually)?
        self.ctx.structure_relaxed_primitive = structure

        inputs = dict(self.ctx.inputs)
        ldos_e = "\n {e1} {e2} eV \n %endblock local-density-of-states".format(
            e1=self.inputs.e1.value, e2=self.inputs.e2.value)
        inputs['parameters']['%block local-density-of-states'] = ldos_e

        kpoints_mesh = KpointsData()
        kpoints_mesh.set_cell_from_structure(
            self.ctx.structure_relaxed_primitive)
        kpoints_mesh.set_kpoints_mesh_from_density(
            distance=self.ctx.protocol['kpoints_mesh_density'],
            offset=self.ctx.protocol['kpoints_mesh_offset'])

        # Final input preparation, wrapping dictionaries in ParameterData nodes
        inputs['kpoints'] = kpoints_mesh
        inputs['structure'] = self.ctx.structure_relaxed_primitive
        inputs['parameters'] = Dict(dict=inputs['parameters'])
        inputs['basis'] = Dict(dict=inputs['basis'])
        inputs['settings'] = Dict(dict=inputs['settings'])
        inputs['options'] = Dict(dict=inputs['options'])

        running = self.submit(SiestaBaseWorkChain, **inputs)
        self.report('launched SiestaBaseWorkChain<{}> in scf+ldos mode'.format(
            running.pk))

        return ToContext(workchain_base_ldos=running)
Esempio n. 9
0
    def _get_kpoints(self, key, structure, previous_workchain):
        from aiida.orm import KpointsData
        if previous_workchain:
            kpoints_mesh = KpointsData()
            kpoints_mesh.set_cell_from_structure(structure)
            previous_wc_kp = previous_workchain.inputs.kpoints
            kpoints_mesh.set_kpoints_mesh(
                previous_wc_kp.get_attribute('mesh'),
                previous_wc_kp.get_attribute('offset'))
            return kpoints_mesh

        if 'kpoints' in self._protocols[key]:
            kpoints_mesh = KpointsData()
            kpoints_mesh.set_cell_from_structure(structure)
            kp_dict = self._protocols[key]['kpoints']
            if 'offset' in kp_dict:
                kpoints_mesh.set_kpoints_mesh_from_density(
                    distance=kp_dict['distance'], offset=kp_dict['offset'])
            else:
                kpoints_mesh.set_kpoints_mesh_from_density(
                    distance=kp_dict['distance'])
            return kpoints_mesh

        return None
Esempio n. 10
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
Esempio n. 11
0
    def run_bands(self):
        """
        Run the SiestaBaseWorkChain in scf+bands mode on the primitive cell of the relaxed input structure
        """

        try:
            structure = self.ctx.workchain_relax.outputs.output_structure
        except:
            return self.exit_codes.ERROR_RELAXED_STRUCTURE_NOT_AVAILABLE

        # Do we need further refinement by Seekpath on this=? (eventually)?
        self.ctx.structure_relaxed_primitive = structure

        inputs = dict(self.ctx.inputs)

        kpoints_mesh = KpointsData()
        kpoints_mesh.set_cell_from_structure(
            self.ctx.structure_relaxed_primitive)
        kpoints_mesh.set_kpoints_mesh_from_density(
            distance=self.ctx.protocol['kpoints_mesh_density'],
            offset=self.ctx.protocol['kpoints_mesh_offset'])

        # For the band-structure kath, it is advised to use the
        # 'seekpath' method, but we try the 'legacy' for now.  In some
        # cases we might not want seekpath to change our structure.
        # Further support for this in the input to the workflow might
        # be needed.  (NOTE: If we ever optimize this workflow to
        # re-use the DM or H resulting from the execution of the Base
        # workflow, a change in structure would cause errors.)

        from aiida.tools import get_explicit_kpoints_path

        legacy_kpath_parameters = Dict(
            dict={
                'kpoint_distance':
                0.05  # In units of b1, b2, b3 (Around 20 points per side...)
            })
        seekpath_kpath_parameters = Dict(dict={
            'reference_distance': 0.02,
            'symprec': 0.0001
        })
        kpath_parameters = legacy_kpath_parameters

        result = get_explicit_kpoints_path(
            self.ctx.structure_relaxed_primitive,
            method='legacy',
            **kpath_parameters.get_dict())
        bandskpoints = result['explicit_kpoints']
        # The 'legacy' method presumably does not change the structure
        ## structure = result['primitive_structure']

        self.ctx.kpoints_path = bandskpoints

        # Final input preparation, wrapping dictionaries in ParameterData nodes
        inputs['bandskpoints'] = self.ctx.kpoints_path
        inputs['kpoints'] = kpoints_mesh
        inputs['structure'] = self.ctx.structure_relaxed_primitive
        inputs['parameters'] = Dict(dict=inputs['parameters'])
        inputs['basis'] = Dict(dict=inputs['basis'])
        inputs['settings'] = Dict(dict=inputs['settings'])

        running = self.submit(SiestaBaseWorkChain, **inputs)
        self.report(
            'launched SiestaBaseWorkChain<{}> in scf+bands mode'.format(
                running.pk))

        return ToContext(workchain_base_bands=running)
Esempio n. 12
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
Esempio n. 13
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