Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement particle-particle random phase approximation (ppRPA)
Browse files Browse the repository at this point in the history
ppRPA can be used to calculate excitation energies
and correlation energies of molecules and gamma points.

Refs:
[1] https://doi.org/10.1103/PhysRevA.88.030501
[2] https://doi.org/10.1063/1.4895792
[3] https://doi.org/10.1021/acs.jpca.3c02834
[4] https://doi.org/10.1021/acs.jpclett.4c00184

Co-authored-by: Jiachen Li <[email protected]>
pi246 and lijiachen417 committed Nov 19, 2024
1 parent 9564956 commit 84d7fbd
Showing 9 changed files with 2,728 additions and 0 deletions.
42 changes: 42 additions & 0 deletions examples/pprpa/01-pprpa_total_energy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from pyscf import gto, dft

# For ppRPA total energy of N-electron system
# mean field is also N-electron

mol = gto.Mole()
mol.verbose = 5
mol.atom = [
["O", (0.0, 0.0, 0.0)],
["H", (0.0, -0.7571, 0.5861)],
["H", (0.0, 0.7571, 0.5861)]]
mol.basis = 'def2-svp'
mol.build()

# =====> Part I. Restricted ppRPA <=====
mf = dft.RKS(mol)
mf.xc = "b3lyp"
mf.kernel()

from pyscf.pprpa.rpprpa_direct import RppRPADirect
pp = RppRPADirect(mf)
ec = pp.get_correlation()
etot, ehf, ec = pp.energy_tot()
print("H2O Hartree-Fock energy = %.8f" % ehf)
print("H2O ppRPA correlation energy = %.8f" % ec)
print("H2O ppRPA total energy = %.8f" % etot)

# =====> Part II. Unrestricted ppRPA <=====
# unrestricted KS-DFT calculation as starting point of UppRPA
umf = dft.UKS(mol)
umf.xc = "b3lyp"
umf.kernel()

# direct diagonalization, N6 scaling
from pyscf.pprpa.upprpa_direct import UppRPADirect
pp = UppRPADirect(umf)
ec = pp.get_correlation()
etot, ehf, ec = pp.energy_tot()
print("H2O Hartree-Fock energy = %.8f" % ehf)
print("H2O ppRPA correlation energy = %.8f" % ec)
print("H2O ppRPA total energy = %.8f" % etot)

64 changes: 64 additions & 0 deletions examples/pprpa/02-pprpa_excitation_energy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from pyscf import gto, dft

# For ppRPA excitation energy of N-electron system in particle-particle channel
# mean field is (N-2)-electron

mol = gto.Mole()
mol.verbose = 5
mol.atom = [
["O", (0.0, 0.0, 0.0)],
["H", (0.0, -0.7571, 0.5861)],
["H", (0.0, 0.7571, 0.5861)]]
mol.basis = 'def2-svp'
# create a (N-2)-electron system for charged-neutral H2O
mol.charge = 2
mol.build()

# =====> Part I. Restricted ppRPA <=====
# restricted KS-DFT calculation as starting point of RppRPA
rmf = dft.RKS(mol)
rmf.xc = "b3lyp"
rmf.kernel()

# direct diagonalization, N6 scaling
from pyscf.pprpa.rpprpa_direct import RppRPADirect
# ppRPA can be solved in an active space
pp = RppRPADirect(rmf, nocc_act=None, nvir_act=10)
# number of two-electron addition states to print
pp.pp_state = 10
# solve for singlet states
pp.kernel("s")
# solve for triplet states
pp.kernel("t")
pp.analyze()

# Davidson algorithm, N4 scaling
from pyscf.pprpa.rpprpa_davidson import RppRPADavidson
# ppRPA can be solved in an active space
pp = RppRPADavidson(rmf, nocc_act=3, nvir_act=None, nroot=10)
# solve for singlet states
pp.kernel("s")
# solve for triplet states
pp.kernel("t")
pp.analyze()

