Example #1
0
 def __init__(self, calc, omega_w, ecut=50, hilbert=False,
              timeordered=False, eta=0.2, ftol=1e-6,
              real_space_derivatives=False,
              world=mpi.world, txt=sys.stdout):
     PairDensity.__init__(self, calc, ecut, ftol,
                          real_space_derivatives, world, txt)
     
     eta /= Hartree
     
     self.omega_w = omega_w = np.asarray(omega_w) / Hartree
     self.hilbert = hilbert
     self.timeordered = bool(timeordered)
     self.eta = eta
     
     if eta == 0.0:
         assert not hilbert
         assert not timeordered
         assert not omega_w.real.any()
         
     self.mysKn1n2 = None  # my (s, K, n1, n2) indices
     self.distribute_k_points_and_bands(self.nocc2)
     
     self.mykpts = [self.get_k_point(s, K, n1, n2)
                    for s, K, n1, n2 in self.mysKn1n2]
     
     wfs = self.calc.wfs
     self.prefactor = 2 / self.vol / wfs.kd.nbzkpts / wfs.nspins
Example #2
0
    def __init__(self, calc,
                 frequencies=None, domega0=0.1, omega2=10.0, omegamax=None,
                 ecut=50, hilbert=True, nbands=None,
                 timeordered=False, eta=0.2, ftol=1e-6, threshold=1,
                 real_space_derivatives=False, intraband=True,
                 world=mpi.world, txt=sys.stdout, timer=None,
                 nblocks=1, no_optical_limit=False,
                 keep_occupied_states=False, gate_voltage=None,
                 disable_point_group=False, disable_time_reversal=False,
                 use_more_memory=0, unsymmetrized=True, eshift=None):

        PairDensity.__init__(self, calc, ecut, ftol, threshold,
                             real_space_derivatives, world, txt, timer,
                             nblocks=nblocks,
                             gate_voltage=gate_voltage, eshift=eshift)

        self.eta = eta / 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.keep_occupied_states = keep_occupied_states
        self.intraband = intraband
        self.no_optical_limit = no_optical_limit
        self.disable_point_group = disable_point_group
        self.disable_time_reversal = disable_time_reversal
        self.use_more_memory = use_more_memory
        self.unsymmetrized = unsymmetrized

        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.omega_w = frequency_grid(self.domega0, self.omega2,
                                          self.omegamax)
        else:
            self.omega_w = np.asarray(frequencies) / Hartree
            assert not hilbert
        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()

        # Occupied states:
        wfs = self.calc.wfs
        self.mysKn1n2 = None  # my (s, K, n1, n2) indices
        self.distribute_k_points_and_bands(0, self.nocc2,
                                           kpts=range(wfs.kd.nibzkpts))
        self.mykpts = None

        self.prefactor = 2 / self.vol / wfs.kd.nbzkpts / wfs.nspins

        self.chi0_vv = None  # strength of intraband peak
Example #3
0
    def __init__(self, calc,
                 frequencies=None, domega0=0.1, omega2=10.0, omegamax=None,
                 ecut=50, hilbert=True, nbands=None,
                 timeordered=False, eta=0.2, ftol=1e-6, threshold=1,
                 real_space_derivatives=False, intraband=True,
                 world=mpi.world, txt=sys.stdout, timer=None,
                 nblocks=1, no_optical_limit=False,
                 keep_occupied_states=False, gate_voltage=None):

        PairDensity.__init__(self, calc, ecut, ftol, threshold,
                             real_space_derivatives, world, txt, timer,
                             nblocks=nblocks,
                             gate_voltage=gate_voltage)

        self.eta = eta / 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.keep_occupied_states = keep_occupied_states
        self.intraband = intraband
        self.no_optical_limit = no_optical_limit
        
        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.omega_w = frequency_grid(self.domega0, self.omega2,
                                          self.omegamax)
        else:
            self.omega_w = np.asarray(frequencies) / Hartree
            assert not hilbert
        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()

        # Occupied states:
        self.mysKn1n2 = None  # my (s, K, n1, n2) indices
        self.distribute_k_points_and_bands(0, self.nocc2)
        self.mykpts = None

        wfs = self.calc.wfs
        self.prefactor = 2 / self.vol / wfs.kd.nbzkpts / wfs.nspins

        self.chi0_vv = None  # strength of intraband peak
