コード例 #1
0
ファイル: dscftools.py プロジェクト: qsnake/gpaw
def dscf_collapse_orbitals(paw, nbands_max='occupied', f_tol=1e-4,
                           verify_density=True, nt_tol=1e-5, D_tol=1e-3):

    bd = paw.wfs.bd
    gd = paw.wfs.gd
    kd = KPointDescriptor(paw.wfs.nspins, paw.wfs.nibzkpts, \
        paw.wfs.kpt_comm, paw.wfs.gamma, paw.wfs.dtype)

    assert paw.wfs.bd.comm.size == 1, 'Band parallelization not implemented.'

    f_skn = np.empty((kd.nspins, kd.nibzkpts, bd.nbands), dtype=float)
    for s, f_kn in enumerate(f_skn):
        for k, f_n in enumerate(f_kn):
            kpt_rank, myu = kd.get_rank_and_index(s, k)
            if kd.comm.rank == kpt_rank:
                f_n[:] = paw.wfs.kpt_u[myu].f_n
            kd.comm.broadcast(f_n, kpt_rank)

    # Find smallest band index, from which all bands have negligeble occupations
    n0 = np.argmax(f_skn<f_tol, axis=-1).max()
    assert np.all(f_skn[...,n0:]<f_tol) # XXX use f_skn[...,n0:].sum()<f_tol

    # Read the number of Delta-SCF orbitals
    norbitals = paw.occupations.norbitals
    if debug: mpi_debug('n0=%d, norbitals=%d, bd:%d, gd:%d, kd:%d' % (n0,norbitals,bd.comm.size,gd.comm.size,kd.comm.size))

    if nbands_max < 0:
        nbands_max = n0 + norbitals - nbands_max
    elif nbands_max == 'occupied':
        nbands_max = n0 + norbitals

    assert nbands_max >= n0 + norbitals, 'Too few bands to include occupations.'
    ncut = nbands_max-norbitals

    if debug: mpi_debug('nbands_max=%d' % nbands_max) 

    paw.wfs.initialize_wave_functions_from_restart_file() # hurts memmory

    for kpt in paw.wfs.kpt_u:
        mol = kpt.P_ani.keys() # XXX stupid
        (f_o, eps_o, wf_oG, P_aoi,) = dscf_reconstruct_orbitals_k_point(paw, norbitals, mol, kpt)

        assert abs(f_o-1) < 1e-9, 'Orbitals must be properly normalized.'
        f_o = kpt.ne_o # actual ocupatiion numbers

        # Crop band-data and inject data for Delta-SCF orbitals
        kpt.f_n = np.hstack((kpt.f_n[:n0], f_o, kpt.f_n[n0:ncut]))
        kpt.eps_n = np.hstack((kpt.eps_n[:n0], eps_o, kpt.eps_n[n0:ncut]))
        for a, P_ni in kpt.P_ani.items():
            kpt.P_ani[a] = np.vstack((P_ni[:n0], P_aoi[a], P_ni[n0:ncut]))

        old_psit_nG = kpt.psit_nG
        kpt.psit_nG = gd.empty(nbands_max, dtype=kd.dtype)

        if isinstance(old_psit_nG, TarFileReference):
            assert old_psit_nG.shape[-3:] == wf_oG.shape[-3:], 'Shape mismatch!'

            # Read band-by-band to save memory as full psit_nG may be large
            for n,psit_G in enumerate(kpt.psit_nG):
                if n < n0:
                    full_psit_G = old_psit_nG[n]
                elif n in range(n0,n0+norbitals):
                    full_psit_G = wf_oG[n-n0]
                else:
                    full_psit_G = old_psit_nG[n-norbitals]
                gd.distribute(full_psit_G, psit_G)
        else:
            kpt.psit_nG[:n0] = old_psit_nG[:n0]
            kpt.psit_nG[n0:n0+norbitals] = wf_oG
            kpt.psit_nG[n0+norbitals:] = old_psit_nG[n0:ncut]

        del kpt.ne_o, kpt.c_on, old_psit_nG

    del paw.occupations.norbitals

    # Change various parameters related to new number of bands
    paw.wfs.mynbands = bd.mynbands = nbands_max
    paw.wfs.nbands = bd.nbands = nbands_max
    if paw.wfs.eigensolver:
        paw.wfs.eigensolver.initialized = False

    # Crop convergence criteria nbands_converge to new number of bands
    par = paw.input_parameters
    if 'convergence' in par:
        cc = par['convergence']
        if 'bands' in cc:
            cc['bands'] = min(nbands_max, cc['bands'])

    # Replace occupations class with a fixed variant (gets the magmom right)
    paw.occupations = FermiDiracFixed(paw.occupations.ne, kd.nspins,
                                      paw.occupations.width,
                                      paw.occupations.fermilevel)
    paw.occupations.set_communicator(kd.comm, bd.comm)
    paw.occupations.find_fermi_level(paw.wfs.kpt_u) # just regenerates magmoms

    # For good measure, self-consistency information should be destroyed
    paw.scf.reset()

    if verify_density:
        paw.initialize_positions()

        # Re-calculate pseudo density and watch for changes
        old_nt_sG = paw.density.nt_sG.copy()
        paw.density.calculate_pseudo_density(paw.wfs)
        if debug: mpi_debug('delta-density: %g' % np.abs(old_nt_sG-paw.density.nt_sG).max())
        assert np.all(np.abs(paw.density.nt_sG-old_nt_sG)<nt_tol), 'Density changed!'

        # Re-calculate atomic density matrices and watch for changes
        old_D_asp = {}
        for a,D_sp in paw.density.D_asp.items():
            old_D_asp[a] = D_sp.copy()
        paw.wfs.calculate_atomic_density_matrices(paw.density.D_asp)
        if debug: mpi_debug('delta-D_asp: %g' % max([np.abs(D_sp-old_D_asp[a]).max() for a,D_sp in paw.density.D_asp.items()]))
        for a,D_sp in paw.density.D_asp.items():
            assert np.all(np.abs(D_sp-old_D_asp[a])< D_tol), 'Atom %d changed!' % a
