Ejemplo n.º 1
0
    def parse_bands(self, bands):
        """Parse bands from fort.25 file"""
        if not bands:
            raise ValueError("Sorry, didn't find bands info in fort.25")

        from aiida.plugins import DataFactory
        # to get BandsData node first we need to get k-points path and set KpointsData
        shrink = self.node.inputs.parameters.dict.band['shrink']
        path = bands["path"]
        k_number = bands["n_k"]
        # for path construction we're getting geometry from fort.9
        with self.node.inputs.wavefunction.open() as f:
            fort9_name = f.name
        geometry_parser = Fort9(fort9_name)
        cell = geometry_parser.get_cell(scale=True)
        path_description = construct_kpoints_path(cell, path, shrink, k_number)
        structure = DataFactory('structure')(ase=geometry_parser.get_ase())
        # and now find k-points along the path
        k_points = get_explicit_kpoints_path(
            structure, path_description)['explicit_kpoints']
        # ...and finally populate bands data
        bands_data = DataFactory('array.bands')()
        bands_data.set_kpointsdata(k_points)
        bands_data.set_bands(bands["bands_up"])
        # TODO: Deal with bands_down?
        bands_down_data = None
        if bands["bands_down"] is not None:
            bands_down_data = DataFactory('array.bands')()
            bands_down_data.set_kpointsdata(k_points)
            bands_down_data.set_bands(bands["bands_down"])
        return bands_data, bands_down_data
Ejemplo n.º 2
0
def read_bands(*args, **kwargs):
    """
    Read a HDF5 in bands_inspect HDF5 format containing an EigenvalsData
    instance, and return an AiiDA BandsData instance. Positional and keyword
    arguments are passed to :class:`h5py.File`.
    """
    with h5py.File(*args, **kwargs) as f:
        kpoints = _parse_kpoints(f['kpoints_obj'])
        # BandsData cannot have a mesh as k-points...
        bands = DataFactory('array.bands')()
        if 'mesh' in kpoints.attributes:
            bands.set_kpoints(kpoints.get_kpoints_mesh(print_list=True))
        else:
            bands.set_kpointsdata(kpoints)
        bands.set_bands(f['eigenvals'].value)
    return bands
Ejemplo n.º 3
0
def run_properties_direct(wf_path, input_dict):
    """
    This procedure runs properties
    outside of AiiDA graph and scheduler
    """
    assert wf_path.endswith('fort.9')
    assert 'band' in input_dict and 'dos' in input_dict
    assert 'first' not in input_dict['dos'] and 'first' not in input_dict[
        'band']
    assert 'last' not in input_dict['dos'] and 'last' not in input_dict['band']
    print('Working with %s' % wf_path)

    work_folder = os.path.join(
        config.get('local', 'data_dir'), '_'.join([
            'props',
            datetime.now().strftime('%Y%m%d_%H%M%S'),
            ''.join([random.choice(string.ascii_lowercase) for _ in range(4)])
        ]))
    os.makedirs(work_folder, exist_ok=False)
    shutil.copy(wf_path, work_folder)
    shutil.copy(os.path.join(os.path.dirname(wf_path), 'fort.34'),
                work_folder)  # save structure

    wf = Fort9(os.path.join(work_folder, 'fort.9'))

    # automatic generation of k-point path
    #structure = wf.get_structure()
    # NB fort.9 may produce slightly different structure, so use fort.34
    f34 = f34_input.read(os.path.join(os.path.dirname(wf_path), 'fort.34'))
    structure = f34.to_aiida()

    shrink, _, kpath = get_shrink_kpoints_path(structure)
    last_state = wf.get_ao_number()
    input_dict['band']['shrink'] = shrink
    input_dict['band']['bands'] = kpath

    # automatic generation of first and last state
    input_dict['band']['first'] = 1
    input_dict['band']['last'] = last_state
    input_dict['dos']['first'] = 1
    input_dict['dos']['last'] = last_state

    d3_content = str(D3(input_dict))
    inp = open(os.path.join(work_folder, 'INPUT'), "w")
    inp.write(d3_content)
    inp.close()

    start_time = time.time()
    p = subprocess.Popen(
        exec_cmd %
        (work_folder, EXEC_PATH, os.path.join(work_folder, 'OUTPUT')),
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        shell=True)
    try:
        p.wait(timeout=EXEC_TIMEOUT)
    except subprocess.TimeoutExpired:
        kill(p.pid)
        print("Killed as too time-consuming")

    print("Done in %1.2f sc" % (time.time() - start_time))

    if p.returncode != 0:
        return None, 'PROPERTIES failed, see %s' % work_folder

    if not os.path.exists(os.path.join(work_folder, 'BAND.DAT')) \
        or not os.path.exists(os.path.join(work_folder, 'DOSS.DAT')) \
        or not os.path.exists(os.path.join(work_folder, 'fort.25')):
        return None, 'No PROPERTIES outputs'

    edata = Fort25(os.path.join(work_folder, 'fort.25')).parse()

    assert sum(edata['DOSS']['e']) == 0  # all zeros, FIXME?
    print('>N DOSS: %s' % len(edata['DOSS']['dos'][0]))

    path = edata['BAND']['path']
    k_number = edata['BAND']['n_k']

    #cell = wf.get_cell(scale=True) # for path construction we're getting geometry from fort.9
    # NB fort.9 may produce slightly different structure, so use fort.34
    cell = f34.abc, f34.positions, f34.atomic_numbers

    path_description = construct_kpoints_path(cell, path, shrink, k_number)
    # find k-points along the path
    k_points = get_explicit_kpoints_path(structure,
                                         path_description)['explicit_kpoints']

    # pass through the internal AiiDA repr, FIXME?
    bands_data = DataFactory('array.bands')()
    bands_data.set_kpointsdata(k_points)
    bands_data.set_bands(edata['BAND']['bands'])

    edata['BAND']['bands'] = bands_data.get_bands()
    k_points = bands_data.get_kpoints().tolist()
    print('>N KPOINTS: %s' % len(k_points))
    print('>N BANDS: %s' % len(edata['BAND']['bands'][0]))

    edata['BAND']['bands'] -= edata['DOSS']['e_fermi']
    edata['BAND']['bands'] *= Hartree
    edata['DOSS']['dos'] -= edata['DOSS']['e_fermi']
    edata['DOSS']['dos'] *= Hartree
    # get rid of the negative DOS artifacts
    edata['DOSS']['dos'][edata['DOSS']['dos'] < 0] = 0

    e_min, e_max = np.amin(edata['BAND']['bands']), np.amax(
        edata['BAND']['bands'])
    dos_energies = np.linspace(e_min, e_max, num=len(edata['DOSS']['dos'][0]))
    stripes = edata['BAND']['bands'].transpose().copy()

    if is_conductor(stripes):
        indirect_gap, direct_gap = None, None
    else:
        indirect_gap, direct_gap = get_band_gap_info(stripes)

    # save only the range of the interest
    E_MIN, E_MAX = -15, 20
    stripes = stripes[(stripes[:, 0] > E_MIN) & (stripes[:, 0] < E_MAX)]
    dos = []
    for n, i in enumerate(dos_energies):  # FIXME use numpy advanced slicing
        if E_MIN < i < E_MAX:
            dos.append(edata['DOSS']['dos'][0][n])
    dos_energies = dos_energies[(dos_energies > E_MIN)
                                & (dos_energies < E_MAX)]

    return {
        # - gaps
        'direct_gap': direct_gap,
        'indirect_gap': indirect_gap,
        # - dos values
        'dos': np.round(np.array(dos), 3).tolist(),
        'levels': np.round(dos_energies, 3).tolist(),
        # - bands values
        'k_points': k_points,
        'stripes': np.round(stripes, 3).tolist(),
        # - auxiliary
        'work_folder': work_folder,
        'units': 'eV'
    }, None