# =====> Part II. Unrestricted ppRPA <=====
# unrestricted KS-DFT calculation as starting point of UppRPA
umf = dft.UKS(mol)
umf.xc = "b3lyp"
umf.kernel()

# direct diagonalization, N6 scaling
from pyscf.pprpa.upprpa_direct import UppRPADirect
# ppRPA can be solved in an active space
pp = UppRPADirect(umf, nocc_act=None, nvir_act=10)
# number of two-electron addition states to print
pp.pp_state = 10
# solve ppRPA in the (alpha alpha, alpha alpha) subspace
pp.kernel(subspace=['aa'])
# solve ppRPA in the (alpha beta, alpha beta) subspace
pp.kernel(subspace=['ab'])
# solve ppRPA in the (beta beta, beta beta) subspace
pp.kernel(subspace=['bb'])
pp.analyze()

63 changes: 63 additions & 0 deletions examples/pprpa/03-hhrpa_excitation_energy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from pyscf import gto, dft

# For ppRPA excitation energy of N-electron system in hole-hole channel
# mean field is (N+2)-electron

mol = gto.Mole()
mol.verbose = 5
mol.atom = [
["O", (0.0, 0.0, 0.0)],
["H", (0.0, -0.7571, 0.5861)],
["H", (0.0, 0.7571, 0.5861)]]
mol.basis = 'def2-svp'
# create a (N+2)-electron system for charged-neutral H2O
mol.charge = -2
mol.build()

# =====> Part I. Restricted ppRPA <=====
mf = dft.RKS(mol)
mf.xc = "b3lyp"
mf.kernel()

# direct diagonalization, N6 scaling
# ppRPA can be solved in an active space
from pyscf.pprpa.rpprpa_direct import RppRPADirect
pp = RppRPADirect(mf, nvir_act=10, nelec="n+2")
# number of two-electron removal states to print
pp.hh_state = 10
# solve for singlet states
pp.kernel("s")
# solve for triplet states
pp.kernel("t")
pp.analyze()

# Davidson algorithm, N4 scaling
# ppRPA can be solved in an active space
from pyscf.pprpa.rpprpa_davidson import RppRPADavidson
pp = RppRPADavidson(mf, nvir_act=10, channel="hh")
# solve for singlet states
pp.kernel("s")
# solve for triplet states
pp.kernel("t")
pp.analyze()

# =====> Part II. Unrestricted ppRPA <=====
# unrestricted KS-DFT calculation as starting point of UppRPA
umf = dft.UKS(mol)
umf.xc = "b3lyp"
umf.kernel()

# direct diagonalization, N6 scaling
from pyscf.pprpa.upprpa_direct import UppRPADirect
# ppRPA can be solved in an active space
pp = UppRPADirect(umf, nvir_act=10, nelec='n+2')
# number of two-electron addition states to print
pp.pp_state = 10
# solve ppRPA in the (alpha alpha, alpha alpha) subspace
pp.kernel(subspace=['aa'])
# solve ppRPA in the (alpha beta, alpha beta) subspace
pp.kernel(subspace=['ab'])
# solve ppRPA in the (beta beta, beta beta) subspace
pp.kernel(subspace=['bb'])
pp.analyze()

166 changes: 166 additions & 0 deletions examples/pprpa/04-gamma_pprpa_excitation_energy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import os

from pyscf.pbc import df, dft, gto, lib

# For ppRPA excitation energy of N-electron system in particle-particle channel
# mean field is (N-2)-electron

