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
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
def get_bands(qpoints, frequencies, labels, path_connections, label=None): qpoints_list = list(qpoints[0]) frequencies_list = list(frequencies[0]) labels_list = [ (0, labels[0]), ] label_index = 1 for pc, qs, fs in zip(path_connections[:-1], qpoints[1:], frequencies[1:]): if labels[label_index] == 'GAMMA' and pc: labels_list.append((len(qpoints_list) - 1, labels[label_index])) if label_index < len(labels): labels_list.append((len(qpoints_list), labels[label_index])) label_index += 1 qpoints_list += list(qs) frequencies_list += list(fs) elif pc: labels_list.append((len(qpoints_list) - 1, labels[label_index])) label_index += 1 qpoints_list += list(qs[1:]) frequencies_list += list(fs[1:]) else: labels_list.append((len(qpoints_list) - 1, labels[label_index])) label_index += 1 if label_index < len(labels): labels_list.append((len(qpoints_list), labels[label_index])) label_index += 1 qpoints_list += list(qs) frequencies_list += list(fs) labels_list.append((len(qpoints_list) - 1, labels[-1])) bs = DataFactory('array.bands')() bs.set_kpoints(np.array(qpoints_list)) bs.set_bands(np.array(frequencies_list), units='THz') bs.labels = labels_list if label is not None: bs.label = label return bs
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
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}