def __init__(self, filename): """ Constructor. filename -- filename to get info from, either Gaussian (out, g03) or netCDF file (nc) """ self.file = filename if os.path.exists(filename): ext = filename.split('.')[-1] self.complex = filename.split('.')[-2] #print ext if ext == 'nc': self.type = 'nc' # read directly from nc to avoid calculation #self.data = netCDF(filename,'r') self.data = Jacapo.read_atoms(filename) elif ext == 'out' or ext == 'g03' or ext == 'log': gout = Gaussian(filename) gout.logger.setLevel(logging.ERROR) self.type = 'gau' self.data = gout.parse() else: raise Exception, 'File is not of identifiable format'
class BandStructure: '''outline of class to facilitate band structure calculations ''' 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 plot(self): ''' Make an interactive band-structure plot. clicking on a band will make it thicker and print which band was selected. ''' # kpoints = self.calc.get_ibz_kpoints() eigenvalues = self.calc.get_all_eigenvalues() - self.ef #eigenvalues = np.array([self.calc.get_eigenvalues(kpt=i)-self.ef # for i in range(len(kpoints))]) self.handles = [] #used to get band indexes from plot fig = plt.figure() #plot DOS in figure ax = fig.add_subplot(122) ax.plot(self.dos_dos, self.dos_energies) plt.title('self-consistent Total DOS') ax.set_xticks([]) ax.set_yticks([]) ax.set_ylim([-20, 20]) ax = fig.add_subplot(121) ax.set_title('Band structure') def onpick(event): 'make picked line bolder, set oldline back to regular thickness' self.lastartist.set_linewidth(1) self.lastartist = thisline = event.artist thisline.set_linewidth(5) plt.draw() #needed to update linewidth print('Band %i selected' % self.handles.index(thisline)) #you could insert code here to plot wavefunction, etc... fig.canvas.mpl_connect('pick_event', onpick) #we use indices for x. the tick labels are not shown and the distance #appears unimportant xdata = list(range(len(eigenvalues))) nkpts, nbands = eigenvalues.shape for i in range(nbands): #eigenvalues has shape(nkpts,nbands) #note the comma after line_handle line_handle, = ax.plot(xdata, eigenvalues[:, i], '.-', ms=1, picker=2) self.handles.append(line_handle) self.lastartist = self.handles[-1] #plot Fermi level ax.plot([0, len(self.kpts)], [0, 0], 'k--', label='$E_f$') plt.xlabel('|k|') plt.ylabel('$E-E_f$ (eV)') #set xtick locations and labels xtick_locs = np.zeros(len(self.kpt_path)) try: #this means the npoints is a list # i_npt = self.npoints[0] for j, npt in enumerate(1, self.npoints): xtick_locs[j] = xtick_locs[j - 1] + npt except TypeError: #npoints is a single number for j in range(1, len(self.labels)): xtick_locs[j] = xtick_locs[j - 1] + self.npoints #the last location is off by one, so we fix it. xtick_locs[-1] -= 1 ax.set_xlim([xtick_locs[0], xtick_locs[-1]]) ax.set_xticks(xtick_locs) ax.set_xticklabels(self.labels) #this seems reasonable to avoid very deep energy states and high energy states ax.set_ylim([-20, 20]) plt.show() return fig
mol = 'NH3' atoms = Atoms(mol, positions=molecules.data[mol]['positions']) sg = SYMMOL(atoms) print(sg.get_point_group()) print(sg.get_moments_of_inertia()) print(atoms.get_moments_of_inertia()) print(sg.get_symmetry_operators()) if __name__ == '__main__': from ase.calculators.jacapo import Jacapo from optparse import OptionParser parser = OptionParser(usage='symmol.py ncfile', version='0.1') parser.add_option('-f', nargs=0, help='print full output') parser.add_option('-o', nargs=1, help='save output in filename') options, args = parser.parse_args() for ncfile in args: sy = SYMMOL(Jacapo.read_atoms(ncfile), outfile=options.o) print('Point group = ', sy.get_point_group()) print('Moments of inertia = ', sy.get_moments_of_inertia()) print('Symmetry operators = ', sy.get_symmetry_operators()) if options.f is not None: print(sy)
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()
cmd = 'bader -p all_atom %s' % (self.densityfile) print(cmd) os.system(cmd) def write_all_bader(self): ''' -p all_bader Write all Bader volumes (containing charge above threshold of 0.0001) to a file. The charge distribution in each volume is written to a separate file, named Bvolxxxx.dat. It will either be of a CHGCAR format or a CUBE file format, depending on the format of the initial charge density file. These files can be quite large, so this option should be used with caution. ''' cmd = 'bader -p all_bader %s' % (self.densityfile) print(cmd) os.system(cmd) if __name__ == '__main__': from ase.calculators.jacapo import Jacapo atoms = Jacapo.read_atoms('ethylene.nc') b = Bader(atoms) print(b.get_bader_charges()) print(b.get_bader_volumes()) b.write_atom_volume([3, 4])
'ScientificPython version 2.8 or greater is required') except (ImportError, NotAvailable): print "No Scientific python found. Check your PYTHONPATH" raise NotAvailable('ScientificPython version 2.8 or greater is required') if not (os.system('which dacapo.run') == 0): print "No Dacapo Fortran executable (dacapo.run) found. Check your path settings." raise NotAvailable( 'dacapo.run is not installed on this machine or not in the path') # Now Scientific 2.8 and dacapo.run should both be available from ase import Atoms, Atom from ase.calculators.jacapo import Jacapo atoms = Atoms([Atom('H', [0, 0, 0])], cell=(2, 2, 2)) calc = Jacapo('Jacapo-test.nc', pw=200, nbands=2, kpts=(1, 1, 1), spinpol=False, dipole=False, symmetry=False, ft=0.01) atoms.set_calculator(calc) print atoms.get_potential_energy() os.system('rm -f Jacapo-test.nc Jacapo-test.txt')
return string.join(self.output) def get_space_group(self): regexp = re.compile('^Space Group') for line in self.output: if regexp.search(line): return line if __name__ == '__main__': from ase.calculators.jacapo import Jacapo from optparse import OptionParser parser = OptionParser(usage='findsym.py ncfile', version='0.1') parser.add_option('-f', nargs=0, help='print full output') parser.add_option('-o', nargs=1, help='save output in filename') options, args = parser.parse_args() for ncfile in args: sg = FINDSYM(Jacapo.read_atoms(ncfile), outfile=options.o) print(sg.get_space_group()) if options.f is not None: print(sg)
''' cmd = 'bader -p all_atom %s' % (self.densityfile) print cmd os.system(cmd) def write_all_bader(self): ''' -p all_bader Write all Bader volumes (containing charge above threshold of 0.0001) to a file. The charge distribution in each volume is written to a separate file, named Bvolxxxx.dat. It will either be of a CHGCAR format or a CUBE file format, depending on the format of the initial charge density file. These files can be quite large, so this option should be used with caution. ''' cmd = 'bader -p all_bader %s' % (self.densityfile) print cmd os.system(cmd) if __name__ == '__main__': from ase.calculators.jacapo import Jacapo atoms = Jacapo.read_atoms('ethylene.nc') b = Bader(atoms) print b.get_bader_charges() print b.get_bader_volumes() b.write_atom_volume([3, 4])
index += 5 symmetry_operators.append(temparray) taus.append(array(temptau)) return symmetry_operators, taus if __name__ == '__main__': from ase.calculators.jacapo import Jacapo from optparse import OptionParser parser = OptionParser(usage='sgroup.py ncfile', version='0.1') parser.add_option('-f', nargs=0, help='print full output') parser.add_option('-o', nargs=1, help='save output in filename') options, args = parser.parse_args() #print options for ncfile in args: sg = SGROUP(Jacapo.read_atoms(ncfile), outfile=options.o) print(sg.get_space_group()) if options.f is not None: print(sg)