# carbon vacancy in diamond
# see Table.1 in https://doi.org/10.1021/acs.jctc.4c00829
cell = gto.Cell()
cell.build(unit='angstrom',
a=[[7.136000, 0.000000, 0.000000],
[0.000000, 7.136000, 0.000000],
[0.000000, 0.000000, 7.136000]],
atom=[
["C", (0.001233209267, 0.001233209267, 1.777383281725)],
["C", (0.012225089066, 1.794731051862, 3.561871956432)],
["C", (1.782392880032, 1.782392880032, 5.362763822515)],
["C", (1.780552680464, -0.013167298675, -0.008776569968)],
["C", (3.557268948138, 0.012225089066, 1.790128043568)],
["C", (5.339774910934, 1.794731051862, 1.790128043568)],
["C", (-0.013167298675, 1.780552680464, -0.008776569968)],
["C", (1.782392880032, 3.569607119968, -0.010763822515)],
["C", (1.794731051862, 5.339774910934, 1.790128043568)],
["C", (2.671194343578, 0.900046784093, 0.881569117555)],
["C", (0.887735886768, 0.887735886768, 6.244403380954)],
["C", (0.900046784093, 2.680805656422, 4.470430882445)],
["C", (2.680805656422, 4.451953215907, 0.881569117555)],
["C", (0.895786995277, 6.238213500378, 0.896853305635)],
["C", (0.930821705350, 0.930821705350, 2.673641624787)],
["C", (4.421178294650, 0.930821705350, 2.678358375213)],
["C", (0.900046784093, 2.671194343578, 0.881569117555)],
["C", (6.238213500378, 0.895786995277, 0.896853305635)],
["C", (2.680805656422, 0.900046784093, 4.470430882445)],
["C", (4.451953215907, 2.680805656422, 0.881569117555)],
["C", (0.930821705350, 4.421178294650, 2.678358375213)],
["C", (1.794731051862, 0.012225089066, 3.561871956432)],
["C", (0.012225089066, 3.557268948138, 1.790128043568)],
["C", (3.569607119968, 1.782392880032, -0.010763822515)],
["C", (1.736746319267, 1.736746319267, 1.671367479693)],
["C", (5.351404126874, 0.000595873126, 0.004129648157)],
["C", (0.000595873126, 5.351404126874, 0.004129648157)],
["C", (2.676000000000, 2.676000000000, 6.244000000000)],
["C", (6.244000000000, 2.676000000000, 2.676000000000)],
["C", (2.676000000000, 6.244000000000, 2.676000000000)],
["C", (0.000595873126, 0.000595873126, 5.347870351843)],
["C", (0.001233209267, 5.350766790733, 3.574616718275)],
["C", (1.780552680464, 5.365167298675, 5.360776569968)],
["C", (3.571447319536, -0.013167298675, 5.360776569968)],
["C", (5.365167298675, 1.780552680464, 5.360776569968)],
["C", (5.365167298675, 3.571447319536, -0.008776569968)],
["C", (5.350766790733, 5.350766790733, 1.777383281725)],
["C", (4.464264113232, 0.887735886768, 6.243596619046)],
["C", (4.451953215907, 2.671194343578, 4.470430882445)],
["C", (2.671194343578, 4.451953215907, 4.470430882445)],
["C", (0.895786995277, 6.249786499622, 4.455146694365)],
["C", (4.421178294650, 4.421178294650, 2.673641624787)],
["C", (6.249786499622, 4.456213004723, 0.896853305635)],
["C", (0.887735886768, 4.464264113232, 6.243596619046)],
["C", (6.249786499622, 0.895786995277, 4.455146694365)],
["C", (4.456213004723, 6.249786499622, 0.896853305635)],
["C", (5.350766790733, 0.001233209267, 3.574616718275)],
["C", (-0.013167298675, 3.571447319536, 5.360776569968)],
["C", (3.571447319536, 5.365167298675, -0.008776569968)],
["C", (3.615253680733, 1.736746319267, 3.680632520307)],
["C", (3.615253680733, 3.615253680733, 1.671367479693)],
["C", (6.244000000000, 2.676000000000, 6.244000000000)],
["C", (6.244000000000, 6.244000000000, 2.676000000000)],
["C", (1.736746319267, 3.615253680733, 3.680632520307)],
["C", (2.676000000000, 6.244000000000, 6.244000000000)],
["C", (3.557268948138, 5.339774910934, 3.561871956432)],
["C", (5.351404126874, 5.351404126874, 5.347870351843)],
["C", (3.569607119968, 3.569607119968, 5.362763822515)],
["C", (5.339774910934, 3.557268948138, 3.561871956432)],
["C", (4.464264113232, 4.464264113232, 6.244403380954)],
["C", (4.456213004723, 6.238213500378, 4.455146694365)],
["C", (6.238213500378, 4.456213004723, 4.455146694365)],
["C", (6.244000000000, 6.244000000000, 6.244000000000)],
],
dimension=3,
max_memory=90000,
verbose=5,
basis='cc-pvdz',
# create a (N-2)-electron system
charge=2,
precision=1e-12)