Example #4
0
    def __init__(self, calc, xc=None, kpts=None, bands=None, ecut=None,
                 omega=None, world=mpi.world, txt=sys.stdout, timer=None):
    
        PairDensity.__init__(self, calc, ecut, world=world, txt=txt,
                             timer=timer)

        if xc is None or xc == 'EXX':
            self.exx_fraction = 1.0
            xc = XC(XCNull())
        elif xc == 'PBE0':
            self.exx_fraction = 0.25
            xc = XC('HYB_GGA_XC_PBEH')
        elif xc == 'HSE03':
            omega = 0.106
            self.exx_fraction = 0.25
            xc = XC('HYB_GGA_XC_HSE03')
        elif xc == 'HSE06':
            omega = 0.11
            self.exx_fraction = 0.25
            xc = XC('HYB_GGA_XC_HSE06')
        elif xc == 'B3LYP':
            self.exx_fraction = 0.2
            xc = XC('HYB_GGA_XC_B3LYP')
            
        self.xc = xc
        self.omega = omega
        self.exc = np.nan  # density dependent part of xc-energy
        
        self.kpts = select_kpts(kpts, self.calc)
        
        if bands is None:
            # Do all occupied bands:
            bands = [0, self.nocc2]
        
        prnt('Calculating exact exchange contributions for band index',
             '%d-%d' % (bands[0], bands[1] - 1), file=self.fd)
        prnt('for IBZ k-points with indices:',
             ', '.join(str(i) for i in self.kpts), file=self.fd)
        
        self.bands = bands

        if self.ecut is None:
            self.ecut = self.calc.wfs.pd.ecut
        prnt('Plane-wave cutoff: %.3f eV' % (self.ecut * Hartree),
             file=self.fd)
        
        shape = (self.calc.wfs.nspins, len(self.kpts), bands[1] - bands[0])
        self.exxvv_sin = np.zeros(shape)   # valence-valence exchange energies
        self.exxvc_sin = np.zeros(shape)   # valence-core exchange energies
        self.f_sin = np.empty(shape)       # occupation numbers

        # The total EXX energy will not be calculated if we are only
        # interested in a few eigenvalues for a few k-points
        self.exx = np.nan    # total EXX energy
        self.exxvv = np.nan  # valence-valence
        self.exxvc = np.nan  # valence-core
        self.exxcc = 0.0     # core-core

        self.mysKn1n2 = None  # my (s, K, n1, n2) indices
        self.distribute_k_points_and_bands(0, self.nocc2)
        
        # All occupied states:
        self.mykpts = [self.get_k_point(s, K, n1, n2)
                       for s, K, n1, n2 in self.mysKn1n2]

        prnt('Using Wigner-Seitz truncated coulomb interaction.',
             file=self.fd)
        self.wstc = WignerSeitzTruncatedCoulomb(self.calc.wfs.gd.cell_cv,
                                                self.calc.wfs.kd.N_c,
                                                self.fd)
        self.iG_qG = {}  # cache
            
        # PAW matrices:
        self.V_asii = []  # valence-valence correction
        self.C_aii = []   # valence-core correction
        self.initialize_paw_exx_corrections()
