示例#1
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