Ejemplo n.º 4
0
def make_reference_bands_inline(wannier_bands, vasp_bands, efermi=None):
    """
    Compare bandstructure results from wannier and vasp.

    Takes two input array.bands nodes, stores them if they're not already
    stored. Takes the relevant bands from the vasp bandstructure and stores and outputs
    them in a node with linkname 'bandcmp'.

    Also returns a parameter data node with linkname 'bandinfo' containing
    fermi energy, bandgap etc of the reference bandstructure.
    """
    import numpy as np
    assert isinstance(wannier_bands, BANDS_CLS)
    assert isinstance(vasp_bands, BANDS_CLS)
    assert hasattr(wannier_bands, 'labels')
    assert hasattr(vasp_bands, 'labels')
    if vasp_bands.labels:
        assert vasp_bands.labels == wannier_bands.labels
    kpcomp = vasp_bands.get_kpoints() == wannier_bands.get_kpoints()
    assert kpcomp.all(), 'kpoints may not differ'

    owindow = get_outer_window(wannier_bands)

    wbands = wannier_bands.get_bands()
    vbands, vocc = vasp_bands.get_bands(also_occupations=True)

    # throw away spin dimension if appropriate
    if vbands.ndim == 3:
        vbands = vbands[0]
        vocc = vocc[0]

    # grab the vbands within the outer_window
    # find wich bands within the window match
    # by searching for the best fit using the sum of square errors
    vbands_window = np.empty(wbands.shape)
    vocc_window = np.empty(wbands.shape)
    w_nbands = wbands.shape[1]
    ref_nbands = vbands.shape[1]
    for band_idx in range(w_nbands):
        errs = [band_error(wbands[:, band_idx], vbands[:, i]) for i in range(ref_nbands)]
        minerr = np.argmin(errs)
        vbands_window[:, band_idx] = vbands[:, minerr]
        vocc_window[:, band_idx] = vocc[:, minerr]

    # For the future:
    # * find each band's index (s, px, py, ...)
    # * store the legend with the comparison node

    # find fermi energy from vasp_bands parent or work without it
    if not efermi:
        try:
            efermi = vasp_bands.inp.bands.out.results.get_dict()['efermi']
        except Exception:  # pylint: disable=broad-except
            pass

    ref_gap_info = band_gap(vbands_window, vocc_window, efermi)
    ref_info = DataFactory('parameter')()
    ref_info.update_dict({'bandgap': ref_gap_info})
    ref_info.update_dict({'efermi': efermi})
    ref_info.update_dict({'outer_window': owindow})

    ref_bands = DataFactory('array.bands')()
    ref_bands.set_kpointsdata(wannier_bands)
    ref_bands.set_bands(vbands_window, occupations=vocc_window)

    return {'bands': ref_bands, 'info': ref_info}