Example #5
0
    def __init__(self,
                 calc,
                 xc=None,
                 kpts=None,
                 bands=None,
                 ecut=None,
                 omega=None,
                 world=mpi.world,
                 txt=sys.stdout,
                 timer=None):

        PairDensity.__init__(self,
                             calc,
                             ecut,
                             world=world,
                             txt=txt,
                             timer=timer)

        if xc is None or xc == 'EXX':
            self.exx_fraction = 1.0
            xc = XC(XCNull())
        elif xc == 'PBE0':
            self.exx_fraction = 0.25
            xc = XC('HYB_GGA_XC_PBEH')
        elif xc == 'HSE03':
            omega = 0.106
            self.exx_fraction = 0.25
            xc = XC('HYB_GGA_XC_HSE03')
        elif xc == 'HSE06':
            omega = 0.11
            self.exx_fraction = 0.25
            xc = XC('HYB_GGA_XC_HSE06')
        elif xc == 'B3LYP':
            self.exx_fraction = 0.2
            xc = XC('HYB_GGA_XC_B3LYP')

        self.xc = xc
        self.omega = omega
        self.exc = np.nan  # density dependent part of xc-energy

        self.kpts = select_kpts(kpts, self.calc)

        if bands is None:
            # Do all occupied bands:
            bands = [0, self.nocc2]

        prnt('Calculating exact exchange contributions for band index',
             '%d-%d' % (bands[0], bands[1] - 1),
             file=self.fd)
        prnt('for IBZ k-points with indices:',
             ', '.join(str(i) for i in self.kpts),
             file=self.fd)

        self.bands = bands

        if self.ecut is None:
            self.ecut = self.calc.wfs.pd.ecut
        prnt('Plane-wave cutoff: %.3f eV' % (self.ecut * Hartree),
             file=self.fd)

        shape = (self.calc.wfs.nspins, len(self.kpts), bands[1] - bands[0])
        self.exxvv_sin = np.zeros(shape)  # valence-valence exchange energies
        self.exxvc_sin = np.zeros(shape)  # valence-core exchange energies
        self.f_sin = np.empty(shape)  # occupation numbers

        # The total EXX energy will not be calculated if we are only
        # interested in a few eigenvalues for a few k-points
        self.exx = np.nan  # total EXX energy
        self.exxvv = np.nan  # valence-valence
        self.exxvc = np.nan  # valence-core
        self.exxcc = 0.0  # core-core

        self.mysKn1n2 = None  # my (s, K, n1, n2) indices
        self.distribute_k_points_and_bands(0, self.nocc2)

        # All occupied states:
        self.mykpts = [
            self.get_k_point(s, K, n1, n2) for s, K, n1, n2 in self.mysKn1n2
        ]

        prnt('Using Wigner-Seitz truncated coulomb interaction.', file=self.fd)
        self.wstc = WignerSeitzTruncatedCoulomb(self.calc.wfs.gd.cell_cv,
                                                self.calc.wfs.kd.N_c, self.fd)
        self.iG_qG = {}  # cache

        # PAW matrices:
        self.V_asii = []  # valence-valence correction
        self.C_aii = []  # valence-core correction
        self.initialize_paw_exx_corrections()
Example #6
0
    def __init__(self, calc, xc=None, kpts=None, bands=None, ecut=150.0,
                 alpha=0.0, skip_gamma=False,
                 world=mpi.world, txt=sys.stdout):
    
        alpha /= Bohr**2

        PairDensity.__init__(self, calc, ecut, world=world, txt=txt)

        ecut /= Hartree
        
        if xc is None:
            self.exx_fraction = 1.0
            xc = XC(XCNull())
        if xc == 'PBE0':
            self.exx_fraction = 0.25
            xc = XC('HYB_GGA_XC_PBEH')
        elif xc == 'B3LYP':
            self.exx_fraction = 0.2
            xc = XC('HYB_GGA_XC_B3LYP')
        self.xc = xc
        self.exc = np.nan  # density dependent part of xc-energy
        
        if kpts is None:
            # Do all k-points in the IBZ:
            kpts = range(self.calc.wfs.kd.nibzkpts)
        
        if bands is None:
            # Do all occupied bands:
            bands = [0, self.nocc2]
        
        prnt('Calculating exact exchange contributions for band index',
             '%d-%d' % (bands[0], bands[1] - 1), file=self.fd)
        prnt('for IBZ k-points with indices:',
             ', '.join(str(i) for i in kpts), file=self.fd)
        
        self.kpts = kpts
        self.bands = bands

        shape = (self.calc.wfs.nspins, len(kpts), bands[1] - bands[0])
        self.exxvv_sin = np.zeros(shape)   # valence-valence exchange energies
        self.exxvc_sin = np.zeros(shape)   # valence-core exchange energies
        self.f_sin = np.empty(shape)       # occupation numbers

        # The total EXX energy will not be calculated if we are only
        # interested in a few eigenvalues for a few k-points
        self.exx = np.nan    # total EXX energy
        self.exxvv = np.nan  # valence-valence
        self.exxvc = np.nan  # valence-core
        self.exxcc = 0.0     # core-core

        self.mysKn1n2 = None  # my (s, K, n1, n2) indices
        self.distribute_k_points_and_bands(self.nocc2)
        
        # All occupied states:
        self.mykpts = [self.get_k_point(s, K, n1, n2)
                       for s, K, n1, n2 in self.mysKn1n2]

        # Compensation charge used for molecular calculations only:
        self.beta = None      # e^(-beta*r^2)
        self.ngauss_G = None  # density
        self.vgauss_G = None  # potential

        self.G0 = None  # effective value for |G+q| when |G+q|=0
        
        self.skip_gamma = skip_gamma
        
        if not self.calc.atoms.pbc.any():
            # Set exponent of exp-function to -19 on the boundary:
            self.beta = 4 * 19 * (self.calc.wfs.gd.icell_cv**2).sum(1).max()
            prnt('Gaussian for electrostatic decoupling: e^(-beta*r^2),',
                 'beta=%.3f 1/Ang^2' % (self.beta / Bohr**2), file=self.fd)
        elif skip_gamma:
            prnt('Skip |G+q|=0 term', file=self.fd)
        else:
            # Volume per q-point:
            dvq = (2 * pi)**3 / self.vol / self.calc.wfs.kd.nbzkpts
            qcut = (dvq / (4 * pi / 3))**(1 / 3)
            if alpha == 0.0:
                self.G0 = (4 * pi * qcut / dvq)**-0.5
            else:
                self.G0 = (2 * pi**1.5 * erf(alpha**0.5 * qcut) / alpha**0.5 /
                           dvq)**-0.5
            prnt('G+q=0 term: Integrate e^(-alpha*q^2)/q^2 for',
                 'q<%.3f 1/Ang and alpha=%.3f Ang^2' %
                 (qcut / Bohr, alpha * Bohr**2), file=self.fd)

        # PAW matrices:
        self.V_asii = []  # valence-valence correction
        self.C_aii = []   # valence-core correction
        self.initialize_paw_exx_corrections()