gdf = df.RSDF(cell)
gdf.auxbasis = "cc-pvdz-ri"
gdf_fname = 'gdf_ints.h5'
gdf._cderi_to_save = gdf_fname
if not os.path.isfile(gdf_fname):
gdf.build()

# =====> Part I. Restricted ppRPA <=====
# After SCF, PySCF might fail in Makov-Payne correction
# save chkfile to restart
chkfname = 'scf.chk'
if os.path.isfile(chkfname):
kmf = dft.RKS(cell).rs_density_fit()
kmf.xc = "b3lyp"
kmf.exxdiv = None
kmf.with_df = gdf
kmf.with_df._cderi = gdf_fname
data = lib.chkfile.load(chkfname, 'scf')
kmf.__dict__.update(data)
else:
kmf = dft.RKS(cell).rs_density_fit()
kmf.xc = "b3lyp"
kmf.exxdiv = None
kmf.with_df = gdf
kmf.with_df._cderi = gdf_fname
kmf.chkfile = chkfname
kmf.kernel()

# direct diagonalization, N6 scaling
# ppRPA can be solved in an active space
from pyscf.pprpa.rpprpa_direct import RppRPADirect
pp = RppRPADirect(kmf, nocc_act=50, nvir_act=50)
# number of two-electron addition states to print
pp.pp_state = 50
# solve for singlet states
pp.kernel("s")
# solve for triplet states
pp.kernel("t")
pp.analyze()

# Davidson algorithm, N4 scaling
# ppRPA can be solved in an active space
from pyscf.pprpa.rpprpa_davidson import RppRPADavidson
pp = RppRPADavidson(kmf, nocc_act=50, nvir_act=50, nroot=50)
# solve for singlet states
pp.kernel("s")
# solve for triplet states
pp.kernel("t")
pp.analyze()

# =====> Part II. Unrestricted ppRPA <=====
chkfname = 'uscf.chk'
if os.path.isfile(chkfname):
kmf = dft.UKS(cell).rs_density_fit()
kmf.xc = "b3lyp"
kmf.exxdiv = None
kmf.with_df = gdf
kmf.with_df._cderi = gdf_fname
data = lib.chkfile.load(chkfname, 'scf')
kmf.__dict__.update(data)
else:
kmf = dft.UKS(cell).rs_density_fit()
kmf.xc = "b3lyp"
kmf.exxdiv = None
kmf.with_df = gdf
kmf.with_df._cderi = gdf_fname
kmf.chkfile = chkfname
kmf.kernel()

# direct diagonalization, N6 scaling
# ppRPA can be solved in an active space
from pyscf.pprpa.upprpa_direct import UppRPADirect
pp = UppRPADirect(kmf, nocc_act=50, nvir_act=50)
# number of two-electron addition states to print
pp.pp_state = 50
# solve ppRPA
pp.kernel()
pp.analyze()

156 changes: 156 additions & 0 deletions examples/pprpa/05-gamma_hhrpa_excitation_energy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import os

from pyscf.pbc import df, dft, gto, lib

# For ppRPA excitation energy of N-electron system in hole-hole channel
# mean field is (N+2)-electron

