Example #1
0
def get_veff(ks, mol=None, dm=None, dm_last=0, vhf_last=0, hermi=1):
    if getattr(dm, 'mo_coeff', None) is not None:
        mo_coeff = dm.mo_coeff
        mo_occ_a = (dm.mo_occ > 0).astype(numpy.double)
        mo_occ_b = (dm.mo_occ ==2).astype(numpy.double)
        dm = lib.tag_array(dm, mo_coeff=(mo_coeff,mo_coeff),
                           mo_occ=(mo_occ_a,mo_occ_b))
    return uks.get_veff(ks, mol, dm, dm_last, vhf_last, hermi)
Example #2
0
def get_veff(ks, mol=None, dm=None, dm_last=0, vhf_last=0, hermi=1):
    if getattr(dm, 'mo_coeff', None) is not None:
        mo_coeff = dm.mo_coeff
        mo_occ_a = (dm.mo_occ > 0).astype(numpy.double)
        mo_occ_b = (dm.mo_occ == 2).astype(numpy.double)
        dm = lib.tag_array(dm,
                           mo_coeff=(mo_coeff, mo_coeff),
                           mo_occ=(mo_occ_a, mo_occ_b))
    return uks.get_veff(ks, mol, dm, dm_last, vhf_last, hermi)
Example #3
0
def get_flosic_veff(ks, mol=None, dm=None, dm_last=0, vhf_last=0, hermi=1):
    # pyscf standard call for scf cycle 0.
    veff = uks.get_veff(ks=ks.calc_uks,
                        mol=ks.mol,
                        dm=dm,
                        dm_last=dm_last,
                        vhf_last=vhf_last,
                        hermi=hermi)

    if mol is None: mol = ks.mol
    # Build the hamiltonian to get the KS wave functions.
    dim = np.shape(ks.calc_uks.mo_coeff)
    s1e = ks.get_ovlp(mol)
    h1e = ks.get_hcore(mol)
    hamil = ks.get_fock(h1e, s1e, vhf_last, dm)

    # Get the KSO.
    ks_new = np.zeros((2, dim[1], dim[1]), dtype=np.float64)

    try:
        if dm_last == 0:
            # First SCF cycle: do nothing.
            pass
    except:
        # Every other DFT cycle: Build the KS wavefunctions with the Hamiltonian, then give them to the UKS object that is the input for flosic.
        trash, ks_new = ks.eig(hamil, s1e)
        ks_inter = np.array(ks_new)

        # Update UKS object.
        ks.calc_uks.mo_coeff = ks_inter.copy()

    # If ldax is enabled, the xc functional is set to LDA exchange only.
    if ks.ldax == True:
        xc_sav = ks.calc_uks.xc
        ks.calc_uks.xc = 'LDA,'

    # Call the FLOSIC routine with the UKS object.

    # This for the fixed Vsic modus.

    # If Vsic values are present and the Vsic potential should not
    # be updated use these values.
    # (THa: the outer if ... clause was added to prevent the
    # sic potentials to be calculated during initialization)
    _t0 = time.time()
    #print('>> ks.fixed_vsic', ks.fixed_vsic)
    #print('>>', ks.neval_vsic)
    #sys.exit()
    if ks.neval_vsic > -1:
        if ks.fixed_vsic != 0.0 and (ks.num_iter % ks.vsic_every) != 0:
            if ks.verbose >= 4:
                print('Use fixed Vsic (cycle = %i)' % ks.num_iter)
            flo_veff = flosic(ks.mol, ks.calc_uks, ks.fod1, ks.fod2,\
            datatype=np.float64,calc_forces=ks.calc_forces,debug=ks.debug,\
            nuclei=ks.nuclei,l_ij=ks.l_ij,ods=ks.ods,\
            fixed_vsic=ks.fixed_vsic,ham_sic=ks.ham_sic)

        # If no Vsic values are present or the the Vsic values should be
        # updated calcualte new Vsic values.

        # !! THa: Possible BUG
        # ks.fixed_vsic == 0.0 may never be 'True' because
        # a float-value is amost never exactly zero
        # better use: np.isclose(ks.fixed_vsic, 0.0)
        # !!
        if ks.fixed_vsic == 0.0 or (ks.num_iter % ks.vsic_every) == 0:
            if ks.verbose >= 4:
                print('Calculate new Vsic (cycle = %i)' % ks.num_iter)
            flo_veff = flosic(ks.mol,ks.calc_uks,ks.fod1,ks.fod2,\
            datatype=np.float64,calc_forces=ks.calc_forces,debug=ks.debug,\
            nuclei=ks.nuclei,l_ij=ks.l_ij,ods=ks.ods,ham_sic=ks.ham_sic)
            ks.fixed_vsic = flo_veff['fixed_vsic']
    else:
        flo_veff = veff

    _t1 = time.time()
    if mol.verbose > 3:
        print("FLO-SIC time for SIC potential: {0:0.1f} [s]".format(_t1 - _t0))
    # increase a magic counter
    ks.num_iter = ks.num_iter + 1

    # If ldax is enabled, the change to xc is only meant for the FLO-SIC part and
    # therefore has to be changed back.
    if ks.ldax == True:
        ks.calc_uks.xc = xc_sav

    # Assign the return values.
    # The total energies of DFT and FLO-SIC
    if ks.neval_vsic > -1:
        sic_etot = flo_veff['etot_sic']
        dft_etot = flo_veff['etot_dft']
        # The FLOs.
        ks.flo = flo_veff['flo']
        # The FOD forces.
        ks.fforces = flo_veff['fforces']
        # The FLO-SIC H**O energy eigenvalue.
        ks.homo_flosic = flo_veff['homo_sic']
        ks.evalues = flo_veff['evalues']
        ks.lambda_ij = flo_veff['lambda_ij']
        # Developer modus: atomic forces (AF)
        if ks.debug == True:
            ks.AF = flo_veff['AF']
    else:
        sic_etot = ks.e_tot
        dft_etot = ks.e_tot
        ks.flo = ks.mo_coeff
        ks.homo_flosic = 0.0

    try:
        # First SCF cycle: veff = veff_dft and the SIC is zero.
        if dm_last == 0:
            sic_veff = veff
            sic_etot = dft_etot
    except:
        # Every other DFT cycle: Build veff as sum of the regular veff and the SIC
        # potential.
        sic_veff = veff + flo_veff['hamil']

        # Update the density matrix.
        dm_new = dynamic_rdm(ks.flo, ks.calc_uks.mo_occ)
        dm = dm_new.copy()
        ks.mo_coeff = ks.flo

    # Give back the FLO-SIC energy correction and the corrected potential. This libtagarray
    # formalism is defined by pyscf.
    sic_back = sic_etot - dft_etot
    veff_sic = lib.tag_array(sic_veff,
                             ecoul=veff.ecoul,
                             exc=veff.exc,
                             vj=veff.vj,
                             vk=veff.vk,
                             esic=(sic_back))

    # Return the exchange-correlation energy and the FLO-SIC energy correction.
    ks.exc = veff.exc
    ks.esic = sic_back

    # increase another magic counter ;-)
    ks.neval_vsic += 1

    return veff_sic