Example #7
0
    def __init__(self, calc, filename='gw',
                 kpts=None, bands=None, nbands=None, ppa=False,
                 wstc=False,
                 ecut=150.0, eta=0.1, E0=1.0 * Hartree,
                 domega0=0.025, omega2=10.0,
                 world=mpi.world):
    
        PairDensity.__init__(self, calc, ecut, world=world,
                             txt=filename + '.txt')
        
        self.filename = filename
        
        ecut /= Hartree
        
        self.ppa = ppa
        self.wstc = wstc
        self.eta = eta / Hartree
        self.E0 = E0 / Hartree
        self.domega0 = domega0 / Hartree
        self.omega2 = omega2 / Hartree

        print('  ___  _ _ _ ', file=self.fd)
        print(' |   || | | |', file=self.fd)
        print(' | | || | | |', file=self.fd)
        print(' |__ ||_____|', file=self.fd)
        print(' |___|       ', file=self.fd)
        print(file=self.fd)

        self.kpts = select_kpts(kpts, self.calc)
                
        if bands is None:
            bands = [0, self.nocc2]
            
        self.bands = bands

        b1, b2 = bands
        self.shape = shape = (self.calc.wfs.nspins, len(self.kpts), b2 - b1)
        self.eps_sin = np.empty(shape)     # KS-eigenvalues
        self.f_sin = np.empty(shape)       # occupation numbers
        self.sigma_sin = np.zeros(shape)   # self-energies
        self.dsigma_sin = np.zeros(shape)  # derivatives of self-energies
        self.vxc_sin = None                # KS XC-contributions
        self.exx_sin = None                # exact exchange contributions
        self.Z_sin = None                  # renormalization factors
        
        if nbands is None:
            nbands = int(self.vol * ecut**1.5 * 2**0.5 / 3 / pi**2)
        self.nbands = nbands

        kd = self.calc.wfs.kd

        self.mysKn1n2 = None  # my (s, K, n1, n2) indices
        self.distribute_k_points_and_bands(b1, b2, kd.ibz2bz_k[self.kpts])
        
        # Find q-vectors and weights in the IBZ:
        assert -1 not in kd.bz2bz_ks
        offset_c = 0.5 * ((kd.N_c + 1) % 2) / kd.N_c
        bzq_qc = monkhorst_pack(kd.N_c) + offset_c
        self.qd = KPointDescriptor(bzq_qc)
        self.qd.set_symmetry(self.calc.atoms, self.calc.wfs.setups,
                             usesymm=self.calc.input_parameters.usesymm,
                             N_c=self.calc.wfs.gd.N_c)
        
        assert self.calc.wfs.nspins == 1