コード例 #2
0
def dscf_collapse_orbitals(paw,
                           nbands_max='occupied',
                           f_tol=1e-4,
                           verify_density=True,
                           nt_tol=1e-5,
                           D_tol=1e-3):

    bd = paw.wfs.bd
    gd = paw.wfs.gd
    kd = KPointDescriptor(paw.wfs.nspins, paw.wfs.nibzkpts, \
        paw.wfs.kpt_comm, paw.wfs.gamma, paw.wfs.dtype)

    assert paw.wfs.bd.comm.size == 1, 'Band parallelization not implemented.'

    f_skn = np.empty((kd.nspins, kd.nibzkpts, bd.nbands), dtype=float)
    for s, f_kn in enumerate(f_skn):
        for k, f_n in enumerate(f_kn):
            kpt_rank, myu = kd.get_rank_and_index(s, k)
            if kd.comm.rank == kpt_rank:
                f_n[:] = paw.wfs.kpt_u[myu].f_n
            kd.comm.broadcast(f_n, kpt_rank)

    # Find smallest band index, from which all bands have negligeble occupations
    n0 = np.argmax(f_skn < f_tol, axis=-1).max()
    assert np.all(
        f_skn[..., n0:] < f_tol)  # XXX use f_skn[...,n0:].sum()<f_tol

    # Read the number of Delta-SCF orbitals
    norbitals = paw.occupations.norbitals
    if debug:
        mpi_debug('n0=%d, norbitals=%d, bd:%d, gd:%d, kd:%d' %
                  (n0, norbitals, bd.comm.size, gd.comm.size, kd.comm.size))

    if nbands_max < 0:
        nbands_max = n0 + norbitals - nbands_max
    elif nbands_max == 'occupied':
        nbands_max = n0 + norbitals

    assert nbands_max >= n0 + norbitals, 'Too few bands to include occupations.'
    ncut = nbands_max - norbitals

    if debug: mpi_debug('nbands_max=%d' % nbands_max)

    paw.wfs.initialize_wave_functions_from_restart_file()  # hurts memmory

    for kpt in paw.wfs.kpt_u:
        mol = kpt.P_ani.keys()  # XXX stupid
        (
            f_o,
            eps_o,
            wf_oG,
            P_aoi,
        ) = dscf_reconstruct_orbitals_k_point(paw, norbitals, mol, kpt)

        assert abs(f_o - 1) < 1e-9, 'Orbitals must be properly normalized.'
        f_o = kpt.ne_o  # actual ocupatiion numbers

        # Crop band-data and inject data for Delta-SCF orbitals
        kpt.f_n = np.hstack((kpt.f_n[:n0], f_o, kpt.f_n[n0:ncut]))
        kpt.eps_n = np.hstack((kpt.eps_n[:n0], eps_o, kpt.eps_n[n0:ncut]))
        for a, P_ni in kpt.P_ani.items():
            kpt.P_ani[a] = np.vstack((P_ni[:n0], P_aoi[a], P_ni[n0:ncut]))

        old_psit_nG = kpt.psit_nG
        kpt.psit_nG = gd.empty(nbands_max, dtype=kd.dtype)

        if isinstance(old_psit_nG, TarFileReference):
            assert old_psit_nG.shape[-3:] == wf_oG.shape[
                -3:], 'Shape mismatch!'

            # Read band-by-band to save memory as full psit_nG may be large
            for n, psit_G in enumerate(kpt.psit_nG):
                if n < n0:
                    full_psit_G = old_psit_nG[n]
                elif n in range(n0, n0 + norbitals):
                    full_psit_G = wf_oG[n - n0]
                else:
                    full_psit_G = old_psit_nG[n - norbitals]
                gd.distribute(full_psit_G, psit_G)
        else:
            kpt.psit_nG[:n0] = old_psit_nG[:n0]
            kpt.psit_nG[n0:n0 + norbitals] = wf_oG
            kpt.psit_nG[n0 + norbitals:] = old_psit_nG[n0:ncut]

        del kpt.ne_o, kpt.c_on, old_psit_nG

    del paw.occupations.norbitals

    # Change various parameters related to new number of bands
    paw.wfs.mynbands = bd.mynbands = nbands_max
    paw.wfs.nbands = bd.nbands = nbands_max
    if paw.wfs.eigensolver:
        paw.wfs.eigensolver.initialized = False

    # Crop convergence criteria nbands_converge to new number of bands
    par = paw.input_parameters
    if 'convergence' in par:
        cc = par['convergence']
        if 'bands' in cc:
            cc['bands'] = min(nbands_max, cc['bands'])

    # Replace occupations class with a fixed variant (gets the magmom right)
    paw.occupations = FermiDiracFixed(paw.occupations.ne, kd.nspins,
                                      paw.occupations.width,
                                      paw.occupations.fermilevel)
    paw.occupations.set_communicator(kd.comm, bd.comm)
    paw.occupations.find_fermi_level(paw.wfs.kpt_u)  # just regenerates magmoms

    # For good measure, self-consistency information should be destroyed
    paw.scf.reset()

    if verify_density:
        paw.initialize_positions()

        # Re-calculate pseudo density and watch for changes
        old_nt_sG = paw.density.nt_sG.copy()
        paw.density.calculate_pseudo_density(paw.wfs)
        if debug:
            mpi_debug('delta-density: %g' %
                      np.abs(old_nt_sG - paw.density.nt_sG).max())
        assert np.all(
            np.abs(paw.density.nt_sG - old_nt_sG) < nt_tol), 'Density changed!'

        # Re-calculate atomic density matrices and watch for changes
        old_D_asp = {}
        for a, D_sp in paw.density.D_asp.items():
            old_D_asp[a] = D_sp.copy()
        paw.wfs.calculate_atomic_density_matrices(paw.density.D_asp)
        if debug:
            mpi_debug('delta-D_asp: %g' % max([
                np.abs(D_sp - old_D_asp[a]).max()
                for a, D_sp in paw.density.D_asp.items()
            ]))
        for a, D_sp in paw.density.D_asp.items():
            assert np.all(
                np.abs(D_sp - old_D_asp[a]) < D_tol), 'Atom %d changed!' % a