def create_ase_object(objtype, dct): # We just try each object type one after another and instantiate # them manually, depending on which kind it is. # We can formalize this later if it ever becomes necessary. if objtype == 'cell': from ase.cell import Cell dct.pop('pbc', None) # compatibility; we once had pbc obj = Cell(**dct) elif objtype == 'bandstructure': from ase.spectrum.band_structure import BandStructure obj = BandStructure(**dct) elif objtype == 'bandpath': from ase.dft.kpoints import BandPath obj = BandPath(path=dct.pop('labelseq'), **dct) elif objtype == 'atoms': from ase import Atoms obj = Atoms.fromdict(dct) elif objtype == 'densityofstates': from ase.dft.dos import DOS obj = DOS(**dct) elif objtype == 'griddoscollection': from ase.spectrum.doscollection import GridDOSCollection obj = GridDOSCollection.fromdict(dct) else: raise ValueError('Do not know how to decode object type {} ' 'into an actual object'.format(objtype)) assert obj.ase_objtype == objtype return obj
def dos(filename, plot=False, output='dos.csv', width=0.1): """Calculate density of states. filename: str Name of restart-file. plot: bool Show a plot. output: str Name of CSV output file. width: float Width of Gaussians. """ calc = GPAW(filename, txt=None) dos = DOS(calc, width) D = [dos.get_dos(spin) for spin in range(calc.get_number_of_spins())] if output: fd = sys.stdout if output == '-' else open(output, 'w') for x in zip(dos.energies, *D): print(*x, sep=', ', file=fd) if output != '-': fd.close() if plot: import matplotlib.pyplot as plt for y in D: plt.plot(dos.energies, y) plt.show()
def get_dos(self, spin=None, **kwargs): """ The total DOS. Uses the ASE DOS module, and returns a tuple with (energies, dos). """ from ase.dft.dos import DOS dos = DOS(self, **kwargs) e = dos.get_energies() d = dos.get_dos(spin=spin) return e, d
def get_dos(self, width=0.15, method='gaussian', npts=501): """ density of states. :param width: smearing width :param method: 'gaussian'| 'tetra' :param npts: number of DOS energies. :returns: energies, dos. two ndarray. TODO: implement spin resolved DOS. """ if method == 'tetra': dos = tetrahedronDosClass(self, width, npts=npts) else: dos = DOS(self, width, window=None, npts=npts) return dos.get_energies(), dos.get_dos()
def test_dos(): from ase.atoms import Atoms from ase.calculators.singlepoint import SinglePointDFTCalculator from ase.calculators.singlepoint import SinglePointKPoint from ase.dft.dos import DOS atoms = Atoms('H') eFermi = [0, 1] kpts = [SinglePointKPoint(1, 0, 0), SinglePointKPoint(1, 1, 0)] kpts[0].eps_n = [-2, -1, 1] kpts[0].f_n = [1, 0, 0] kpts[1].eps_n = [-2.5, -1.5, 0.5] kpts[1].f_n = [1, 0, 0] calc = SinglePointDFTCalculator(atoms, efermi=eFermi) calc.kpts = kpts DOS(calc)
def get_dos(self, width=None, smearing='gaussian', npts=501): """ density of states. :param width: smearing width :param method: 'gaussian'| 'tetra' :param npts: number of DOS energies. :returns: energies, dos. two ndarray. TODO: implement spin resolved DOS. """ if width is None: width = self._width if smearing == 'tetra': raise NotImplementedError('tetrahedron DOS not implemented') #dos = tetrahedronDosClass(self, width, npts=npts) else: dos = DOS(self, width, window=None, npts=npts) return dos.get_energies(), dos.get_dos()
def get_dos(self,kpoints=None,width=0.1,window=None,npts=201,spin=None): """ calculate density of states. :param kpoints: set k-points for DOS calculation. :param width: smearing width :param window: energy windown. e.g. [-5,5] :param npts: number of points. :param spin: No use here. Just to keep with the ase API. """ if kpoints is not None: self.params['calculation']='nscf' self.kpts=['automatic',kpoints] self.params['occupations']='tetrahedra' self.initialize(self.atoms) self.calculate() self.read_output() mydos=DOS(self,width=width,window=window,npts=201) self.dos_energies=mydos.get_energies() self.dos=mydos.get_dos() if self.spin_polarized: self.dos_up=mydos.get_dos(spin=0) self.dos_down=mydos.get_dos(spin=1)
# Get band structure and dos Ebs = atoms.calc.band_structure() # Get the band structure # if world.rank == 0: print('Electronic band structure calculated') kpts = {'size': (40,40,40)} calc.set( kpts = kpts, fixdensity=True, symmetry='off', ) # Fix the potential calc.get_potential_energy() # e, dos = calc.get_dos(spin=0, npts=1001, width=0.5) # Get energy and density of states dos = DOS(calc, npts=2000, width=0.1) d = dos.get_dos() e = dos.get_energies() f = calc.get_fermi_level() print('Electronic DOS computed') e_f = calc.get_fermi_level() Edos = { 'e': e, 'dos': d, 'fermi': e_f } # Save results pickle.dump( Ebs, open( "Ebs.p", "wb" ) ) # Save the electronic band structure pickle.dump( Edos, open( "Edos.p", "wb" ) ) # Save the electronic DOS # if world.rank == 0:
from ase.atoms import Atoms from ase.calculators.singlepoint import SinglePointDFTCalculator from ase.calculators.singlepoint import SinglePointKPoint from ase.dft.dos import DOS atoms = Atoms('H') eFermi = [0, 1] kpts = [SinglePointKPoint(1, 0, 0), SinglePointKPoint(1, 1, 0)] kpts[0].eps_n = [-2, -1, 1] kpts[0].f_n = [1, 0, 0] kpts[1].eps_n = [-2.5, -1.5, 0.5] kpts[1].f_n = [1, 0, 0] calc = SinglePointDFTCalculator(atoms, efermi=eFermi) calc.kpts = kpts dos = DOS(calc)
def __init__(self, atoms, BZpath=[], npoints=10, outnc='harris.nc'): """Headline here ... XXX. atoms is an ase.Atoms object with calculator attached. Presumably the self-consistent charge density has already been calculated, otherwise, it will be. BZpath is a list of tuples describing the path through the Brillouin zone. The tuples have the form (label, kpt), e.g. :: [('$\Gamma$',[0.0, 0.0, 0.0]), ('X',[0.0, 0.5, 0.5]), ('L',[0.5, 0.0, 0.0]), ('$\Gamma$',[0.0, 0.0, 0.0])] the label is used in the figure and can include latex markup. npoints is the number of points on each segment. It can either be a constant, which is used for every segment, or a list of integers that is an integer for each segment. """ self.atoms = atoms self.calc = atoms.get_calculator() #first, we make sure the charge density is up to date. self.calc.get_charge_density() self.ef = self.calc.get_ef() #self-consistent fermi level self.labels = [x[0] for x in BZpath] self.kpt_path = [np.array(x[1], dtype=np.float) for x in BZpath] self.npoints = npoints #first, setup the kpt path kpts = [] #start at second kpt and go to second to last segment nsegments = len(self.kpt_path) - 1 for i in range(nsegments - 1): #get number of points on path. this counts the first point try: i_npt = npoints[i] except TypeError: i_npt = npoints #this is the vector connecting the two endpoint kpts of a segment kdiff = self.kpt_path[i + 1] - self.kpt_path[i] #make a vector of evenly spaced intervals, one longer than needed #because we chop off the last entry. for j in np.linspace(0, 1, i_npt + 1)[0:-1]: k = self.kpt_path[i] + j * kdiff #shift by small random amount to break symmetry and #prevent time-inversion reduction krand = (1. + np.random.random(3)) / 1.e4 k += krand kpts.append(k) #now fill in the last segment, and end on the last point try: i_npt = npoints[-1] except TypeError: i_npt = npoints kdiff = self.kpt_path[-1] - self.kpt_path[-2] for j in np.linspace(0, 1, i_npt + 1)[1:]: k = self.kpt_path[-2] + j * kdiff #shift by small random amount to break symmetry and #prevent time-inversion reduction krand = (1. + np.random.random(3)) / 1.e4 k += krand kpts.append(k) #these are now the points needed for the Harris calculation. self.kpts = kpts self.dos = DOS(self.calc) self.dos_energies = self.dos.get_energies() self.dos_dos = self.dos.get_dos() #try to avoid rerunning the calculation if it is already done! if os.path.exists(outnc): self.calc = Jacapo(outnc) else: print('calculation of harris required') self.calc.set_nc(outnc) #self.calc.debug=10 #save some time by not calculating stress self.calc.set_stress(False) #this seems to be necessary sometimes self.calc.delete_ncattdimvar(outnc, ncdims=['number_plane_waves']) #this has to come after removing number_of_planewaves self.calc.set_kpts(self.kpts) #freeze charge density self.calc.set_charge_mixing(updatecharge='No') #and, run calculation self.calc.calculate()
def calc_to_dict(calc, **kwargs): """Convert calc to a dictionary.""" d = { 'doc': '''JSON representation of a VASP calculation. energy is in eV forces are in eV/\AA stress is in GPa (sxx, syy, szz, syz, sxz, sxy) magnetic moments are in Bohr-magneton The density of states is reported with E_f at 0 eV. Volume is reported in \AA^3 Coordinates and cell parameters are reported in \AA If atom-projected dos are included they are in the form: {ados:{energy:data, {atom index: {orbital : dos}}} ''' } d['incar'] = {'doc': 'INCAR parameters'} d['incar'].update( dict( filter(lambda item: item[1] is not None, calc.float_params.items()))) d['incar'].update( dict(filter(lambda item: item[1] is not None, calc.exp_params.items()))) d['incar'].update( dict( filter(lambda item: item[1] is not None, calc.string_params.items()))) d['incar'].update( dict(filter(lambda item: item[1] is not None, calc.int_params.items()))) d['incar'].update( dict(filter(lambda item: item[1] is not None, calc.bool_params.items()))) d['incar'].update( dict(filter(lambda item: item[1] is not None, calc.list_params.items()))) d['incar'].update( dict(filter(lambda item: item[1] is not None, calc.dict_params.items()))) d['input'] = calc.input_params d['potcar'] = calc.get_pseudopotentials() d['atoms'] = atoms_to_dict(calc.get_atoms()) d['data'] = {'doc': 'Data from the output of the calculation'} atoms = calc.get_atoms() d['data']['total_energy'] = atoms.get_potential_energy() d['data']['forces'] = atoms.get_forces().tolist() # There are times when no stress is calculated try: stress = atoms.get_stress() except NotImplementedError: stress = None except AssertionError: stress = None if stress is not None: d['data']['stress'] = atoms.get_stress().tolist() else: d['data']['stress'] = None d['data']['fermi_level'] = calc.get_fermi_level() d['data']['volume'] = atoms.get_volume() if calc.spinpol: d['data']['magmom'] = atoms.get_magnetic_moment() if (calc.int_params.get('lorbit', 0) >= 10 or calc.list_params.get('rwigs', None)): try: d['data']['magmoms'] = atoms.get_magnetic_moments().tolist() except AttributeError: d['data']['magmoms'] = None # store the metadata if hasattr(calc, 'metadata'): d['metadata'] = calc.metadata if kwargs.get('dos', None): from ase.dft.dos import DOS dos = DOS(calc, width=kwargs.get('width', 0.2)) e = dos.get_energies() d['data']['dos'] = {'doc': 'Total density of states'} d['data']['dos']['e'] = e.tolist() if calc.spinpol: d['data']['dos']['dos-up'] = dos.get_dos(spin=0).tolist() d['data']['dos']['dos-down'] = dos.get_dos(spin=1).tolist() else: d['data']['dos']['dos'] = dos.get_dos().tolist() if kwargs.get('ados', None): from ase.calculators.vasp import VaspDos ados = VaspDos(efermi=calc.get_fermi_level()) d['data']['ados'] = {'doc': 'Atom projected DOS'} nonspin_orbitals_no_phase = ['s', 'p', 'd'] nonspin_orbitals_phase = [ 's', 'py', 'pz', 'px', 'dxy', 'dyz', 'dz2', 'dxz', 'dx2' ] spin_orbitals_no_phase = [] for x in nonspin_orbitals_no_phase: spin_orbitals_no_phase += ['{0}-up'.format(x)] spin_orbitals_no_phase += ['{0}-down'.format(x)] spin_orbitals_phase = [] for x in nonspin_orbitals_phase: spin_orbitals_phase += ['{0}-up'.format(x)] spin_orbitals_phase += ['{0}-down'.format(x)] if calc.spinpol and calc.int_params['lorbit'] != 11: orbitals = spin_orbitals_no_phase elif calc.spinpol and calc.int_params['lorbit'] == 11: orbitals = spin_orbitals_phase elif calc.int_params['lorbit'] != 11: orbitals = nonspin_orbitals_no_phase else: orbitals = nonspin_orbitals_phase for i, atom in enumerate(atoms): d['data']['ados']['energy'] = ados.energy.tolist() d['data']['ados'][i] = {} for orbital in orbitals: d['data']['ados'][i][orbital] = ados.site_dos( 0, orbital).tolist() # convert all numpy arrays to lists for key in d: try: d[key] = d[key].tolist() except: pass for key in d['input']: try: d['input'][key] = d['input'][key].tolist() except: pass return d
def dos(filename, plot=False, output='dos.csv', width=0.1, integrated=False, projection=None, emin=None, emax=None, npoints=400, show_total=None): """Calculate density of states. filename: str Name of restart-file. plot: bool Show a plot. output: str Name of CSV output file. width: float Width of Gaussians. integrated: bool Calculate integrated DOS. """ calc = GPAW(filename, txt=None) dos = DOS(calc, width, (emin, emax), npoints) nspins = calc.get_number_of_spins() spinlabels = [''] if nspins == 1 else [' up', ' dn'] if projection is None or show_total: D = [dos.get_dos(spin) for spin in range(nspins)] labels = ['DOS' + sl for sl in spinlabels] else: D = [] labels = [] if projection is not None: for p in projection.split(','): s, ll = p.split('-') if s.isdigit(): A = [int(s)] s = '#' + s else: A = [a for a, symbol in enumerate(calc.atoms.get_chemical_symbols()) if symbol == s] if not A: raise ValueError('No such atom: ' + s) for spin in range(nspins): for l in ll: d = 0.0 for a in A: d += ldos(calc, a, spin, l, width, dos.energies) labels.append(s + '-' + l + spinlabels[spin]) D.append(d) if integrated: de = dos.energies[1] - dos.energies[0] dos.energies += de / 2 D = [np.cumsum(d) * de for d in D] ylabel = 'iDOS [electrons]' else: ylabel = 'DOS [electrons/eV]' if output: fd = sys.stdout if output == '-' else open(output, 'w') for x in zip(dos.energies, *D): print(*x, sep=', ', file=fd) if output != '-': fd.close() if plot: import matplotlib.pyplot as plt for y, label in zip(D, labels): plt.plot(dos.energies, y, label=label) plt.legend() plt.ylabel(ylabel) plt.xlabel(r'$\epsilon-\epsilon_F$ [eV]') plt.show()
testRun = False file_name_py = basename(__file__) file_name = file_name_py.replace('.py','') file_traj = file_name + '.traj' start_file = '../In2O3_110_clean.traj' try: sys = Trajectory(file_traj, 'r')[-1] except (IOError, RuntimeError): print(("Importing trajectory file from: %s" % start_file)) sys = read(start_file) else: print(("Importing trajectory file from: %s" % file_traj)) calc = set_calc_In2O3(sys) print("Constraints:") print("\tc: Fix bottom two layers.") c = FixAtoms(mask=[atom.z < 8 for atom in sys]) sys.set_constraint(c) if testRun == True: run_testRun(sys) else: dos = DOS(calc = calc) ds = dos.get_dos() es = dos.get_energies() print("Energy\tDOS") for (e, d) in zip(es, ds): print(("%f\t%f" % (e, d))) print(("Completed %s" % file_name_py))
import matplotlib.pyplot as plt from gpaw import GPAW from ase.dft.dos import DOS calc = GPAW('groundstate.gpw') dos = DOS(calc, npts=800, width=0.1) energies = dos.get_energies() weights = dos.get_dos() ax = plt.gca() ax.plot(energies, weights) ax.set_xlabel(r'$E - E_{\mathrm{Fermi}}$ [eV]') ax.set_ylabel('DOS [1/eV]') plt.savefig('dos.png') plt.show()
def add_to_plot(self, readoutfilesobj, label=None): """ |Here you add individual plots that need to be plot and then just plot them with the plot() method |Use this method which is a part of the BandPlotterASE class you will have to give the bands to plot using a readoutfilesobj type of object """ try: Ef = readoutfilesobj.atoms_objects[0].calc.get_fermi_level() except: print(f"add_to_plot: Could not read fermi level on scf file") try: kpts = readoutfilesobj.atoms_bands_objects[ 0].calc.get_ibz_k_points() except: print(f"add_to_plot: Could not read k points on bands file") if self.include_dos or self.plot_only_dos: if self.plot_from_QE_dos_file: E = [] dos = [] with open(readoutfilesobj.dos_file_name, "r") as dos_file: for line in dos_file: # print(line) if "#" not in line: data = line.strip().split() E.append(float(data[0]) - Ef) dos.append(float(data[1])) # self.y_to_plot.append(dos) # self.x_to_plot.append(E) self.dos.append(dos) self.E_dos.append(E) if self.plot_only_dos: # Other wise we wil lappend to labels twice sicnce we will do it again at theloading of bands self.labels.append(label) else: # we are here getting the required information for DOS # self.get_dos(readoutfilesobj) calc = readoutfilesobj.atoms_nscf_objects[0].calc Ef_nscf = readoutfilesobj.atoms_nscf_objects[ 0].calc.get_fermi_level() dos = DOS(calc, width=0.2) self.dos.append(dos.get_dos()) E_nscf = dos.get_energies() Ef_diff = Ef - Ef_nscf if abs(Ef_diff) >= 0.001: print( f"Warning!!! In {readoutfilesobj.identifier[0]}:\t|E_f_scf-E_f_nscf| = {abs(Ef_diff):.3} eV (>= 0.001 eV); E_f_scf = {Ef} eV, E_f_nscf = {Ef_nscf} eV" ) if self.pin_fermi != "scf": self.E_dos.append(E_nscf) else: self.E_dos.append([E - Ef_diff for E in E_nscf]) # Test space for k path and k high symmetry points # print(kpts) # print(self.plot_only_dos) if self.plot_only_dos == False: # This is for teh band structure path = readoutfilesobj.atoms_bands_objects[0].cell.bandpath( npoints=0) kinks = find_bandpath_kinks( readoutfilesobj.atoms_bands_objects[0].cell, kpts, eps=1e-5) # These are the high symmetry points in use pathspec = resolve_custom_points( kpts[kinks], path.special_points, eps=1e-5 ) # This gives the postions for the relevant high symmetry points # path.kpts = kpts # path.path = pathspec klengths = [] for x in range(0, len(kpts)): if x == 0: kdist = np.sqrt((0.0 - kpts[x][0])**2 + (0.0 - kpts[x][1])**2 + (0.0 - kpts[x][2])**2) klengths.append(kdist) else: kdist = np.sqrt((kpts[x - 1][0] - kpts[x][0])**2 + (kpts[x - 1][1] - kpts[x][1])**2 + (kpts[x - 1][2] - kpts[x][2])**2) klengths.append(kdist + klengths[x - 1]) self.k_locations = [] for x in range(len(kinks)): self.k_locations.append(klengths[kinks[x]]) self.k_symbols = [] for x in pathspec: if x == "G": self.k_symbols.append("$\Gamma$") else: self.k_symbols.append(x) energies = [] for s in range(readoutfilesobj.atoms_bands_objects[0].calc. get_number_of_spins()): energies.append([ readoutfilesobj.atoms_bands_objects[0].calc. get_eigenvalues(kpt=k, spin=s) for k in range(len(kpts)) ]) # print(f"lenght of kpoints: {range(len(kpts))}") Energy_to_plot = [] if self.Ef_shift == True: for band in energies[0]: if self.pin_fermi != "nscf": Energy_to_plot.append([E - Ef for E in band]) else: Energy_to_plot.append( [E - Ef_nscf for E in band] ) # here the assumption is that if this option is ever reached then the idea is that an nscf calculation has already being done and dos is being plotted. tempMain = [] temp = [] for x in range(len(Energy_to_plot[0])): for kpoint in Energy_to_plot: temp.append(kpoint[x]) tempMain.append(temp) temp = [] self.y_to_plot.append(tempMain) self.x_to_plot.append(klengths) self.labels.append(label)
'''Write DOS to JSON file, starting from GPAW calculator file. ''' import sys import json from gpaw import GPAW from ase.dft.dos import DOS if len(sys.argv) != 2: raise RuntimeError('I want one and only one argument, the filename!') filename = sys.argv[1] calc = GPAW(filename, txt=None) dos = DOS(calc, width=0.1) dos_dict = {} dos_dict['dos'] = list(dos.get_dos()) dos_dict['energies'] = list(dos.get_energies()) out_name = filename + '_dos.json' with open(out_name, 'w') as outfile: json.dump(dos_dict, outfile) print('DOS written to', out_name)