def __init__( self, atoms, # XXX do we need atoms at this stage ? *args, name='raman', exext='.alpha', txt='-', verbose=False, comm=world, **kwargs): """ Parameters ---------- atoms: ase Atoms object exext: string Extension for excitation filenames txt: Output stream verbose: Verbosity level of output comm: Communicator, default world """ kwargs['name'] = name self.exname = kwargs.pop('exname', name) super().__init__(atoms, *args, **kwargs) self.exext = exext self.timer = Timer() self.txt = convert_string_to_fd(txt) self.verbose = verbose self.comm = comm
def __init__(self, cell_cv, response='density', comm=mpi.world, txt='-', timer=None, nblocks=1, eshift=0.0): """Baseclass for Brillouin zone integration and band summation. Simple class to calculate integrals over Brilloun zones and summation of bands. comm: mpi.communicator nblocks: block parallelization """ self.response = response self.comm = comm self.eshift = eshift self.nblocks = nblocks self.vol = abs(np.linalg.det(cell_cv)) if nblocks == 1: self.blockcomm = self.comm.new_communicator([comm.rank]) self.kncomm = comm else: assert comm.size % nblocks == 0, comm.size rank1 = comm.rank // nblocks * nblocks rank2 = rank1 + nblocks self.blockcomm = self.comm.new_communicator(range(rank1, rank2)) ranks = range(comm.rank % nblocks, comm.size, nblocks) self.kncomm = self.comm.new_communicator(ranks) if comm.rank != 0: txt = devnull self.fd = convert_string_to_fd(txt, comm) self.timer = timer or Timer()
def calculate_renormalized_kernel(pd, calc, functional, fd): """Renormalized kernel""" from gpaw.xc.fxc import KernelDens kernel = KernelDens(calc, functional, [pd.kd.bzk_kc[0]], fd, calc.wfs.kd.N_c, None, ecut=pd.ecut * Ha, tag='', timer=Timer()) kernel.calculate_fhxc() r = Reader('fhxc_%s_%s_%s_%s.gpw' % ('', functional, pd.ecut * Ha, 0)) Kxc_sGG = np.array([r.get('fhxc_sGsG')]) v_G = 4 * np.pi / pd.G2_qG[0] Kxc_sGG[0] -= np.diagflat(v_G) if pd.kd.gamma: Kxc_sGG[:, 0, :] = 0.0 Kxc_sGG[:, :, 0] = 0.0 return Kxc_sGG
def __init__( self, atoms, Excitations, indices=None, gsname='rraman', # name for ground state calculations exname=None, # name for excited state calculations delta=0.01, nfree=2, directions=None, exkwargs={}, # kwargs to be passed to Excitations exext='.ex.gz', # extension for Excitation names txt='-', verbose=False): assert (nfree == 2) Vibrations.__init__(self, atoms, indices, gsname, delta, nfree) self.name = gsname + '-d%.3f' % delta if exname is None: exname = gsname self.exname = exname + '-d%.3f' % delta self.exext = exext if directions is None: self.directions = np.array([0, 1, 2]) else: self.directions = np.array(directions) self.exobj = Excitations self.exkwargs = exkwargs self.timer = Timer() self.txt = get_txt(txt, rank) self.verbose = verbose
def __init__(self, calc, xc='RPA', filename=None, skip_gamma=False, qsym=True, nlambda=None, nfrequencies=16, frequency_max=800.0, frequency_scale=2.0, frequencies=None, weights=None, world=mpi.world, nblocks=1, wstc=False, txt=sys.stdout): if isinstance(calc, str): calc = GPAW(calc, txt=None, communicator=mpi.serial_comm) self.calc = calc if world.rank != 0: txt = devnull elif isinstance(txt, str): txt = open(txt, 'w') self.fd = txt self.timer = Timer() if frequencies is None: frequencies, weights = get_gauss_legendre_points( nfrequencies, frequency_max, frequency_scale) user_spec = False else: assert weights is not None user_spec = True self.omega_w = frequencies / Hartree self.weight_w = weights / Hartree if nblocks > 1: assert len(self.omega_w) % nblocks == 0 assert wstc self.wstc = wstc self.nblocks = nblocks self.world = world self.skip_gamma = skip_gamma self.ibzq_qc = None self.weight_q = None self.initialize_q_points(qsym) # Energies for all q-vetors and cutoff energies: self.energy_qi = [] self.filename = filename self.print_initialization(xc, frequency_scale, nlambda, user_spec)
def get_xc_kernel(pd, chi0, functional='ALDA', chi0_wGG=None): """Factory function that calls the relevant functions below""" calc = chi0.calc fd = chi0.fd nspins = len(calc.density.nt_sG) assert nspins == 1 if functional[0] == 'A': # Standard adiabatic kernel print('Calculating %s kernel' % functional, file=fd) Kxc_sGG = calculate_Kxc(pd, calc, functional=functional) elif functional[0] == 'r': # Renormalized kernel print('Calculating %s kernel' % functional, file=fd) from gpaw.xc.fxc import KernelDens kernel = KernelDens( calc, functional, [pd.kd.bzk_kc[0]], fd, calc.wfs.kd.N_c, None, ecut=pd.ecut * Ha, tag='', timer=Timer(), ) kernel.calculate_fhxc() r = Reader('fhxc_%s_%s_%s_%s.gpw' % ('', functional, pd.ecut * Ha, 0)) Kxc_sGG = np.array([r.get('fhxc_sGsG')]) v_G = 4 * np.pi / pd.G2_qG[0] Kxc_sGG[0] -= np.diagflat(v_G) if pd.kd.gamma: Kxc_sGG[:, 0, :] = 0.0 Kxc_sGG[:, :, 0] = 0.0 elif functional[:2] == 'LR': print('Calculating LR kernel with alpha = %s' % functional[2:], file=fd) Kxc_sGG = calculate_lr_kernel(pd, calc, alpha=float(functional[2:])) elif functional == 'DM': print('Calculating DM kernel', file=fd) Kxc_sGG = calculate_dm_kernel(pd, calc) elif functional == 'Bootstrap': print('Calculating Bootstrap kernel', file=fd) if chi0.world.rank == 0: chi0_GG = chi0_wGG[0] chi0.world.broadcast(chi0_GG, 0) else: nG = pd.ngmax chi0_GG = np.zeros((nG, nG), complex) chi0.world.broadcast(chi0_GG, 0) Kxc_sGG = calculate_bootstrap_kernel(pd, chi0_GG, fd) else: raise ValueError('%s kernel not implemented' % functional) return Kxc_sGG
def __init__(self, lrtddft=None, index=0, d=0.001, txt=None, parallel=0, communicator=None, name=None, restart=None): """ExcitedState object. parallel: Can be used to parallelize the numerical force calculation over images. """ self.timer = Timer() self.atoms = None if isinstance(index, int): self.index = UnconstraintIndex(index) else: self.index = index self.results = {} self.results['forces'] = None self.results['energy'] = None if communicator is None: try: communicator = lrtddft.calculator.wfs.world except: communicator = mpi.world self.world = communicator if restart is not None: self.read(restart) if txt is None: self.txt = self.lrtddft.txt else: self.txt = convert_string_to_fd(txt, self.world) if lrtddft is not None: self.lrtddft = lrtddft self.calculator = self.lrtddft.calculator self.atoms = self.calculator.atoms self.parameters = self.calculator.parameters if txt is None: self.txt = self.lrtddft.txt else: self.txt = convert_string_to_fd(txt, self.world) self.d = d self.parallel = parallel self.name = name self.log = GPAWLogger(self.world) self.log.fd = self.txt self.reader = None self.calculator.log.fd = self.txt self.log('#', self.__class__.__name__, __version__) self.log('#', self.index) if name: self.log('name=' + name) self.log('# Force displacement:', self.d) self.log
def __init__(self, calculator=None, **kwargs): self.timer = Timer() self.diagonalized = False changed = self.set(**kwargs) if isinstance(calculator, basestring): ExcitationList.__init__(self, None, self.txt) self.filename = calculator else: ExcitationList.__init__(self, calculator, self.txt) if self.filename is not None: self.read(self.filename) if set(['istart', 'jend', 'energy_range']) & set(changed): # the user has explicitely demanded these self.diagonalize() return if self.eh_comm is None: self.eh_comm = mpi.serial_comm elif isinstance(self.eh_comm, (mpi.world.__class__, mpi.serial_comm.__class__)): # Correct type already. pass else: # world should be a list of ranks: self.eh_comm = mpi.world.new_communicator(np.asarray(self.eh_comm)) if calculator is not None and calculator.initialized: # XXXX not ready for k-points assert (len(calculator.wfs.kd.ibzk_kc) == 1) if not isinstance(calculator.wfs, FDWaveFunctions): raise RuntimeError( 'Linear response TDDFT supported only in real space mode') if calculator.wfs.kd.comm.size > 1: err_txt = 'Spin parallelization with Linear response ' err_txt += "TDDFT. Use parallel={'domain': world.size} " err_txt += 'calculator parameter.' raise NotImplementedError(err_txt) if self.xc == 'GS': self.xc = calculator.hamiltonian.xc if calculator.parameters.mode != 'lcao': calculator.converge_wave_functions() if calculator.density.nct_G is None: spos_ac = calculator.initialize_positions() calculator.wfs.initialize(calculator.density, calculator.hamiltonian, spos_ac) self.update(calculator)
def __init__(self, restart=None, ignore_bad_restart_file=False, label=None, atoms=None, timer=None, communicator=None, txt='-', parallel=None, **kwargs): self.parallel = dict(self.default_parallel) if parallel: for key in parallel: if key not in self.default_parallel: allowed = ', '.join(list(self.default_parallel.keys())) raise TypeError('Unexpected keyword "{}" in "parallel" ' 'dictionary. Must be one of: {}'.format( key, allowed)) self.parallel.update(parallel) if timer is None: self.timer = Timer() else: self.timer = timer self.scf = None self.wfs = None self.occupations = None self.density = None self.hamiltonian = None self.spos_ac = None # XXX store this in some better way. self.observers = [] # XXX move to self.scf self.initialized = False self.world = communicator if self.world is None: self.world = mpi.world elif not hasattr(self.world, 'new_communicator'): self.world = mpi.world.new_communicator(np.asarray(self.world)) self.log = GPAWLogger(world=self.world) self.log.fd = txt self.reader = None Calculator.__init__(self, restart, ignore_bad_restart_file, label, atoms, **kwargs)
def __init__(self, calculator=None, **kwargs): self.timer = Timer() self.set(**kwargs) if isinstance(calculator, str): ExcitationList.__init__(self, None, self.txt) self.filename = calculator else: ExcitationList.__init__(self, calculator, self.txt) if self.filename is not None: return self.read(self.filename) if self.eh_comm is None: self.eh_comm = mpi.serial_comm elif isinstance(self.eh_comm, (mpi.world.__class__, mpi.serial_comm.__class__)): # Correct type already. pass else: # world should be a list of ranks: self.eh_comm = mpi.world.new_communicator(np.asarray(eh_comm)) if calculator is not None and calculator.initialized: if not isinstance(calculator.wfs, FDWaveFunctions): raise RuntimeError( 'Linear response TDDFT supported only in real space mode') if calculator.wfs.kd.comm.size > 1: err_txt = 'Spin parallelization with Linear response ' err_txt += "TDDFT. Use parallel = {'domain' : 'domain_only'} " err_txt += 'calculator parameter.' raise NotImplementedError(err_txt) if self.xc == 'GS': self.xc = calculator.hamiltonian.xc.name if calculator.input_parameters.mode != 'lcao': calculator.converge_wave_functions() if calculator.density.nct_G is None: spos_ac = calculator.initialize_positions() calculator.wfs.initialize(calculator.density, calculator.hamiltonian, spos_ac) self.update(calculator)
def __init__(self, restart=None, ignore_bad_restart_file=False, label=None, atoms=None, timer=None, communicator=None, txt='-', parallel=None, **kwargs): self.parallel = dict(self.default_parallel) if parallel: self.parallel.update(parallel) if timer is None: self.timer = Timer() else: self.timer = timer self.scf = None self.wfs = None self.occupations = None self.density = None self.hamiltonian = None self.observers = [] # XXX move to self.scf self.initialized = False self.world = communicator if self.world is None: self.world = mpi.world elif not hasattr(self.world, 'new_communicator'): self.world = mpi.world.new_communicator(np.asarray(self.world)) self.log = GPAWLogger(world=self.world) self.log.fd = txt self.reader = None Calculator.__init__(self, restart, ignore_bad_restart_file, label, atoms, **kwargs)
def __init__(self, lrtddft, d=0.001, txt=None, parallel=None): """Finite difference calculator for LrTDDFT. parallel: Can be used to parallelize the numerical force calculation over images """ self.timer = Timer() self.atoms = None world = mpi.world if lrtddft is not None: self.lrtddft = lrtddft self.calculator = self.lrtddft.calculator self.atoms = self.calculator.atoms if self.calculator.initialized: world = self.calculator.wfs.world if txt is None: self.txt = self.lrtddft.txt else: self.txt = get_txt(txt, world.rank) prnt('#', self.__class__.__name__, version, file=self.txt) self.d = d self.parallel = { 'world': world, 'mycomm': world, 'ncalcs': 1, 'icalc': 0} if world.size < 2: if parallel > 0: prnt('#', (self.__class__.__name__ + ':'), 'Serial calculation, keyword parallel ignored.', file=self.txt) elif parallel > 0: mycomm, ncalcs, icalc = distribute_cpus(parallel, world) if type(ncalcs) != type(1): # this is ase < r3431 ncalcs = world.size / parallel self.parallel = {'world': world, 'mycomm': mycomm, 'ncalcs': ncalcs, 'icalc': icalc} self.calculator.set(communicator=mycomm)
def __init__( self, atoms, Excitations, indices=None, gsname='rraman', # name for ground state calculations exname=None, # name for excited state calculations delta=0.01, nfree=2, directions=None, approximation='Profeta', observation={'geometry': '-Z(XX)Z'}, exkwargs={}, # kwargs to be passed to Excitations exext='.ex.gz', # extension for Excitation names txt='-', verbose=False, ): assert (nfree == 2) Vibrations.__init__(self, atoms, indices, gsname, delta, nfree) self.name = gsname + '-d%.3f' % delta if exname is None: exname = gsname self.exname = exname + '-d%.3f' % delta self.exext = exext if directions is None: self.directions = np.array([0, 1, 2]) else: self.directions = np.array(directions) self.approximation = approximation self.observation = observation self.exobj = Excitations self.exkwargs = exkwargs self.timer = Timer() self.txt = convert_string_to_fd(txt) self.verbose = verbose
def get_rpa(self): """Calculate RPA and Hartree-fock part of the A+-B matrices.""" # shorthands kss = self.fullkss finegrid = self.finegrid yukawa = hasattr(self.xc, 'rsf') and (self.xc.rsf == 'Yukawa') # calculate omega matrix nij = len(kss) print('RPAhyb', nij, 'transitions', file=self.txt) AmB = np.zeros((nij, nij)) ApB = self.ApB # storage place for Coulomb integrals integrals = {} if yukawa: rsf_integrals = {} # setup things for IVOs if self.xc.excitation is not None or self.xc.excited != 0: sin_tri_weight = 1 if self.xc.excitation is not None: ex_type = self.xc.excitation.lower() if ex_type == 'singlet': sin_tri_weight = 2 elif ex_type == 'triplet': sin_tri_weight = 0 h**o = int(self.paw.get_number_of_electrons() // 2) ivo_l = h**o - self.xc.excited - 1 else: ivo_l = None for ij in range(nij): print('RPAhyb kss[' + '%d' % ij + ']=', kss[ij], file=self.txt) timer = Timer() timer.start('init') timer2 = Timer() # smooth density including compensation charges timer2.start('with_compensation_charges 0') rhot_p = kss[ij].with_compensation_charges(finegrid != 0) timer2.stop() # integrate with 1/|r_1-r_2| timer2.start('poisson') phit_p = np.zeros(rhot_p.shape, rhot_p.dtype) self.poisson.solve(phit_p, rhot_p, charge=None) timer2.stop() timer.stop() t0 = timer.get_time('init') timer.start(ij) if finegrid == 1: rhot = kss[ij].with_compensation_charges() phit = self.gd.zeros() self.restrict(phit_p, phit) else: phit = phit_p rhot = rhot_p for kq in range(ij, nij): if kq != ij: # smooth density including compensation charges timer2.start('kq with_compensation_charges') rhot = kss[kq].with_compensation_charges(finegrid == 2) timer2.stop() pre = self.weight_Kijkq(ij, kq) timer2.start('integrate') I = self.Coulomb_integral_kss(kss[ij], kss[kq], phit, rhot) if kss[ij].spin == kss[kq].spin: name = self.Coulomb_integral_name(kss[ij].i, kss[ij].j, kss[kq].i, kss[kq].j, kss[ij].spin) integrals[name] = I ApB[ij, kq] = pre * I timer2.stop() if ij == kq: epsij = kss[ij].get_energy() / kss[ij].get_weight() AmB[ij, kq] += epsij ApB[ij, kq] += epsij timer.stop() # timer2.write() if ij < (nij - 1): print('RPAhyb estimated time left', self.time_left(timer, t0, ij, nij), file=self.txt) # add HF parts and apply symmetry if hasattr(self.xc, 'hybrid'): weight = self.xc.hybrid else: weight = 0.0 for ij in range(nij): print('HF kss[' + '%d' % ij + ']', file=self.txt) timer = Timer() timer.start('init') timer.stop() t0 = timer.get_time('init') timer.start(ij) i = kss[ij].i j = kss[ij].j s = kss[ij].spin for kq in range(ij, nij): if kss[ij].pspin == kss[kq].pspin: k = kss[kq].i q = kss[kq].j ikjq = self.Coulomb_integral_ijkq(i, k, j, q, s, integrals) iqkj = self.Coulomb_integral_ijkq(i, q, k, j, s, integrals) if yukawa: # Yukawa integrals might be caches ikjq -= self.Coulomb_integral_ijkq( i, k, j, q, s, rsf_integrals, yukawa) iqkj -= self.Coulomb_integral_ijkq( i, q, k, j, s, rsf_integrals, yukawa) ApB[ij, kq] -= weight * (ikjq + iqkj) AmB[ij, kq] -= weight * (ikjq - iqkj) ApB[kq, ij] = ApB[ij, kq] AmB[kq, ij] = AmB[ij, kq] timer.stop() if ij < (nij - 1): print('HF estimated time left', self.time_left(timer, t0, ij, nij), file=self.txt) if ivo_l is not None: # IVO RPA after Berman, Kaldor, Chem. Phys. 43 (3) 1979 # doi: 10.1016/0301-0104(79)85205-2 l = ivo_l for ij in range(nij): i = kss[ij].i j = kss[ij].j s = kss[ij].spin for kq in range(ij, nij): if kss[kq].i == i and kss[ij].pspin == kss[kq].pspin: k = kss[kq].i q = kss[kq].j jqll = self.Coulomb_integral_ijkq( j, q, l, l, s, integrals) jllq = self.Coulomb_integral_ijkq( j, l, l, q, s, integrals) if yukawa: jqll -= self.Coulomb_integral_ijkq( j, q, l, l, s, rsf_integrals, yukawa) jllq -= self.Coulomb_integral_ijkq( j, l, l, q, s, rsf_integrals, yukawa) jllq *= sin_tri_weight ApB[ij, kq] += weight * (jqll - jllq) AmB[ij, kq] += weight * (jqll - jllq) ApB[kq, ij] = ApB[ij, kq] AmB[kq, ij] = AmB[ij, kq] return AmB
def __init__(self, atoms, Excitations, indices=None, gsname='rraman', # name for ground state calculations exname=None, # name for excited state calculations delta=0.01, nfree=2, directions=None, observation={'geometry': '-Z(XX)Z'}, form='v', # form of the dipole operator exkwargs={}, # kwargs to be passed to Excitations exext='.ex.gz', # extension for Excitation names txt='-', verbose=False, overlap=False, minoverlap=0.02, minrep=0.8, comm=world, ): """ Parameters ---------- atoms: ase Atoms object Excitations: class Type of the excitation list object. The class object is initialized as:: Excitations(atoms.get_calculator()) or by reading form a file as:: Excitations('filename', **exkwargs) The file is written by calling the method Excitations.write('filename'). Excitations should work like a list of ex obejects, where: ex.get_dipole_me(form='v'): gives the velocity form dipole matrix element in units |e| * Angstrom ex.energy: is the transition energy in Hartrees indices: list gsname: string name for ground state calculations exname: string name for excited state calculations delta: float Finite difference displacement in Angstrom. nfree: float directions: approximation: string Level of approximation used. observation: dict Polarization settings form: string Form of the dipole operator, 'v' for velocity form (default) and 'r' for length form. exkwargs: dict Arguments given to the Excitations objects in reading. exext: string Extension for filenames of Excitation lists. txt: Output stream verbose: Verbosity level of output overlap: bool or function Use wavefunction overlaps. minoverlap: float ord dict Minimal absolute overlap to consider. Defaults to 0.02 to avoid numerical garbage. minrep: float Minimal represention to consider derivative, defaults to 0.8 """ assert(nfree == 2) Vibrations.__init__(self, atoms, indices, gsname, delta, nfree) self.name = gsname + '-d%.3f' % delta if exname is None: exname = gsname self.exname = exname + '-d%.3f' % delta self.exext = exext if directions is None: self.directions = np.array([0, 1, 2]) else: self.directions = np.array(directions) self.observation = observation self.exobj = Excitations self.exkwargs = exkwargs self.dipole_form = form self.timer = Timer() self.txt = convert_string_to_fd(txt) self.verbose = verbose self.overlap = overlap if not isinstance(minoverlap, dict): # assume it's a number self.minoverlap = {'orbitals': minoverlap, 'excitations': minoverlap} else: self.minoverlap = minoverlap self.minrep = minrep self.comm = comm
def __init__(self, calc, xc='RPA', filename=None, skip_gamma=False, qsym=True, nlambda=None, nfrequencies=16, frequency_max=800.0, frequency_scale=2.0, frequencies=None, weights=None, truncation=None, world=mpi.world, nblocks=1, txt=sys.stdout): """Creates the RPACorrelation object calc: str or calculator object The string should refer to the .gpw file contaning KS orbitals xc: str Exchange-correlation kernel. This is only different from RPA when this object is constructed from a different module - e.g. fxc.py filename: str txt output skip_gamme: bool If True, skip q = [0,0,0] from the calculation qsym: bool Use symmetry to reduce q-points nlambda: int Number of lambda points. Only used for numerical coupling constant integration involved when called from fxc.py nfrequencies: int Number of frequency points used in the Gauss-Legendre integration frequency_max: float Largest frequency point in Gauss-Legendre integration frequency_scale: float Determines density of frequency points at low frequencies. A slight increase to e.g. 2.5 or 3.0 improves convergence wth respect to frequency points for metals frequencies: list List of frequancies for user-specified frequency integration weights: list list of weights (integration measure) for a user specified frequency grid. Must be specified and have the same length as frequencies if frequencies is not None truncation: str Coulomb truncation scheme. Can be either wigner-seitz, 2D, 1D, or 0D world: communicator nblocks: int Number of parallelization blocks. Frequency parallelization can be specified by setting nblocks=nfrequencies and is useful for memory consuming calculations txt: str txt file for saving and loading contributions to the correlation energy from different q-points """ if isinstance(calc, str): calc = GPAW(calc, txt=None, communicator=mpi.serial_comm) self.calc = calc if world.rank != 0: txt = devnull elif isinstance(txt, str): txt = open(txt, 'w', 1) self.fd = txt self.timer = Timer() if frequencies is None: frequencies, weights = get_gauss_legendre_points(nfrequencies, frequency_max, frequency_scale) user_spec = False else: assert weights is not None user_spec = True self.omega_w = frequencies / Hartree self.weight_w = weights / Hartree if nblocks > 1: assert len(self.omega_w) % nblocks == 0 self.nblocks = nblocks self.world = world self.truncation = truncation self.skip_gamma = skip_gamma self.ibzq_qc = None self.weight_q = None self.initialize_q_points(qsym) # Energies for all q-vetors and cutoff energies: self.energy_qi = [] self.filename = filename self.print_initialization(xc, frequency_scale, nlambda, user_spec)
def __init__(self): self.timer = Timer()
from __future__ import print_function from ase import Atoms from ase.parallel import parprint from ase.utils.timing import Timer from gpaw import GPAW from gpaw.test import equal from gpaw.xc.hybrid import HybridXC timer = Timer() loa = Atoms('Be2', [(0, 0, 0), (2.45, 0, 0)], cell=[5.9, 4.8, 5.0]) loa.center() txt = None xc = 'PBE0' nbands = 4 unocc = True load = False # usual calculation fname = 'Be2.gpw' if not load: xco = HybridXC(xc) cocc = GPAW(h=0.3, eigensolver='rmm-diis', xc=xco, nbands=nbands, convergence={'eigenstates': 1e-4},
def __init__(self, calc, response='density', frequencies=None, domega0=0.1, omega2=10.0, omegamax=None, ecut=50, gammacentered=False, hilbert=True, nbands=None, timeordered=False, eta=0.2, ftol=1e-6, threshold=1, real_space_derivatives=False, intraband=True, world=mpi.world, txt='-', timer=None, nblocks=1, gate_voltage=None, disable_point_group=False, disable_time_reversal=False, disable_non_symmorphic=True, scissor=None, integrationmode=None, pbc=None, rate=0.0, eshift=0.0): """Construct Chi0 object. Parameters ---------- calc : str The groundstate calculation file that the linear response calculation is based on. response : str Type of response function. Currently collinear, scalar options 'density', '+-' and '-+' are implemented. frequencies : ndarray or None Array of frequencies to evaluate the response function at. If None, frequencies are determined using the frequency_grid function in gpaw.response.chi0. domega0, omega2, omegamax : float Input parameters for frequency_grid. ecut : float Energy cutoff. gammacentered : bool Center the grid of plane waves around the gamma point or q-vector hilbert : bool Switch for hilbert transform. If True, the full density response is determined from a hilbert transform of its spectral function. This is typically much faster, but does not work for imaginary frequencies. nbands : int Maximum band index to include. timeordered : bool Switch for calculating the time ordered density response function. In this case the hilbert transform cannot be used. eta : float Artificial broadening of spectra. ftol : float Threshold determining whether a band is completely filled (f > 1 - ftol) or completely empty (f < ftol). threshold : float Numerical threshold for the optical limit k dot p perturbation theory expansion (used in gpaw/response/pair.py). real_space_derivatives : bool Switch for calculating nabla matrix elements (in the optical limit) using a real space finite difference approximation. intraband : bool Switch for including the intraband contribution to the density response function. world : MPI comm instance MPI communicator. txt : str Output file. timer : gpaw.utilities.timing.timer instance nblocks : int Divide the response function into nblocks. Useful when the response function is large. gate_voltage : float Shift the fermi level by gate_voltage [Hartree]. disable_point_group : bool Do not use the point group symmetry operators. disable_time_reversal : bool Do not use time reversal symmetry. disable_non_symmorphic : bool Do no use non symmorphic symmetry operators. scissor : tuple ([bands], shift [eV]) Use scissor operator on bands. integrationmode : str Integrator for the kpoint integration. If == 'tetrahedron integration' then the kpoint integral is performed using the linear tetrahedron method. pbc : list Periodic directions of the system. Defaults to [True, True, True]. eshift : float Shift unoccupied bands Attributes ---------- pair : gpaw.response.pair.PairDensity instance Class for calculating matrix elements of pairs of wavefunctions. """ self.response = response self.timer = timer or Timer() self.pair = PairDensity(calc, ecut, self.response, ftol, threshold, real_space_derivatives, world, txt, self.timer, nblocks=nblocks, gate_voltage=gate_voltage) self.disable_point_group = disable_point_group self.disable_time_reversal = disable_time_reversal self.disable_non_symmorphic = disable_non_symmorphic self.integrationmode = integrationmode self.eshift = eshift / Hartree calc = self.pair.calc self.calc = calc if world.rank != 0: txt = devnull elif isinstance(txt, str): txt = open(txt, 'w') self.fd = txt self.vol = abs(np.linalg.det(calc.wfs.gd.cell_cv)) self.world = world if nblocks == 1: self.blockcomm = self.world.new_communicator([world.rank]) self.kncomm = world else: assert world.size % nblocks == 0, world.size rank1 = world.rank // nblocks * nblocks rank2 = rank1 + nblocks self.blockcomm = self.world.new_communicator(range(rank1, rank2)) ranks = range(world.rank % nblocks, world.size, nblocks) self.kncomm = self.world.new_communicator(ranks) self.nblocks = nblocks if world.rank != 0: txt = devnull elif isinstance(txt, str): txt = open(txt, 'w') self.fd = txt if ecut is not None: ecut /= Hartree self.ecut = ecut self.gammacentered = gammacentered self.eta = eta / Hartree if rate == 'eta': self.rate = self.eta else: self.rate = rate / Hartree self.domega0 = domega0 / Hartree self.omega2 = omega2 / Hartree self.omegamax = None if omegamax is None else omegamax / Hartree self.nbands = nbands or self.calc.wfs.bd.nbands self.include_intraband = intraband omax = self.find_maximum_frequency() if frequencies is None: if self.omegamax is None: self.omegamax = omax print('Using nonlinear frequency grid from 0 to %.3f eV' % (self.omegamax * Hartree), file=self.fd) self.wd = FrequencyDescriptor(self.domega0, self.omega2, self.omegamax) else: self.wd = ArrayDescriptor(np.asarray(frequencies) / Hartree) assert not hilbert self.omega_w = self.wd.get_data() self.hilbert = hilbert self.timeordered = bool(timeordered) if self.eta == 0.0: assert not hilbert assert not timeordered assert not self.omega_w.real.any() self.nocc1 = self.pair.nocc1 # number of completely filled bands self.nocc2 = self.pair.nocc2 # number of non-empty bands self.Q_aGii = None if pbc is not None: self.pbc = np.array(pbc) else: self.pbc = np.array([True, True, True]) if self.pbc is not None and (~self.pbc).any(): assert np.sum((~self.pbc).astype(int)) == 1, \ print('Only one non-periodic direction supported atm.') print('Nonperiodic BC\'s: ', (~self.pbc), file=self.fd) if integrationmode is not None: print('Using integration method: ' + self.integrationmode, file=self.fd) else: print('Using integration method: PointIntegrator', file=self.fd)
def get_rpa(self): """calculate RPA part of the omega matrix""" # shorthands kss = self.fullkss finegrid = self.finegrid wfs = self.paw.wfs eh_comm = self.eh_comm # calculate omega matrix nij = len(kss) print('RPA', nij, 'transitions', file=self.txt) Om = self.Om for ij in range(eh_comm.rank, nij, eh_comm.size): print('RPA kss[' + '%d' % ij + ']=', kss[ij], file=self.txt) timer = Timer() timer.start('init') timer2 = Timer() # smooth density including compensation charges timer2.start('with_compensation_charges 0') rhot_p = kss[ij].with_compensation_charges( finegrid is not 0) timer2.stop() # integrate with 1/|r_1-r_2| timer2.start('poisson') phit_p = np.zeros(rhot_p.shape, rhot_p.dtype.char) self.poisson.solve(phit_p, rhot_p, charge=None) timer2.stop() timer.stop() t0 = timer.get_time('init') timer.start(ij) if finegrid == 1: rhot = kss[ij].with_compensation_charges() phit = self.gd.zeros() # print "shapes 0=",phit.shape,rhot.shape self.restrict(phit_p, phit) else: phit = phit_p rhot = rhot_p for kq in range(ij, nij): if kq != ij: # smooth density including compensation charges timer2.start('kq with_compensation_charges') rhot = kss[kq].with_compensation_charges( finegrid is 2) timer2.stop() pre = 2 * sqrt(kss[ij].get_energy() * kss[kq].get_energy() * kss[ij].get_weight() * kss[kq].get_weight()) I = self.Coulomb_integral_kss(kss[ij], kss[kq], rhot, phit, timer2) Om[ij, kq] = pre * I if ij == kq: Om[ij, kq] += kss[ij].get_energy() ** 2 else: Om[kq, ij] = Om[ij, kq] timer.stop() # timer2.write() if ij < (nij - 1): t = timer.get_time(ij) # time for nij-ij calculations t = .5 * t * \ (nij - ij) # estimated time for n*(n+1)/2, n=nij-(ij+1) print('RPA estimated time left', self.timestring(t0 * (nij - ij - 1) + t), file=self.txt)
def get_xc(self): """Add xc part of the coupling matrix""" # shorthands paw = self.paw wfs = paw.wfs gd = paw.density.finegd comm = gd.comm eh_comm = self.eh_comm fg = self.finegrid is 2 kss = self.fullkss nij = len(kss) Om_xc = self.Om # initialize densities # nt_sg is the smooth density on the fine grid with spin index if kss.nvspins == 2: # spin polarised ground state calc. nt_sg = paw.density.nt_sg else: # spin unpolarised ground state calc. if kss.npspins == 2: # construct spin polarised densities nt_sg = np.array([.5 * paw.density.nt_sg[0], .5 * paw.density.nt_sg[0]]) else: nt_sg = paw.density.nt_sg # check if D_sp have been changed before D_asp = self.paw.density.D_asp for a, D_sp in D_asp.items(): if len(D_sp) != kss.npspins: if len(D_sp) == 1: D_asp[a] = np.array([0.5 * D_sp[0], 0.5 * D_sp[0]]) else: D_asp[a] = np.array([D_sp[0] + D_sp[1]]) # restrict the density if needed if fg: nt_s = nt_sg else: nt_s = self.gd.zeros(nt_sg.shape[0]) for s in range(nt_sg.shape[0]): self.restrict(nt_sg[s], nt_s[s]) gd = paw.density.gd # initialize vxc or fxc if self.derivativeLevel == 0: raise NotImplementedError if kss.npspins == 2: v_g = nt_sg[0].copy() else: v_g = nt_sg.copy() elif self.derivativeLevel == 1: pass elif self.derivativeLevel == 2: fxc_sg = np.zeros(nt_sg.shape) self.xc.calculate_fxc(gd, nt_sg, fxc_sg) else: raise ValueError('derivativeLevel can only be 0,1,2') # self.paw.my_nuclei = [] ns = self.numscale xc = self.xc print('XC', nij, 'transitions', file=self.txt) for ij in range(eh_comm.rank, nij, eh_comm.size): print('XC kss[' + '%d' % ij + ']', file=self.txt) timer = Timer() timer.start('init') timer2 = Timer() if self.derivativeLevel >= 1: # vxc is available # We use the numerical two point formula for calculating # the integral over fxc*n_ij. The results are # vvt_s smooth integral # nucleus.I_sp atom based correction matrices (pack2) # stored on each nucleus timer2.start('init v grids') vp_s = np.zeros(nt_s.shape, nt_s.dtype.char) vm_s = np.zeros(nt_s.shape, nt_s.dtype.char) if kss.npspins == 2: # spin polarised nv_s = nt_s.copy() nv_s[kss[ij].pspin] += ns * kss[ij].get(fg) xc.calculate(gd, nv_s, vp_s) nv_s = nt_s.copy() nv_s[kss[ij].pspin] -= ns * kss[ij].get(fg) xc.calculate(gd, nv_s, vm_s) else: # spin unpolarised nv = nt_s + ns * kss[ij].get(fg) xc.calculate(gd, nv, vp_s) nv = nt_s - ns * kss[ij].get(fg) xc.calculate(gd, nv, vm_s) vvt_s = (0.5 / ns) * (vp_s - vm_s) timer2.stop() # initialize the correction matrices timer2.start('init v corrections') I_asp = {} for a, P_ni in wfs.kpt_u[kss[ij].spin].P_ani.items(): # create the modified density matrix Pi_i = P_ni[kss[ij].i] Pj_i = P_ni[kss[ij].j] P_ii = np.outer(Pi_i, Pj_i) # we need the symmetric form, hence we can pack P_p = pack(P_ii) D_sp = self.paw.density.D_asp[a].copy() D_sp[kss[ij].pspin] -= ns * P_p setup = wfs.setups[a] I_sp = np.zeros_like(D_sp) self.xc.calculate_paw_correction(setup, D_sp, I_sp) I_sp *= -1.0 D_sp = self.paw.density.D_asp[a].copy() D_sp[kss[ij].pspin] += ns * P_p self.xc.calculate_paw_correction(setup, D_sp, I_sp) I_sp /= 2.0 * ns I_asp[a] = I_sp timer2.stop() timer.stop() t0 = timer.get_time('init') timer.start(ij) for kq in range(ij, nij): weight = self.weight_Kijkq(ij, kq) if self.derivativeLevel == 0: # only Exc is available if kss.npspins == 2: # spin polarised nv_g = nt_sg.copy() nv_g[kss[ij].pspin] += kss[ij].get(fg) nv_g[kss[kq].pspin] += kss[kq].get(fg) Excpp = xc.get_energy_and_potential( nv_g[0], v_g, nv_g[1], v_g) nv_g = nt_sg.copy() nv_g[kss[ij].pspin] += kss[ij].get(fg) nv_g[kss[kq].pspin] -= kss[kq].get(fg) Excpm = xc.get_energy_and_potential( nv_g[0], v_g, nv_g[1], v_g) nv_g = nt_sg.copy() nv_g[kss[ij].pspin] -=\ kss[ij].get(fg) nv_g[kss[kq].pspin] +=\ kss[kq].get(fg) Excmp = xc.get_energy_and_potential( nv_g[0], v_g, nv_g[1], v_g) nv_g = nt_sg.copy() nv_g[kss[ij].pspin] -= \ kss[ij].get(fg) nv_g[kss[kq].pspin] -=\ kss[kq].get(fg) Excpp = xc.get_energy_and_potential( nv_g[0], v_g, nv_g[1], v_g) else: # spin unpolarised nv_g = nt_sg + ns * kss[ij].get(fg)\ + ns * kss[kq].get(fg) Excpp = xc.get_energy_and_potential(nv_g, v_g) nv_g = nt_sg + ns * kss[ij].get(fg)\ - ns * kss[kq].get(fg) Excpm = xc.get_energy_and_potential(nv_g, v_g) nv_g = nt_sg - ns * kss[ij].get(fg)\ + ns * kss[kq].get(fg) Excmp = xc.get_energy_and_potential(nv_g, v_g) nv_g = nt_sg - ns * kss[ij].get(fg)\ - ns * kss[kq].get(fg) Excmm = xc.get_energy_and_potential(nv_g, v_g) Om_xc[ij, kq] += weight *\ 0.25 * \ (Excpp - Excmp - Excpm + Excmm) / (ns * ns) elif self.derivativeLevel == 1: # vxc is available timer2.start('integrate') Om_xc[ij, kq] += weight *\ self.gd.integrate(kss[kq].get(fg) * vvt_s[kss[kq].pspin]) timer2.stop() timer2.start('integrate corrections') Exc = 0. for a, P_ni in wfs.kpt_u[kss[kq].spin].P_ani.items(): # create the modified density matrix Pk_i = P_ni[kss[kq].i] Pq_i = P_ni[kss[kq].j] P_ii = np.outer(Pk_i, Pq_i) # we need the symmetric form, hence we can pack # use pack as I_sp used pack2 P_p = pack(P_ii) Exc += np.dot(I_asp[a][kss[kq].pspin], P_p) Om_xc[ij, kq] += weight * self.gd.comm.sum(Exc) timer2.stop() elif self.derivativeLevel == 2: # fxc is available if kss.npspins == 2: # spin polarised Om_xc[ij, kq] += weight *\ gd.integrate(kss[ij].get(fg) * kss[kq].get(fg) * fxc_sg[kss[ij].pspin, kss[kq].pspin]) else: # spin unpolarised Om_xc[ij, kq] += weight *\ gd.integrate(kss[ij].get(fg) * kss[kq].get(fg) * fxc_sg) # XXX still numeric derivatives for local terms timer2.start('integrate corrections') Exc = 0. for a, P_ni in wfs.kpt_u[kss[kq].spin].P_ani.items(): # create the modified density matrix Pk_i = P_ni[kss[kq].i] Pq_i = P_ni[kss[kq].j] P_ii = np.outer(Pk_i, Pq_i) # we need the symmetric form, hence we can pack # use pack as I_sp used pack2 P_p = pack(P_ii) Exc += np.dot(I_asp[a][kss[kq].pspin], P_p) Om_xc[ij, kq] += weight * self.gd.comm.sum(Exc) timer2.stop() if ij != kq: Om_xc[kq, ij] = Om_xc[ij, kq] timer.stop() # timer2.write() if ij < (nij - 1): print('XC estimated time left', self.time_left(timer, t0, ij, nij), file=self.txt)
def __init__(self, name, hybrid=None, xc=None, alpha=None, gamma_point=1, method='standard', bandstructure=False, logfilename='-', bands=None, fcut=1e-10, molecule=False, qstride=1, world=None): """Mix standard functionals with exact exchange. name: str Name of functional: EXX, PBE0, HSE03, HSE06 hybrid: float Fraction of exact exchange. xc: str or XCFunctional object Standard DFT functional with scaled down exchange. method: str Use 'standard' standard formula and 'acdf for adiabatic-connection dissipation fluctuation formula. alpha: float XXX describe gamma_point: bool 0: Skip k2-k1=0 interactions. 1: Use the alpha method. 2: Integrate the gamma point. bandstructure: bool Calculate bandstructure instead of just the total energy. bands: list of int List of bands to calculate bandstructure for. Default is all bands. molecule: bool Decouple electrostatic interactions between periodically repeated images. fcut: float Threshold for empty band. """ self.alpha = alpha self.fcut = fcut self.gamma_point = gamma_point self.method = method self.bandstructure = bandstructure self.bands = bands self.fd = logfilename self.write_timing_information = True HybridXCBase.__init__(self, name, hybrid, xc) # EXX energies: self.exx = None # total self.evv = None # valence-valence (pseudo part) self.evvacdf = None # valence-valence (pseudo part) self.devv = None # valence-valence (PAW correction) self.evc = None # valence-core self.ecc = None # core-core self.exx_skn = None # bandstructure self.qlatest = None if world is None: world = mpi.world self.world = world self.molecule = molecule if isinstance(qstride, int): qstride = [qstride] * 3 self.qstride_c = np.asarray(qstride) self.timer = Timer()
def get_rpa(self): """Calculate RPA and Hartree-fock part of the A+-B matrices.""" # shorthands kss = self.fullkss finegrid = self.finegrid # calculate omega matrix nij = len(kss) print('RPAhyb', nij, 'transitions', file=self.txt) AmB = np.zeros((nij, nij)) ApB = self.ApB # storage place for Coulomb integrals integrals = {} for ij in range(nij): print('RPAhyb kss[' + '%d' % ij + ']=', kss[ij], file=self.txt) timer = Timer() timer.start('init') timer2 = Timer() # smooth density including compensation charges timer2.start('with_compensation_charges 0') rhot_p = kss[ij].with_compensation_charges(finegrid is not 0) timer2.stop() # integrate with 1/|r_1-r_2| timer2.start('poisson') phit_p = np.zeros(rhot_p.shape, rhot_p.dtype) self.poisson.solve(phit_p, rhot_p, charge=None) timer2.stop() timer.stop() t0 = timer.get_time('init') timer.start(ij) if finegrid == 1: rhot = kss[ij].with_compensation_charges() phit = self.gd.zeros() self.restrict(phit_p, phit) else: phit = phit_p rhot = rhot_p for kq in range(ij, nij): if kq != ij: # smooth density including compensation charges timer2.start('kq with_compensation_charges') rhot = kss[kq].with_compensation_charges(finegrid is 2) timer2.stop() pre = self.weight_Kijkq(ij, kq) timer2.start('integrate') I = self.Coulomb_integral_kss(kss[ij], kss[kq], phit, rhot) if kss[ij].spin == kss[kq].spin: name = self.Coulomb_integral_name(kss[ij].i, kss[ij].j, kss[kq].i, kss[kq].j, kss[ij].spin) integrals[name] = I ApB[ij, kq] = pre * I timer2.stop() if ij == kq: epsij = kss[ij].get_energy() / kss[ij].get_weight() AmB[ij, kq] += epsij ApB[ij, kq] += epsij timer.stop() # timer2.write() if ij < (nij - 1): print('RPAhyb estimated time left', self.time_left(timer, t0, ij, nij), file=self.txt) # add HF parts and apply symmetry if hasattr(self.xc, 'hybrid'): weight = self.xc.hybrid else: weight = 0.0 for ij in range(nij): print('HF kss[' + '%d' % ij + ']', file=self.txt) timer = Timer() timer.start('init') timer.stop() t0 = timer.get_time('init') timer.start(ij) i = kss[ij].i j = kss[ij].j s = kss[ij].spin for kq in range(ij, nij): if kss[ij].pspin == kss[kq].pspin: k = kss[kq].i q = kss[kq].j ikjq = self.Coulomb_integral_ijkq(i, k, j, q, s, integrals) iqkj = self.Coulomb_integral_ijkq(i, q, k, j, s, integrals) ApB[ij, kq] -= weight * (ikjq + iqkj) AmB[ij, kq] -= weight * (ikjq - iqkj) ApB[kq, ij] = ApB[ij, kq] AmB[kq, ij] = AmB[ij, kq] timer.stop() if ij < (nij - 1): print('HF estimated time left', self.time_left(timer, t0, ij, nij), file=self.txt) return AmB
def __init__(self, calc, ecut=50, ftol=1e-6, threshold=1, real_space_derivatives=False, world=mpi.world, txt=sys.stdout, timer=None, nblocks=1, gate_voltage=None): if ecut is not None: ecut /= Hartree if gate_voltage is not None: gate_voltage /= Hartree self.ecut = ecut self.ftol = ftol self.threshold = threshold self.real_space_derivatives = real_space_derivatives self.world = world self.gate_voltage = gate_voltage if nblocks == 1: self.blockcomm = self.world.new_communicator([world.rank]) self.kncomm = world else: assert world.size % nblocks == 0, world.size rank1 = world.rank // nblocks * nblocks rank2 = rank1 + nblocks self.blockcomm = self.world.new_communicator(range(rank1, rank2)) ranks = range(world.rank % nblocks, world.size, nblocks) self.kncomm = self.world.new_communicator(ranks) if world.rank != 0: txt = devnull elif isinstance(txt, str): txt = open(txt, 'w') self.fd = txt self.timer = timer or Timer() if isinstance(calc, str): print('Reading ground state calculation:\n %s' % calc, file=self.fd) if not calc.split('.')[-1] == 'gpw': calc = calc + '.gpw' self.reader = io.Reader(calc, comm=mpi.serial_comm) calc = GPAW(calc, txt=None, communicator=mpi.serial_comm, read_projections=False) else: self.reader = None assert calc.wfs.world.size == 1 assert calc.wfs.kd.symmetry.symmorphic self.calc = calc if gate_voltage is not None: self.add_gate_voltage(gate_voltage) self.spos_ac = calc.atoms.get_scaled_positions() self.nocc1 = None # number of completely filled bands self.nocc2 = None # number of non-empty bands self.count_occupied_bands() self.vol = abs(np.linalg.det(calc.wfs.gd.cell_cv)) self.ut_sKnvR = None # gradient of wave functions for optical limit print('Number of blocks:', nblocks, file=self.fd)
def __init__(self, filename=None, timer=None, read_projections=True, **kwargs): """ASE-calculator interface. The following parameters can be used: nbands, xc, kpts, spinpol, gpts, h, charge, symmetry, width, mixer, hund, lmax, fixdensity, convergence, txt, parallel, communicator, dtype, softgauss and stencils. If you don't specify any parameters, you will get: Defaults: neutrally charged, LDA, gamma-point calculation, a reasonable grid-spacing, zero Kelvin electronic temperature, and the number of bands will be equal to the number of atomic orbitals present in the setups. Only occupied bands are used in the convergence decision. The calculation will be spin-polarized if and only if one or more of the atoms have non-zero magnetic moments. Text output will be written to standard output. For a non-gamma point calculation, the electronic temperature will be 0.1 eV (energies are extrapolated to zero Kelvin) and all symmetries will be used to reduce the number of **k**-points.""" PAWTextOutput.__init__(self) self.grid_descriptor_class = GridDescriptor self.input_parameters = InputParameters() if timer is None: self.timer = Timer() else: self.timer = timer self.scf = None self.forces = ForceCalculator(self.timer) self.stress_vv = None self.dipole_v = None self.magmom_av = None self.wfs = EmptyWaveFunctions() self.occupations = None self.density = None self.hamiltonian = None self.atoms = None self.iter = 0 self.initialized = False self.nbands_parallelization_adjustment = None # Somehow avoid this? # Possibly read GPAW keyword arguments from file: if filename is not None and filename.endswith('.gkw'): from gpaw.utilities.kwargs import load parameters = load(filename) parameters.update(kwargs) kwargs = parameters filename = None # XXX if filename is not None: comm = kwargs.get('communicator', mpi.world) reader = gpaw.io.open(filename, 'r', comm) self.atoms = gpaw.io.read_atoms(reader) par = self.input_parameters par.read(reader) # _changed_keywords contains those keywords that have been # changed by set() since last time initialize() was called. self._changed_keywords = set() self.set(**kwargs) # Here in the beginning, effectively every keyword has been changed. self._changed_keywords.update(self.input_parameters) if filename is not None: # Setups are not saved in the file if the setups were not loaded # *from* files in the first place if par.setups is None: if par.idiotproof: raise RuntimeError('Setups not specified in file. Use ' 'idiotproof=False to proceed anyway.') else: par.setups = {None: 'paw'} if par.basis is None: if par.idiotproof: raise RuntimeError('Basis not specified in file. Use ' 'idiotproof=False to proceed anyway.') else: par.basis = {} self.initialize() self.read(reader, read_projections) if self.hamiltonian.xc.type == 'GLLB': self.occupations.calculate(self.wfs) self.print_cell_and_parameters() self.observers = []