# nitrogen vacancy in diamond (NV-)
# see in Table.1 https://doi.org/10.1021/acs.jpclett.4c00184
cell = gto.Cell()
cell.build(unit='angstrom',
a=[[7.136000, 0.000000, 0.000000],
[0.000000, 7.136000, 0.000000],
[0.000000, 0.000000, 7.136000]],
atom=[
["C", (0.906073512160, 2.664323563008, 2.694339584224)],
["C", (0.894090626784, 2.684866651264, 6.241909316128)],
["C", (0.899084378176, 6.235829736704, 2.679298965664)],
["C", (0.892434989152, 6.244294788160, 6.243564953760)],
["C", (4.459048614208, 2.719457426496, 2.676951150304)],
["C", (4.441660180288, 2.664323563008, 6.229926430752)],
["C", (4.460040375488, 6.254734827520, 2.675959389024)],
["C", (4.456700798848, 6.235829736704, 6.236915564736)],
["C", (0.000121369088, 0.000121369088, -0.000121369088)],
["C", (-0.010102670688, -0.010102670688, 3.575517319296)],
["C", (-0.010102670688, 3.560482680704, 0.010102670688)],
["C", (0.008425625056, 3.562468772224, 3.573531227776)],
["C", (3.560482680704, -0.010102670688, 0.010102670688)],
["C", (3.562468772224, 0.008425625056, 3.573531227776)],
["C", (3.562468772224, 3.562468772224, -0.008425625056)],
["C", (0.892434989152, 0.892434989152, 0.891705154752)],
["C", (0.894090626784, 0.894090626784, 4.451133113248)],
["C", (0.899084378176, 4.456700798848, 0.900170206208)],
["C", (0.906073512160, 4.441660180288, 4.471676201504)],
["C", (4.456700798848, 0.899084378176, 0.900170206208)],
["C", (4.441660180288, 0.906073512160, 4.471676201504)],
["C", (4.460040375488, 4.460040375488, 0.881265115392)],
["C", (4.459048614208, 4.459048614208, 4.416542338016)],
["C", (-0.006901660896, 1.786905622208, 1.780569760480)],
["C", (0.002512956672, 1.784927308928, 5.351072569760)],
["C", (0.006719393184, 5.349206041920, 1.786793836768)],
["C", (-0.006901660896, 5.355430118208, 5.349094256480)],
["C", (3.557699819104, 1.801090513056, 1.799927287968)],
["C", (3.623443694336, 1.707240281568, 5.428759597120)],
["C", (3.570268719936, 5.363769868640, 1.772230010048)],
["C", (3.557699819104, 5.336072590720, 5.334909365632)],
["C", (2.675027363200, 2.675027363200, 0.892428602432)],
["C", (2.675779925760, 6.243436648480, 0.892563294432)],
["C", (2.675027363200, 6.243571340480, 4.460972401312)],
["C", (6.243436648480, 2.675779925760, 0.892563294432)],
["C", (6.243571340480, 2.675027363200, 4.460972401312)],
["C", (6.244306769504, 6.244306769504, 0.891693173408)],
["C", (6.243436648480, 6.243436648480, 4.460219838752)],
["C", (1.786905622208, -0.006901660896, 1.780569760480)],
["C", (1.784927308928, 0.002512956672, 5.351072569760)],
["C", (1.801090513056, 3.557699819104, 1.799927287968)],
["C", (1.707240281568, 3.623443694336, 5.428759597120)],
["C", (5.349206041920, 0.006719393184, 1.786793836768)],
["C", (5.355430118208, -0.006901660896, 5.349094256480)],
["C", (5.363769868640, 3.570268719936, 1.772230010048)],
["C", (5.336072590720, 3.557699819104, 5.334909365632)],
["C", (2.664323563008, 0.906073512160, 2.694339584224)],
["C", (2.684866651264, 0.894090626784, 6.241909316128)],
["C", (2.719457426496, 4.459048614208, 2.676951150304)],
["C", (2.664323563008, 4.441660180288, 6.229926430752)],
["C", (6.235829736704, 0.899084378176, 2.679298965664)],
["C", (6.244294788160, 0.892434989152, 6.243564953760)],
["C", (6.254734827520, 4.460040375488, 2.675959389024)],
["C", (6.235829736704, 4.456700798848, 6.236915564736)],
["C", (1.784927308928, 1.784927308928, -0.002512956672)],
["C", (1.707240281568, 1.707240281568, 3.512556305664)],
["C", (1.786905622208, 5.355430118208, 0.006901660896)],
["C", (1.801090513056, 5.336072590720, 3.578300180896)],
["C", (5.355430118208, 1.786905622208, 0.006901660896)],
["C", (5.336072590720, 1.801090513056, 3.578300180896)],
["C", (5.349206041920, 5.349206041920, -0.006719393184)],
["C", (5.363769868640, 5.363769868640, 3.565731280064)],
["N", (3.661895773440, 3.661895773440, 3.474104226560)],
],
dimension=3,
max_memory=90000,
verbose=5,
basis='cc-pvdz',
# create a (N+2)-electron system
charge=-3,
precision=1e-12)