Example #8
0
    def __init__(self,
                 calc,
                 gwfile,
                 filename=None,
                 kpts=[0],
                 bands=None,
                 structure=None,
                 d=None,
                 layer=0,
                 dW_qw=None,
                 qqeh=None,
                 wqeh=None,
                 txt=sys.stdout,
                 world=mpi.world,
                 domega0=0.025,
                 omega2=10.0,
                 eta=0.1,
                 include_q0=True,
                 metal=False):
        """ 
        Class for calculating quasiparticle energies of van der Waals
        heterostructures using the GW approximation for the self-energy. 
        The quasiparticle energy correction due to increased screening from
        surrounding layers is obtained from the QEH model.
        Parameters:
        
        calc: str or PAW object
            GPAW calculator object or filename of saved calculator object.
        gwfile: str
            name of gw results file from the monolayer calculation
        filename: str
            filename for gwqeh output
        kpts: list
            List of indices of sthe IBZ k-points to calculate the quasi
            particle energies for. Set to [0] by default since the QP 
            correction is generally the same for all k. 
        bands: tuple
            Range of band indices, like (n1, n2+1), to calculate the quasi
            particle energies for. Note that the second band index is not
            included. Should be the same as used for the GW calculation.
        structure: list of str
            Heterostructure set up. Each entry should consist of number of
            layers + chemical formula.
            For example: ['3H-MoS2', graphene', '10H-WS2'] gives 3 layers of
            H-MoS2, 1 layer of graphene and 10 layers of H-WS2.
            The name of the layers should correspond to building block files:
            "<name>-chi.pckl" in the local repository. 
        d: array of floats
            Interlayer distances for neighboring layers in Ang.
            Length of array = number of layers - 1
        layer: int
            index of layer to calculate QP correction for. 
        dW_qw: 2D array of floats dimension q X w
            Change in screened interaction. Should be set to None to calculate 
            dW directly from buildingblocks.
        qqeh: array of floats
            q-grid used for dW_qw (only needed if dW is given by hand).
        wqeh: array of floats
            w-grid used for dW_qw. So far this have to be the same as for the 
            GWQEH calculation.  (only needed if dW is given by hand).
        domega0: float
            Minimum frequency step (in eV) used in the generation of the non-
            linear frequency grid.
        omega2: float
            Control parameter for the non-linear frequency grid, equal to the
            frequency where the grid spacing has doubled in size.
        eta: float
            Broadening parameter.
        include_q0: bool
            include q=0 in W or not. if True an integral arround q=0 is
            performed, if False the q=0 contribution is set to zero. 
        metal: bool
            If True, the point at q=0 is omitted when averaging the screened
            potential close to q=0. 
        """

        self.gwfile = gwfile

        self.inputcalc = calc
        # Set low ecut in order to use PairDensity object since only
        # G=0 is needed.
        self.ecut = 1.
        PairDensity.__init__(self,
                             calc,
                             ecut=self.ecut,
                             world=world,
                             txt=filename + '.txt')

        self.filename = filename
        self.ecut /= Hartree
        self.eta = eta / Hartree
        self.domega0 = domega0 / Hartree
        self.omega2 = omega2 / Hartree

        self.kpts = list(select_kpts(kpts, self.calc))

        if bands is None:
            bands = [0, self.nocc2]

        self.bands = bands

        b1, b2 = bands
        self.shape = shape = (self.calc.wfs.nspins, len(self.kpts), b2 - b1)
        self.eps_sin = np.empty(shape)  # KS-eigenvalues
        self.f_sin = np.empty(shape)  # occupation numbers
        self.sigma_sin = np.zeros(shape)  # self-energies
        self.dsigma_sin = np.zeros(shape)  # derivatives of self-energies
        self.Z_sin = None  # renormalization factors
        self.qp_sin = None
        self.Qp_sin = None

        self.ecutnb = 150 / Hartree
        vol = abs(np.linalg.det(self.calc.wfs.gd.cell_cv))
        self.vol = vol
        self.nbands = min(self.calc.get_number_of_bands(),
                          int(vol * (self.ecutnb)**1.5 * 2**0.5 / 3 / pi**2))

        self.nspins = self.calc.wfs.nspins

        kd = self.calc.wfs.kd

        self.mysKn1n2 = None  # my (s, K, n1, n2) indices
        self.distribute_k_points_and_bands(b1, b2, kd.ibz2bz_k[self.kpts])

        # Find q-vectors and weights in the IBZ:
        assert -1 not in kd.bz2bz_ks
        offset_c = 0.5 * ((kd.N_c + 1) % 2) / kd.N_c
        bzq_qc = monkhorst_pack(kd.N_c) + offset_c
        self.qd = KPointDescriptor(bzq_qc)
        self.qd.set_symmetry(self.calc.atoms, kd.symmetry)

        # frequency grid
        omax = self.find_maximum_frequency()
        self.omega_w = frequency_grid(self.domega0, self.omega2, omax)
        self.nw = len(self.omega_w)
        self.wsize = 2 * self.nw

        # Calculate screened potential of Heterostructure
        if dW_qw is None:
            try:
                self.qqeh, self.wqeh, dW_qw = pickle.load(
                    open(filename + '_dW_qw.pckl', 'rb'))
            except:
                dW_qw = self.calculate_W_QEH(structure, d, layer)
        else:
            self.qqeh = qqeh
            self.wqeh = None  # wqeh

        self.dW_qw = self.get_W_on_grid(dW_qw,
                                        include_q0=include_q0,
                                        metal=metal)

        assert self.nw == self.dW_qw.shape[1], \
            ('Frequency grids doesnt match!')

        self.htp = HilbertTransform(self.omega_w, self.eta, gw=True)
        self.htm = HilbertTransform(self.omega_w, -self.eta, gw=True)

        self.complete = False
        self.nq = 0
        if self.load_state_file():
            if self.complete:
                print('Self-energy loaded from file', file=self.fd)
