def efield(efield=0.05, n=30): printit('running GS calculation for {}'.format(efield)) fname = "sb_relaxed.cif" a = read(fname) atom = read(fname) wire = make_supercell(atom, [[n, 0, 0], [0, 1, 0], [ 0, 0, 1]], wrap=True, tol=1e-05) wire.center(vacuum=15, axis=0) a = wire.copy() if not os.path.isfile('gs_{}.gpw'.format(efield)): calc = GPAW( # mode='lcao', mode='fd', basis='szp(dzp)', # eigensolver='cg', #mixer=Mixer(beta=0.2, nmaxold=3, weight=70.0), xc='PBE', # poissonsolver=DipoleCorrection(PoissonSolver(relax='GS'), 2), mixer=Mixer(beta=0.06, nmaxold=5, weight=100.0), occupations=FermiDirac(width=0.1), kpts={'density': 4.5}, txt='gs_output_{}.txt'.format(efield), h=0.20, external=ConstantElectricField(efield, [0, 0, 1])) a.set_calculator(calc) a.get_potential_energy() calc.write('gs_{}.gpw'.format(efield)) calc = GPAW('gs_{}.gpw'.format(efield), nbands=-100, fixdensity=True, symmetry='off', kpts={'path': 'XGX', 'npoints': 100}, convergence={'bands': 'CBM+1'}, txt='gs_output_{}.txt'.format(efield)) calc.get_potential_energy() bs = calc.band_structure() bs.plot(filename='bandstructure_{}.png'.format( efield), show=False, emax=calc.get_fermi_level()+1, emin=calc.get_fermi_level()-1) bs.write('bs_{}.json'.format( efield)) try: gap, p1, p2 = get_gap(calc) printit("{} {} {} {}".format(efield, gap, p1, p2), fname="gaps.dat") except: None
# Get the valence band maximum efermi = calc.get_fermi_level() Nk = len(calc.get_ibz_k_points()) Ns = calc.get_number_of_spins() eigval = np.array([[calc.get_eigenvalues(kpt=k, spin=s) for k in range(Nk)] for s in range(Ns)]) evbm = np.max(eigval[eigval < efermi]) # Next, a band structure calculation calc.set( nbands=nbnd, # 4 occupied and 4 unoccupied bands fixdensity=True, eigensolver=CG(niter=5), symmetry='off', kpts={ 'path': spath, 'npoints': 50 }, convergence={'bands': 'all'}, ) calc.get_potential_energy() bs_gpaw = calc.band_structure() #bs_gpaw.reference = evbm bs_gpaw_reference = evbm bs_gpaw.plot(filename='bs_gpaw_data.png', show=False, emax=evbm + 5., emin=evbm - 15.) write_json('bs_gpaw.json', bs_gpaw)
from gpaw import GPAW calc = GPAW('groundstate.rutile.gpw') atoms = calc.get_atoms() path = calc.bandpath(density=7) path.write('path.rutile.json') calc.set(kpts=path, fixdensity=True, symmetry='off') atoms.get_potential_energy() bs = calc.band_structure() bs.write('bs.rutile.json')
e = atom.get_potential_energy() calc.write('coo_gs.gpw') parprint("total energy = {}".format(e)) calc.set(nbands='nao', fixdensity=True, symmetry='off', kpts={ 'path': atom.cell.bandpath().path, 'npoints': 200 }, convergence={'bands': 'all'}) calc.get_potential_energy() calc.write('coo_bands.gpw') bs = calc.band_structure() with open('band_energies.pickle', 'wb') as handle: pickle.dump(calc.band_structure().todict(), handle, protocol=pickle.HIGHEST_PROTOCOL) bs.plot(filename='bandstructure.png', show=False, emax=8.0, emin=-8.0, reference=8.84354) else: atom = read("sqs_coo.cif") parprint("Reading from restart file") calc = GPAW('coo_gs.gpw', nbands='nao',
def test_bs(self): sb = StructureBuilder() atoms, *_ = sb.get_structure("Si", "diamond") # print(atoms) base_dir = os.path.join(os.path.dirname(__file__), "../../tmp/Si-class/") m_calc = MaterCalc(atoms=atoms, base_dir=base_dir) self.assertTrue(m_calc.relax(fmax=0.002)) # Very tight limit! self.assertTrue(m_calc.ground_state()) # get the PBE BS lattice_type = get_cellinfo(m_calc.atoms.cell).lattice self.assertTrue(lattice_type in special_paths.keys()) kpts_bs = dict(path=special_paths[lattice_type], npoints=120) gpw_name = os.path.join(base_dir, "gs.gpw") self.assertTrue(os.path.exists(gpw_name)) calc_bs = GPAW(restart=gpw_name, kpts=kpts_bs, fixdensity=True, symmetry='off', txt=os.path.join(base_dir, "pbe-bs.txt")) calc_bs.get_potential_energy() # PBE bandgap bg_pbe_min, *_ = bandgap(calc_bs, direct=False) bg_pbe_dir, *_ = bandgap(calc_bs, direct=True) calc_bs.write(os.path.join(base_dir, "pbe-bs.gpw")) bs_pbe = calc_bs.band_structure() bs_pbe.plot(emin=-10, emax=10, filename=os.path.join(base_dir, "pbe-bs.png")) # get the gllbsc by steps calc_ = GPAW(restart=gpw_name) calc_gllb = GPAW(**calc_.parameters) calc_gllb.set(xc="GLLBSC", txt=os.path.join(base_dir, "gllb-gs.txt")) calc_gllb.atoms = calc_.atoms del calc_ calc_gllb.get_potential_energy() # SC calculation calc_gllb.write("gllb-gs.gpw") calc_gllb_bs = GPAW(restart="gllb-gs.gpw", kpts=kpts_bs, fixdensity=True, symmetry="off", txt=os.path.join(base_dir, "gllb-bs.txt")) world.barrier() calc_gllb_bs.get_potential_energy() homolumo = calc_gllb_bs.get_homo_lumo() bg_gllb_ks = homolumo[1] - homolumo[0] response = calc_gllb_bs.hamiltonian.xc.xcs["RESPONSE"] response.calculate_delta_xc(homolumo / Ha) EKs, Dxc = response.calculate_delta_xc_perturbation() bg_gllb_deltaxc = EKs + Dxc ibz_kpts = calc_gllb_bs.get_ibz_k_points() e_kn = numpy.array([calc_gllb_bs.get_eigenvalues(kpt=k) \ for k in range(len(ibz_kpts))]) efermi = calc_gllb_bs.get_fermi_level() e_kn[e_kn > efermi] += Dxc bg_gllb_min, *_ = bandgap(eigenvalues=e_kn, efermi=efermi, direct=False) bg_gllb_dir, *_ = bandgap(eigenvalues=e_kn, efermi=efermi, direct=True) parprint("PBE: E_min \t E_dir") parprint("{:.3f}\t{:.3f}".format(bg_pbe_min, bg_pbe_dir)) parprint("Gllb: EKS \t E_deltaxc") parprint("{:.3f}\t{:.3f}".format(bg_gllb_ks, bg_gllb_deltaxc)) parprint("Gllb: E_min \t E_dir") parprint("{:.3f}\t{:.3f}".format(bg_gllb_min, bg_gllb_dir)) bs_gllb = calc_gllb_bs.band_structure() bs_gllb.energies[bs_gllb.energies > bs_gllb.reference] += Dxc bs_gllb.plot(emin=-10, emax=10, filename=os.path.join(base_dir, "gllb-bs.png")) calc_gllb_bs.write(os.path.join(base_dir, "gllb-bs.gpw"))
def _main(): si = make_Si_cell() # First step: find the ground-state charge density. # Use plane-wave basis with 200 eV wavefunction cutoff energy. # Cutoff energy should be chosen such that the error introduced by the incompleteness # of the basis is not too high. # The appropriate energy is different for each atom. # See here: https://wiki.fysik.dtu.dk/gpaw/setups/Si.html calc = GPAW( mode=PW(200), # PBE exchange-correlation functional xc='PBE', # Sample the Brillouin zone with 8 k-points in each reciprocal lattice direction kpts=(8, 8, 8), # Smear step functions appearing in Brillouin zone integrals using Fermi-Dirac # distribution at temperature k_B T = 0.01 eV. occupations=FermiDirac(0.01), # Start calculation using random wavefunctions. # We have a physically-reasonable initial value for the charge density based # on the atomic positions. # The Hamiltonian is diagonalized iteratively, so we also need an initial guess for # the wavefunctions. Random starting wavefunctions generally work well. random=True, # Set the log file for the ground-state DFT calculation. txt="Si_gs.txt") si.calc = calc # To make GPAW perform the DFT calculation, we need to ask it for something # that it needs to perform the calculation to know. si.get_potential_energy() # Save the result for the ground state so we can load it later. ground_state_file = "Si_gs.gpw" calc.write(ground_state_file) # Second step: using the converged ground-state charge density, calculate the # wavefunctions along a high-symmetry path in the Brilllouin zone. # The energies along this path give the band structure diagram. calc = GPAW( ground_state_file, # Include the 16 lowest-energy valence bands in the calculation. nbands=16, # Keep the charge density constant, using our converged ground-state density. fixdensity=True, # Don't consider symmetry in the k-point distribution: we want to use exactly # the k-points we specify. # (In the ground-state calculation, many k-points can be eliminated due to # being redundant by symmetry.) symmetry='off', # Use a high-symmetry k-point path. # High-symmetry paths following the [SC10] convention for band structure are # built-in (can use these if our unit cell also follows the [SC10] convention). # Use 300 k-points total. kpts={ 'path': special_paths['fcc'], 'npoints': 300 }, # Require that the energies of the lowest 8 bands are well-converged. convergence={'bands': 8}, # Set the log file for the band-structure calculation. txt="Si_bands.txt") # Make GPAW perform the band-structure calculation. calc.get_potential_energy() # Plot the band structure. # Since we used kpoints={'path': ...}, we can use an ASE convenience function for this. bs = calc.band_structure() bs.plot(filename="Si_bands.png")
from gpaw import GPAW # Restart from ground state and fix potential: calc = GPAW("Si_gs.gpw", nbands=16, fixdensity=True, symmetry="off", kpts={"path": "GXWKL", "npoints": 60}, convergence={"bands": 8}, txt="LOG_Si_bands.txt") calc.get_potential_energy() bs = calc.band_structure() # band structure info, such as energies, path, etc bs.plot(filename="bandstructure.png", emax=10.0) calc.write("Si_bands.gpw")
def bandgap(self, method="GLLB", save=True, skip=False): # Check method input method = method.strip().lower() if method not in ("pbe", "gllb", "hse", "gw"): raise ValueError("Method for bandgap calculation not known!") # Check ground state if not os.path.exists(self.__gs_file): raise FileNotFoundError("Ground state not calculated!") # Check bandgap? self.__bg_file = self.__bg_file_template.format(method) if os.path.exists(self.__bg_file): parprint( "Bandgap for method {} is already calculated!".format(method)) data = numpy.load(self.__bg_file) return data["Eg_min"], data["Eg_dir"], None # Real calculation now if method == "pbe": # Use band_structure or simple sampling kpts? calc = GPAW(restart=self.__gs_file) try: lattice_type = get_cellinfo(calc.atoms.cell).lattice use_bs = lattice_type in special_paths.keys() except (ValueError, AssertionError): # Monolithic cell? use_bs = False parprint("Use bandpath?", use_bs) if use_bs: kpts = dict(path=special_paths[lattice_type], npoints=self.params["gap"][method]["npoints"]) calc.set(kpts=kpts, fixdensity=True, symmetry="off", txt=None) # non-SC calc.get_potential_energy( ) # Otherwise the wavefunction not known? bg_min, *_ = bg(calc, direct=False) bg_dir, *_ = bg(calc, direct=True) # Possibly no gap if bg_min is None: bg_min = 0 if bg_dir is None: bg_dir = 0 if use_bs: bs = calc.band_structure() xcoords, label_xcoords, labels = bs.get_labels() res_bs = bs.todict() res_bs.update(xcoords=xcoords, label_xcoords=label_xcoords, labels=labels) else: res_bs = {} # no result if save: if rank == 0: numpy.savez(self.__bg_file, Eg_min=bg_min, Eg_dir=bg_dir, **res_bs) print("Bandgap saved!") world.barrier() return bg_min, bg_dir, res_bs elif method == "gllb": # Need to restart the SC calculation if not os.path.exists(self.__gs_gllb_file): if not os.path.exists(self.__relaxed_gllb_traj): self.relax(fmax=0.002, steps=200, xc="gllb", skip=skip) world.barrier() atoms = read(self.__relaxed_gllb_traj) calc = GPAW(**self.params["gs"], txt=os.path.join(self.__base_dir, "gs_gllb.txt")) atoms.set_calculator(calc) calc.set(xc="GLLBSC") atoms.get_potential_energy() # Recalculate GS calc.write(self.__gs_gllb_file, mode="all") #TODO: merge with PBE method calc_bs = GPAW(restart=self.__gs_gllb_file) try: lattice_type = get_cellinfo(calc_bs.atoms.cell).lattice use_bs = lattice_type in special_paths.keys() except (ValueError, AssertionError): # Monolithic cell? use_bs = False if use_bs: kpts = dict(path=special_paths[lattice_type], npoints=self.params["gap"][method]["npoints"]) calc_bs.set(kpts=kpts, fixdensity=True, symmetry="off") calc_bs.get_potential_energy() homolumo = calc_bs.get_homo_lumo() response = calc_bs.hamiltonian.xc.xcs["RESPONSE"] response.calculate_delta_xc(homolumo / Ha) EKs, Dxc = response.calculate_delta_xc_perturbation() ns = calc_bs.get_number_of_spins() nk = len(calc_bs.get_ibz_k_points()) e_kn = numpy.array([[calc_bs.get_eigenvalues(kpt=k, spin=s) \ for k in range(nk)] for s in range(ns)]) efermi = calc_bs.get_fermi_level() e_kn[e_kn > efermi] += Dxc bg_gllb_min, *_ = bg(eigenvalues=e_kn, efermi=efermi, direct=False) bg_gllb_dir, *_ = bg(eigenvalues=e_kn, efermi=efermi, direct=True) if bg_gllb_min is None: bg_gllb_min = 0 if bg_gllb_dir is None: bg_gllb_dir = 0 if use_bs: bs = calc_bs.band_structure() bs.energies[bs.energies > bs.reference] += Dxc # Shift gllbsc discontinuous res_bs = bs.todict() xcoords, label_xcoords, labels = bs.get_labels() res_bs.update(xcoords=xcoords, label_xcoords=label_xcoords, labels=labels) else: res_bs = {} if save: if rank == 0: numpy.savez(self.__bg_file, Eg_min=bg_gllb_min, Eg_dir=bg_gllb_dir, **res_bs) print("Bandgap saved!") world.barrier() return bg_gllb_min, bg_gllb_dir, res_bs else: raise NotImplementedError("Method not implemented yet")