gdf = df.RSDF(cell)
gdf.auxbasis = "cc-pvdz-ri"
gdf_fname = 'gdf_ints.h5'
gdf._cderi_to_save = gdf_fname
if not os.path.isfile(gdf_fname):
gdf.build()

# =====> Part I. Restricted ppRPA <=====
# After SCF, PySCF might fail in Makov-Payne correction
# save chkfile to restart
chkfname = 'scf.chk'
if os.path.isfile(chkfname):
kmf = dft.RKS(cell).rs_density_fit()
kmf.xc = "b3lyp"
kmf.exxdiv = None
kmf.with_df = gdf
kmf.with_df._cderi = gdf_fname
data = lib.chkfile.load(chkfname, 'scf')
kmf.__dict__.update(data)
else:
kmf = dft.RKS(cell).rs_density_fit()
kmf.xc = "b3lyp"
kmf.exxdiv = None
kmf.with_df = gdf
kmf.with_df._cderi = gdf_fname
kmf.chkfile = chkfname
kmf.kernel()

# direct diagonalization, N6 scaling
# ppRPA can be solved in an active space
from pyscf.pprpa.rpprpa_direct import RppRPADirect
pp = RppRPADirect(kmf, nocc_act=50, nvir_act=50, nelec="n+2")
# number of two-electron removal states to print
pp.hh_state = 50
# solve for singlet states
pp.kernel("s")
# solve for triplet states
pp.kernel("t")
pp.analyze()

# =====> Part II. Unrestricted ppRPA <=====
chkfname = 'uscf.chk'
if os.path.isfile(chkfname):
kmf = dft.UKS(cell).rs_density_fit()
kmf.xc = "b3lyp"
kmf.exxdiv = None
kmf.with_df = gdf
kmf.with_df._cderi = gdf_fname
data = lib.chkfile.load(chkfname, 'scf')
kmf.__dict__.update(data)
else:
kmf = dft.UKS(cell).rs_density_fit()
kmf.xc = "b3lyp"
kmf.exxdiv = None
kmf.with_df = gdf
kmf.with_df._cderi = gdf_fname
kmf.chkfile = chkfname
kmf.kernel()

# direct diagonalization, N6 scaling
# ppRPA can be solved in an active space
from pyscf.pprpa.upprpa_direct import UppRPADirect
pp = UppRPADirect(kmf, nocc_act=50, nvir_act=50, nelec="n+2")
# number of two-electron addition states to print
pp.pp_state = 50
# solve ppRPA
pp.kernel()
pp.analyze()

Empty file added pyscf/pprpa/__init__.py
Empty file.
726 changes: 726 additions & 0 deletions pyscf/pprpa/rpprpa_davidson.py

Large diffs are not rendered by default.

760 changes: 760 additions & 0 deletions pyscf/pprpa/rpprpa_direct.py

Large diffs are not rendered by default.

751 changes: 751 additions & 0 deletions pyscf/pprpa/upprpa_direct.py

Large diffs are not rendered by default.

0 comments on commit 84d7fbd

Please sign in to comment.