Example #9
0
    def __init__(self, calc, filename='gw',
                 kpts=None, bands=None, nbands=None, ppa=False,
                 wstc=False,
                 ecut=150.0, eta=0.1, E0=1.0 * Hartree,
                 domega0=0.025, omega2=10.0,
                 nblocks=1, savew=False,
                 world=mpi.world):

        if world.rank != 0:
            txt = devnull
        else:
            txt = open(filename + '.txt', 'w')

        p = functools.partial(print, file=txt)
        p('  ___  _ _ _ ')
        p(' |   || | | |')
        p(' | | || | | |')
        p(' |__ ||_____|')
        p(' |___|')
        p()

        PairDensity.__init__(self, calc, ecut, world=world, nblocks=nblocks,
                             txt=txt)

        self.filename = filename
        self.savew = savew
        
        ecut /= Hartree
        
        self.ppa = ppa
        self.wstc = wstc
        self.eta = eta / Hartree
        self.E0 = E0 / Hartree
        self.domega0 = domega0 / Hartree
        self.omega2 = omega2 / Hartree

        self.kpts = select_kpts(kpts, self.calc)
                
        if bands is None:
            bands = [0, self.nocc2]
            
        self.bands = bands

        b1, b2 = bands
        self.shape = shape = (self.calc.wfs.nspins, len(self.kpts), b2 - b1)
        self.eps_sin = np.empty(shape)     # KS-eigenvalues
        self.f_sin = np.empty(shape)       # occupation numbers
        self.sigma_sin = np.zeros(shape)   # self-energies
        self.dsigma_sin = np.zeros(shape)  # derivatives of self-energies
        self.vxc_sin = None                # KS XC-contributions
        self.exx_sin = None                # exact exchange contributions
        self.Z_sin = None                  # renormalization factors
        
        if nbands is None:
            nbands = int(self.vol * ecut**1.5 * 2**0.5 / 3 / pi**2)
        self.nbands = nbands

        p()
        p('Quasi particle states:')
        if kpts is None:
            p('All k-points in IBZ')
        else:
            kptstxt = ', '.join(['{0:d}'.format(k) for k in self.kpts])
            p('k-points (IBZ indices): [' + kptstxt + ']')
        p('Band range: ({0:d}, {1:d})'.format(b1, b2))
        p()
        p('Computational parameters:')
        p('Plane wave cut-off: {0:g} eV'.format(self.ecut * Hartree))
        p('Number of bands: {0:d}'.format(self.nbands))
        p('Broadening: {0:g} eV'.format(self.eta * Hartree))

        kd = self.calc.wfs.kd

        self.mysKn1n2 = None  # my (s, K, n1, n2) indices
        self.distribute_k_points_and_bands(b1, b2, kd.ibz2bz_k[self.kpts])
        
        # Find q-vectors and weights in the IBZ:
        assert -1 not in kd.bz2bz_ks
        offset_c = 0.5 * ((kd.N_c + 1) % 2) / kd.N_c
        bzq_qc = monkhorst_pack(kd.N_c) + offset_c
        self.qd = KPointDescriptor(bzq_qc)
        self.qd.set_symmetry(self.calc.atoms, kd.symmetry)
        
        assert self.calc.wfs.nspins == 1