├── .gitignore
├── LICENSE
├── README.md
├── examples
├── NiO
│ ├── CAS-CCSD
│ │ └── run_dmft.py
│ ├── nio_dft.py
│ ├── nio_gw.py
│ ├── nio_set_ham.py
│ ├── run_dft
│ ├── run_dmft
│ ├── run_dmft.py
│ ├── run_gw
│ └── run_ham
├── Si
│ ├── CAS-CCSD
│ │ └── run_dmft.py
│ ├── run_dmft
│ ├── run_dmft.py
│ ├── run_gw
│ ├── run_ham
│ ├── si_gw.py
│ └── si_set_ham.py
├── SrMoO3
│ ├── README.md
│ ├── run_dmft.py
│ ├── srmoo3_gw.py
│ ├── srmoo3_interpolate.py
│ ├── srmoo3_lda.py
│ └── srmoo3_set_ham.py
└── interpolation
│ ├── diamond_gw_interpolate.py
│ ├── diamond_gw_interpolate_iao.py
│ └── diamond_hf_interpolate.py
└── fcdmft
├── __init__.py
├── dmft
├── __init__.py
├── dmft_solver.py
├── gwdmft.py
└── run_dmft.py
├── gw
├── __init__.py
├── mol
│ ├── __init__.py
│ ├── gw_ac.py
│ ├── gw_dc.py
│ ├── gw_gf.py
│ ├── ugw_ac.py
│ ├── ugw_dc.py
│ └── ugw_gf.py
└── pbc
│ ├── __init__.py
│ ├── krgw_ac.py
│ ├── krgw_gf.py
│ ├── kugw_ac.py
│ └── kugw_gf.py
├── rpa
├── __init__.py
├── mol
│ ├── __init__.py
│ ├── rpa.py
│ └── urpa.py
└── pbc
│ ├── __init__.py
│ ├── krpa.py
│ ├── kurpa.py
│ ├── rpa.py
│ └── urpa.py
├── solver
├── casno.py
├── ccgf.py
├── gfdmrg.py
├── gfdmrg_sz.py
├── gmres.py
├── mpiccgf.py
├── mpiuccgf.py
├── scf_mu.py
├── ucc_eri.py
└── uccgf.py
└── utils
├── cholesky.py
├── interpolate.py
└── write.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | ENV/
110 | env.bak/
111 | venv.bak/
112 |
113 | # Spyder project settings
114 | .spyderproject
115 | .spyproject
116 |
117 | # Rope project settings
118 | .ropeproject
119 |
120 | # mkdocs documentation
121 | /site
122 |
123 | # mypy
124 | .mypy_cache/
125 | .dmypy.json
126 | dmypy.json
127 |
128 | # Pyre type checker
129 | .pyre/
130 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | fcdmft
2 | ======
3 |
4 | Ab initio full cell dynamical mean-field theory (DMFT) and GW+DMFT for solids based on PySCF
5 |
6 | Authors: Tianyu Zhu (tianyu.zhu@yale.edu), Huanchen Zhai, Zhihao Cui, Linqing Peng, Garnet Chan
7 |
8 | Installation
9 | ------------
10 |
11 | * Prerequisites
12 | - PySCF 1.7 or higher, and all dependencies
13 | - libdmet (by Zhi-Hao Cui, https://github.com/gkclab/libdmet_preview)
14 | - block2 (optional, by Huanchen Zhai, https://github.com/block-hczhai/block2-preview)
15 | - CheMPS2 (optional)
16 |
17 | * You need to set environment variable `PYTHONPATH` to export fcdmft to Python.
18 | E.g. if fcdmft is installed in `/opt`, your `PYTHONPATH` should be
19 |
20 | export PYTHONPATH=/opt/fcdmft:$PYTHONPATH
21 |
22 | Features
23 | --------
24 |
25 | * Full cell G0W0+DMFT and HF+DMFT (mixed MPI and OpenMP parallelization)
26 |
27 | * Hamiltonian-based impurity solvers
28 | * Coupled-cluster Green's function
29 | * Quantum chemistry dynamical DMRG (from block2)
30 | * DMRG-MRCI Green's function (from block2)
31 | * FCI/ED Green's function (from CheMPS2, for test only)
32 |
33 | * Molecular and periodic G0W0
34 |
35 | * Molecular and periodic RPA
36 |
37 | * CAS-CI treatment of the impurity problem
38 |
39 | QuickStart
40 | ----------
41 |
42 | You can find Python scripts for running DMFT calculations in `/fcdmft/examples`.
43 | For example, in `/fcdmft/examples/Si`, the steps to run a full cell GW+DMFT
44 | calculation are:
45 |
46 | 1. Perform DFT and GW calculations by running `si_gw.py`
47 | (Note: For large systems, GW should be performed separately using multiple nodes,
48 | i.e. MPI, see `/fcdmft/examples/NiO`);
49 |
50 | 2. Derive impurity Hamiltonian and GW double counting term by running `si_set_ham.py`;
51 |
52 | 3. Perform GW+DMFT calculation by running `run_dmft.py` (serial or MPI/OpenMP).
53 | All DMFT parameters should be set in `run_dmft.py`. In this example, CCSD-GF is used
54 | as impurity solver. See `run_dmft` for sample Slurm submission script.
55 |
56 | 4. (Optional) One may use a CAS-CI treatment when solving the impurity problem. See
57 | `CAS-CCSD/run_dmft.py` for setting CAS-related parameters.
58 |
59 | References
60 | ----------
61 |
62 | Please cite the following papers in publications utilizing the fcdmft package:
63 |
64 | * T. Zhu and G. K.-L. Chan, Phys. Rev. X 11, 021006 (2021)
65 |
66 | * T. Zhu, Z.-H. Cui, and G. K.-L. Chan, J. Chem. Theory Comput. 16, 141-153 (2020)
67 |
68 | * T. Zhu, C. A. Jimenez-Hoyos, J. McClain, T. C. Berkelbach, and G. K.-L. Chan, Phys. Rev. B 100, 115154 (2019)
69 |
70 | Cite the following paper if GW code is used:
71 |
72 | * T. Zhu and G. K.-L. Chan, J. Chem. Theory Comput. 17, 727-741 (2021)
73 |
74 | Cite the following paper if libdmet package is used:
75 |
76 | * Z.-H. Cui, T. Zhu, and G. K.-L. Chan, J. Chem. Theory Comput. 16, 119-129 (2020)
77 |
--------------------------------------------------------------------------------
/examples/NiO/nio_dft.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | from pyscf.pbc import df, dft, gto
3 | import numpy as np
4 | import os, h5py
5 | from pyscf.pbc.lib import chkfile
6 | from pyscf import lib
7 |
8 | einsum = lib.einsum
9 |
10 | def at(a0):
11 | a = np.zeros((3,3)) # generators of rhombohedral cell
12 | a[0,:] = ( 1.00, 0.50, 0.50) #
13 | a[1,:] = ( 0.50, 1.00, 0.50) #
14 | a[2,:] = ( 0.50, 0.50, 1.00)
15 | a *= a0
16 |
17 | g = np.zeros((4,3)) # ions in the cell, in crystal coordinates
18 | g[0,:] = ( 0.00, 0.00, 0.00) # Ni
19 | g[1,:] = ( 0.50, 0.50, 0.50) # Ni
20 | g[2,:] = ( 0.25, 0.25, 0.25) # O
21 | g[3,:] = ( 0.75, 0.75, 0.75) # O
22 |
23 | pos=[]
24 | for mu in range(4):
25 | v=[0.00,0.00,0.00]
26 | for nu in range(3):
27 | v=v[:]+g[mu,nu]*a[nu,:] # actual coordinates of the ions
28 | z='Ni'
29 | if(mu>1): z='O'
30 | pos.append([z,v])
31 |
32 | return a,pos
33 |
34 | a0 = 4.17
35 | vec, posion = at(a0)
36 | cell = gto.Cell()
37 | cell.build(unit = 'angstrom',
38 | a = vec,
39 | atom = posion,
40 | dimension = 3,
41 | max_memory = 64000,
42 | verbose = 5,
43 | basis='gth-dzvp-molopt-sr',
44 | pseudo='gth-pbe',
45 | precision=1e-12)
46 |
47 | kmesh = [4,4,4]
48 | kpts = cell.make_kpts(kmesh,scaled_center=[0,0,0],wrap_around=True)
49 | gdf = df.GDF(cell, kpts)
50 | gdf.auxbasis = df.aug_etb(cell, beta=2.3)
51 | gdf_fname = 'gdf_ints_444.h5'
52 | gdf._cderi_to_save = gdf_fname
53 | gdf.mesh = np.asarray([25, 25, 25])
54 | if not os.path.isfile(gdf_fname):
55 | gdf.build()
56 |
57 | chkfname = 'nio_444.chk'
58 | if os.path.isfile(chkfname):
59 | kmf = dft.KUKS(cell, kpts).density_fit()
60 | kmf.xc = 'pbe'
61 | kmf.with_df = gdf
62 | kmf.with_df._cderi = gdf_fname
63 | kmf.conv_tol = 1e-12
64 | data = chkfile.load(chkfname, 'scf')
65 | kmf.__dict__.update(data)
66 | else:
67 | kmf = dft.KUKS(cell, kpts).density_fit()
68 | kmf.xc = 'pbe'
69 | kmf.with_df = gdf
70 | kmf.with_df._cderi = gdf_fname
71 | kmf.conv_tol = 1e-12
72 | kmf.chkfile = chkfname
73 |
74 | aoind = cell.aoslice_by_atom()
75 | dm = kmf.get_init_guess()
76 | dm[0,:,aoind[0][2]:aoind[0][3], aoind[0][2]:aoind[0][3]] = 2. * dm[0,:,aoind[0][2]:aoind[0][3], aoind[0][2]:aoind[0][3]]
77 | dm[0,:,aoind[1][2]:aoind[1][3], aoind[1][2]:aoind[1][3]] = 0. * dm[0,:,aoind[1][2]:aoind[1][3], aoind[1][2]:aoind[1][3]]
78 | dm[1,:,aoind[0][2]:aoind[0][3], aoind[0][2]:aoind[0][3]] = 0. * dm[1,:,aoind[0][2]:aoind[0][3], aoind[0][2]:aoind[0][3]]
79 | dm[1,:,aoind[1][2]:aoind[1][3], aoind[1][2]:aoind[1][3]] = 2. * dm[1,:,aoind[1][2]:aoind[1][3], aoind[1][2]:aoind[1][3]]
80 | kmf.kernel(dm)
81 |
82 |
--------------------------------------------------------------------------------
/examples/NiO/nio_gw.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | from pyscf.pbc import df, dft, gto
3 | import numpy as np
4 | import os, h5py
5 | from pyscf.pbc.lib import chkfile
6 | from pyscf import lib
7 | from fcdmft.gw.pbc import kugw_gf
8 | from fcdmft.utils import write
9 | from mpi4py import MPI
10 |
11 | rank = MPI.COMM_WORLD.Get_rank()
12 | size = MPI.COMM_WORLD.Get_size()
13 | comm = MPI.COMM_WORLD
14 |
15 | einsum = lib.einsum
16 |
17 | def at(a0):
18 | a = np.zeros((3,3)) # generators of rhombohedral cell
19 | a[0,:] = ( 1.00, 0.50, 0.50) #
20 | a[1,:] = ( 0.50, 1.00, 0.50) #
21 | a[2,:] = ( 0.50, 0.50, 1.00)
22 | a *= a0
23 |
24 | g = np.zeros((4,3)) # ions in the cell, in crystal coordinates
25 | g[0,:] = ( 0.00, 0.00, 0.00) # Ni
26 | g[1,:] = ( 0.50, 0.50, 0.50) # Ni
27 | g[2,:] = ( 0.25, 0.25, 0.25) # O
28 | g[3,:] = ( 0.75, 0.75, 0.75) # O
29 |
30 | pos=[]
31 | for mu in range(4):
32 | v=[0.00,0.00,0.00]
33 | for nu in range(3):
34 | v=v[:]+g[mu,nu]*a[nu,:] # actual coordinates of the ions
35 | z='Ni'
36 | if(mu>1): z='O'
37 | pos.append([z,v])
38 |
39 | return a,pos
40 |
41 | a0 = 4.17
42 | vec, posion = at(a0)
43 | cell = gto.Cell()
44 | cell.build(unit = 'angstrom',
45 | a = vec,
46 | atom = posion,
47 | dimension = 3,
48 | max_memory = 32000,
49 | verbose = 5,
50 | basis='gth-dzvp-molopt-sr',
51 | pseudo='gth-pbe',
52 | precision=1e-12)
53 |
54 | kmesh = [4,4,4]
55 | kpts = cell.make_kpts(kmesh,scaled_center=[0,0,0],wrap_around=True)
56 | gdf = df.GDF(cell, kpts)
57 | gdf.auxbasis = df.aug_etb(cell, beta=2.3)
58 | gdf_fname = 'gdf_ints_444.h5'
59 | gdf._cderi_to_save = gdf_fname
60 | gdf.mesh = np.asarray([25, 25, 25])
61 | if not os.path.isfile(gdf_fname):
62 | gdf.build()
63 |
64 | chkfname = 'nio_444.chk'
65 | if os.path.isfile(chkfname):
66 | kmf = dft.KUKS(cell, kpts).density_fit()
67 | kmf.xc = 'pbe'
68 | kmf.with_df = gdf
69 | kmf.with_df._cderi = gdf_fname
70 | kmf.conv_tol = 1e-12
71 | data = chkfile.load(chkfname, 'scf')
72 | kmf.__dict__.update(data)
73 | else:
74 | kmf = dft.KUKS(cell, kpts).density_fit()
75 | kmf.xc = 'pbe'
76 | kmf.with_df = gdf
77 | kmf.with_df._cderi = gdf_fname
78 | kmf.conv_tol = 1e-12
79 | kmf.chkfile = chkfname
80 |
81 | aoind = cell.aoslice_by_atom()
82 | dm = kmf.get_init_guess()
83 | dm[0,:,aoind[0][2]:aoind[0][3], aoind[0][2]:aoind[0][3]] = 2. * dm[0,:,aoind[0][2]:aoind[0][3], aoind[0][2]:aoind[0][3]]
84 | dm[0,:,aoind[1][2]:aoind[1][3], aoind[1][2]:aoind[1][3]] = 0. * dm[0,:,aoind[1][2]:aoind[1][3], aoind[1][2]:aoind[1][3]]
85 | dm[1,:,aoind[0][2]:aoind[0][3], aoind[0][2]:aoind[0][3]] = 0. * dm[1,:,aoind[0][2]:aoind[0][3], aoind[0][2]:aoind[0][3]]
86 | dm[1,:,aoind[1][2]:aoind[1][3], aoind[1][2]:aoind[1][3]] = 2. * dm[1,:,aoind[1][2]:aoind[1][3], aoind[1][2]:aoind[1][3]]
87 | kmf.kernel(dm)
88 |
89 | gw = kugw_gf.KUGWGF(kmf)
90 | gw.ac = 'pade'
91 | Ha2ev = 27.211386
92 | gw.eta = 0.2/Ha2ev
93 | gw.fullsigma = True
94 | gw.fc = True
95 | omega = np.linspace(6./Ha2ev,24./Ha2ev,91)
96 | # writefile must >= 1 for GW+DMFT calc
97 | gf, gf0, sigma = gw.kernel(omega=omega, writefile=1)
98 | nkpts = gw.nkpts
99 | gf = 1./nkpts * np.sum(gf, axis=1)
100 | gf0 = 1./nkpts * np.sum(gf0, axis=1)
101 |
102 | if rank == 0:
103 | outdir = 'GW_DOS'
104 | if not os.path.isdir(outdir):
105 | os.mkdir(outdir)
106 | write.write_gf_to_dos(outdir+'/nio_gw_dos', omega, gf)
107 | write.write_gf_to_dos(outdir+'/nio_pbe_dos', omega, gf0)
108 |
109 | mo_energy = gw.mo_energy
110 | nocca, noccb = gw.nocc
111 | homo = -99.; lumo = 99.
112 | for k in range(nkpts):
113 | if homo < mo_energy[0][k][nocca-1]:
114 | homo = mo_energy[0][k][nocca-1]
115 | if lumo > mo_energy[1][k][nocca]:
116 | lumo = mo_energy[1][k][nocca]
117 | if rank == 0:
118 | print ('VBM, CBM, Gap', homo*Ha2ev, lumo*Ha2ev, (lumo-homo)*Ha2ev)
119 |
--------------------------------------------------------------------------------
/examples/NiO/nio_set_ham.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import numpy as np
3 | import h5py, os
4 | from libdmet_solid.system import lattice
5 | from libdmet_solid.basis_transform import make_basis
6 | from libdmet_solid.basis_transform import eri_transform
7 | import libdmet_solid.utils.logger as log
8 |
9 | from pyscf.pbc import df, dft, scf, gto
10 | from pyscf.pbc.lib import chkfile
11 | from pyscf import lib
12 | from pyscf import gto as gto_mol
13 | from pyscf import scf as scf_mol
14 |
15 | from fcdmft.gw.mol import ugw_dc
16 | from fcdmft.utils import cholesky
17 |
18 | log.verbose = 'DEBUG1'
19 |
20 | einsum = lib.einsum
21 |
22 | # NOTE: lattice system setup by user
23 | def at(a0):
24 | a = np.zeros((3,3)) # generators of rhombohedral cell
25 | a[0,:] = ( 1.00, 0.50, 0.50) #
26 | a[1,:] = ( 0.50, 1.00, 0.50) #
27 | a[2,:] = ( 0.50, 0.50, 1.00)
28 | a *= a0
29 |
30 | g = np.zeros((4,3)) # ions in the cell, in crystal coordinates
31 | g[0,:] = ( 0.00, 0.00, 0.00) # Ni
32 | g[1,:] = ( 0.50, 0.50, 0.50) # Ni
33 | g[2,:] = ( 0.25, 0.25, 0.25) # O
34 | g[3,:] = ( 0.75, 0.75, 0.75) # O
35 |
36 | pos=[]
37 | for mu in range(4):
38 | v=[0.00,0.00,0.00]
39 | for nu in range(3):
40 | v=v[:]+g[mu,nu]*a[nu,:] # actual coordinates of the ions
41 | z='Ni'
42 | if(mu>1): z='O'
43 | pos.append([z,v])
44 |
45 | return a,pos
46 |
47 | a0 = 4.17
48 | vec, posion = at(a0)
49 | cell = gto.Cell()
50 | cell.build(unit = 'angstrom',
51 | a = vec,
52 | atom = posion,
53 | dimension = 3,
54 | max_memory = 128000,
55 | verbose = 5,
56 | basis='gth-dzvp-molopt-sr',
57 | pseudo='gth-pbe',
58 | precision=1e-12)
59 |
60 | kmesh = [4,4,4]
61 | Lat = lattice.Lattice(cell, kmesh)
62 | kpts = Lat.kpts
63 | nao = Lat.nao
64 | nkpts = Lat.nkpts
65 |
66 | gdf = df.GDF(cell, kpts)
67 | gdf.auxbasis = df.aug_etb(cell, beta=2.3)
68 | gdf_fname = 'gdf_ints_444.h5'
69 | gdf._cderi_to_save = gdf_fname
70 | gdf.mesh = np.asarray([25, 25, 25])
71 | if not os.path.isfile(gdf_fname):
72 | gdf.build()
73 |
74 | # NOTE: set up KRKS by user
75 | # obtain spin-restricted IAO basis (currently required by gw_dc)
76 | chkfname = 'nio_444_rks.chk'
77 | if os.path.isfile(chkfname):
78 | krmf = dft.KRKS(cell, kpts).density_fit()
79 | krmf = scf.addons.smearing_(krmf, sigma=5e-3, method="fermi")
80 | krmf.xc = 'pbe'
81 | krmf.with_df = gdf
82 | krmf.with_df._cderi = gdf_fname
83 | krmf.conv_tol = 1e-12
84 | data = chkfile.load(chkfname, 'scf')
85 | krmf.__dict__.update(data)
86 | else:
87 | krmf = dft.KRKS(cell, kpts).density_fit()
88 | krmf = scf.addons.smearing_(krmf, sigma=5e-3, method="fermi")
89 | krmf.xc = 'pbe'
90 | krmf.with_df = gdf
91 | krmf.with_df._cderi = gdf_fname
92 | krmf.conv_tol = 1e-12
93 | krmf.chkfile = chkfname
94 | krmf.kernel()
95 |
96 | # read KUKS
97 | chkfname = 'nio_444.chk'
98 | if os.path.isfile(chkfname):
99 | kmf = dft.KUKS(cell, kpts).density_fit()
100 | kmf.xc = 'pbe'
101 | kmf.with_df = gdf
102 | kmf.with_df._cderi = gdf_fname
103 | kmf.conv_tol = 1e-12
104 | data = chkfile.load(chkfname, 'scf')
105 | kmf.__dict__.update(data)
106 |
107 | # set spin
108 | mo_energy = np.asarray(kmf.mo_energy)
109 | mo_coeff = np.asarray(kmf.mo_coeff)
110 | if len(mo_energy.shape) == 2:
111 | spin = 1
112 | mo_energy = mo_energy[np.newaxis, ...]
113 | mo_coeff = mo_coeff[np.newaxis, ...]
114 | else:
115 | spin = 2
116 |
117 | # NOTE: choose IAO basis and use krmf by user
118 | # C_ao_lo: transformation matrix from AO to LO (IAO) basis
119 | MINAO = {'Ni':'gth-szv-molopt-sr', 'O':'gth-szv-molopt-sr'}
120 | C_ao_iao, C_ao_iao_val, C_ao_iao_virt = make_basis.get_C_ao_lo_iao(Lat, krmf, minao=MINAO, full_return=True)
121 | C_ao_lo = np.zeros((spin,nkpts,nao,nao),dtype=np.complex128)
122 | for s in range(spin):
123 | C_ao_lo[s] = C_ao_iao
124 |
125 | # C_mo_lo: transformation matrix from MO to LO (IAO) basis
126 | S_ao_ao = kmf.get_ovlp()
127 | C_mo_lo = np.zeros((spin,nkpts,nao,nao),dtype=np.complex128)
128 | for s in range(spin):
129 | for ki in range(nkpts):
130 | C_mo_lo[s][ki] = np.dot(np.dot(mo_coeff[s][ki].T.conj(), S_ao_ao[ki]), C_ao_lo[s][ki])
131 | fn = 'C_mo_lo.h5'
132 | feri = h5py.File(fn, 'w')
133 | feri['C_ao_lo'] = np.asarray(C_ao_lo)
134 | feri['C_mo_lo'] = np.asarray(C_mo_lo)
135 | feri.close()
136 |
137 | # get DFT density matrix in IAO basis
138 | DM_ao = np.asarray(kmf.make_rdm1())
139 | if len(DM_ao.shape) == 3:
140 | DM_ao = DM_ao[np.newaxis, ...]
141 | DM_lo = np.zeros((spin,nkpts,nao,nao),dtype=DM_ao.dtype)
142 | for s in range(spin):
143 | for ki in range(nkpts):
144 | Cinv = np.dot(C_ao_lo[s][ki].T.conj(),S_ao_ao[ki])
145 | DM_lo[s][ki] = np.dot(np.dot(Cinv, DM_ao[s][ki]), Cinv.T.conj())
146 |
147 | for s in range(spin):
148 | nelec_lo = np.trace(DM_lo[s].sum(axis=0)/nkpts)
149 | print ('Nelec imp', nelec_lo.real)
150 | fn = 'DM_iao_k.h5'
151 | feri = h5py.File(fn, 'w')
152 | feri['DM'] = np.asarray(DM_lo)
153 | feri.close()
154 |
155 | # get 4-index ERI
156 | eri = eri_transform.get_unit_eri_fast(cell, gdf, C_ao_lo=C_ao_lo, feri=gdf_fname)
157 | fn = 'eri_imp111_iao.h5'
158 | feri = h5py.File(fn, 'w')
159 | feri['eri'] = np.asarray(eri.real)
160 | feri.close()
161 |
162 | # get one-electron integrals
163 | hcore_ao = np.asarray(kmf.get_hcore())
164 | JK_ao = np.asarray(kmf.get_veff())
165 | if len(JK_ao.shape) == 3:
166 | JK_ao = JK_ao[np.newaxis, ...]
167 | hcore_lo = np.zeros((spin,nkpts,nao,nao),dtype=hcore_ao.dtype)
168 | JK_lo = np.zeros((spin,nkpts,nao,nao),dtype=JK_ao.dtype)
169 | for s in range(spin):
170 | for ki in range(nkpts):
171 | hcore_lo[s,ki] = np.dot(np.dot(C_ao_lo[s,ki].T.conj(), hcore_ao[ki]), C_ao_lo[s,ki])
172 | JK_lo[s,ki] = np.dot(np.dot(C_ao_lo[s,ki].T.conj(), JK_ao[s,ki]), C_ao_lo[s,ki])
173 |
174 | fn = 'hcore_JK_iao_k_dft.h5'
175 | feri = h5py.File(fn, 'w')
176 | feri['hcore'] = np.asarray(hcore_lo)
177 | feri['JK'] = np.asarray(JK_lo)
178 | feri.close()
179 | assert(np.max(np.abs(hcore_lo.sum(axis=1).imag/nkpts))<1e-6)
180 | assert(np.max(np.abs(JK_lo.sum(axis=1).imag/nkpts))<1e-6)
181 |
182 | # get HF JK term using DFT density
183 | kmf_hf = scf.KUHF(cell, kpts, exxdiv=None)
184 | kmf_hf.with_df = gdf
185 | kmf_hf.with_df._cderi = gdf_fname
186 | kmf_hf.max_cycle = 0
187 | JK_ao = np.asarray(kmf_hf.get_veff(dm_kpts=DM_ao))
188 | if len(JK_ao.shape) == 3:
189 | JK_ao = JK_ao[np.newaxis, ...]
190 |
191 | # NOTE: choose finite size correction by user
192 | # set gw_fc to True if finite size correction is used in kgw
193 | gw_fc = True
194 | if gw_fc:
195 | # finite size correction to exchange
196 | vk_corr = -2./np.pi * (6.*np.pi**2/cell.vol/nkpts)**(1./3.)
197 | nocca = (cell.nelectron+cell.spin) // 2
198 | noccb = cell.nelectron - nocca
199 | JK_mo = np.zeros((spin,nkpts,nao,nao),dtype=JK_ao.dtype)
200 | for s in range(spin):
201 | if s == 0:
202 | nocc = nocca
203 | else:
204 | nocc = noccb
205 | for ki in range(nkpts):
206 | JK_mo[s,ki] = np.dot(np.dot(mo_coeff[s][ki].T.conj(), JK_ao[s,ki]), mo_coeff[s][ki])
207 | for i in range(nocc):
208 | JK_mo[s,ki][i,i] = JK_mo[s,ki][i,i] + vk_corr
209 |
210 | JK_lo = np.zeros((spin,nkpts,nao,nao),dtype=JK_ao.dtype)
211 | for s in range(spin):
212 | for ki in range(nkpts):
213 | JK_lo[s,ki] = np.dot(np.dot(C_mo_lo[s,ki].T.conj(), JK_mo[s,ki]), C_mo_lo[s,ki])
214 | else:
215 | JK_lo = np.zeros((spin,nkpts,nao,nao),dtype=JK_ao.dtype)
216 | for s in range(spin):
217 | for ki in range(nkpts):
218 | JK_lo[s,ki] = np.dot(np.dot(C_ao_lo[s,ki].T.conj(), JK_ao[s,ki]), C_ao_lo[s,ki])
219 |
220 | fn = 'hcore_JK_iao_k_hf.h5'
221 | feri = h5py.File(fn, 'w')
222 | feri['JK'] = np.asarray(JK_lo)
223 | feri.close()
224 |
225 | # Cholesky decomposition for generating 3-index density-fitted ERI (required by gw_dc)
226 | if not os.path.isfile('cderi.h5'):
227 | try:
228 | cd = cholesky.cholesky(eri[0], tau=1e-7, dimQ=50)
229 | except:
230 | cd = cholesky.cholesky(eri[0], tau=1e-6, dimQ=50)
231 | cderi = cd.kernel()
232 | cderi = cderi.reshape(-1,nao,nao)
233 | print ('3-index ERI', cderi.shape)
234 | fn = 'cderi.h5'
235 | feri = h5py.File(fn, 'w')
236 | feri['cderi'] = np.asarray(cderi)
237 | feri.close()
238 | else:
239 | fn = 'cderi.h5'
240 | feri = h5py.File(fn, 'r')
241 | cderi = np.asarray(feri['cderi'])
242 | feri.close()
243 |
244 | # Compute GW double counting self-energy
245 | naux, nimp, nimp = cderi.shape
246 | nocca = (cell.nelectron+cell.spin)//2
247 | noccb = cell.nelectron - nocca
248 | homo = -99.; lumo = 99.
249 | for k in range(nkpts):
250 | if homo < max(mo_energy[0,k][nocca-1],mo_energy[1,k][noccb-1]):
251 | homo = max(mo_energy[0,k][nocca-1],mo_energy[1,k][noccb-1])
252 | if lumo > min(mo_energy[0,k][nocca],mo_energy[1,k][noccb]):
253 | lumo = min(mo_energy[0,k][nocca],mo_energy[1,k][noccb])
254 | ef = (homo+lumo) / 2.
255 |
256 | # NOTE: check analytic continuation stability (sigma) by user
257 | mol = gto_mol.M()
258 | mol.verbose = 5
259 | mol.max_memory = cell.max_memory
260 | mf = scf_mol.UHF(mol)
261 | gw = ugw_dc.UGWGF(mf)
262 | gw.nmo = (nimp, nimp)
263 | gw.nocc = (nocca, noccb)
264 | gw.eta = 0.2/27.211386
265 | gw.ac = 'pade'
266 | gw.ef = ef
267 | gw.fullsigma = True
268 | omega = np.linspace(6./27.211386,24./27.211386,91)
269 | sigma_lo = gw.kernel(Lpq=cderi, omega=omega, kmf=kmf, C_mo_lo=C_mo_lo, nw=100, nt=2000)
270 | print('### local GW self-energy (trace) on real axis ###')
271 | print('# freq imag real #')
272 | for i in range(len(omega)):
273 | print (omega[i], np.trace(sigma_lo[0,:,:,i].imag), np.trace(sigma_lo[0,:,:,i].real))
274 |
--------------------------------------------------------------------------------
/examples/NiO/run_dft:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #SBATCH --partition=smallmem,parallel
3 | #SBATCH -N 1
4 | #SBATCH --ntasks-per-node=1
5 | #SBATCH -c 28
6 | #SBATCH -t 05-00:00:00
7 | #SBATCH --mem=64000
8 | #SBATCH --output=nio_dft.out
9 |
10 | export SLURM_MPI_TYPE=pmi2
11 | export OMP_NUM_THREADS=28
12 |
13 | srun python -u nio_dft.py
14 |
15 |
--------------------------------------------------------------------------------
/examples/NiO/run_dmft:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #SBATCH --partition=smallmem,parallel
3 | #SBATCH -N 2
4 | #SBATCH --ntasks-per-node=4
5 | #SBATCH --cpus-per-task=7
6 | #SBATCH --mem=126000
7 | #SBATCH -t 01-00:00:00
8 | #SBATCH --output=run_dmft.out
9 |
10 | srun hostname
11 | MKL_NUM_THREADS=7 OMP_NUM_THREADS=7 mpirun -np 8 python -u run_dmft.py
12 |
--------------------------------------------------------------------------------
/examples/NiO/run_gw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #SBATCH --partition=smallmem,serial,parallel
3 | #SBATCH -N 4
4 | #SBATCH --ntasks-per-node=4
5 | #SBATCH --cpus-per-task=7
6 | #SBATCH --mem=126000
7 | #SBATCH -t 02-00:00:00
8 | #SBATCH --output=nio_gw.out
9 |
10 | srun hostname
11 | MKL_NUM_THREADS=7 OMP_NUM_THREADS=7 mpirun -np 16 python -u nio_gw.py
12 |
--------------------------------------------------------------------------------
/examples/NiO/run_ham:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #SBATCH --partition=smallmem,parallel
3 | #SBATCH -N 1
4 | #SBATCH --ntasks-per-node=1
5 | #SBATCH -c 28
6 | #SBATCH -t 05-00:00:00
7 | #SBATCH --mem=126000
8 | #SBATCH --output=nio_set_ham.out
9 |
10 | export SLURM_MPI_TYPE=pmi2
11 | export OMP_NUM_THREADS=28
12 |
13 | srun python -u nio_set_ham.py
14 |
15 |
--------------------------------------------------------------------------------
/examples/Si/run_dmft:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #SBATCH --partition=smallmem,serial,parallel
3 | #SBATCH -N 4
4 | #SBATCH --ntasks-per-node=4
5 | #SBATCH --cpus-per-task=7
6 | #SBATCH --mem=126000
7 | #SBATCH -t 05-00:00:00
8 | #SBATCH --output=run_dmft.out
9 |
10 | srun hostname
11 | MKL_NUM_THREADS=7 OMP_NUM_THREADS=7 mpirun -np 16 python -u run_dmft.py
12 |
--------------------------------------------------------------------------------
/examples/Si/run_dmft.py:
--------------------------------------------------------------------------------
1 | '''
2 | Main routine to set up DMFT parameters and run DMFT
3 | '''
4 |
5 | try:
6 | import block2
7 | from block2.su2 import MPICommunicator
8 | dmrg_ = True
9 | except:
10 | dmrg_ = False
11 | pass
12 | import numpy as np
13 | import scipy, os, h5py
14 | from fcdmft.utils import write
15 | from fcdmft.dmft import gwdmft
16 | from mpi4py import MPI
17 |
18 | rank = MPI.COMM_WORLD.Get_rank()
19 | size = MPI.COMM_WORLD.Get_size()
20 | comm = MPI.COMM_WORLD
21 |
22 | def dmft_abinitio():
23 | '''
24 | List of DMFT parameters
25 |
26 | gw_dmft : choose to run GW+DMFT (True) or HF+DMFT (False)
27 | opt_mu : whether to optimize chemical potential during DMFT cycles
28 | solver_type : choose impurity solver ('cc', 'ucc', 'dmrg', 'dmrgsz', 'fci')
29 | disc_type : choose bath discretization method ('opt', 'direct', 'linear', 'gauss', 'log')
30 | max_memory : maximum memory for DMFT calculation (per MPI process for CC, per node for DMRG)
31 | dmft_max_cycle : maximum number of DMFT iterations (set to 0 for one-shot DMFT)
32 | chkfile : chkfile for saving DMFT self-consistent quantities (hyb and self-energy)
33 | diag_only : choose to only fit diagonal hybridization (optional)
34 | orb_fit : special orbitals (e.g. 3d/4f) with x5 weight in bath optimization (optional)
35 | delta : broadening for discretizing hybridization (often 0.02-0.1 Ha)
36 | nbath : number of bath energies (can be any integer)
37 | nb_per_e : number of bath orbitals per bath energy (should be no greater than nval-ncore)
38 | total bath number = nb_per_e * nbath
39 | mu : initial chemical potential
40 | nval : number of valence (plus core) impurity orbitals (only ncore:nval orbs coupled to bath)
41 | ncore : number of core impurity orbitals
42 | nelectron : electron number per cell
43 | gmres_tol : GMRES/GCROTMK convergence criteria for solvers in production run (often 1e-3)
44 | wl0, wh0: (optional) real-axis frequency range [wl0+mu, wh0+mu] for bath discretization
45 | in DMFT self-consistent iterations (defualt: -0.4, 0.4)
46 | wl, wh : real-axis frequnecy range [wl, wh] for production run
47 | eta : spectral broadening for production run (often 0.1-0.4 eV)
48 | twist_average : whether to use twist-averaged HF/GW for lattice GF and hybridization
49 | band_interpolation : whether to use interpolated HF/GW for lattice GF and hybridization
50 | '''
51 | # DMFT self-consistent loop parameters
52 | gw_dmft = True
53 | opt_mu = False
54 | solver_type = 'cc'
55 | disc_type = 'opt'
56 | max_memory = 32000
57 | dmft_max_cycle = 10
58 | chkfile = 'DMFT_chk.h5'
59 | diag_only = False
60 | orb_fit = None
61 | twist_average = False
62 | band_interpolate = False
63 |
64 | delta = 0.1
65 | mu = 0.267
66 | nbath = 12
67 | nb_per_e = 8
68 | wl0 = -0.4
69 | wh0 = 0.4
70 |
71 | nval = 8
72 | ncore = 0
73 | nelectron = 8
74 |
75 | # DMFT production run parameters
76 | Ha2eV = 27.211386
77 | wl = 2./Ha2eV
78 | wh = 13./Ha2eV
79 | eta = 0.1/Ha2eV
80 | gmres_tol = 1e-3
81 | # final self-energy on imag or real axis
82 | run_imagfreq = False
83 |
84 | '''
85 | load_mf : bool
86 | Load DMFT imp+bath mean-field object from saved file. if True, dmft_max_cycle = 0.
87 | save_mf : bool
88 | Save DMFT imp+bath mean-field object to saved file at the end of DMFT cycles.
89 | load_mf and save_mf cannot be True at the same time.
90 | '''
91 | load_mf = False
92 | save_mf = True
93 |
94 | '''
95 | specific parameters for CAS treatment of impurity problem:
96 | cas : use CASCI or not (default: False)
97 | casno : natural orbital method for CASCI
98 | (choices: 'gw': GW@HF, 'cc': CCSD, 'ci': CISD, 'hf' : HF)
99 | composite : whether to use GW or CCSD Green's function as the low-level GF
100 | for impurity problem; if False, use HF Green's function as low-level GF
101 | thresh : float
102 | Threshold on NO occupation numbers. Default is 1e-4.
103 | nvir_act : int
104 | Number of virtual NOs to keep. Default is None. If present, overrides `thresh`.
105 | nocc_act : int
106 | Number of occupied NOs to keep. Default is None. If present, overrides `thresh` and `vno_only`.
107 | save_gf : bool
108 | Save CAS Green's function. Default is False.
109 | read_gf : bool
110 | Read saved CAS Green's function and skip solving CAS problem. Default is False.
111 | thresh2 : float
112 | Threshold on NO occupation numbers for a larger CAS problem solved
113 | by a cheaper impurity solver. Default is None.
114 | load_cas : bool
115 | Load DMFT CAS problem mean-field object from saved file (only support CCSD-NO based CAS).
116 | '''
117 | cas = False
118 | casno = 'gw'
119 | composite = False
120 | thresh = None
121 | nvir_act = None
122 | nocc_act = None
123 | save_gf = False
124 | read_gf = False
125 | thresh2 = None
126 |
127 | # spin-unrestricted
128 | nvir_act_a = None
129 | nocc_act_a = None
130 | nvir_act_b = None
131 | nocc_act_b = None
132 |
133 | load_cas = False
134 |
135 | # specific parameters for DMRG solvers (see fcdmft/solver/gfdmrg.py for detailed comments)
136 | gs_n_steps = 20
137 | gf_n_steps = 6
138 | gs_tol = 1E-10
139 | gf_tol = 1E-3
140 | gs_bond_dims = [400] * 5 + [800] * 5 + [1500] * 5 + [2000] * 5
141 | gs_noises = [1E-3] * 7 + [1E-4] * 5 + [1e-7] * 5 + [0]
142 | gf_bond_dims = [200] * 2 + [500] * 4
143 | gf_noises = [1E-4] * 1 + [1E-5] * 1 + [1E-7] * 1 + [0]
144 | dmrg_gmres_tol = 1E-7
145 | dmrg_verbose = 2
146 | reorder_method = 'gaopt'
147 | dmrg_local = True
148 | n_off_diag_cg = -2
149 | extra_nw = 5
150 | extra_dw = 0.1/Ha2eV
151 | # if extra_delta is not None, approx. DMRG treatment of freq will be used
152 | extra_delta = None
153 | # at lease one of 'load_dir' and 'save_dir' should be None
154 | load_dir = None
155 | save_dir = './gs_mps'
156 |
157 | # DMRG-MRCI parameters
158 | dyn_corr_method = None
159 | nocc_act_low = None # number of lowest occ orbs treated by MRCI
160 | nvir_act_high = None # number of highest vir orbs treated by MRCI
161 |
162 | ### Finishing parameter settings ###
163 |
164 | # read hcore
165 | fn = 'hcore_JK_iao_k_dft.h5'
166 | feri = h5py.File(fn, 'r')
167 | hcore_k = np.asarray(feri['hcore'])
168 | feri.close()
169 |
170 | # read HF-JK matrix
171 | fn = 'hcore_JK_iao_k_hf.h5'
172 | feri = h5py.File(fn, 'r')
173 | JK_k = np.asarray(feri['JK'])
174 | feri.close()
175 |
176 | # read density matrix
177 | fn = 'DM_iao_k.h5'
178 | feri = h5py.File(fn, 'r')
179 | DM_k = np.asarray(feri['DM'])
180 | feri.close()
181 |
182 | # read 4-index ERI
183 | fn = 'eri_imp111_iao.h5'
184 | feri = h5py.File(fn, 'r')
185 | eri = np.asarray(feri['eri'])
186 | feri.close()
187 | eri_new = eri
188 | if eri_new.shape[0] == 3:
189 | eri_new = np.zeros_like(eri)
190 | eri_new[0] = eri[0]
191 | eri_new[1] = eri[2]
192 | eri_new[2] = eri[1]
193 | del eri
194 |
195 | # Read interpolated Fock for more accurate hybridization
196 | if band_interpolate:
197 | fn = 'hcore_JK_iao_k_dft_band.h5'
198 | feri = h5py.File(fn, 'r')
199 | hcore_k_band = np.asarray(feri['hcore'])
200 | JK_k_dft_band = np.asarray(feri['JK'])
201 | feri.close()
202 | if hcore_k_band.ndim == 3:
203 | hcore_k_band = hcore_k_band[np.newaxis, ...]
204 | JK_k_dft_band = JK_k_dft_band[np.newaxis, ...]
205 |
206 | # Read twist average Fock for more accurate hybridization
207 | if twist_average:
208 | from pyscf import lib
209 | mesh = [0,1]
210 | center_list = lib.cartesian_prod((mesh, mesh, mesh))[1:]
211 | spin, nkpts, nao, nao = hcore_k.shape
212 | hcore_k_TA = np.zeros((len(center_list), spin, nkpts, nao, nao), dtype=np.complex)
213 | JK_k_TA = np.zeros((len(center_list), spin, nkpts, nao, nao), dtype=np.complex)
214 | for i in range(len(center_list)):
215 | center = center_list[i]
216 |
217 | # read hcore
218 | fn = 'hcore_JK_iao_k_dft_%d_%d_%d.h5'%(center[0],center[1],center[2])
219 | feri = h5py.File(fn, 'r')
220 | hcore_k_TA[i] = np.asarray(feri['hcore'])
221 | feri.close()
222 |
223 | # read HF-JK matrix
224 | fn = 'hcore_JK_iao_k_hf_%d_%d_%d.h5'%(center[0],center[1],center[2])
225 | feri = h5py.File(fn, 'r')
226 | JK_k_TA[i] = np.asarray(feri['JK'])
227 | feri.close()
228 |
229 | hcore_k_TA = hcore_k_TA.transpose(1,0,2,3,4).reshape(spin, len(center_list)*nkpts, nao, nao)
230 | JK_k_TA = JK_k_TA.transpose(1,0,2,3,4).reshape(spin, len(center_list)*nkpts, nao, nao)
231 |
232 | assert (not (band_interpolate and twist_average))
233 |
234 | # run self-consistent DMFT
235 | mydmft = gwdmft.DMFT(hcore_k, JK_k, DM_k, eri_new, nval, ncore, nbath,
236 | nb_per_e, disc_type=disc_type, solver_type=solver_type)
237 | mydmft.gw_dmft = gw_dmft
238 | mydmft.verbose = 5
239 | mydmft.diis = True
240 | mydmft.gmres_tol = gmres_tol
241 | mydmft.max_memory = max_memory
242 | mydmft.chkfile = chkfile
243 | mydmft.diag_only = diag_only
244 | mydmft.orb_fit = orb_fit
245 | mydmft.twist_average = twist_average
246 | mydmft.band_interpolate = band_interpolate
247 | if twist_average:
248 | mydmft.center_list = center_list
249 | mydmft.hcore_k_band = hcore_k_TA
250 | mydmft.JK_k_band = JK_k_TA
251 | if band_interpolate:
252 | mydmft.hcore_k_band = hcore_k_band
253 | mydmft.JK_k_dft_band = JK_k_dft_band
254 |
255 | assert (not (load_mf and save_mf))
256 | if load_mf:
257 | dmft_max_cycle = 0
258 | mydmft.max_cycle = dmft_max_cycle
259 | mydmft.run_imagfreq = run_imagfreq
260 | if solver_type == 'dmrg' or solver_type == 'dmrgsz':
261 | if not dmrg_:
262 | raise ImportError
263 | mydmft.load_mf = load_mf
264 | mydmft.save_mf = save_mf
265 |
266 | if cas:
267 | mydmft.cas = cas
268 | mydmft.casno = casno
269 | mydmft.composite = composite
270 | mydmft.thresh = thresh
271 | mydmft.thresh2 = thresh2
272 | mydmft.nvir_act = nvir_act
273 | mydmft.nocc_act = nocc_act
274 | mydmft.save_gf = save_gf
275 | mydmft.read_gf = read_gf
276 | if casno == 'gw':
277 | assert(gw_dmft)
278 | if eri_new.shape[0] == 3:
279 | mydmft.nvir_act_a = nvir_act_a
280 | mydmft.nocc_act_a = nocc_act_a
281 | mydmft.nvir_act_b = nvir_act_b
282 | mydmft.nocc_act_b = nocc_act_b
283 | mydmft.load_cas = load_cas
284 |
285 | if solver_type == 'dmrg' or solver_type == 'dmrgsz':
286 | mydmft.gs_n_steps = gs_n_steps
287 | mydmft.gf_n_steps = gf_n_steps
288 | mydmft.gs_tol = gs_tol
289 | mydmft.gf_tol = gf_tol
290 | mydmft.gs_bond_dims = gs_bond_dims
291 | mydmft.gs_noises = gs_noises
292 | mydmft.gf_bond_dims = gf_bond_dims
293 | mydmft.gf_noises = gf_noises
294 | mydmft.dmrg_gmres_tol = dmrg_gmres_tol
295 | mydmft.dmrg_verbose = dmrg_verbose
296 | mydmft.reorder_method = reorder_method
297 | mydmft.n_off_diag_cg = n_off_diag_cg
298 | mydmft.load_dir = load_dir
299 | mydmft.save_dir = save_dir
300 | mydmft.dmrg_local = dmrg_local
301 | mydmft.dyn_corr_method = dyn_corr_method
302 | mydmft.nvir_act_high = nvir_act_high
303 | mydmft.nocc_act_low = nocc_act_low
304 | if nocc_act_low is not None:
305 | assert (nocc_act_low <= nocc_act)
306 | if nvir_act_high is not None:
307 | assert (nvir_act_high <= nvir_act)
308 |
309 | mydmft.kernel(mu0=mu, wl=wl0, wh=wh0, delta=delta, occupancy=nelectron, opt_mu=opt_mu)
310 | occupancy = np.trace(mydmft.get_rdm_imp())
311 | if rank == 0:
312 | print ('At mu =', mydmft.mu, ', occupancy =', occupancy)
313 |
314 | mydmft.verbose = 5
315 | mydmft._scf.mol.verbose = 5
316 | spin = mydmft.spin
317 |
318 | if not mydmft.run_imagfreq:
319 | # extra_freqs and extra_delta only for DMRG solver
320 | if extra_delta is not None and (mydmft.solver_type=='dmrg' or mydmft.solver_type=='dmrgsz'):
321 | nw = int(round((wh-wl)/(extra_dw * extra_nw)))+1
322 | freqs = np.linspace(wl, wh, nw)
323 | extra_freqs = []
324 | for i in range(len(freqs)):
325 | freqs_tmp = []
326 | if extra_nw % 2 == 0:
327 | for w in range(-extra_nw // 2, extra_nw // 2):
328 | freqs_tmp.append(freqs[i] + extra_dw * w)
329 | else:
330 | for w in range(-(extra_nw-1) // 2, (extra_nw+1) // 2):
331 | freqs_tmp.append(freqs[i] + extra_dw * w)
332 | extra_freqs.append(np.array(freqs_tmp))
333 | mydmft.extra_freqs = extra_freqs
334 | mydmft.extra_delta = extra_delta
335 | freqs_comp = np.array(extra_freqs).reshape(-1)
336 | else:
337 | nw = int(round((wh-wl)/eta))+1
338 | freqs = np.linspace(wl, wh, nw)
339 | freqs_comp = freqs
340 |
341 | # Get impurity DOS (production run)
342 | #ldos = mydmft.get_ldos_imp(freqs, eta)
343 |
344 | # Get lattice DOS (production run)
345 | ldos, ldos_gw = mydmft.get_ldos_latt(freqs, eta)
346 | spin = mydmft.spin
347 |
348 | filename = 'mu-%0.3f_n-%0.2f_%d-%d_eta-%.2f_d-%.2f_%s'%(
349 | mu,occupancy,nval,nbath,eta*Ha2eV,delta,solver_type)
350 | if rank == 0:
351 | write.write_dos(filename, freqs_comp, ldos, occupancy=occupancy)
352 |
353 | if mydmft.gw_dmft:
354 | filename = 'mu-%0.3f_n-%0.2f_%d-%d_eta-%.2f_d-%.2f_gw'%(
355 | mu,occupancy,nval,nbath,eta*Ha2eV,delta)
356 | else:
357 | filename = 'mu-%0.3f_n-%0.2f_%d-%d_eta-%.2f_d-%.2f_hf'%(
358 | mu,occupancy,nval,nbath,eta*Ha2eV,delta)
359 | if rank == 0:
360 | write.write_dos(filename, freqs_comp, ldos_gw, occupancy=occupancy)
361 |
362 | else:
363 | nimp = eri_new.shape[-1]
364 | omega_ns = np.linspace(0./27.211386, 10.0/27.211386, 21)[1:]
365 | if solver_type == 'dmrg' or solver_type == 'dmrgsz':
366 | # TODO: check DMRG load_dir is correct
367 | if mydmft.load_dir is None:
368 | mydmft.load_dir = mydmft.save_dir
369 | mydmft.save_dir = None
370 | assert(mydmft.load_dir is not None)
371 | sigma = np.zeros((spin,nimp,nimp,len(omega_ns)),dtype=complex)
372 | for iw in range(len(omega_ns)):
373 | sigma[:,:,:,iw] = mydmft.get_sigma_imp(np.array([mu]), omega_ns[iw],
374 | save_gf=save_gf, read_gf=read_gf)[:,:nimp,:nimp,0]
375 | else:
376 | sigma = mydmft.get_sigma_imp(mu+1j*omega_ns, 0.0,
377 | save_gf=save_gf, read_gf=read_gf)[:,:nimp,:nimp]
378 |
379 | tmpdir = 'dmft_dos'
380 | if rank == 0:
381 | if not os.path.isdir(tmpdir):
382 | os.mkdir(tmpdir)
383 | for i in range(nimp):
384 | write.write_sigma_elem(tmpdir+'/dmft_sigma_imag_orb-%d'%(i), omega_ns, sigma[:,i,i,:])
385 |
386 | if __name__ == '__main__':
387 | dmft_abinitio()
388 |
--------------------------------------------------------------------------------
/examples/Si/run_gw:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #SBATCH --partition=smallmem,parallel
3 | #SBATCH -N 1
4 | #SBATCH --ntasks-per-node=1
5 | #SBATCH -c 28
6 | #SBATCH -t 05-00:00:00
7 | #SBATCH --mem=32000
8 | #SBATCH --output=si_gw.out
9 |
10 | export SLURM_MPI_TYPE=pmi2
11 | export OMP_NUM_THREADS=28
12 |
13 | srun python -u si_gw.py
14 |
15 |
--------------------------------------------------------------------------------
/examples/Si/run_ham:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #SBATCH --partition=smallmem,parallel
3 | #SBATCH -N 1
4 | #SBATCH --ntasks-per-node=1
5 | #SBATCH -c 28
6 | #SBATCH -t 05-00:00:00
7 | #SBATCH --mem=32000
8 | #SBATCH --output=si_set_ham.out
9 |
10 | export SLURM_MPI_TYPE=pmi2
11 | export OMP_NUM_THREADS=28
12 |
13 | srun python -u si_set_ham.py
14 |
15 |
--------------------------------------------------------------------------------
/examples/Si/si_gw.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | from pyscf.pbc import df, dft, gto
3 | import numpy as np
4 | import os, h5py
5 | from pyscf.pbc.lib import chkfile
6 | from pyscf import lib
7 | from fcdmft.gw.pbc import krgw_gf
8 | from fcdmft.utils import write
9 |
10 | einsum = lib.einsum
11 |
12 | cell = gto.Cell()
13 | cell.build(unit = 'angstrom',
14 | a = '''
15 | 0.000000 2.715000 2.715000
16 | 2.715000 0.000000 2.715000
17 | 2.715000 2.715000 0.000000
18 | ''',
19 | atom = 'Si 2.03625 2.03625 2.03625; Si 3.39375 3.39375 3.39375',
20 | dimension = 3,
21 | max_memory = 32000,
22 | verbose = 5,
23 | basis='gth-dzvp',
24 | pseudo='gth-pbe',
25 | precision=1e-12)
26 |
27 | kmesh = [4,4,4]
28 | kpts = cell.make_kpts(kmesh,scaled_center=[0,0,0])
29 | gdf = df.GDF(cell, kpts)
30 | gdf.auxbasis = df.aug_etb(cell, beta=2.0)
31 | gdf_fname = 'gdf_ints_444.h5'
32 | gdf._cderi_to_save = gdf_fname
33 | if not os.path.isfile(gdf_fname):
34 | gdf.build()
35 |
36 | chkfname = 'si_444.chk'
37 | if os.path.isfile(chkfname):
38 | kmf = dft.KRKS(cell, kpts).density_fit()
39 | kmf.xc = 'pbe'
40 | kmf.with_df = gdf
41 | kmf.with_df._cderi = gdf_fname
42 | kmf.conv_tol = 1e-12
43 | data = chkfile.load(chkfname, 'scf')
44 | kmf.__dict__.update(data)
45 | else:
46 | kmf = dft.KRKS(cell, kpts).density_fit()
47 | kmf.xc = 'pbe'
48 | kmf.with_df = gdf
49 | kmf.with_df._cderi = gdf_fname
50 | kmf.conv_tol = 1e-12
51 | kmf.chkfile = chkfname
52 | kmf.kernel()
53 |
54 | gw = krgw_gf.KRGWGF(kmf)
55 | gw.ac = 'pade'
56 | Ha2ev = 27.211386
57 | gw.eta = 0.1/Ha2ev
58 | gw.fullsigma = True
59 | gw.fc = True
60 | omega = np.linspace(0.,18./Ha2ev,181)
61 | # writefile must >= 1 for GW+DMFT calc
62 | gf, gf0, sigma = gw.kernel(omega=omega, writefile=1)
63 |
64 | gf = gf[np.newaxis, ...]
65 | gf0 = gf0[np.newaxis, ...]
66 | nkpts = gw.nkpts
67 | gf = 1./nkpts * np.sum(gf, axis=1)
68 | gf0 = 1./nkpts * np.sum(gf0, axis=1)
69 |
70 | outdir = 'GW_DOS'
71 | if not os.path.isdir(outdir):
72 | os.mkdir(outdir)
73 | write.write_gf_to_dos(outdir+'/si_gw_dos', omega, gf)
74 | write.write_gf_to_dos(outdir+'/si_pbe_dos', omega, gf0)
75 |
76 | mo_energy = gw.mo_energy
77 | nocc = gw.nocc
78 | homo = -99.; lumo = 99.
79 | for k in range(nkpts):
80 | if homo < mo_energy[k][nocc-1]:
81 | homo = mo_energy[k][nocc-1]
82 | if lumo > mo_energy[k][nocc]:
83 | lumo = mo_energy[k][nocc]
84 | print ('VBM, CBM, Gap', homo*Ha2ev, lumo*Ha2ev, (lumo-homo)*Ha2ev)
85 |
--------------------------------------------------------------------------------
/examples/Si/si_set_ham.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import numpy as np
3 | import h5py, os
4 | from libdmet_solid.system import lattice
5 | from libdmet_solid.basis_transform import make_basis
6 | from libdmet_solid.basis_transform import eri_transform
7 | import libdmet_solid.utils.logger as log
8 |
9 | from pyscf.pbc import df, dft, scf, gto
10 | from pyscf.pbc.lib import chkfile
11 | from pyscf import lib
12 | from pyscf import gto as gto_mol
13 | from pyscf import scf as scf_mol
14 |
15 | from fcdmft.gw.mol import gw_dc
16 | from fcdmft.utils import cholesky
17 |
18 | log.verbose = 'DEBUG1'
19 |
20 | einsum = lib.einsum
21 |
22 | # NOTE: lattice system setup by user
23 | cell = gto.Cell()
24 | cell.build(unit = 'angstrom',
25 | a = '''
26 | 0.000000 2.715000 2.715000
27 | 2.715000 0.000000 2.715000
28 | 2.715000 2.715000 0.000000
29 | ''',
30 | atom = 'Si 2.03625 2.03625 2.03625; Si 3.39375 3.39375 3.39375',
31 | dimension = 3,
32 | max_memory = 32000,
33 | verbose = 5,
34 | basis='gth-dzvp',
35 | pseudo='gth-pbe',
36 | precision=1e-12)
37 |
38 | kmesh = [4,4,4]
39 | Lat = lattice.Lattice(cell, kmesh)
40 | kpts = Lat.kpts
41 | nao = Lat.nao
42 | nkpts = Lat.nkpts
43 |
44 | gdf = df.GDF(cell, kpts)
45 | gdf.auxbasis = df.aug_etb(cell, beta=2.0)
46 | gdf_fname = 'gdf_ints_444.h5'
47 | gdf._cderi_to_save = gdf_fname
48 | if not os.path.isfile(gdf_fname):
49 | gdf.build()
50 |
51 | chkfname = 'si_444.chk'
52 | if os.path.isfile(chkfname):
53 | kmf = dft.KRKS(cell, kpts).density_fit()
54 | kmf.xc = 'pbe'
55 | kmf.with_df = gdf
56 | kmf.with_df._cderi = gdf_fname
57 | kmf.conv_tol = 1e-12
58 | data = chkfile.load(chkfname, 'scf')
59 | kmf.__dict__.update(data)
60 | else:
61 | kmf = dft.KRKS(cell, kpts).density_fit()
62 | kmf.xc = 'pbe'
63 | kmf.with_df = gdf
64 | kmf.with_df._cderi = gdf_fname
65 | kmf.conv_tol = 1e-12
66 | kmf.chkfile = chkfname
67 | kmf.kernel()
68 |
69 | # set spin
70 | mo_energy = np.asarray(kmf.mo_energy)
71 | mo_coeff = np.asarray(kmf.mo_coeff)
72 | if len(mo_energy.shape) == 2:
73 | spin = 1
74 | mo_energy = mo_energy[np.newaxis, ...]
75 | mo_coeff = mo_coeff[np.newaxis, ...]
76 | else:
77 | spin = 2
78 |
79 | # NOTE: choose IAO basis by user
80 | # C_ao_lo: transformation matrix from AO to LO (IAO) basis
81 | MINAO = {'Si':'gth-szv'}
82 | C_ao_iao, C_ao_iao_val, C_ao_iao_virt = make_basis.get_C_ao_lo_iao(Lat, kmf, minao=MINAO, full_return=True)
83 | C_ao_lo = np.zeros((spin,nkpts,nao,nao),dtype=np.complex128)
84 | for s in range(spin):
85 | C_ao_lo[s] = C_ao_iao
86 |
87 | # C_mo_lo: transformation matrix from MO to LO (IAO) basis
88 | S_ao_ao = kmf.get_ovlp()
89 | C_mo_lo = np.zeros((spin,nkpts,nao,nao),dtype=np.complex128)
90 | for s in range(spin):
91 | for ki in range(nkpts):
92 | C_mo_lo[s][ki] = np.dot(np.dot(mo_coeff[s][ki].T.conj(), S_ao_ao[ki]), C_ao_lo[s][ki])
93 | fn = 'C_mo_lo.h5'
94 | feri = h5py.File(fn, 'w')
95 | feri['C_ao_lo'] = np.asarray(C_ao_lo)
96 | feri['C_mo_lo'] = np.asarray(C_mo_lo)
97 | feri.close()
98 |
99 | # get DFT density matrix in IAO basis
100 | DM_ao = np.asarray(kmf.make_rdm1())
101 | if len(DM_ao.shape) == 3:
102 | DM_ao = DM_ao[np.newaxis, ...]
103 | DM_lo = np.zeros((spin,nkpts,nao,nao),dtype=DM_ao.dtype)
104 | for s in range(spin):
105 | for ki in range(nkpts):
106 | Cinv = np.dot(C_ao_lo[s][ki].T.conj(),S_ao_ao[ki])
107 | DM_lo[s][ki] = np.dot(np.dot(Cinv, DM_ao[s][ki]), Cinv.T.conj())
108 |
109 | for s in range(spin):
110 | nelec_lo = np.trace(DM_lo[s].sum(axis=0)/nkpts)
111 | print ('Nelec imp', nelec_lo.real)
112 | fn = 'DM_iao_k.h5'
113 | feri = h5py.File(fn, 'w')
114 | feri['DM'] = np.asarray(DM_lo)
115 | feri.close()
116 |
117 | # get 4-index ERI
118 | eri = eri_transform.get_unit_eri_fast(cell, gdf, C_ao_lo=C_ao_lo, feri=gdf_fname)
119 | fn = 'eri_imp111_iao.h5'
120 | feri = h5py.File(fn, 'w')
121 | feri['eri'] = np.asarray(eri.real)
122 | feri.close()
123 |
124 | # get one-electron integrals
125 | hcore_ao = np.asarray(kmf.get_hcore())
126 | JK_ao = np.asarray(kmf.get_veff())
127 | if len(JK_ao.shape) == 3:
128 | JK_ao = JK_ao[np.newaxis, ...]
129 | hcore_lo = np.zeros((spin,nkpts,nao,nao),dtype=hcore_ao.dtype)
130 | JK_lo = np.zeros((spin,nkpts,nao,nao),dtype=JK_ao.dtype)
131 | for s in range(spin):
132 | for ki in range(nkpts):
133 | hcore_lo[s,ki] = np.dot(np.dot(C_ao_lo[s,ki].T.conj(), hcore_ao[ki]), C_ao_lo[s,ki])
134 | JK_lo[s,ki] = np.dot(np.dot(C_ao_lo[s,ki].T.conj(), JK_ao[s,ki]), C_ao_lo[s,ki])
135 |
136 | fn = 'hcore_JK_iao_k_dft.h5'
137 | feri = h5py.File(fn, 'w')
138 | feri['hcore'] = np.asarray(hcore_lo)
139 | feri['JK'] = np.asarray(JK_lo)
140 | feri.close()
141 | assert(np.max(np.abs(hcore_lo.sum(axis=1).imag/nkpts))<1e-6)
142 | assert(np.max(np.abs(JK_lo.sum(axis=1).imag/nkpts))<1e-6)
143 |
144 | # get HF JK term using DFT density
145 | kmf_hf = scf.KRHF(cell, kpts, exxdiv=None)
146 | kmf_hf.with_df = gdf
147 | kmf_hf.with_df._cderi = gdf_fname
148 | kmf_hf.max_cycle = 0
149 | JK_ao = np.asarray(kmf_hf.get_veff(dm_kpts=DM_ao[0]))
150 | if len(JK_ao.shape) == 3:
151 | JK_ao = JK_ao[np.newaxis, ...]
152 |
153 | # NOTE: choose finite size correction by user
154 | # set gw_fc to True if finite size correction is used in kgw
155 | gw_fc = True
156 | if gw_fc:
157 | # finite size correction to exchange
158 | vk_corr = -2./np.pi * (6.*np.pi**2/cell.vol/nkpts)**(1./3.)
159 | nocc = cell.nelectron // 2
160 | JK_mo = np.zeros((spin,nkpts,nao,nao),dtype=JK_ao.dtype)
161 | for s in range(spin):
162 | for ki in range(nkpts):
163 | JK_mo[s,ki] = np.dot(np.dot(mo_coeff[s,ki].T.conj(), JK_ao[s,ki]), mo_coeff[s,ki])
164 | for i in range(nocc):
165 | JK_mo[s,ki][i,i] = JK_mo[s,ki][i,i] + vk_corr
166 |
167 | JK_lo = np.zeros((spin,nkpts,nao,nao),dtype=JK_ao.dtype)
168 | for s in range(spin):
169 | for ki in range(nkpts):
170 | JK_lo[s,ki] = np.dot(np.dot(C_mo_lo[s,ki].T.conj(), JK_mo[s,ki]), C_mo_lo[s,ki])
171 | else:
172 | JK_lo = np.zeros((spin,nkpts,nao,nao),dtype=JK_ao.dtype)
173 | for s in range(spin):
174 | for ki in range(nkpts):
175 | JK_lo[s,ki] = np.dot(np.dot(C_ao_lo[s,ki].T.conj(), JK_ao[s,ki]), C_ao_lo[s,ki])
176 |
177 | fn = 'hcore_JK_iao_k_hf.h5'
178 | feri = h5py.File(fn, 'w')
179 | feri['JK'] = np.asarray(JK_lo)
180 | feri.close()
181 |
182 | # Cholesky decomposition for generating 3-index density-fitted ERI (required by gw_dc)
183 | if not os.path.isfile('cderi.h5'):
184 | try:
185 | cd = cholesky.cholesky(eri[0], tau=1e-8, dimQ=50)
186 | except:
187 | cd = cholesky.cholesky(eri[0], tau=1e-6, dimQ=50)
188 | cderi = cd.kernel()
189 | cderi = cderi.reshape(-1,nao,nao)
190 | print ('3-index ERI', cderi.shape)
191 | fn = 'cderi.h5'
192 | feri = h5py.File(fn, 'w')
193 | feri['cderi'] = np.asarray(cderi)
194 | feri.close()
195 | else:
196 | fn = 'cderi.h5'
197 | feri = h5py.File(fn, 'r')
198 | cderi = np.asarray(feri['cderi'])
199 | feri.close()
200 |
201 | # Compute GW double counting self-energy
202 | naux, nimp, nimp = cderi.shape
203 | nocc = cell.nelectron // 2
204 | homo = -99.; lumo = 99.
205 | for k in range(nkpts):
206 | if homo < mo_energy[0,k][nocc-1]:
207 | homo = mo_energy[0,k][nocc-1]
208 | if lumo > mo_energy[0,k][nocc]:
209 | lumo = mo_energy[0,k][nocc]
210 | ef = 0.5 * (homo + lumo)
211 |
212 | # NOTE: check analytic continuation stability (sigma) by user
213 | mol = gto_mol.M()
214 | mol.verbose = 5
215 | mol.max_memory = cell.max_memory
216 | mf = scf_mol.RHF(mol)
217 | gw = gw_dc.GWGF(mf)
218 | gw.nmo = nimp
219 | gw.nocc = nocc
220 | gw.eta = 0.1/27.211386
221 | gw.ac = 'pade'
222 | gw.ef = ef
223 | gw.fullsigma = True
224 | omega = np.linspace(0,18./27.211386,181)
225 | sigma_lo = gw.kernel(Lpq=cderi, omega=omega, kmf=kmf, C_mo_lo=C_mo_lo, nw=100, nt=2000)
226 | print('### local GW self-energy (trace) on real axis ###')
227 | print('# freq imag real #')
228 | for i in range(len(omega)):
229 | print (omega[i], np.trace(sigma_lo[:,:,i].imag), np.trace(sigma_lo[:,:,i].real))
230 |
--------------------------------------------------------------------------------
/examples/SrMoO3/README.md:
--------------------------------------------------------------------------------
1 | This folder contains scripts for running GW+DMFT for SrMoO3, a moderately correlated metal.
2 | Band interpolation is used for getting large k-mesh GW bands, which is used for computing
3 | DMFT lattie GF and hybridization function.
4 |
5 | Steps
6 | -----
7 |
8 | 1. Run `srmoo3_lda.py` (serial run) at 5x5x5 k-mesh to get LDA results and GDF integrals.
9 | 2. Run `srmoo3_gw.py` (parallel run, normally 2-3 nodes, each node 4 MPI processes), to get GW results at 5x5x5 k-mesh.
10 | 3. Run `srmoo3_set_ham.py` (serial run) to get local basis and impurity Hamiltonian for DMFT.
11 | 4. Run `srmoo3_interpolate.py` (serial run) to get LDA bands at 12x12x12 k-mesh and interpolate GW results to 12x12x12 k-mesh. Steps 3 and 4 can be run simultaneously.
12 | 5. Run `run_dmft.py` to perform GW+DMFT calculation using local basis, impurity Hamiltonian, and interpolated GW bands from Steps 3 and 4.
13 |
--------------------------------------------------------------------------------
/examples/SrMoO3/srmoo3_gw.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | from pyscf.pbc import df, dft, scf, cc, gto
3 | import numpy as np
4 | import h5py
5 | from libdmet_solid.system import lattice
6 | from pyscf.pbc.lib import chkfile
7 | import os
8 | from pyscf import lib
9 | import libdmet_solid.utils.logger as log
10 | from fcdmft.gw.pbc import krgw_gf
11 | from mpi4py import MPI
12 |
13 | rank = MPI.COMM_WORLD.Get_rank()
14 | size = MPI.COMM_WORLD.Get_size()
15 | comm = MPI.COMM_WORLD
16 |
17 | log.verbose = 'DEBUG1'
18 |
19 | einsum = lib.einsum
20 |
21 | cell = gto.Cell()
22 | cell.build(unit = 'angstrom',
23 | a = '''
24 | 3.97600 0.00000 0.00000
25 | 0.00000 3.97600 0.00000
26 | 0.00000 0.00000 3.97600
27 | ''',
28 | atom = '''
29 | Mo 1.98800 1.98800 1.98800
30 | Sr 0.00000 0.00000 0.00000
31 | O 1.98800 1.98800 0.00000
32 | O 1.98800 0.00000 1.98800
33 | O 0.00000 1.98800 1.98800
34 | ''',
35 | dimension = 3,
36 | max_memory = 40000,
37 | verbose = 5,
38 | pseudo = 'gth-pade',
39 | basis='gth-dzvp-molopt-sr',
40 | precision=1e-12)
41 |
42 | kmesh = [5,5,5]
43 | kpts = cell.make_kpts(kmesh,scaled_center=[0,0,0])
44 | Lat = lattice.Lattice(cell, kmesh)
45 | nao = Lat.nao
46 | Lat.kpts = kpts
47 | nkpts = Lat.nkpts
48 |
49 | gdf_fname = 'gdf_ints_555.h5'
50 | gdf = df.GDF(cell, kpts)
51 | gdf._cderi_to_save = gdf_fname
52 | gdf.auxbasis = df.aug_etb(cell, beta=2.3, use_lval=True, l_val_set={'Mo':2,'O':1,'Sr':1})
53 | if not os.path.isfile(gdf_fname):
54 | gdf.build()
55 |
56 | chkfname = 'srmoo3_555.chk'
57 | if os.path.isfile(chkfname):
58 | kmf = dft.KRKS(cell, kpts)
59 | kmf.xc = 'lda'
60 | kmf.exxdiv = None
61 | kmf = scf.addons.smearing_(kmf, sigma=5e-3, method="fermi")
62 | kmf.with_df = gdf
63 | kmf.with_df._cderi = gdf_fname
64 | data = chkfile.load(chkfname, 'scf')
65 | kmf.__dict__.update(data)
66 | else:
67 | kmf = dft.KRKS(cell, kpts)
68 | kmf.xc = 'lda'
69 | kmf.exxdiv = None
70 | kmf = scf.addons.smearing_(kmf, sigma=5e-3, method="fermi")
71 | kmf.with_df = gdf
72 | kmf.with_df._cderi = gdf_fname
73 | kmf.conv_tol = 1e-12
74 | kmf.chkfile = chkfname
75 | kmf.diis_space = 15
76 | kmf.max_cycle = 50
77 | kmf.kernel()
78 |
79 | gw = krgw_gf.KRGWGF(kmf)
80 | nmo = len(kmf.mo_energy[0])
81 | gw.ac = 'pade'
82 | gw.eta = 0.1/27.211386
83 | gw.fullsigma = True
84 | gw.ef = 0.560479331479
85 | omega = np.linspace(6./27.211386,24./27.211386,181)
86 | gf, gf0, sigma = gw.kernel(omega=omega, orbs=range(0,nmo), writefile=1)
87 |
88 | if rank == 0:
89 | for i in range(len(omega)):
90 | print (omega[i],(-np.trace(gf0[:,:,:,i].imag.sum(axis=0)/nkpts))/np.pi, \
91 | (-np.trace(gf[:,:,:,i].imag.sum(axis=0)/nkpts))/np.pi)
92 | print ('------------------')
93 | for i in range(len(omega)):
94 | print (omega[i],(-np.trace(gf0[1,:,:,i].imag))/np.pi, \
95 | (-np.trace(gf[1,:,:,i].imag))/np.pi)
96 |
97 |
--------------------------------------------------------------------------------
/examples/SrMoO3/srmoo3_interpolate.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | from pyscf.pbc import df, dft, scf, cc, gto
3 | import numpy as np
4 | import h5py
5 | from libdmet_solid.system import lattice
6 | from libdmet_solid.basis_transform import make_basis
7 | from libdmet_solid.basis_transform import eri_transform
8 | from pyscf.pbc.lib import chkfile
9 | import os
10 | from pyscf import lib
11 | import libdmet_solid.utils.logger as log
12 | from fcdmft.utils import interpolate
13 |
14 | log.verbose = 'DEBUG1'
15 |
16 | einsum = lib.einsum
17 |
18 | def get_kgw_sigma_diff(freqs, eta):
19 | from fcdmft.gw.pbc import krgw_gf
20 | '''
21 | Get k-point GW-AC self-energy in MO basis
22 | sigma = v_hf + sigma_c - v_xc
23 | '''
24 | fn = 'ac_coeff.h5'
25 | feri = h5py.File(fn, 'r')
26 | coeff = np.asarray(feri['coeff'])
27 | ef = np.asarray(feri['fermi'])
28 | omega_fit = np.asarray(feri['omega_fit'])
29 | feri.close()
30 |
31 | fn = 'vxc.h5'
32 | feri = h5py.File(fn, 'r')
33 | vk = np.array(feri['vk'])
34 | v_mf = np.array(feri['v_mf'])
35 | feri.close()
36 |
37 | nkpts, nao, nao = vk.shape
38 | nw = len(freqs)
39 | sigma = np.zeros([nkpts,nao,nao,nw], dtype=np.complex)
40 | for k in range(nkpts):
41 | for p in range(nao):
42 | for q in range(nao):
43 | sigma[k,p,q] = krgw_gf.pade_thiele(freqs-ef+1j*eta, omega_fit, coeff[k,:,p,q])
44 | sigma[k,p,q] += vk[k,p,q] - v_mf[k,p,q]
45 |
46 | return sigma
47 |
48 | def get_gf(hcore, sigma, freqs, delta):
49 | nw = len(freqs)
50 | nao = hcore.shape[0]
51 | gf = np.zeros([nao, nao, nw], np.complex128)
52 | for iw, w in enumerate(freqs):
53 | gf[:,:,iw] = np.linalg.inv((w+1j*delta)*np.eye(nao)-hcore-sigma[:,:,iw])
54 | return gf
55 |
56 | def get_gf0(hcore, freqs, delta):
57 | nw = len(freqs)
58 | nao = hcore.shape[0]
59 | gf = np.zeros([nao, nao, nw], np.complex128)
60 | for iw, w in enumerate(freqs):
61 | gf[:,:,iw] = np.linalg.inv((w+1j*delta)*np.eye(nao)-hcore)
62 | return gf
63 |
64 | cell = gto.Cell()
65 | cell.build(unit = 'angstrom',
66 | a = '''
67 | 3.97600 0.00000 0.00000
68 | 0.00000 3.97600 0.00000
69 | 0.00000 0.00000 3.97600
70 | ''',
71 | atom = '''
72 | Mo 1.98800 1.98800 1.98800
73 | Sr 0.00000 0.00000 0.00000
74 | O 1.98800 1.98800 0.00000
75 | O 1.98800 0.00000 1.98800
76 | O 0.00000 1.98800 1.98800
77 | ''',
78 | dimension = 3,
79 | max_memory = 140000,
80 | verbose = 5,
81 | pseudo = 'gth-pade',
82 | basis='gth-dzvp-molopt-sr',
83 | precision=1e-12)
84 |
85 | # save cell object (required for using band_interpolate in DMFT)
86 | scf.chkfile.save_cell(cell, 'cell.chk')
87 |
88 | kmesh = [5,5,5]
89 | Lat = lattice.Lattice(cell, kmesh)
90 | kpts = Lat.kpts
91 | nao = Lat.nao
92 | nkpts = Lat.nkpts
93 |
94 | gdf = df.GDF(cell, kpts)
95 | gdf_fname = 'gdf_ints_555.h5'
96 | gdf._cderi_to_save = gdf_fname
97 | gdf.auxbasis = df.aug_etb(cell, beta=2.3, use_lval=True, l_val_set={'Mo':2,'O':1,'Sr':1})
98 | if not os.path.isfile(gdf_fname):
99 | gdf.build()
100 |
101 | chkfname = 'srmoo3_555.chk'
102 | # save kmf object (required for using band_interpolate in DMFT)
103 | os.system('cp %s kmf.chk'%(chkfname))
104 | if os.path.isfile(chkfname):
105 | kmf = dft.KRKS(cell, kpts)
106 | kmf.xc = 'lda'
107 | kmf.exxdiv = None
108 | kmf = scf.addons.smearing_(kmf, sigma=5e-3, method="fermi")
109 | kmf.with_df = gdf
110 | kmf.with_df._cderi = gdf_fname
111 | data = chkfile.load(chkfname, 'scf')
112 | kmf.__dict__.update(data)
113 | else:
114 | kmf = dft.KRKS(cell, kpts)
115 | kmf.xc = 'lda'
116 | kmf.exxdiv = None
117 | kmf = scf.addons.smearing_(kmf, sigma=5e-3, method="fermi")
118 | kmf.with_df = gdf
119 | kmf.with_df._cderi = gdf_fname
120 | kmf.conv_tol = 1e-12
121 | kmf.chkfile = chkfname
122 | kmf.diis_space = 15
123 | kmf.max_cycle = 50
124 | kmf.kernel()
125 |
126 | from libdmet_solid.lo.iao import reference_mol, get_labels, get_idx_each
127 | import copy
128 | ### Set up IAO Basis ###
129 | # set IAO (core+val)
130 | minao = 'gth-szv-molopt-sr'
131 | pmol = reference_mol(cell, minao=minao)
132 | basis = pmol._basis
133 |
134 | # set valence IAO
135 | basis_val = {}
136 | minao_val = 'gth-szv-molopt-sr-val'
137 | pmol_val = pmol.copy()
138 | pmol_val.basis = minao_val
139 | pmol_val.build()
140 | basis_val["Sr"] = copy.deepcopy(pmol_val._basis["Sr"])
141 | basis_val["Mo"] = copy.deepcopy(pmol_val._basis["Mo"])
142 | basis_val["O"] = copy.deepcopy(pmol_val._basis["O"])
143 |
144 | pmol_val = pmol.copy()
145 | pmol_val.basis = basis_val
146 | pmol_val.build()
147 |
148 | val_labels = pmol_val.ao_labels()
149 | for i in range(len(val_labels)):
150 | val_labels[i] = val_labels[i].replace("Mo 4s", "Mo 5s")
151 | val_labels[i] = val_labels[i].replace("Sr 4s", "Sr 5s")
152 | pmol_val.ao_labels = lambda *args: val_labels
153 |
154 | # set core IAO
155 | basis_core = {}
156 | minao_core = 'gth-szv-molopt-sr-core'
157 | pmol_core = pmol.copy()
158 | pmol_core.basis = minao_core
159 | pmol_core.build()
160 | basis_core["Sr"] = copy.deepcopy(pmol_core._basis["Sr"])
161 | basis_core["Mo"] = copy.deepcopy(pmol_core._basis["Mo"])
162 | basis_core["O"] = copy.deepcopy(pmol_core._basis["O"])
163 |
164 | pmol_core = pmol.copy()
165 | pmol_core.basis = basis_core
166 | pmol_core.build()
167 | core_labels = pmol_core.ao_labels()
168 |
169 | ncore = len(pmol_core.ao_labels())
170 | nval = pmol_val.nao_nr()
171 | nvirt = cell.nao_nr() - ncore - nval
172 | Lat.set_val_virt_core(nval, nvirt, ncore)
173 |
174 | # construct IAO and PAO.
175 | C_ao_iao, C_ao_iao_val, C_ao_iao_virt, C_ao_iao_core \
176 | = make_basis.get_C_ao_lo_iao(Lat, kmf, minao=minao, full_return=True, \
177 | pmol_val=pmol_val, pmol_core=pmol_core, tol=1e-9)
178 | C_ao_lo = C_ao_iao[:,:,ncore:]
179 | nlo = C_ao_lo.shape[-1]
180 |
181 | ### Band Interpolation ###
182 | # get DFT bands at kpts_L, this kpts_L will be used for computing lattice GF/hyb in DMFT
183 | # Note: Running DFT (LDA/GGA) only needs diagonal k-block of GDF (j_only=True)
184 | kmesh_L = [12,12,12]
185 | kpts_L = cell.make_kpts(kmesh_L,scaled_center=[0,0,0])
186 | gdf2 = df.GDF(cell, kpts)
187 | gdf2_fname = 'gdf_ints_555_band.h5'
188 | gdf2._cderi_to_save = gdf2_fname
189 | gdf2.auxbasis = gdf.auxbasis
190 | gdf2.kpts_band = kpts_L
191 | if not os.path.isfile(gdf2_fname):
192 | gdf2._j_only = True
193 | gdf2.build(j_only=True, kpts_band=kpts_L)
194 |
195 | kmf2 = dft.KRKS(cell, kpts).density_fit()
196 | kmf2.xc = 'lda'
197 | kmf2.exxdiv = None
198 | kmf2 = scf.addons.smearing_(kmf2, sigma=5e-3, method="fermi")
199 | kmf2.with_df = gdf2
200 | kmf2.with_df._cderi = gdf2_fname
201 | kmf2.mo_energy = kmf.mo_energy
202 | kmf2.mo_occ = kmf.mo_occ
203 | kmf2.mo_coeff = kmf.mo_coeff
204 |
205 | mo_energy_band, mo_coeff_band, hcore_band, veff_band = interpolate.get_bands(kmf2, kpts_L)
206 |
207 | # set up a new mean-field object at kpts_L
208 | kmf3 = dft.KRKS(cell, kpts_L).density_fit()
209 | kmf3.xc = 'lda'
210 | kmf3.exxdiv = None
211 | kmf3 = scf.addons.smearing_(kmf3, sigma=5e-3, method="fermi")
212 | kmf3.mo_energy = mo_energy_band
213 | kmf3.mo_coeff = mo_coeff_band
214 | kmf3.mo_occ = kmf3.get_occ(mo_energy_kpts=mo_energy_band, mo_coeff_kpts=mo_coeff_band)
215 |
216 | # IAO+PAO orbitals at kpts_L
217 | Lat2 = lattice.Lattice(cell, kmesh)
218 | Lat2.kpts = kpts_L
219 | Lat2.set_val_virt_core(nval, nvirt, ncore)
220 | C_ao_iao, C_ao_iao_val, C_ao_iao_virt, C_ao_iao_core \
221 | = make_basis.get_C_ao_lo_iao(Lat2, kmf3, minao=minao, full_return=True, \
222 | pmol_val=pmol_val, pmol_core=pmol_core, tol=1e-9)
223 | C_ao_lo_L = C_ao_iao[:,:,ncore:]
224 |
225 | # Make sure two sets of wannier orbitals have same order and phase
226 | ovlp = np.dot(C_ao_lo[0].T.conj(), kmf.get_ovlp()[0]).dot(C_ao_lo_L[0])
227 | C_ao_lo_L_ordered = np.zeros_like(C_ao_lo_L)
228 | for i in range(ovlp.shape[0]):
229 | idx = np.argmax(np.abs(ovlp[i]))
230 | C_ao_lo_L_ordered[:,:,i] = C_ao_lo_L[:,:,idx]
231 | if (ovlp[i,idx].real < 0):
232 | C_ao_lo_L_ordered[:,:,i] = -C_ao_lo_L_ordered[:,:,i]
233 | C_ao_lo_L = C_ao_lo_L_ordered
234 |
235 | # Get DFT Fock at kpts_L in LO basis
236 | fock_band = hcore_band + veff_band
237 | hcore_dft_band = np.zeros((len(kpts_L),nlo,nlo),dtype=np.complex)
238 | veff_dft_band = np.zeros((len(kpts_L),nlo,nlo),dtype=np.complex)
239 | for k in range(len(kpts_L)):
240 | hcore_dft_band[k] = np.dot(C_ao_lo_L[k].T.conj(), hcore_band[k]).dot(C_ao_lo_L[k])
241 | veff_dft_band[k] = np.dot(C_ao_lo_L[k].T.conj(), veff_band[k]).dot(C_ao_lo_L[k])
242 | fock_dft_band = hcore_dft_band + veff_dft_band
243 |
244 | # Save DFT get_bands results
245 | fn = 'hcore_JK_iao_k_dft_band.h5'
246 | feri = h5py.File(fn, 'w')
247 | feri['hcore'] = np.asarray(hcore_dft_band)
248 | feri['JK'] = np.asarray(veff_dft_band)
249 | feri['kpts'] = np.asarray(kpts_L)
250 | feri['C_ao_lo'] = np.asarray(C_ao_lo_L)
251 | feri.close()
252 |
253 | # Interpolate GW self-energy (this part will be rerun in DMFT, can be skipped here)
254 | freqs = np.linspace(0.2, 0.9, 141)
255 | delta = 0.005
256 | sigma = get_kgw_sigma_diff(freqs, delta)
257 | sigma_band_lo = interpolate.interpolate_selfenergy(kmf, kpts_L, sigma, C_ao_lo=C_ao_lo)
258 |
259 | nkpts_band = len(kpts_L)
260 | gf = np.zeros((nlo, nlo, len(freqs)), dtype=np.complex)
261 | for k in range(nkpts_band):
262 | gf += 1./nkpts_band * get_gf(fock_dft_band[k], sigma_band_lo[k], freqs, delta)
263 |
264 | print ('GW t2g, eg')
265 | for i in range(len(freqs)):
266 | print (freqs[i], -gf[1,1,i].imag/np.pi, -gf[3,3,i].imag/np.pi)
267 |
268 | print ('GW total')
269 | for i in range(len(freqs)):
270 | print (freqs[i], -np.trace(gf[:,:,i]).imag/np.pi)
271 |
272 | nkpts_band = len(kpts_L)
273 | gf = np.zeros((nlo, nlo, len(freqs)), dtype=np.complex)
274 | for k in range(nkpts_band):
275 | gf += 1./nkpts_band * get_gf0(fock_dft_band[k], freqs, delta)
276 |
277 | print ('DFT t2g, eg')
278 | for i in range(len(freqs)):
279 | print (freqs[i], -gf[1,1,i].imag/np.pi, -gf[3,3,i].imag/np.pi)
280 |
281 | print ('DFT total')
282 | for i in range(len(freqs)):
283 | print (freqs[i], -np.trace(gf[:,:,i]).imag/np.pi)
284 |
285 |
--------------------------------------------------------------------------------
/examples/SrMoO3/srmoo3_lda.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | from pyscf.pbc import df, dft, scf, cc, gto
3 | import numpy as np
4 | import h5py
5 | from libdmet_solid.system import lattice
6 | from libdmet_solid.basis_transform import make_basis
7 | from libdmet_solid.basis_transform import eri_transform
8 | from pyscf.pbc.lib import chkfile
9 | import os
10 | from pyscf import lib
11 | import libdmet_solid.utils.logger as log
12 |
13 | log.verbose = 'DEBUG1'
14 |
15 | einsum = lib.einsum
16 |
17 | cell = gto.Cell()
18 | cell.build(unit = 'angstrom',
19 | a = '''
20 | 3.97600 0.00000 0.00000
21 | 0.00000 3.97600 0.00000
22 | 0.00000 0.00000 3.97600
23 | ''',
24 | atom = '''
25 | Mo 1.98800 1.98800 1.98800
26 | Sr 0.00000 0.00000 0.00000
27 | O 1.98800 1.98800 0.00000
28 | O 1.98800 0.00000 1.98800
29 | O 0.00000 1.98800 1.98800
30 | ''',
31 | dimension = 3,
32 | max_memory = 150000,
33 | verbose = 5,
34 | pseudo = 'gth-pade',
35 | basis='gth-dzvp-molopt-sr',
36 | precision=1e-12)
37 |
38 | kmesh = [5,5,5]
39 | Lat = lattice.Lattice(cell, kmesh)
40 | kpts = Lat.kpts
41 | nao = Lat.nao
42 | nkpts = Lat.nkpts
43 |
44 | gdf = df.GDF(cell, kpts)
45 | gdf._cderi_to_save = 'gdf_ints_555.h5'
46 | gdf.auxbasis = df.aug_etb(cell, beta=2.3, use_lval=True, l_val_set={'Mo':2,'O':1,'Sr':1})
47 | gdf.build()
48 |
49 | chkfname = 'srmoo3_555.chk'
50 | if os.path.isfile(chkfname):
51 | kmf = dft.KRKS(cell, kpts)
52 | kmf.xc = 'lda'
53 | kmf.exxdiv = None
54 | kmf = scf.addons.smearing_(kmf, sigma=5e-3, method="fermi")
55 | kmf.with_df = gdf
56 | kmf.with_df._cderi = 'gdf_ints_555.h5'
57 | data = chkfile.load(chkfname, 'scf')
58 | kmf.__dict__.update(data)
59 | else:
60 | kmf = dft.KRKS(cell, kpts)
61 | kmf.xc = 'lda'
62 | kmf.exxdiv = None
63 | kmf = scf.addons.smearing_(kmf, sigma=5e-3, method="fermi")
64 | kmf.with_df = gdf
65 | kmf.with_df._cderi = 'gdf_ints_555.h5'
66 | kmf.conv_tol = 1e-12
67 | kmf.chkfile = chkfname
68 | kmf.diis_space = 15
69 | kmf.max_cycle = 50
70 | kmf.kernel()
71 |
72 | nmo = len(kmf.mo_energy[0])
73 |
74 | import copy
75 | mo_occ_old = copy.deepcopy(kmf.mo_occ)
76 | homo = -99; lumo = 99
77 | for k in range(nkpts):
78 | for i in range(nmo):
79 | if kmf.mo_occ[k][i] > 1.0:
80 | kmf.mo_occ[k][i] = 2.
81 | if kmf.mo_energy[k][i] > homo:
82 | homo = kmf.mo_energy[k][i]
83 | else:
84 | kmf.mo_occ[k][i] = 0.
85 | if kmf.mo_energy[k][i] < lumo:
86 | lumo = kmf.mo_energy[k][i]
87 |
88 | print (homo, lumo)
89 |
90 |
--------------------------------------------------------------------------------
/examples/SrMoO3/srmoo3_set_ham.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | import numpy as np
3 | import h5py, os
4 | from libdmet_solid.system import lattice
5 | from libdmet_solid.basis_transform import make_basis
6 | from libdmet_solid.basis_transform import eri_transform
7 | import libdmet_solid.utils.logger as log
8 |
9 | from pyscf.pbc import df, dft, scf, gto
10 | from pyscf.pbc.lib import chkfile
11 | from pyscf import lib
12 | from pyscf import gto as gto_mol
13 | from pyscf import scf as scf_mol
14 |
15 | from fcdmft.gw.mol import gw_dc
16 | from fcdmft.utils import cholesky
17 |
18 | import copy
19 | from libdmet_solid.utils.misc import kdot, mdot
20 | from libdmet_solid.lo.iao import get_idx, get_idx_each_atom, \
21 | get_idx_each_orbital
22 | from libdmet_solid.lo.iao import reference_mol, get_labels, get_idx_each
23 |
24 | log.verbose = 'DEBUG1'
25 |
26 | einsum = lib.einsum
27 |
28 | # NOTE: lattice system setup by user
29 | cell = gto.Cell()
30 | cell.build(unit = 'angstrom',
31 | a = '''
32 | 3.97600 0.00000 0.00000
33 | 0.00000 3.97600 0.00000
34 | 0.00000 0.00000 3.97600
35 | ''',
36 | atom = '''
37 | Mo 1.98800 1.98800 1.98800
38 | Sr 0.00000 0.00000 0.00000
39 | O 1.98800 1.98800 0.00000
40 | O 1.98800 0.00000 1.98800
41 | O 0.00000 1.98800 1.98800
42 | ''',
43 | dimension = 3,
44 | max_memory = 100000,
45 | verbose = 5,
46 | pseudo = 'gth-pade',
47 | basis='gth-dzvp-molopt-sr',
48 | precision=1e-12)
49 |
50 | kmesh = [5,5,5]
51 | Lat = lattice.Lattice(cell, kmesh)
52 | kpts = Lat.kpts
53 | nao = Lat.nao
54 | nkpts = Lat.nkpts
55 |
56 | gdf = df.GDF(cell, kpts)
57 | gdf_fname = 'gdf_ints_555.h5'
58 | gdf._cderi_to_save = gdf_fname
59 | gdf.auxbasis = df.aug_etb(cell, beta=2.3, use_lval=True, l_val_set={'Mo':2,'O':1,'Sr':1})
60 | if not os.path.isfile(gdf_fname):
61 | gdf.build()
62 |
63 | chkfname = 'srmoo3_555.chk'
64 | if os.path.isfile(chkfname):
65 | kmf = dft.KRKS(cell, kpts)
66 | kmf.xc = 'lda'
67 | kmf.exxdiv = None
68 | kmf = scf.addons.smearing_(kmf, sigma=5e-3, method="fermi")
69 | kmf.with_df = gdf
70 | kmf.with_df._cderi = gdf_fname
71 | data = chkfile.load(chkfname, 'scf')
72 | kmf.__dict__.update(data)
73 | else:
74 | kmf = dft.KRKS(cell, kpts)
75 | kmf.xc = 'lda'
76 | kmf.exxdiv = None
77 | kmf = scf.addons.smearing_(kmf, sigma=5e-3, method="fermi")
78 | kmf.with_df = gdf
79 | kmf.with_df._cderi = gdf_fname
80 | kmf.conv_tol = 1e-12
81 | kmf.chkfile = chkfname
82 | kmf.diis_space = 15
83 | kmf.max_cycle = 50
84 | kmf.kernel()
85 |
86 | # set spin
87 | mo_energy = np.asarray(kmf.mo_energy)
88 | mo_coeff = np.asarray(kmf.mo_coeff)
89 | if len(mo_energy.shape) == 2:
90 | spin = 1
91 | mo_energy = mo_energy[np.newaxis, ...]
92 | mo_coeff = mo_coeff[np.newaxis, ...]
93 | else:
94 | spin = 2
95 |
96 | # NOTE: choose IAO basis by user
97 | # set IAO (core+val)
98 | minao = 'gth-szv-molopt-sr'
99 | pmol = reference_mol(cell, minao=minao)
100 | basis = pmol._basis
101 |
102 | # set valence IAO
103 | basis_val = {}
104 | minao_val = 'gth-szv-molopt-sr-val'
105 | pmol_val = pmol.copy()
106 | pmol_val.basis = minao_val
107 | pmol_val.build()
108 | basis_val["Sr"] = copy.deepcopy(pmol_val._basis["Sr"])
109 | basis_val["Mo"] = copy.deepcopy(pmol_val._basis["Mo"])
110 | basis_val["O"] = copy.deepcopy(pmol_val._basis["O"])
111 |
112 | pmol_val = pmol.copy()
113 | pmol_val.basis = basis_val
114 | pmol_val.build()
115 |
116 | val_labels = pmol_val.ao_labels()
117 | for i in range(len(val_labels)):
118 | val_labels[i] = val_labels[i].replace("Mo 4s", "Mo 5s")
119 | val_labels[i] = val_labels[i].replace("Sr 4s", "Sr 5s")
120 | pmol_val.ao_labels = lambda *args: val_labels
121 |
122 | # set core IAO
123 | basis_core = {}
124 | minao_core = 'gth-szv-molopt-sr-core'
125 | pmol_core = pmol.copy()
126 | pmol_core.basis = minao_core
127 | pmol_core.build()
128 | basis_core["Sr"] = copy.deepcopy(pmol_core._basis["Sr"])
129 | basis_core["Mo"] = copy.deepcopy(pmol_core._basis["Mo"])
130 | basis_core["O"] = copy.deepcopy(pmol_core._basis["O"])
131 |
132 | pmol_core = pmol.copy()
133 | pmol_core.basis = basis_core
134 | pmol_core.build()
135 | core_labels = pmol_core.ao_labels()
136 |
137 | ncore = len(pmol_core.ao_labels())
138 | nval = pmol_val.nao_nr()
139 | nvirt = cell.nao_nr() - ncore - nval
140 | Lat.set_val_virt_core(nval, nvirt, ncore)
141 |
142 | # First construct IAO and PAO.
143 | C_ao_iao, C_ao_iao_val, C_ao_iao_virt, C_ao_iao_core \
144 | = make_basis.get_C_ao_lo_iao(Lat, kmf, minao=minao, full_return=True, \
145 | pmol_val=pmol_val, pmol_core=pmol_core, tol=1e-9)
146 |
147 | # C_ao_lo: transformation matrix from AO to LO (IAO) basis
148 | nlo = nao - ncore
149 | C_ao_lo = np.zeros((spin,nkpts,nao,nlo),dtype=np.complex128)
150 | for s in range(spin):
151 | C_ao_lo[s] = C_ao_iao[:,:,ncore:]
152 |
153 | # C_mo_lo: transformation matrix from MO to LO (IAO) basis
154 | S_ao_ao = kmf.get_ovlp()
155 | C_mo_lo = np.zeros((spin,nkpts,nao,nlo),dtype=np.complex128)
156 | for s in range(spin):
157 | for ki in range(nkpts):
158 | C_mo_lo[s][ki] = np.dot(np.dot(mo_coeff[s][ki].T.conj(), S_ao_ao[ki]), C_ao_lo[s][ki])
159 | fn = 'C_mo_lo.h5'
160 | feri = h5py.File(fn, 'w')
161 | feri['C_ao_lo'] = np.asarray(C_ao_lo)
162 | feri['C_mo_lo'] = np.asarray(C_mo_lo)
163 | feri.close()
164 |
165 | # get DFT density matrix in IAO basis
166 | DM_ao = np.asarray(kmf.make_rdm1())
167 | if len(DM_ao.shape) == 3:
168 | DM_ao = DM_ao[np.newaxis, ...]
169 | DM_lo = np.zeros((spin,nkpts,nlo,nlo),dtype=DM_ao.dtype)
170 | for s in range(spin):
171 | for ki in range(nkpts):
172 | Cinv = np.dot(C_ao_lo[s][ki].T.conj(),S_ao_ao[ki])
173 | DM_lo[s][ki] = np.dot(np.dot(Cinv, DM_ao[s][ki]), Cinv.T.conj())
174 |
175 | for s in range(spin):
176 | nelec_lo = np.trace(DM_lo[s].sum(axis=0)/nkpts)
177 | print ('Nelec imp', nelec_lo.real)
178 | fn = 'DM_iao_k.h5'
179 | feri = h5py.File(fn, 'w')
180 | feri['DM'] = np.asarray(DM_lo)
181 | feri.close()
182 |
183 | # get 4-index ERI
184 | eri = eri_transform.get_unit_eri_fast(cell, gdf, C_ao_lo=C_ao_lo, feri=gdf_fname)
185 | fn = 'eri_imp111_iao.h5'
186 | feri = h5py.File(fn, 'w')
187 | feri['eri'] = np.asarray(eri.real)
188 | feri.close()
189 |
190 | # get one-electron integrals
191 | hcore_ao = np.asarray(kmf.get_hcore())
192 | JK_ao = np.asarray(kmf.get_veff())
193 | if len(JK_ao.shape) == 3:
194 | JK_ao = JK_ao[np.newaxis, ...]
195 | hcore_lo = np.zeros((spin,nkpts,nlo,nlo),dtype=hcore_ao.dtype)
196 | JK_lo = np.zeros((spin,nkpts,nlo,nlo),dtype=JK_ao.dtype)
197 | for s in range(spin):
198 | for ki in range(nkpts):
199 | hcore_lo[s,ki] = np.dot(np.dot(C_ao_lo[s,ki].T.conj(), hcore_ao[ki]), C_ao_lo[s,ki])
200 | JK_lo[s,ki] = np.dot(np.dot(C_ao_lo[s,ki].T.conj(), JK_ao[s,ki]), C_ao_lo[s,ki])
201 |
202 | fn = 'hcore_JK_iao_k_dft.h5'
203 | feri = h5py.File(fn, 'w')
204 | feri['hcore'] = np.asarray(hcore_lo)
205 | feri['JK'] = np.asarray(JK_lo)
206 | feri.close()
207 | assert(np.max(np.abs(hcore_lo.sum(axis=1).imag/nkpts))<1e-6)
208 | assert(np.max(np.abs(JK_lo.sum(axis=1).imag/nkpts))<1e-6)
209 |
210 | # get HF JK term using DFT density
211 | kmf_hf = scf.KRHF(cell, kpts, exxdiv=None)
212 | kmf_hf.with_df = gdf
213 | kmf_hf.with_df._cderi = gdf_fname
214 | kmf_hf.max_cycle = 0
215 | JK_ao = np.asarray(kmf_hf.get_veff(dm_kpts=DM_ao[0]))
216 | if len(JK_ao.shape) == 3:
217 | JK_ao = JK_ao[np.newaxis, ...]
218 |
219 | # NOTE: choose finite size correction by user
220 | # set gw_fc to True if finite size correction is used in kgw
221 | gw_fc = False
222 | if gw_fc:
223 | # finite size correction to exchange
224 | vk_corr = -2./np.pi * (6.*np.pi**2/cell.vol/nkpts)**(1./3.)
225 | nocc = cell.nelectron // 2
226 | JK_mo = np.zeros((spin,nkpts,nao,nao),dtype=JK_ao.dtype)
227 | for s in range(spin):
228 | for ki in range(nkpts):
229 | JK_mo[s,ki] = np.dot(np.dot(mo_coeff[s,ki].T.conj(), JK_ao[s,ki]), mo_coeff[s,ki])
230 | for i in range(nocc):
231 | JK_mo[s,ki][i,i] = JK_mo[s,ki][i,i] + vk_corr
232 |
233 | JK_lo = np.zeros((spin,nkpts,nlo,nlo),dtype=JK_ao.dtype)
234 | for s in range(spin):
235 | for ki in range(nkpts):
236 | JK_lo[s,ki] = np.dot(np.dot(C_mo_lo[s,ki].T.conj(), JK_mo[s,ki]), C_mo_lo[s,ki])
237 | else:
238 | JK_lo = np.zeros((spin,nkpts,nlo,nlo),dtype=JK_ao.dtype)
239 | for s in range(spin):
240 | for ki in range(nkpts):
241 | JK_lo[s,ki] = np.dot(np.dot(C_ao_lo[s,ki].T.conj(), JK_ao[s,ki]), C_ao_lo[s,ki])
242 |
243 | fn = 'hcore_JK_iao_k_hf.h5'
244 | feri = h5py.File(fn, 'w')
245 | feri['JK'] = np.asarray(JK_lo)
246 | feri.close()
247 |
248 | # Cholesky decomposition for generating 3-index density-fitted ERI (required by gw_dc)
249 | if not os.path.isfile('cderi.h5'):
250 | try:
251 | cd = cholesky.cholesky(eri[0], tau=1e-7, dimQ=50)
252 | except:
253 | cd = cholesky.cholesky(eri[0], tau=1e-6, dimQ=50)
254 | cderi = cd.kernel()
255 | cderi = cderi.reshape(-1,nlo,nlo)
256 | print ('3-index ERI', cderi.shape)
257 | fn = 'cderi.h5'
258 | feri = h5py.File(fn, 'w')
259 | feri['cderi'] = np.asarray(cderi)
260 | feri.close()
261 | else:
262 | fn = 'cderi.h5'
263 | feri = h5py.File(fn, 'r')
264 | cderi = np.asarray(feri['cderi'])
265 | feri.close()
266 |
267 | # Compute GW double counting self-energy
268 | naux, nimp, nimp = cderi.shape
269 | nocc = cell.nelectron // 2
270 | # NOTE: set ef by user for metals
271 | ef = 0.560479331479
272 |
273 | # NOTE: check analytic continuation stability (sigma) by user
274 | mol = gto_mol.M()
275 | mol.verbose = 5
276 | mf = scf_mol.RHF(mol)
277 | mf.max_memory = kmf.max_memory
278 | gw = gw_dc.GWGF(mf)
279 | gw.nmo = nimp
280 | gw.nocc = nocc
281 | gw.eta = 0.1/27.211386
282 | gw.ac = 'pade'
283 | gw.ef = ef
284 | gw.fullsigma = True
285 | omega = np.linspace(7./27.211386,23./27.211386,161)
286 | sigma_lo = gw.kernel(Lpq=cderi, omega=omega, kmf=kmf, C_mo_lo=C_mo_lo, nw=100, nt=20000)
287 | print('### local GW self-energy (trace) on real axis ###')
288 | print('# freq imag real #')
289 | for i in range(len(omega)):
290 | print (omega[i], np.trace(sigma_lo[:,:,i].imag), np.trace(sigma_lo[:,:,i].real))
291 |
--------------------------------------------------------------------------------
/examples/interpolation/diamond_gw_interpolate.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from pyscf.pbc import df, gto, dft, scf
3 | from pyscf.pbc.lib import chkfile
4 | import os
5 | import matplotlib.pyplot as plt
6 | from ase.lattice import bulk
7 | from ase.dft.kpoints import sc_special_points as special_points, get_bandpath
8 | from fcdmft.utils import interpolate
9 |
10 | '''
11 | GW Wannier band interpolation:
12 | Step 1: Get LDA bands at larger k-mesh (6x6x6) from get_bands (non-SCF diagonalization)
13 | Step 2: Interpolate LDA bands at random kpts_band using 6x6x6 results -> fock_dft_band
14 | Step 3: Interpolate GW self-energy at kpts_band using 4x4x4 results ->
15 | sigma_band_lo, then get GW bands
16 |
17 | Note: Currently a k-mesh must be used for constructing Wannier orbitals
18 | '''
19 |
20 | cell = gto.Cell()
21 | cell.build(unit = 'angstrom',
22 | a = np.array([[0.000000, 1.783500, 1.783500],
23 | [1.783500, 0.000000, 1.783500],
24 | [1.783500, 1.783500, 0.000000]]),
25 | atom = 'C 1.337625 1.337625 1.337625; C 2.229375 2.229375 2.229375',
26 | dimension = 3,
27 | max_memory = 32000,
28 | verbose = 5,
29 | pseudo = 'gth-pade',
30 | basis='gth-dzv',
31 | precision=1e-10)
32 |
33 | kmesh = [4,4,4]
34 | kpts = cell.make_kpts(kmesh,scaled_center=[0,0,0])
35 | gdf = df.GDF(cell, kpts)
36 | gdf_fname = 'gdf_ints_444.h5'
37 | gdf._cderi_to_save = gdf_fname
38 | if not os.path.isfile(gdf_fname):
39 | gdf.build()
40 |
41 | chkfname = 'diamond_444.chk'
42 | if os.path.isfile(chkfname):
43 | kmf = dft.KRKS(cell, kpts)
44 | kmf.with_df = gdf
45 | kmf.with_df._cderi = gdf_fname
46 | data = chkfile.load(chkfname, 'scf')
47 | kmf.__dict__.update(data)
48 | else:
49 | kmf = dft.KRKS(cell, kpts)
50 | kmf.with_df = gdf
51 | kmf.with_df._cderi = gdf_fname
52 | kmf.conv_tol = 1e-12
53 | kmf.chkfile = chkfname
54 | kmf.kernel()
55 |
56 | # GW@LDA
57 | from fcdmft.gw.pbc import krgw_gf
58 | gw = krgw_gf.KRGWGF(kmf)
59 | gw.eta = 1e-2
60 | gw.fullsigma = True
61 | gw.fc = True
62 | omega = np.linspace(-12./27.211386, 34./27.211386, 231)
63 | gf, gf0, sigma = gw.kernel(omega=omega, writefile=0)
64 |
65 | from libdmet_solid.basis_transform import make_basis
66 | from libdmet_solid.lo import pywannier90
67 | # valence Wannier orbitals
68 | num_wann = 8
69 | keywords = \
70 | '''
71 | num_iter = 1000
72 | begin projections
73 | C:sp3
74 | end projections
75 | exclude_bands : 9-%s
76 | num_cg_steps = 100
77 | precond = T
78 | '''%(kmf.cell.nao_nr())
79 |
80 | w90 = pywannier90.W90(kmf, kmesh, num_wann, other_keywords = keywords)
81 | #w90.use_atomic = True
82 | #w90.use_bloch_phases = True
83 | #w90.use_scdm = True
84 | #w90.guiding_centres = False
85 | w90.kernel()
86 |
87 | C_ao_mo = np.asarray(w90.mo_coeff)[:, :, w90.band_included_list]
88 | C_mo_lo = make_basis.tile_u_matrix(np.array(w90.U_matrix.transpose(2, 0, 1), \
89 | order='C'), u_virt=None, u_core=None)
90 | C_ao_lo = make_basis.multiply_basis(C_ao_mo, C_mo_lo)
91 | nbands = C_ao_lo.shape[-1]
92 |
93 | # set up band_kpts
94 | points = special_points['fcc']
95 | G = points['G']
96 | X = points['X']
97 | W = points['W']
98 | K = points['K']
99 | L = points['L']
100 | band_kpts, kpath, sp_points = get_bandpath([L, G, X, W, K, G], cell.a, npoints=100)
101 | band_kpts = cell.get_abs_kpts(band_kpts)
102 |
103 | # get DFT bands for a large k-mesh
104 | kmesh_L = [6,6,6]
105 | kpts_L = cell.make_kpts(kmesh_L,scaled_center=[0,0,0])
106 | gdf2 = df.GDF(cell, kpts)
107 | gdf2_fname = 'gdf_ints_large.h5'
108 | gdf2._cderi_to_save = gdf2_fname
109 | gdf2.auxbasis = gdf.auxbasis
110 | gdf2.kpts_band = kpts_L
111 | if not os.path.isfile(gdf2_fname):
112 | gdf2._j_only = True
113 | gdf2.build(j_only=True, kpts_band=kpts_L)
114 |
115 | kmf2 = dft.KRKS(cell, kpts).density_fit()
116 | kmf2.xc = kmf.xc
117 | kmf2.exxdiv = kmf.exxdiv
118 | if hasattr(kmf, 'sigma'):
119 | kmf2 = scf.addons.smearing_(kmf2, sigma=kmf.sigma, method="fermi")
120 | kmf2.with_df = gdf2
121 | kmf2.with_df._cderi = gdf2_fname
122 | kmf2.mo_energy = kmf.mo_energy
123 | kmf2.mo_occ = kmf.mo_occ
124 | kmf2.mo_coeff = kmf.mo_coeff
125 |
126 | mo_energy_L, mo_coeff_L, hcore_L, veff_L = interpolate.get_bands(kmf2, kpts_L)
127 |
128 | # set up a new mean-field object at large k-mesh
129 | kmf3 = dft.KRKS(cell, kpts_L).density_fit()
130 | kmf3.xc = kmf.xc
131 | kmf3.exxdiv = kmf.exxdiv
132 | if hasattr(kmf, 'sigma'):
133 | kmf3 = scf.addons.smearing_(kmf3, sigma=kmf.sigma, method="fermi")
134 | kmf3.mo_energy = mo_energy_L
135 | kmf3.mo_coeff = mo_coeff_L
136 | kmf3.mo_occ = kmf3.get_occ(mo_energy_kpts=mo_energy_L, mo_coeff_kpts=mo_coeff_L)
137 |
138 | # Wannier basis for large k-mesh
139 | w90_L = pywannier90.W90(kmf3, kmesh_L, num_wann, other_keywords = keywords)
140 | w90_L.kernel()
141 | C_ao_mo = np.asarray(w90_L.mo_coeff)[:, :, w90_L.band_included_list]
142 | C_mo_lo = make_basis.tile_u_matrix(np.array(w90_L.U_matrix.transpose(2, 0, 1), \
143 | order='C'), u_virt=None, u_core=None)
144 | C_ao_lo_L = make_basis.multiply_basis(C_ao_mo, C_mo_lo)
145 |
146 | # Make sure two sets of wannier orbitals have same order and phase
147 | # Search for Gamma point in kpts_L
148 | idx_G = None
149 | for i in range(len(kpts_L)):
150 | if np.linalg.norm(kpts_L[i]-kpts[0]) < 1e-8:
151 | idx_G = i
152 | break
153 | assert (idx_G is not None)
154 | ovlp = np.dot(C_ao_lo[0].T.conj(), kmf.get_ovlp()[0]).dot(C_ao_lo_L[idx_G])
155 | C_ao_lo_L_ordered = np.zeros_like(C_ao_lo_L)
156 | for i in range(ovlp.shape[0]):
157 | idx = np.argmax(np.abs(ovlp[i]))
158 | C_ao_lo_L_ordered[:,:,i] = C_ao_lo_L[:,:,idx]
159 | if (ovlp[i,idx].real < 0):
160 | C_ao_lo_L_ordered[:,:,i] = -C_ao_lo_L_ordered[:,:,i]
161 | C_ao_lo_L = C_ao_lo_L_ordered
162 |
163 | # Get DFT Fock at band_kpts through interpolation
164 | mo_energy_band, mo_coeff_band, fock_dft_band = interpolate.interpolate_mf(kmf3, band_kpts, C_ao_lo=C_ao_lo_L,
165 | veff=veff_L, hcore=hcore_L, w90=w90_L)
166 |
167 | # Interpolate GW self-energy
168 | sigma_band_lo = interpolate.interpolate_selfenergy(kmf, band_kpts, sigma, C_ao_lo=C_ao_lo, w90=w90)
169 |
170 | # Get GW bands at band_kpts through interpolating mo diff
171 | e_kn_2 = interpolate.interpolate_hf_diff(kmf, band_kpts, fock_dft_band, mo_interpolate=True,
172 | mo_energy_hf=gw.mo_energy, C_ao_lo=C_ao_lo, w90=w90)[0]
173 | vbmax = -99
174 | for en in e_kn_2:
175 | vb_k = en[cell.nelectron//2-1]
176 | if vb_k > vbmax:
177 | vbmax = vb_k
178 | e_kn_2 = [en - vbmax for en in e_kn_2]
179 |
180 | # plot
181 | nkpts_band, nlo, nlo, nw = sigma_band_lo.shape
182 | delta = 0.2/27.211386
183 | dens = np.zeros((nkpts_band, nw))
184 | for iw in range(nw):
185 | for k in range(nkpts_band):
186 | gf_band = np.linalg.inv((omega[iw]+1j*delta)*np.eye(nbands)-fock_dft_band[k]-sigma_band_lo[k,:,:,iw])
187 | dens[k,iw] = -1./np.pi*np.trace(gf_band.imag)/27.211386
188 | dens = dens.T
189 |
190 | omega_new = omega
191 | for iw in range(len(omega_new)):
192 | omega_new[iw] -= gw.mo_energy[0][3]
193 |
194 | space_max = 0.
195 | for i in range(1,nkpts_band):
196 | if kpath[i]-kpath[i-1] > space_max:
197 | space_max = kpath[i]-kpath[i-1]
198 | k_max = (nkpts_band-1)*space_max
199 | kpath_new = np.linspace(0,k_max,nkpts_band)
200 |
201 | sp_points_new = np.zeros_like(sp_points)
202 | for i in range(len(sp_points)):
203 | for j in range(nkpts_band):
204 | if sp_points[i] == kpath[j]:
205 | sp_points_new[i] = kpath_new[j]
206 |
207 | xi = kpath_new
208 | yi = omega_new*27.211386
209 | fig = plt.subplots(figsize=(3.375,1.8))
210 | ax = plt.subplot(111)
211 | interpolation_method = 'gaussian'
212 | extent = (xi[0],xi[-1],yi[0],yi[-1])
213 | plt.imshow(dens, cmap='viridis', aspect=0.11, extent=extent, origin='lower', interpolation=interpolation_method)
214 | cbar = plt.colorbar()
215 | cbar.set_label('DOS [1/eV]', size=6)
216 | cbar.ax.tick_params(labelsize=6)
217 |
218 | emin = yi[0]
219 | emax = yi[-1]
220 | ax.axis(xmin=0, xmax=sp_points_new[-1], ymin=emin, ymax=emax)
221 | plt.xticks(sp_points_new, ['%s' % n for n in ['L', r'$\Gamma$', 'X', 'W', 'K', r'$\Gamma$']])
222 |
223 | for p in sp_points_new:
224 | ax.plot([p, p], [emin, emax], '-', color='k', linewidth=0.6)
225 | ax.plot([0, sp_points_new[-1]], [0, 0], '--', color='k',linewidth=0.6)
226 |
227 | au2ev = 27.211386
228 | for n in range(nbands):
229 | ax.plot(kpath_new, [e[n]*au2ev for e in e_kn_2], '--',dashes=([2.2,1.4]),alpha=0.6,linewidth=0.6,color='white')
230 |
231 | ax.set_ylabel('Energy(eV)',fontsize=9)
232 | ax.yaxis.labelpad = -1
233 |
234 | major_yticks=np.arange(-25,20.1,5.0)
235 | #minor_yticks=np.arange(-25,20.1,1.0)
236 | ax.set_yticks(major_yticks)
237 | #ax.set_yticks(minor_yticks,minor=True)
238 | for axis in ['top','bottom','left','right']:
239 | ax.spines[axis].set_linewidth(0.5)
240 | ax.tick_params(axis='both',which='major',labelsize=8)
241 | ax.tick_params(axis='both',which='major',length=2.4,width=0.4,pad=2)
242 | ax.tick_params(axis='both',which='minor',length=1.5,width=0.4)
243 |
244 | plt.subplots_adjust(left=0.08,right=0.99,bottom=0.10,top=0.95)
245 | plt.savefig('diamond_444_GW.png', dpi=600)
246 |
--------------------------------------------------------------------------------
/examples/interpolation/diamond_gw_interpolate_iao.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from pyscf.pbc import df, gto, dft, scf
3 | from pyscf.pbc.lib import chkfile
4 | import os
5 | import matplotlib.pyplot as plt
6 | from ase.lattice import bulk
7 | from ase.dft.kpoints import sc_special_points as special_points, get_bandpath
8 | from fcdmft.utils import interpolate
9 |
10 | '''
11 | GW IAO+PAO band interpolation:
12 | Step 1: Get LDA bands at band_kpts from get_bands (non-SCF diagonalization)
13 | Step 2: Interpolate GW self-energy at kpts_band using 4x4x4 results ->
14 | sigma_band_lo, then get GW bands
15 | '''
16 |
17 | cell = gto.Cell()
18 | cell.build(unit = 'angstrom',
19 | a = np.array([[0.000000, 1.783500, 1.783500],
20 | [1.783500, 0.000000, 1.783500],
21 | [1.783500, 1.783500, 0.000000]]),
22 | atom = 'C 1.337625 1.337625 1.337625; C 2.229375 2.229375 2.229375',
23 | dimension = 3,
24 | max_memory = 32000,
25 | verbose = 5,
26 | pseudo = 'gth-pade',
27 | basis='gth-dzv',
28 | precision=1e-10)
29 |
30 | kmesh = [4,4,4]
31 | kpts = cell.make_kpts(kmesh,scaled_center=[0,0,0])
32 | gdf = df.GDF(cell, kpts)
33 | gdf_fname = 'gdf_ints_444.h5'
34 | gdf._cderi_to_save = gdf_fname
35 | if not os.path.isfile(gdf_fname):
36 | gdf.build()
37 |
38 | chkfname = 'diamond_444.chk'
39 | if os.path.isfile(chkfname):
40 | kmf = dft.KRKS(cell, kpts)
41 | kmf.with_df = gdf
42 | kmf.with_df._cderi = gdf_fname
43 | data = chkfile.load(chkfname, 'scf')
44 | kmf.__dict__.update(data)
45 | else:
46 | kmf = dft.KRKS(cell, kpts)
47 | kmf.with_df = gdf
48 | kmf.with_df._cderi = gdf_fname
49 | kmf.conv_tol = 1e-12
50 | kmf.chkfile = chkfname
51 | kmf.kernel()
52 |
53 | # GW@LDA
54 | from fcdmft.gw.pbc import krgw_gf
55 | gw = krgw_gf.KRGWGF(kmf)
56 | gw.eta = 1e-2
57 | gw.fullsigma = True
58 | gw.fc = True
59 | omega = np.linspace(-12./27.211386, 44./27.211386, 281)
60 | gf, gf0, sigma = gw.kernel(omega=omega, writefile=0)
61 |
62 | from libdmet_solid.system import lattice
63 | from libdmet_solid.basis_transform import make_basis
64 | # IAO+PAO orbitals
65 | Lat = lattice.Lattice(cell, kmesh)
66 | MINAO = {'C':'gth-szv'}
67 | C_ao_iao, C_ao_iao_val, C_ao_iao_virt = make_basis.get_C_ao_lo_iao(Lat, kmf, minao=MINAO, full_return=True)
68 | C_ao_lo = C_ao_iao
69 | nbands = C_ao_lo.shape[-1]
70 |
71 | # set up band_kpts
72 | points = special_points['fcc']
73 | G = points['G']
74 | X = points['X']
75 | W = points['W']
76 | K = points['K']
77 | L = points['L']
78 | band_kpts, kpath, sp_points = get_bandpath([L, G, X, W, K, G], cell.a, npoints=100)
79 | band_kpts = cell.get_abs_kpts(band_kpts)
80 |
81 | # get DFT bands at band_kpts
82 | gdf2 = df.GDF(cell, kpts)
83 | gdf2_fname = 'gdf_ints_444_band.h5'
84 | gdf2._cderi_to_save = gdf2_fname
85 | gdf2.auxbasis = gdf.auxbasis
86 | gdf2.kpts_band = band_kpts
87 | if not os.path.isfile(gdf2_fname):
88 | gdf2._j_only = True
89 | gdf2.build(j_only=True, kpts_band=band_kpts)
90 |
91 | kmf2 = dft.KRKS(cell, kpts).density_fit()
92 | kmf2.xc = kmf.xc
93 | kmf2.exxdiv = kmf.exxdiv
94 | if hasattr(kmf, 'sigma'):
95 | kmf2 = scf.addons.smearing_(kmf2, sigma=kmf.sigma, method="fermi")
96 | kmf2.with_df = gdf2
97 | kmf2.with_df._cderi = gdf2_fname
98 | kmf2.mo_energy = kmf.mo_energy
99 | kmf2.mo_occ = kmf.mo_occ
100 | kmf2.mo_coeff = kmf.mo_coeff
101 |
102 | mo_energy_band, mo_coeff_band, hcore_band, veff_band = interpolate.get_bands(kmf2, band_kpts)
103 |
104 | # set up a new mean-field object at band_kpts
105 | kmf3 = dft.KRKS(cell, band_kpts).density_fit()
106 | kmf3.xc = kmf.xc
107 | kmf3.exxdiv = kmf.exxdiv
108 | if hasattr(kmf, 'sigma'):
109 | kmf3 = scf.addons.smearing_(kmf3, sigma=kmf.sigma, method="fermi")
110 | kmf3.mo_energy = mo_energy_band
111 | kmf3.mo_coeff = mo_coeff_band
112 | kmf3.mo_occ = kmf3.get_occ(mo_energy_kpts=mo_energy_band, mo_coeff_kpts=mo_coeff_band)
113 |
114 | # IAO+PAO orbitals at band_kpts
115 | Lat2 = lattice.Lattice(cell, kmesh)
116 | Lat2.kpts = band_kpts
117 | MINAO = {'C':'gth-szv'}
118 | C_ao_iao, C_ao_iao_val, C_ao_iao_virt = make_basis.get_C_ao_lo_iao(Lat2, kmf3, minao=MINAO, full_return=True)
119 | C_ao_lo_L = C_ao_iao
120 |
121 | # Make sure two sets of wannier orbitals have same order and phase
122 | # Search for Gamma point in band_kpts
123 | idx_G = None
124 | for i in range(len(band_kpts)):
125 | if np.linalg.norm(band_kpts[i]-kpts[0]) < 1e-8:
126 | idx_G = i
127 | break
128 | assert (idx_G is not None)
129 | ovlp = np.dot(C_ao_lo[0].T.conj(), kmf.get_ovlp()[0]).dot(C_ao_lo_L[idx_G])
130 | C_ao_lo_L_ordered = np.zeros_like(C_ao_lo_L)
131 | for i in range(ovlp.shape[0]):
132 | idx = np.argmax(np.abs(ovlp[i]))
133 | C_ao_lo_L_ordered[:,:,i] = C_ao_lo_L[:,:,idx]
134 | if (ovlp[i,idx].real < 0):
135 | C_ao_lo_L_ordered[:,:,i] = -C_ao_lo_L_ordered[:,:,i]
136 | C_ao_lo_L = C_ao_lo_L_ordered
137 |
138 | # Get DFT Fock at band_kpts in LO basis
139 | fock_band = hcore_band + veff_band
140 | fock_dft_band = np.zeros((len(band_kpts),nbands,nbands),dtype=np.complex)
141 | for k in range(len(band_kpts)):
142 | fock_dft_band[k] = np.dot(C_ao_lo_L[k].T.conj(), fock_band[k]).dot(C_ao_lo_L[k])
143 |
144 | # Interpolate GW self-energy
145 | sigma_band_lo = interpolate.interpolate_selfenergy(kmf, band_kpts, sigma, C_ao_lo=C_ao_lo)
146 |
147 | # Get GW bands at band_kpts through interpolating mo diff
148 | e_kn_2 = interpolate.interpolate_hf_diff(kmf, band_kpts, fock_dft_band, mo_interpolate=True,
149 | mo_energy_hf=gw.mo_energy, C_ao_lo=C_ao_lo)[0]
150 | vbmax = -99
151 | for en in e_kn_2:
152 | vb_k = en[cell.nelectron//2-1]
153 | if vb_k > vbmax:
154 | vbmax = vb_k
155 | e_kn_2 = [en - vbmax for en in e_kn_2]
156 |
157 | # plot
158 | nkpts_band, nlo, nlo, nw = sigma_band_lo.shape
159 | delta = 0.2/27.211386
160 | dens = np.zeros((nkpts_band, nw))
161 | for iw in range(nw):
162 | for k in range(nkpts_band):
163 | gf_band = np.linalg.inv((omega[iw]+1j*delta)*np.eye(nbands)-fock_dft_band[k]-sigma_band_lo[k,:,:,iw])
164 | dens[k,iw] = -1./np.pi*np.trace(gf_band.imag)/27.211386
165 | dens = dens.T
166 |
167 | omega_new = omega
168 | for iw in range(len(omega_new)):
169 | omega_new[iw] -= gw.mo_energy[0][3]
170 |
171 | space_max = 0.
172 | for i in range(1,nkpts_band):
173 | if kpath[i]-kpath[i-1] > space_max:
174 | space_max = kpath[i]-kpath[i-1]
175 | k_max = (nkpts_band-1)*space_max
176 | kpath_new = np.linspace(0,k_max,nkpts_band)
177 |
178 | sp_points_new = np.zeros_like(sp_points)
179 | for i in range(len(sp_points)):
180 | for j in range(nkpts_band):
181 | if sp_points[i] == kpath[j]:
182 | sp_points_new[i] = kpath_new[j]
183 |
184 | xi = kpath_new
185 | yi = omega_new*27.211386
186 | fig = plt.subplots(figsize=(3.375,1.8))
187 | ax = plt.subplot(111)
188 | interpolation_method = 'gaussian'
189 | extent = (xi[0],xi[-1],yi[0],yi[-1])
190 | plt.imshow(dens, cmap='viridis', aspect=0.09, extent=extent, origin='lower', interpolation=interpolation_method)
191 | cbar = plt.colorbar()
192 | cbar.set_label('DOS [1/eV]', size=6)
193 | cbar.ax.tick_params(labelsize=6)
194 |
195 | emin = yi[0]
196 | emax = yi[-1]
197 | ax.axis(xmin=0, xmax=sp_points_new[-1], ymin=emin, ymax=emax)
198 | plt.xticks(sp_points_new, ['%s' % n for n in ['L', r'$\Gamma$', 'X', 'W', 'K', r'$\Gamma$']])
199 |
200 | for p in sp_points_new:
201 | ax.plot([p, p], [emin, emax], '-', color='k', linewidth=0.6)
202 | ax.plot([0, sp_points_new[-1]], [0, 0], '--', color='k',linewidth=0.6)
203 |
204 | au2ev = 27.211386
205 | for n in range(nbands):
206 | ax.plot(kpath_new, [e[n]*au2ev for e in e_kn_2], '--',dashes=([2.2,1.4]),alpha=0.6,linewidth=0.6,color='white')
207 |
208 | ax.set_ylabel('Energy(eV)',fontsize=9)
209 | ax.yaxis.labelpad = -1
210 |
211 | major_yticks=np.arange(-25,30.1,5.0)
212 | #minor_yticks=np.arange(-25,20.1,1.0)
213 | ax.set_yticks(major_yticks)
214 | #ax.set_yticks(minor_yticks,minor=True)
215 | for axis in ['top','bottom','left','right']:
216 | ax.spines[axis].set_linewidth(0.5)
217 | ax.tick_params(axis='both',which='major',labelsize=8)
218 | ax.tick_params(axis='both',which='major',length=2.4,width=0.4,pad=2)
219 | ax.tick_params(axis='both',which='minor',length=1.5,width=0.4)
220 |
221 | plt.subplots_adjust(left=0.08,right=0.99,bottom=0.10,top=0.95)
222 | plt.savefig('diamond_444_GW_iao.png', dpi=600)
223 |
--------------------------------------------------------------------------------
/examples/interpolation/diamond_hf_interpolate.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from pyscf.pbc import df, gto, dft, scf
3 | from pyscf.pbc.lib import chkfile
4 | import os
5 | import matplotlib.pyplot as plt
6 | from ase.lattice import bulk
7 | from ase.dft.kpoints import sc_special_points as special_points, get_bandpath
8 | from fcdmft.utils import interpolate
9 |
10 | '''
11 | HF Wannier band interpolation:
12 | Step 1: Get LDA bands at larger k-mesh (6x6x6) from get_bands (non-SCF diagonalization)
13 | Step 2: Interpolate LDA bands at random kpts_band using 6x6x6 results -> fock_dft_band
14 | Step 3: Interpolate difference between HF and LDA (deltaFock) at kpts_band using 4x4x4 results ->
15 | dfock_band_lo, then get HF bands: fock_dft_band + dfock_band_lo
16 |
17 | Note: Currently a k-mesh must be used for constructing Wannier orbitals
18 | '''
19 |
20 | cell = gto.Cell()
21 | cell.build(unit = 'angstrom',
22 | a = np.array([[0.000000, 1.783500, 1.783500],
23 | [1.783500, 0.000000, 1.783500],
24 | [1.783500, 1.783500, 0.000000]]),
25 | atom = 'C 1.337625 1.337625 1.337625; C 2.229375 2.229375 2.229375',
26 | dimension = 3,
27 | max_memory = 32000,
28 | verbose = 4,
29 | pseudo = 'gth-pade',
30 | basis='gth-dzv',
31 | precision=1e-10)
32 |
33 | kmesh = [4,4,4]
34 | kpts = cell.make_kpts(kmesh,scaled_center=[0,0,0])
35 | gdf = df.GDF(cell, kpts)
36 | gdf_fname = 'gdf_ints_444.h5'
37 | gdf._cderi_to_save = gdf_fname
38 | if not os.path.isfile(gdf_fname):
39 | gdf.build()
40 |
41 | chkfname = 'diamond_444.chk'
42 | if os.path.isfile(chkfname):
43 | kmf = dft.KRKS(cell, kpts)
44 | kmf.with_df = gdf
45 | kmf.with_df._cderi = gdf_fname
46 | data = chkfile.load(chkfname, 'scf')
47 | kmf.__dict__.update(data)
48 | else:
49 | kmf = dft.KRKS(cell, kpts)
50 | kmf.with_df = gdf
51 | kmf.with_df._cderi = gdf_fname
52 | kmf.conv_tol = 1e-12
53 | kmf.chkfile = chkfname
54 | kmf.kernel()
55 |
56 | from libdmet_solid.basis_transform import make_basis
57 | from libdmet_solid.lo import pywannier90
58 | # valence Wannier orbitals
59 | num_wann = 8
60 | keywords = \
61 | '''
62 | num_iter = 1000
63 | begin projections
64 | C:sp3
65 | end projections
66 | exclude_bands : 9-%s
67 | num_cg_steps = 100
68 | precond = T
69 | '''%(kmf.cell.nao_nr())
70 |
71 | w90 = pywannier90.W90(kmf, kmesh, num_wann, other_keywords = keywords)
72 | #w90.use_atomic = True
73 | #w90.use_bloch_phases = True
74 | #w90.use_scdm = True
75 | #w90.guiding_centres = False
76 | w90.kernel()
77 |
78 | C_ao_mo = np.asarray(w90.mo_coeff)[:, :, w90.band_included_list]
79 | C_mo_lo = make_basis.tile_u_matrix(np.array(w90.U_matrix.transpose(2, 0, 1), \
80 | order='C'), u_virt=None, u_core=None)
81 | C_ao_lo = make_basis.multiply_basis(C_ao_mo, C_mo_lo)
82 | nbands = C_ao_lo.shape[-1]
83 |
84 | # set up band_kpts
85 | points = special_points['fcc']
86 | G = points['G']
87 | X = points['X']
88 | W = points['W']
89 | K = points['K']
90 | L = points['L']
91 | band_kpts, kpath, sp_points = get_bandpath([L, G, X, W, K, G], cell.a, npoints=50)
92 | band_kpts = cell.get_abs_kpts(band_kpts)
93 |
94 | # get DFT bands for a large k-mesh
95 | kmesh_L = [6,6,6]
96 | kpts_L = cell.make_kpts(kmesh_L,scaled_center=[0,0,0])
97 | gdf2 = df.GDF(cell, kpts)
98 | gdf2_fname = 'gdf_ints_large.h5'
99 | gdf2._cderi_to_save = gdf2_fname
100 | gdf2.auxbasis = gdf.auxbasis
101 | gdf2.kpts_band = kpts_L
102 | if not os.path.isfile(gdf2_fname):
103 | gdf2._j_only = True
104 | gdf2.build(j_only=True, kpts_band=kpts_L)
105 |
106 | kmf2 = dft.KRKS(cell, kpts).density_fit()
107 | kmf2.xc = kmf.xc
108 | kmf2.exxdiv = kmf.exxdiv
109 | if hasattr(kmf, 'sigma'):
110 | kmf2 = scf.addons.smearing_(kmf2, sigma=kmf.sigma, method="fermi")
111 | kmf2.with_df = gdf2
112 | kmf2.with_df._cderi = gdf2_fname
113 | kmf2.mo_energy = kmf.mo_energy
114 | kmf2.mo_occ = kmf.mo_occ
115 | kmf2.mo_coeff = kmf.mo_coeff
116 |
117 | mo_energy_L, mo_coeff_L, hcore_L, veff_L = interpolate.get_bands(kmf2, kpts_L)
118 |
119 | # set up a new mean-field object at large k-mesh
120 | kmf3 = dft.KRKS(cell, kpts_L).density_fit()
121 | kmf3.xc = kmf.xc
122 | kmf3.exxdiv = kmf.exxdiv
123 | if hasattr(kmf, 'sigma'):
124 | kmf3 = scf.addons.smearing_(kmf3, sigma=kmf.sigma, method="fermi")
125 | kmf3.mo_energy = mo_energy_L
126 | kmf3.mo_coeff = mo_coeff_L
127 | kmf3.mo_occ = kmf3.get_occ(mo_energy_kpts=mo_energy_L, mo_coeff_kpts=mo_coeff_L)
128 |
129 | # Wannier basis for large k-mesh
130 | w90_L = pywannier90.W90(kmf3, kmesh_L, num_wann, other_keywords = keywords)
131 | w90_L.kernel()
132 | C_ao_mo = np.asarray(w90_L.mo_coeff)[:, :, w90_L.band_included_list]
133 | C_mo_lo = make_basis.tile_u_matrix(np.array(w90_L.U_matrix.transpose(2, 0, 1), \
134 | order='C'), u_virt=None, u_core=None)
135 | C_ao_lo_L = make_basis.multiply_basis(C_ao_mo, C_mo_lo)
136 |
137 | # Make sure two sets of wannier orbitals have same order and phase
138 | # Search for Gamma point in kpts_L
139 | idx_G = None
140 | for i in range(len(kpts_L)):
141 | if np.linalg.norm(kpts_L[i]-kpts[0]) < 1e-8:
142 | idx_G = i
143 | break
144 | assert (idx_G is not None)
145 | ovlp = np.dot(C_ao_lo[0].T.conj(), kmf.get_ovlp()[0]).dot(C_ao_lo_L[idx_G])
146 | C_ao_lo_L_ordered = np.zeros_like(C_ao_lo_L)
147 | for i in range(ovlp.shape[0]):
148 | idx = np.argmax(np.abs(ovlp[i]))
149 | C_ao_lo_L_ordered[:,:,i] = C_ao_lo_L[:,:,idx]
150 | if (ovlp[i,idx].real < 0):
151 | C_ao_lo_L_ordered[:,:,i] = -C_ao_lo_L_ordered[:,:,i]
152 | C_ao_lo_L = C_ao_lo_L_ordered
153 |
154 | # Get DFT Fock at band_kpts through interpolation
155 | mo_energy_band, mo_coeff_band, fock_dft_band = interpolate.interpolate_mf(kmf3, band_kpts, C_ao_lo=C_ao_lo_L,
156 | veff=veff_L, hcore=hcore_L, w90=w90_L)
157 |
158 | # Get HF bands at band_kpts through interpolating veff diff
159 | e_kn = interpolate.interpolate_hf_diff(kmf, band_kpts, fock_dft_band, C_ao_lo=C_ao_lo, w90=w90)[0]
160 | vbmax = -99
161 | for en in e_kn:
162 | vb_k = en[cell.nelectron//2-1]
163 | if vb_k > vbmax:
164 | vbmax = vb_k
165 | e_kn = [en - vbmax for en in e_kn]
166 |
167 | # Get HF bands at band_kpts through interpolating mo diff
168 | e_kn_2 = interpolate.interpolate_hf_diff(kmf, band_kpts, fock_dft_band, mo_interpolate=True, C_ao_lo=C_ao_lo, w90=w90)[0]
169 | vbmax = -99
170 | for en in e_kn_2:
171 | vb_k = en[cell.nelectron//2-1]
172 | if vb_k > vbmax:
173 | vbmax = vb_k
174 | e_kn_2 = [en - vbmax for en in e_kn_2]
175 |
176 | au2ev = 27.21139
177 | emin = -1.2*au2ev
178 | emax = 1.2*au2ev
179 |
180 | plt.figure(figsize=(5, 6))
181 | for n in range(nbands):
182 | plt.plot(kpath, [e[n]*au2ev for e in e_kn_2], color='orange', alpha=0.7)
183 | plt.plot(kpath, [e[n]*au2ev for e in e_kn], color='#4169E1')
184 | for p in sp_points:
185 | plt.plot([p, p], [emin, emax], 'k-')
186 | plt.plot([0, sp_points[-1]], [0, 0], 'k-')
187 | plt.xticks(sp_points, ['$%s$' % n for n in ['L', r'\Gamma', 'X', 'W', 'K', r'\Gamma']])
188 | plt.axis(xmin=0, xmax=sp_points[-1], ymin=emin, ymax=emax)
189 | plt.xlabel('k-vector')
190 | plt.savefig('diamond_444_hf.png',dpi=600)
191 |
--------------------------------------------------------------------------------
/fcdmft/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZhuGroup-Yale/fcdmft/98d93f863bc1ad9dc9d17982de4f5e89581a811c/fcdmft/__init__.py
--------------------------------------------------------------------------------
/fcdmft/dmft/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZhuGroup-Yale/fcdmft/98d93f863bc1ad9dc9d17982de4f5e89581a811c/fcdmft/dmft/__init__.py
--------------------------------------------------------------------------------
/fcdmft/gw/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZhuGroup-Yale/fcdmft/98d93f863bc1ad9dc9d17982de4f5e89581a811c/fcdmft/gw/__init__.py
--------------------------------------------------------------------------------
/fcdmft/gw/mol/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZhuGroup-Yale/fcdmft/98d93f863bc1ad9dc9d17982de4f5e89581a811c/fcdmft/gw/mol/__init__.py
--------------------------------------------------------------------------------
/fcdmft/gw/mol/gw_dc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2014-2021 The PySCF Developers. All Rights Reserved.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 | # Author: Tianyu Zhu
17 | #
18 |
19 | """
20 | Spin-restricted G0W0 double counting self-energy term in GW+DMFT
21 |
22 | Method:
23 | T. Zhu and G.K.-L. Chan, Phys. Rev. X 11, 021006 (2021)
24 | T. Zhu and G.K.-L. Chan, J. Chem. Theory. Comput. 17, 727-741 (2021)
25 | Compute polarizability on imaginary time, then transform to imag frequency
26 | to compute self-energy, then analytically continued to real frequency
27 |
28 | Other useful references:
29 | J. Phys. Chem. Lett. 9, 306 (2018)
30 | Phys. Rev. B 94, 165109 (2016)
31 | """
32 |
33 | import time, h5py
34 | from functools import reduce
35 | import numpy
36 | import numpy as np
37 |
38 | from pyscf import lib
39 | from pyscf.lib import logger
40 | from pyscf.ao2mo import _ao2mo
41 | from pyscf import gto, df, dft, scf
42 | from pyscf.mp.mp2 import get_nocc, get_nmo, get_frozen_mask
43 | from pyscf import __config__
44 | from fcdmft.gw.mol.gw_ac import _get_scaled_legendre_roots, \
45 | two_pole, pade_thiele, GWAC, AC_twopole_full, AC_pade_thiele_full
46 |
47 | einsum = lib.einsum
48 |
49 | def kernel(gw, gfomega, Lpq=None, kmf=None, C_mo_lo=None, orbs=None,
50 | nw=None, nt=None, verbose=logger.NOTE, small_mem=False):
51 | '''
52 | Returns:
53 | sigma : GW double counting self-energy on real axis
54 | '''
55 | mf = gw._scf
56 | assert(gw.frozen == 0)
57 |
58 | if orbs is None:
59 | orbs = range(gw.nmo)
60 | norbs = len(orbs)
61 |
62 | nmo = gw.nmo
63 | nocc = gw.nocc
64 | assert(gw.ef)
65 | ef = gw.ef
66 |
67 | # Imaginary frequency grids
68 | freqs, wts_w = _get_scaled_legendre_roots(nw)
69 |
70 | # Imaginary time grids
71 | time, wts_t = _get_scaled_legendre_roots(nt, x0=1.0)
72 |
73 | eta = gw.eta
74 | nomega = len(gfomega)
75 | sigma = np.zeros((nmo,nmo,nomega),dtype=np.complex128)
76 |
77 | # Compute full self-energy on imaginary axis i*[0,iw_cutoff]
78 | sigmaI, omega = get_sigma_full(gw, orbs, Lpq, kmf, C_mo_lo,
79 | freqs, wts_w, time, wts_t, iw_cutoff=5., small_mem=small_mem)
80 | fn = 'gw_dc_sigmaI.h5'
81 | feri = h5py.File(fn, 'w')
82 | feri['sigmaI'] = np.asarray(sigmaI)
83 | feri['omega'] = np.asarray(omega)
84 | feri.close()
85 |
86 | # Analytic continuation
87 | if gw.ac == 'twopole':
88 | coeff = AC_twopole_full(sigmaI, omega, orbs, nocc)
89 | elif gw.ac == 'pade':
90 | coeff, omega_fit = AC_pade_thiele_full(sigmaI, omega, npts=18, step_ratio=2.5/3.0)
91 |
92 | # Compute real-axis self-energy
93 | for p in orbs:
94 | for q in orbs:
95 | if gw.ac == 'twopole':
96 | sigma[p,q] = two_pole(gfomega-ef+1j*eta, coeff[:,p-orbs[0],q-orbs[0]])
97 | elif gw.ac == 'pade':
98 | sigma[p,q] = pade_thiele(gfomega-ef+1j*eta, omega_fit, coeff[:,p-orbs[0],q-orbs[0]])
99 |
100 | fn = 'imp_ac_coeff.h5'
101 | feri = h5py.File(fn, 'w')
102 | feri['coeff'] = np.asarray(coeff)
103 | feri['fermi'] = np.asarray(ef)
104 | feri['omega_fit'] = np.asarray(omega_fit)
105 | feri.close()
106 |
107 | return sigma
108 |
109 | def get_sigma_full(gw, orbs, Lpq, kmf, C_mo_lo, freqs, wts_w, time, wts_t, iw_cutoff=None, small_mem=False):
110 | '''
111 | Compute GW correlation self-energy (all elements) in LO basis
112 | on imaginary axis
113 | '''
114 | nmo = gw.nmo
115 | nw = len(freqs)
116 | naux = Lpq.shape[0]
117 | norbs = len(orbs)
118 | nocc = gw.nocc
119 | ef = gw.ef
120 |
121 | print('### computing polarization in imag time and freq domain ###')
122 | tchunk = 100
123 | n_tchunk = len(time) // tchunk
124 | tlist = []; wtslist = []
125 | for i in range(n_tchunk):
126 | tlist.append(time[i*tchunk:(i+1)*tchunk])
127 | wtslist.append(wts_t[i*tchunk:(i+1)*tchunk])
128 | if len(time) % tchunk != 0:
129 | tlist.append(time[n_tchunk*tchunk:])
130 | wtslist.append(wts_t[n_tchunk*tchunk:])
131 | n_tchunk += 1
132 |
133 | # Integration on numerical grids
134 | if iw_cutoff is not None:
135 | nw_sigma = sum(iw < iw_cutoff for iw in freqs) + 1
136 | else:
137 | nw_sigma = nw + 1
138 |
139 | omega = np.zeros((nw_sigma),dtype=np.complex128)
140 | omega[0] = 1j*0.
141 | omega[1:] = 1j*freqs[:(nw_sigma-1)]
142 |
143 | # Compute time-domain density response kernel and transform to freq domain
144 | Pi = np.zeros((naux,naux,nw),dtype=np.complex128)
145 | for i in range(n_tchunk):
146 | Pi_t = get_response_t(kmf, nocc, C_mo_lo, tlist[i], Lpq, ef)
147 | for w in range(nw):
148 | Pi[:,:,w] += CT_t_to_w(Pi_t, tlist[i], wtslist[i], freqs[w])
149 |
150 | print('### computing self-energy in imag freq domain ###')
151 | sigma = np.zeros((norbs,norbs,nw_sigma),dtype=np.complex128)
152 | if small_mem:
153 | for w in range(nw):
154 | Pi_inv = np.linalg.inv(np.eye(naux)-Pi[:,:,w])-np.eye(naux)
155 | Qnu = einsum('Pnu,PQ->Qnu',Lpq[:,orbs,:],Pi_inv)
156 | g0_pos = get_g0_w_from_kmf(kmf, C_mo_lo, ef, omega+1j*freqs[w])
157 | g0_neg = get_g0_w_from_kmf(kmf, C_mo_lo, ef, omega-1j*freqs[w])
158 | for w2 in range(nw_sigma):
159 | Qnv = -wts_w[w] * einsum('Qnu,uv->Qnv',Qnu,g0_pos[:,:,w2]+g0_neg[:,:,w2]) / 2. / np.pi
160 | sigma[:,:,w2] += einsum('Qnv,Qvl->nl',Qnv,Lpq[:,:,orbs])
161 | else:
162 | Qnvw = np.zeros((naux,norbs,nmo,nw_sigma),dtype=np.complex128)
163 | for w in range(nw):
164 | Pi_inv = np.linalg.inv(np.eye(naux)-Pi[:,:,w])-np.eye(naux)
165 | Qnu = einsum('Pnu,PQ->Qnu',Lpq[:,orbs,:],Pi_inv)
166 | g0_pos = get_g0_w_from_kmf(kmf, C_mo_lo, ef, omega+1j*freqs[w])
167 | g0_neg = get_g0_w_from_kmf(kmf, C_mo_lo, ef, omega-1j*freqs[w])
168 | Qnvw += -wts_w[w] * einsum('Qnu,uvw->Qnvw',Qnu,g0_pos+g0_neg) / 2. / np.pi
169 | sigma = einsum('Qnvw,Qvl->nlw',Qnvw,Lpq[:,:,orbs])
170 |
171 | return sigma, omega
172 |
173 | def get_response_t(kmf, nocc, C_mo_lo, time, Lpq, mu):
174 | """
175 | Compute polarization in time domain
176 | """
177 | mo_occ = [x/2. for x in kmf.mo_occ]
178 | nkpts = len(mo_occ)
179 | nmo = len(kmf.mo_energy[0])
180 | # Approximate metal as gapped system
181 | # TODO: exact treatment of metal
182 | for k in range(nkpts):
183 | for i in range(nmo):
184 | if mo_occ[k][i] > 0.5:
185 | mo_occ[k][i] = 1.0
186 | else:
187 | mo_occ[k][i] = 0.0
188 |
189 | nt = len(time)
190 | naux = Lpq.shape[0]
191 | PQ = np.zeros((naux,naux,nt))
192 |
193 | for t in range(nt):
194 | g0_pos = get_g0_t_from_kmf(kmf, mo_occ, C_mo_lo, mu, time[t])
195 | g0_neg = get_g0_t_from_kmf(kmf, mo_occ, C_mo_lo, mu, -time[t])
196 | Pkj = einsum('Pij,ki->Pkj',Lpq,g0_pos)
197 | Qkj = einsum('Qkl,lj->Qkj',Lpq,g0_neg)
198 | PQ[:,:,t] = 2. * einsum('Pkj,Qkj->PQ',Pkj,Qkj)
199 | return PQ
200 |
201 | def get_g0_t_from_kmf(kmf, mo_occ, C_mo_lo, mu, time):
202 | """
203 | Get impurity imaginary-time mean-field Green's function in LO basis
204 | """
205 | mo_energy = np.asarray(kmf.mo_energy)
206 | nlo = C_mo_lo.shape[-1]
207 | nkpts, nmo = mo_energy.shape
208 | g0 = np.zeros((nkpts,nmo,nmo))
209 | for k in range(nkpts):
210 | if time < 0.:
211 | idx = np.where(mo_occ[k] > 0.99)[0]
212 | g0[k,idx,idx] = np.exp(-(mo_energy[k][idx]-mu)*time) * mo_occ[k][idx]
213 | else:
214 | idx = np.where(mo_occ[k] < 0.01)[0]
215 | g0[k,idx,idx] = -np.exp(-(mo_energy[k][idx]-mu)*time) * (1.-mo_occ[k][idx])
216 |
217 | g0_lo = np.zeros((nkpts,nlo,nlo),dtype=np.complex128)
218 | for k in range(nkpts):
219 | g0_lo[k,:,:] = np.dot(np.dot(C_mo_lo[0,k].T.conj(), g0[k,:,:]), C_mo_lo[0,k])
220 |
221 | g0_imp = g0_lo.sum(axis=0)/nkpts
222 |
223 | return g0_imp.real
224 |
225 | def get_g0_w_from_kmf(kmf, C_mo_lo, mu, freqs):
226 | """
227 | Get impurity imaginary-freq mean-field Green's function in LO basis
228 | """
229 | mo_energy = np.asarray(kmf.mo_energy)
230 | nlo = C_mo_lo.shape[-1]
231 | nkpts, nmo = mo_energy.shape
232 | nw = len(freqs)
233 | g0 = np.zeros((nkpts,nmo,nmo,nw),np.complex128)
234 | for iw in range(nw):
235 | for k in range(nkpts):
236 | g0[k,:,:,iw] = np.diag(1./(freqs[iw]+mu-mo_energy[k]))
237 |
238 | g0_lo = np.zeros((nkpts,nlo,nlo,nw),np.complex128)
239 | for iw in range(nw):
240 | for k in range(nkpts):
241 | g0_lo[k,:,:,iw] = reduce(numpy.dot, (C_mo_lo[0,k].T.conj(), g0[k,:,:,iw], C_mo_lo[0,k]))
242 |
243 | g0_imp = g0_lo.sum(axis=0)/nkpts
244 |
245 | return g0_imp
246 |
247 | def CT_t_to_w(Gt, time, wts, omega):
248 | """
249 | Cosine transform of even function from time to frequency
250 | """
251 | cos_tw = einsum('t,t->t',np.cos(time*omega),wts)
252 | Gw = 2. * einsum('PQt,t->PQ',Gt,cos_tw)
253 | return Gw
254 |
255 |
256 | class GWGF(GWAC):
257 |
258 | eta = getattr(__config__, 'gw_dc_GWGF_eta', 5e-3)
259 | # Analytic continuation: pade or twopole
260 | ac = getattr(__config__, 'gw_dc_GWGF_ac', 'pade')
261 |
262 | def __init__(self, mf, frozen=0):
263 | GWAC.__init__(self, mf, frozen=0)
264 | #TODO: implement frozen orbs
265 | if frozen > 0:
266 | raise NotImplementedError
267 | self.frozen = frozen
268 | self.ef = None
269 |
270 | keys = set(('eta','ac'))
271 | self._keys = set(self.__dict__.keys()).union(keys)
272 |
273 | def dump_flags(self):
274 | log = logger.Logger(self.stdout, self.verbose)
275 | log.info('')
276 | log.info('******** %s ********', self.__class__)
277 | log.info('method = %s', self.__class__.__name__)
278 | nocc = self.nocc
279 | nvir = self.nmo - nocc
280 | log.info('GW nocc = %d, nvir = %d', nocc, nvir)
281 | if self.frozen > 0:
282 | log.info('frozen orbitals = %d', self.frozen)
283 | logger.info(self, 'analytic continuation method = %s', self.ac)
284 | return self
285 |
286 | get_nocc = get_nocc
287 | get_nmo = get_nmo
288 | get_frozen_mask = get_frozen_mask
289 |
290 | def kernel(self, omega, Lpq=None, kmf=None, C_mo_lo=None, orbs=None, nw=100, nt=2000, small_mem=False):
291 | """
292 | Args:
293 | omega : 1D array (nomega), real freq
294 | kmf : PBC mean-field class
295 | Lpq : 3D array (naux, nlo, nlo), 3-index ERI
296 | C_mo_lo: 4D array (spin, nkpts, nmo, nlo), transformation matrix MO -> LO
297 | orbs: list, orbital indices
298 | nw: interger, grid number
299 |
300 | Returns:
301 | self.sigma : 3D array (nlo, nlo, nomega), GW self-energy (double counting)
302 | """
303 | cput0 = (time.process_time(), time.perf_counter())
304 | self.dump_flags()
305 |
306 | naux, nao, nao = Lpq.shape
307 | mem_incore = (2*nao**2*naux*nw + naux**2*100) * 8 / 1e6
308 | mem_now = lib.current_memory()[0]
309 | if (mem_incore + mem_now > 0.95 * self.max_memory):
310 | mem_incore_small = (nao**2*naux + naux**2*100) * 16 / 1e6
311 | if (mem_incore_small + mem_now < 0.95 * self.max_memory):
312 | small_mem = True
313 | else:
314 | logger.warn(self, 'Memory may not be enough, even with the small memory option!')
315 | raise NotImplementedError
316 |
317 | self.sigma = kernel(self, omega, Lpq=Lpq, kmf=kmf,
318 | C_mo_lo=C_mo_lo, orbs=orbs, nw=nw, nt=nt, verbose=self.verbose, small_mem=small_mem)
319 |
320 | logger.timer(self, 'GWGF', *cput0)
321 | return self.sigma
322 |
--------------------------------------------------------------------------------
/fcdmft/gw/mol/ugw_dc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2014-2021 The PySCF Developers. All Rights Reserved.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 | # Author: Tianyu Zhu
17 | #
18 |
19 | """
20 | Spin-unrestricted G0W0 double counting self-energy term in GW+DMFT
21 |
22 | Method:
23 | T. Zhu and G.K.-L. Chan, Phys. Rev. X 11, 021006 (2021)
24 | T. Zhu and G.K.-L. Chan, J. Chem. Theory. Comput. 17, 727-741 (2021)
25 | Compute polarizability on imaginary time, then transform to imag frequency
26 | to compute self-energy, then analytically continued to real frequency
27 |
28 | Other useful references:
29 | J. Phys. Chem. Lett. 9, 306 (2018)
30 | Phys. Rev. B 94, 165109 (2016)
31 | """
32 |
33 | import time, h5py
34 | from functools import reduce
35 | import numpy
36 | import numpy as np
37 |
38 | from pyscf import lib
39 | from pyscf.lib import logger
40 | from pyscf.ao2mo import _ao2mo
41 | from pyscf import gto, df, dft, scf
42 | from pyscf.mp.ump2 import get_nocc, get_nmo, get_frozen_mask
43 | from pyscf import __config__
44 | from fcdmft.gw.mol.gw_ac import _get_scaled_legendre_roots, \
45 | two_pole, pade_thiele, AC_twopole_full, AC_pade_thiele_full
46 | from fcdmft.gw.mol.ugw_ac import UGWAC
47 | from fcdmft.gw.mol.gw_dc import CT_t_to_w
48 |
49 | einsum = lib.einsum
50 |
51 | def kernel(gw, gfomega, Lpq=None, kmf=None, C_mo_lo=None, orbs=None,
52 | nw=None, nt=None, verbose=logger.NOTE, small_mem=False):
53 | '''
54 | Returns:
55 | sigma : GW double counting self-energy on real axis
56 | '''
57 | mf = gw._scf
58 | assert(gw.frozen == 0)
59 |
60 | nocca, noccb = gw.nocc
61 | nmoa, nmob = gw.nmo
62 | nvira = nmoa - nocca
63 | nvirb = nmob - noccb
64 | assert(gw.ef)
65 | ef = gw.ef
66 |
67 | if orbs is None:
68 | orbs = range(nmoa)
69 |
70 | # Imaginary frequency grids
71 | freqs, wts_w = _get_scaled_legendre_roots(nw)
72 |
73 | # Imaginary time grids
74 | time, wts_t = _get_scaled_legendre_roots(nt, x0=1.0)
75 |
76 | eta = gw.eta
77 | nomega = len(gfomega)
78 | sigma = np.zeros((2,nmoa,nmoa,nomega),dtype=np.complex128)
79 |
80 | # Compute full self-energy on imaginary axis i*[0,iw_cutoff]
81 | sigmaI,omega = get_sigma_full(gw, orbs, Lpq, kmf, C_mo_lo,
82 | freqs, wts_w, time, wts_t, iw_cutoff=5., small_mem=small_mem)
83 | fn = 'gw_dc_sigmaI.h5'
84 | feri = h5py.File(fn, 'w')
85 | feri['sigmaI'] = np.asarray(sigmaI)
86 | feri['omega'] = np.asarray(omega)
87 | feri.close()
88 |
89 | # Analytic continuation
90 | if gw.ac == 'twopole':
91 | coeff_a = AC_twopole_full(sigmaI[0], omega, orbs, nocca)
92 | coeff_b = AC_twopole_full(sigmaI[1], omega, orbs, noccb)
93 | elif gw.ac == 'pade':
94 | coeff_a, omega_fit_a = AC_pade_thiele_full(sigmaI[0], omega, npts=18, step_ratio=2.5/3.0)
95 | coeff_b, omega_fit_b = AC_pade_thiele_full(sigmaI[1], omega, npts=18, step_ratio=2.5/3.0)
96 | omega_fit = omega_fit_a
97 | coeff = np.asarray((coeff_a,coeff_b))
98 |
99 | # Compute real-axis self-energy
100 | for s in range(2):
101 | for p in orbs:
102 | for q in orbs:
103 | if gw.ac == 'twopole':
104 | sigma[s,p,q] = two_pole(gfomega-ef+1j*eta, coeff[s,:,p-orbs[0],q-orbs[0]])
105 | elif gw.ac == 'pade':
106 | sigma[s,p,q] = pade_thiele(gfomega-ef+1j*eta, omega_fit, coeff[s,:,p-orbs[0],q-orbs[0]])
107 |
108 | fn = 'imp_ac_coeff.h5'
109 | feri = h5py.File(fn, 'w')
110 | feri['coeff'] = np.asarray(coeff)
111 | feri['fermi'] = np.asarray(ef)
112 | feri['omega_fit'] = np.asarray(omega_fit)
113 | feri.close()
114 |
115 | return sigma
116 |
117 | def get_sigma_full(gw, orbs, Lpq, kmf, C_mo_lo, freqs, wts_w, time, wts_t, iw_cutoff=None, small_mem=False):
118 | '''
119 | Compute GW correlation self-energy (all elements) in AO basis
120 | on imaginary axis
121 | '''
122 | nocca, noccb = gw.nocc
123 | nmoa, nmob = gw.nmo
124 | nw = len(freqs)
125 | naux = Lpq.shape[0]
126 | norbs = len(orbs)
127 | ef = gw.ef
128 |
129 | print('### computing polarization in imag time and freq domain ###')
130 | tchunk = 100
131 | n_tchunk = len(time) // tchunk
132 | tlist = []; wtslist = []
133 | for i in range(n_tchunk):
134 | tlist.append(time[i*tchunk:(i+1)*tchunk])
135 | wtslist.append(wts_t[i*tchunk:(i+1)*tchunk])
136 | if len(time) % tchunk != 0:
137 | tlist.append(time[n_tchunk*tchunk:])
138 | wtslist.append(wts_t[n_tchunk*tchunk:])
139 | n_tchunk += 1
140 |
141 | # Integration on numerical grids
142 | if iw_cutoff is not None:
143 | nw_sigma = sum(iw < iw_cutoff for iw in freqs) + 1
144 | else:
145 | nw_sigma = nw + 1
146 |
147 | omega = np.zeros((nw_sigma),dtype=np.complex128)
148 | omega[0] = 1j*0.
149 | omega[1:] = 1j*freqs[:(nw_sigma-1)]
150 |
151 | # Compute time-domain density response kernel and transform to freq domain
152 | Pi = np.zeros((naux,naux,nw),dtype=np.complex128)
153 | for i in range(n_tchunk):
154 | Pi_t = get_response_t(kmf, gw.nocc, C_mo_lo, tlist[i], Lpq, ef)
155 | for w in range(nw):
156 | Pi[:,:,w] += CT_t_to_w(Pi_t, tlist[i], wtslist[i], freqs[w])
157 |
158 | print('### computing self-energy in imag freq domain ###')
159 | sigma = np.zeros((2,norbs,norbs,nw_sigma),dtype=np.complex128)
160 | if small_mem:
161 | for w in range(nw):
162 | Pi_inv = np.linalg.inv(np.eye(naux)-Pi[:,:,w])-np.eye(naux)
163 | Qnu = einsum('Pnu,PQ->Qnu',Lpq[:,orbs,:],Pi_inv)
164 | g0_pos = get_g0_w_from_kmf(kmf, C_mo_lo, ef, omega+1j*freqs[w])
165 | g0_neg = get_g0_w_from_kmf(kmf, C_mo_lo, ef, omega-1j*freqs[w])
166 | for w2 in range(nw_sigma):
167 | Qnv = -wts_w[w] * einsum('Qnu,suv->sQnv',Qnu,g0_pos[:,:,:,w2]+g0_neg[:,:,:,w2])/2./np.pi
168 | sigma[:,:,:,w2] += einsum('sQnv,Qvl->snl',Qnv,Lpq[:,:,orbs])
169 | else:
170 | Qnvw = np.zeros((2,naux,norbs,nmoa,nw_sigma),dtype=np.complex128)
171 | for w in range(nw):
172 | Pi_inv = np.linalg.inv(np.eye(naux)-Pi[:,:,w])-np.eye(naux)
173 | Qnu = einsum('Pnu,PQ->Qnu',Lpq[:,orbs,:],Pi_inv)
174 | g0_pos = get_g0_w_from_kmf(kmf, C_mo_lo, ef, omega+1j*freqs[w])
175 | g0_neg = get_g0_w_from_kmf(kmf, C_mo_lo, ef, omega-1j*freqs[w])
176 | Qnvw[0] += -wts_w[w] * einsum('Qnu,uvw->Qnvw',Qnu,g0_pos[0]+g0_neg[0])/2./np.pi
177 | Qnvw[1] += -wts_w[w] * einsum('Qnu,uvw->Qnvw',Qnu,g0_pos[1]+g0_neg[1])/2./np.pi
178 | sigma[0] = einsum('Qnvw,Qvl->nlw',Qnvw[0],Lpq[:,:,orbs])
179 | sigma[1] = einsum('Qnvw,Qvl->nlw',Qnvw[1],Lpq[:,:,orbs])
180 |
181 | return sigma, omega
182 |
183 | def get_response_t(kmf, nocc, C_mo_lo, time, Lpq, mu):
184 | """
185 | Compute polarization in time domain
186 | """
187 | nt = len(time)
188 | naux = Lpq.shape[0]
189 | PQ = np.zeros((naux,naux,nt))
190 | for t in range(nt):
191 | g0_pos = get_g0_t_from_kmf(kmf, nocc, C_mo_lo, mu, time[t])
192 | g0_neg = get_g0_t_from_kmf(kmf, nocc, C_mo_lo, mu, -time[t])
193 | Pkj_a = einsum('Pij,ki->Pkj',Lpq,g0_pos[0]).reshape(naux,-1)
194 | Pkj_b = einsum('Pij,ki->Pkj',Lpq,g0_pos[1]).reshape(naux,-1)
195 | Qkj_a = einsum('Qkl,lj->Qkj',Lpq,g0_neg[0]).reshape(naux,-1)
196 | Qkj_b = einsum('Qkl,lj->Qkj',Lpq,g0_neg[1]).reshape(naux,-1)
197 | PQ[:,:,t] = np.dot(Pkj_a,Qkj_a.transpose()) + np.dot(Pkj_b,Qkj_b.transpose())
198 | return PQ
199 |
200 | def get_g0_t_from_kmf(kmf, nocc, C_mo_lo, mu, time):
201 | """
202 | Get impurity imaginary-time mean-field Green's function in IAO basis
203 | """
204 | nocca, noccb = nocc
205 | mo_energy = np.asarray(kmf.mo_energy)
206 | nlo = C_mo_lo.shape[-1]
207 | spin, nkpts, nmo = mo_energy.shape
208 | g0 = np.zeros((spin,nkpts,nmo,nmo))
209 | for s in range(spin):
210 | noccs = nocc[s]
211 | if time < 0.:
212 | for k in range(nkpts):
213 | g0[s,k,:noccs,:noccs] = np.diag(np.exp(-(mo_energy[s][k,:noccs]-mu)*time))
214 | else:
215 | for k in range(nkpts):
216 | g0[s,k,noccs:,noccs:] = -np.diag(np.exp(-(mo_energy[s][k,noccs:]-mu)*time))
217 |
218 | g0_lo = np.zeros((spin,nkpts,nlo,nlo),dtype=np.complex128)
219 | for s in range(spin):
220 | for k in range(nkpts):
221 | g0_lo[s,k,:,:] = reduce(numpy.dot, (C_mo_lo[s,k].T.conj(), g0[s,k,:,:], C_mo_lo[s,k]))
222 |
223 | g0_imp = g0_lo.sum(axis=1)/nkpts
224 |
225 | return g0_imp.real
226 |
227 | def get_g0_w_from_kmf(kmf, C_mo_lo, mu, freqs):
228 | """
229 | Get impurity imaginary-freq mean-field Green's function in IAO basis
230 | """
231 | mo_energy = np.asarray(kmf.mo_energy)
232 | spin, nkpts, nmo = mo_energy.shape
233 | nlo = C_mo_lo.shape[-1]
234 | nw = len(freqs)
235 | g0 = np.zeros((spin,nkpts,nmo,nmo,nw),np.complex128)
236 | for s in range(spin):
237 | for iw in range(nw):
238 | for k in range(nkpts):
239 | g0[s,k,:,:,iw] = np.diag(1./(freqs[iw]+mu-mo_energy[s,k]))
240 |
241 | g0_lo = np.zeros((spin,nkpts,nlo,nlo,nw),np.complex128)
242 | for s in range(spin):
243 | for iw in range(nw):
244 | for k in range(nkpts):
245 | g0_lo[s,k,:,:,iw] = reduce(numpy.dot, (C_mo_lo[s,k].T.conj(), g0[s,k,:,:,iw], C_mo_lo[s,k]))
246 |
247 | g0_imp = g0_lo.sum(axis=1)/nkpts
248 |
249 | return g0_imp
250 |
251 |
252 | class UGWGF(UGWAC):
253 |
254 | eta = getattr(__config__, 'ugw_dc_UGWGF_eta', 5e-3)
255 | # Analytic continuation: pade or twopole
256 | ac = getattr(__config__, 'ugw_dc_UGWGF_ac', 'pade')
257 |
258 | def __init__(self, mf, frozen=0):
259 | UGWAC.__init__(self, mf, frozen=0)
260 | #TODO: implement frozen orbs
261 | if frozen > 0:
262 | raise NotImplementedError
263 | self.frozen = frozen
264 | self.ef = None
265 |
266 | keys = set(('eta','ac'))
267 | self._keys = set(self.__dict__.keys()).union(keys)
268 |
269 | def dump_flags(self):
270 | log = logger.Logger(self.stdout, self.verbose)
271 | log.info('')
272 | log.info('******** %s ********', self.__class__)
273 | log.info('method = %s', self.__class__.__name__)
274 | nocca, noccb = self.nocc
275 | nmoa, nmob = self.nmo
276 | nvira = nmoa - nocca
277 | nvirb = nmob - noccb
278 | log.info('GW (nocca, noccb) = (%d, %d), (nvira, nvirb) = (%d, %d)',
279 | nocca, noccb, nvira, nvirb)
280 | if self.frozen > 0:
281 | log.info('frozen orbitals = %s', str(self.frozen))
282 | logger.info(self, 'analytic continuation method = %s', self.ac)
283 | return self
284 |
285 | get_nocc = get_nocc
286 | get_nmo = get_nmo
287 | get_frozen_mask = get_frozen_mask
288 |
289 | def kernel(self, omega, Lpq=None, kmf=None, C_mo_lo=None, orbs=None, nw=100, nt=2000, small_mem=False):
290 | """
291 | Args:
292 | omega : 1D array (nomega), real freq
293 | kmf : PBC mean-field class
294 | Lpq : 4D array (2, naux, nlo, nlo), 3-index ERI
295 | C_mo_lo: 4D array (spin, nkpts, nmo, nlo), transformation matrix MO -> LO
296 | orbs: list, orbital indices
297 | nw: interger, grid number
298 |
299 | Returns:
300 | self.sigma : 4D array (2, nlo, nlo, nomega), GW self-energy (double counting)
301 | """
302 | cput0 = (time.process_time(), time.perf_counter())
303 | self.dump_flags()
304 |
305 | naux, nao, nao = Lpq.shape
306 | mem_incore = (3*nao**2*naux*nw + naux**2*100) * 16 / 1e6
307 | mem_now = lib.current_memory()[0]
308 | if (mem_incore + mem_now > 0.95 * self.max_memory):
309 | mem_incore_small = (2*nao**2*naux + naux**2*100) * 16 / 1e6
310 | if (mem_incore_small + mem_now < 0.95 * self.max_memory):
311 | small_mem = True
312 | else:
313 | logger.warn(self, 'Memory may not be enough, even with the small memory option!')
314 | raise NotImplementedError
315 |
316 | self.sigma = kernel(self, omega, Lpq=Lpq, kmf=kmf,
317 | C_mo_lo=C_mo_lo, orbs=orbs, nw=nw, nt=nt, verbose=self.verbose, small_mem=small_mem)
318 |
319 | logger.timer(self, 'UGWGF', *cput0)
320 | return self.sigma
321 |
--------------------------------------------------------------------------------
/fcdmft/gw/pbc/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZhuGroup-Yale/fcdmft/98d93f863bc1ad9dc9d17982de4f5e89581a811c/fcdmft/gw/pbc/__init__.py
--------------------------------------------------------------------------------
/fcdmft/rpa/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZhuGroup-Yale/fcdmft/98d93f863bc1ad9dc9d17982de4f5e89581a811c/fcdmft/rpa/__init__.py
--------------------------------------------------------------------------------
/fcdmft/rpa/mol/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZhuGroup-Yale/fcdmft/98d93f863bc1ad9dc9d17982de4f5e89581a811c/fcdmft/rpa/mol/__init__.py
--------------------------------------------------------------------------------
/fcdmft/rpa/mol/rpa.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2014-2021 The PySCF Developers. All Rights Reserved.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 | # Author: Tianyu Zhu
17 | #
18 |
19 | """
20 | Spin-restricted random phase approximation (direct RPA/dRPA in chemistry)
21 | with N^4 scaling
22 |
23 | Method:
24 | Main routines are based on GW-AC method descirbed in:
25 | T. Zhu and G.K.-L. Chan, J. Chem. Theory. Comput. 17, 727-741 (2021)
26 | X. Ren et al., New J. Phys. 14, 053020 (2012)
27 | """
28 |
29 | import time, h5py
30 | from functools import reduce
31 | import numpy as np
32 |
33 | from pyscf import lib
34 | from pyscf.lib import logger
35 | from pyscf.ao2mo import _ao2mo
36 | from pyscf import df, dft, scf
37 | from pyscf.mp.mp2 import get_nocc, get_nmo, get_frozen_mask
38 | from pyscf import __config__
39 |
40 | einsum = lib.einsum
41 |
42 | # ****************************************************************************
43 | # core routines, kernel, rpa_ecorr, rho_response
44 | # ****************************************************************************
45 |
46 | def kernel(rpa, mo_energy, mo_coeff, Lpq=None, nw=None, verbose=logger.NOTE):
47 | """
48 | RPA correlation and total energy
49 |
50 | Args:
51 | Lpq : density fitting 3-center integral in MO basis.
52 | nw : number of frequency point on imaginary axis.
53 | vhf_df : using density fitting integral to compute HF exchange.
54 |
55 | Returns:
56 | e_tot : RPA total energy
57 | e_hf : EXX energy
58 | e_corr : RPA correlation energy
59 | """
60 | mf = rpa._scf
61 | # only support frozen core
62 | if rpa.frozen is not None:
63 | assert isinstance(rpa.frozen, int)
64 | assert rpa.frozen < rpa.nocc
65 |
66 | if Lpq is None:
67 | Lpq = rpa.ao2mo(mo_coeff)
68 |
69 | # Grids for integration on imaginary axis
70 | freqs, wts = _get_scaled_legendre_roots(nw)
71 |
72 | # Compute HF exchange energy (EXX)
73 | dm = mf.make_rdm1()
74 | rhf = scf.RHF(rpa.mol)
75 | e_hf = rhf.energy_elec(dm=dm)[0]
76 | e_hf += mf.energy_nuc()
77 |
78 | # Compute RPA correlation energy
79 | e_corr = get_rpa_ecorr(rpa, Lpq, freqs, wts)
80 |
81 | # Compute totol energy
82 | e_tot = e_hf + e_corr
83 |
84 | logger.debug(rpa, ' RPA total energy = %s', e_tot)
85 | logger.debug(rpa, ' EXX energy = %s, RPA corr energy = %s', e_hf, e_corr)
86 |
87 | return e_tot, e_hf, e_corr
88 |
89 | def get_rpa_ecorr(rpa, Lpq, freqs, wts):
90 | """
91 | Compute RPA correlation energy
92 | """
93 | mo_energy = _mo_energy_without_core(rpa, rpa._scf.mo_energy)
94 | nocc = rpa.nocc
95 | nw = len(freqs)
96 | naux = Lpq.shape[0]
97 |
98 | if (mo_energy[nocc] - mo_energy[nocc-1]) < 1e-3:
99 | logger.warn(rpa, 'Current RPA code not well-defined for degeneracy!')
100 |
101 | e_corr = 0.
102 | for w in range(nw):
103 | Pi = get_rho_response(freqs[w], mo_energy, Lpq[:, :nocc, nocc:])
104 | ec_w = np.log(np.linalg.det(np.eye(naux) - Pi))
105 | ec_w += np.trace(Pi)
106 | e_corr += 1./(2.*np.pi) * ec_w * wts[w]
107 |
108 | return e_corr
109 |
110 | def get_rho_response(omega, mo_energy, Lpq):
111 | """
112 | Compute density response function in auxiliary basis at freq iw.
113 | """
114 | naux, nocc, nvir = Lpq.shape
115 | eia = mo_energy[:nocc, None] - mo_energy[None, nocc:]
116 | eia = eia / (omega**2 + eia * eia)
117 | # Response from both spin-up and spin-down density
118 | Pia = Lpq * (eia * 4.0)
119 | Pi = einsum('Pia, Qia -> PQ', Pia, Lpq)
120 | return Pi
121 |
122 | # ****************************************************************************
123 | # frequency integral quadrature, legendre, clenshaw_curtis
124 | # ****************************************************************************
125 |
126 | def _get_scaled_legendre_roots(nw, x0=0.5):
127 | """
128 | Scale nw Legendre roots, which lie in the
129 | interval [-1, 1], so that they lie in [0, inf)
130 | Ref: www.cond-mat.de/events/correl19/manuscripts/ren.pdf
131 |
132 | Returns:
133 | freqs : 1D array
134 | wts : 1D array
135 | """
136 | freqs, wts = np.polynomial.legendre.leggauss(nw)
137 | freqs_new = x0 * (1.0 + freqs) / (1.0 - freqs)
138 | wts = wts * 2.0 * x0 / (1.0 - freqs)**2
139 | return freqs_new, wts
140 |
141 | def _get_clenshaw_curtis_roots(nw):
142 | """
143 | Clenshaw-Curtis qaudrature on [0,inf)
144 | Ref: J. Chem. Phys. 132, 234114 (2010)
145 | Returns:
146 | freqs : 1D array
147 | wts : 1D array
148 | """
149 | freqs = np.zeros(nw)
150 | wts = np.zeros(nw)
151 | a = 0.2
152 | for w in range(nw):
153 | t = (w + 1.0) / nw * np.pi * 0.5
154 | freqs[w] = a / np.tan(t)
155 | if w != nw - 1:
156 | wts[w] = a*np.pi * 0.5 / nw / (np.sin(t)**2)
157 | else:
158 | wts[w] = a*np.pi * 0.25 / nw / (np.sin(t)**2)
159 | return freqs[::-1], wts[::-1]
160 |
161 | def _mo_energy_without_core(rpa, mo_energy):
162 | return mo_energy[get_frozen_mask(rpa)]
163 |
164 | def _mo_without_core(rpa, mo):
165 | return mo[:,get_frozen_mask(rpa)]
166 |
167 | def as_scanner(rpa):
168 | '''Generating a scanner/solver for RPA PES.'''
169 | if isinstance(rpa, lib.SinglePointScanner):
170 | return rpa
171 |
172 | logger.info(rpa, 'Set %s as a scanner', rpa.__class__)
173 |
174 | class RPA_Scanner(rpa.__class__, lib.SinglePointScanner):
175 | def __init__(self, rpa):
176 | self.__dict__.update(rpa.__dict__)
177 | self._scf = rpa._scf.as_scanner()
178 | def __call__(self, mol_or_geom, **kwargs):
179 | if isinstance(mol_or_geom, gto.Mole):
180 | mol = mol_or_geom
181 | else:
182 | mol = self.mol.set_geom_(mol_or_geom, inplace=False)
183 |
184 | self.reset(mol)
185 |
186 | mf_scanner = self._scf
187 | mf_scanner(mol)
188 | self.mo_coeff = mf_scanner.mo_coeff
189 | self.mo_occ = mf_scanner.mo_occ
190 | self.kernel(**kwargs)
191 | return self.e_tot
192 | return RPA_Scanner(rpa)
193 |
194 |
195 | class RPA(lib.StreamObject):
196 |
197 | def __init__(self, mf, frozen=None, auxbasis=None):
198 | self.mol = mf.mol
199 | self._scf = mf
200 | self.verbose = self.mol.verbose
201 | self.stdout = self.mol.stdout
202 | self.max_memory = mf.max_memory
203 | self.frozen = frozen
204 |
205 | # DF-RPA must use density fitting integrals
206 | if getattr(mf, 'with_df', None):
207 | self.with_df = mf.with_df
208 | else:
209 | self.with_df = df.DF(mf.mol)
210 | if auxbasis:
211 | self.with_df.auxbasis = auxbasis
212 | else:
213 | try:
214 | self.with_df.auxbasis = df.make_auxbasis(mf.mol, mp2fit=True)
215 | except:
216 | self.with_df.auxbasis = df.make_auxbasis(mf.mol, mp2fit=False)
217 | self._keys.update(['with_df'])
218 |
219 | ##################################################
220 | # don't modify the following attributes, they are not input options
221 | self._nocc = None
222 | self._nmo = None
223 | self.mo_energy = mf.mo_energy
224 | self.mo_coeff = mf.mo_coeff
225 | self.mo_occ = mf.mo_occ
226 | self.e_corr = None
227 | self.e_hf = None
228 | self.e_tot = None
229 |
230 | def dump_flags(self, verbose=None):
231 | log = logger.Logger(self.stdout, self.verbose)
232 | log.info('')
233 | log.info('******** %s ********', self.__class__)
234 | log.info('method = %s', self.__class__.__name__)
235 | nocc = self.nocc
236 | nvir = self.nmo - nocc
237 | log.info('RPA nocc = %d, nvir = %d', nocc, nvir)
238 | if self.frozen is not None:
239 | log.info('frozen orbitals = %d', self.frozen)
240 | return self
241 |
242 | @property
243 | def nocc(self):
244 | return self.get_nocc()
245 | @nocc.setter
246 | def nocc(self, n):
247 | self._nocc = n
248 |
249 | @property
250 | def nmo(self):
251 | return self.get_nmo()
252 | @nmo.setter
253 | def nmo(self, n):
254 | self._nmo = n
255 |
256 | get_nocc = get_nocc
257 | get_nmo = get_nmo
258 | get_frozen_mask = get_frozen_mask
259 |
260 | as_scanner = as_scanner
261 |
262 | def kernel(self, mo_energy=None, mo_coeff=None, Lpq=None, nw=40):
263 | """
264 | Args:
265 | mo_energy : 1D array (nmo), mean-field mo energy
266 | mo_coeff : 2D array (nmo, nmo), mean-field mo coefficient
267 | Lpq : 3D array (naux, nmo, nmo), 3-index ERI
268 | nw: interger, grid number
269 |
270 | Returns:
271 | self.e_tot : RPA total eenrgy
272 | self.e_hf : EXX energy
273 | self.e_corr : RPA correlation energy
274 | """
275 | if mo_coeff is None:
276 | mo_coeff = _mo_without_core(self, self._scf.mo_coeff)
277 | if mo_energy is None:
278 | mo_energy = _mo_energy_without_core(self, self._scf.mo_energy)
279 |
280 | cput0 = (time.process_time(), time.perf_counter())
281 | self.dump_flags()
282 | self.e_tot, self.e_hf, self.e_corr = \
283 | kernel(self, mo_energy, mo_coeff, Lpq=Lpq, nw=nw, verbose=self.verbose)
284 |
285 | logger.timer(self, 'RPA', *cput0)
286 | return self.e_corr
287 |
288 | def ao2mo(self, mo_coeff=None):
289 | if mo_coeff is None:
290 | mo_coeff = self.mo_coeff
291 | nmo = self.nmo
292 | nao = self.mo_coeff.shape[0]
293 | naux = self.with_df.get_naoaux()
294 | mem_incore = (2 * nmo**2*naux) * 8 / 1e6
295 | mem_now = lib.current_memory()[0]
296 |
297 | mo = np.asarray(mo_coeff, order='F')
298 | ijslice = (0, nmo, 0, nmo)
299 | Lpq = None
300 | if (mem_incore + mem_now < 0.99 * self.max_memory) or self.mol.incore_anyway:
301 | Lpq = _ao2mo.nr_e2(self.with_df._cderi, mo, ijslice, aosym='s2', out=Lpq)
302 | return Lpq.reshape(naux, nmo, nmo)
303 | else:
304 | logger.warn(self, 'Memory may not be enough!')
305 | raise NotImplementedError
306 |
307 | if __name__ == '__main__':
308 | from pyscf import gto, dft, scf
309 | mol = gto.Mole()
310 | mol.verbose = 4
311 | mol.atom = [
312 | [8 , (0. , 0. , 0.)],
313 | [1 , (0. , -0.7571 , 0.5861)],
314 | [1 , (0. , 0.7571 , 0.5861)]]
315 | mol.basis = 'def2-svp'
316 | mol.build()
317 |
318 | mf = dft.RKS(mol)
319 | mf.xc = 'pbe'
320 | mf.kernel()
321 |
322 | rpa = RPA(mf)
323 | rpa.kernel()
324 | print ('RPA e_tot, e_hf, e_corr = ', rpa.e_tot, rpa.e_hf, rpa.e_corr)
325 | assert(abs(rpa.e_corr- -0.30783004035780076) < 1e-6)
326 | assert(abs(rpa.e_tot- -76.26428191794182) < 1e-6)
327 |
--------------------------------------------------------------------------------
/fcdmft/rpa/mol/urpa.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2014-2021 The PySCF Developers. All Rights Reserved.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 | # Author: Tianyu Zhu
17 | #
18 |
19 | """
20 | Spin-unrestricted random phase approximation (direct RPA/dRPA in chemistry)
21 | with N^4 scaling
22 |
23 | Method:
24 | Main routines are based on GW-AC method descirbed in:
25 | T. Zhu and G.K.-L. Chan, J. Chem. Theory. Comput. 17, 727-741 (2021)
26 | X. Ren et al., New J. Phys. 14, 053020 (2012)
27 | """
28 |
29 | import time, h5py
30 | from functools import reduce
31 | import numpy as np
32 |
33 | from pyscf import lib
34 | from pyscf.lib import logger
35 | from pyscf.ao2mo import _ao2mo
36 | from pyscf import df, dft, scf
37 | from pyscf.mp.ump2 import get_nocc, get_nmo, get_frozen_mask
38 | from pyscf import __config__
39 | from fcdmft.rpa.mol.rpa import RPA, _get_scaled_legendre_roots
40 |
41 | einsum = lib.einsum
42 |
43 | # ****************************************************************************
44 | # core routines, kernel, rpa_ecorr, rho_response
45 | # ****************************************************************************
46 |
47 | def kernel(rpa, mo_energy, mo_coeff, Lpq=None, nw=None, verbose=logger.NOTE):
48 | """
49 | RPA correlation and total energy
50 |
51 | Args:
52 | Lpq : density fitting 3-center integral in MO basis.
53 | nw : number of frequency point on imaginary axis.
54 | vhf_df : using density fitting integral to compute HF exchange.
55 |
56 | Returns:
57 | e_tot : RPA total energy
58 | e_hf : EXX energy
59 | e_corr : RPA correlation energy
60 | """
61 | mf = rpa._scf
62 | # only support frozen core
63 | if rpa.frozen is not None:
64 | assert isinstance(rpa.frozen, int)
65 | assert (rpa.frozen < rpa.nocc[0] and rpa.frozen < rpa.nocc[1])
66 |
67 | if Lpq is None:
68 | Lpq = rpa.ao2mo(mo_coeff)
69 |
70 | # Grids for integration on imaginary axis
71 | freqs, wts = _get_scaled_legendre_roots(nw)
72 |
73 | # Compute HF exchange energy (EXX)
74 | dm = mf.make_rdm1()
75 | uhf = scf.UHF(rpa.mol)
76 | e_hf = uhf.energy_elec(dm=dm)[0]
77 | e_hf += mf.energy_nuc()
78 |
79 | # Compute RPA correlation energy
80 | e_corr = get_rpa_ecorr(rpa, Lpq, freqs, wts)
81 |
82 | # Compute totol energy
83 | e_tot = e_hf + e_corr
84 |
85 | logger.debug(rpa, ' RPA total energy = %s', e_tot)
86 | logger.debug(rpa, ' EXX energy = %s, RPA corr energy = %s', e_hf, e_corr)
87 |
88 | return e_tot, e_hf, e_corr
89 |
90 | def get_rpa_ecorr(rpa, Lpq, freqs, wts):
91 | """
92 | Compute RPA correlation energy
93 | """
94 | mo_energy = _mo_energy_without_core(rpa, rpa._scf.mo_energy)
95 | nocca, noccb = rpa.nocc
96 | nw = len(freqs)
97 | naux = Lpq[0].shape[0]
98 |
99 | homo = max(mo_energy[0][nocca-1], mo_energy[1][noccb-1])
100 | lumo = min(mo_energy[0][nocca], mo_energy[1][noccb])
101 | if (lumo-homo) < 1e-3:
102 | logger.warn(rpa, 'Current RPA code not well-defined for degeneracy!')
103 |
104 | e_corr = 0.
105 | for w in range(nw):
106 | Pi = get_rho_response(freqs[w], mo_energy, Lpq[0,:,:nocca,nocca:], Lpq[1,:,:noccb,noccb:])
107 | ec_w = np.log(np.linalg.det(np.eye(naux) - Pi))
108 | ec_w += np.trace(Pi)
109 | e_corr += 1./(2.*np.pi) * ec_w * wts[w]
110 |
111 | return e_corr
112 |
113 | def get_rho_response(omega, mo_energy, Lpqa, Lpqb):
114 | '''
115 | Compute density response function in auxiliary basis at freq iw
116 | '''
117 | naux, nocca, nvira = Lpqa.shape
118 | naux, noccb, nvirb = Lpqb.shape
119 | eia_a = mo_energy[0,:nocca,None] - mo_energy[0,None,nocca:]
120 | eia_b = mo_energy[1,:noccb,None] - mo_energy[1,None,noccb:]
121 | eia_a = eia_a / (omega**2 + eia_a*eia_a)
122 | eia_b = eia_b / (omega**2 + eia_b*eia_b)
123 | Pia_a = Lpqa * (eia_a * 2.0)
124 | Pia_b = Lpqb * (eia_b * 2.0)
125 | # Response from both spin-up and spin-down density
126 | Pi = einsum('Pia, Qia -> PQ', Pia_a, Lpqa) + einsum('Pia, Qia -> PQ', Pia_b, Lpqb)
127 | return Pi
128 |
129 | def _mo_energy_without_core(rpa, mo_energy):
130 | moidx = get_frozen_mask(rpa)
131 | mo_energy = (mo_energy[0][moidx[0]], mo_energy[1][moidx[1]])
132 | return np.asarray(mo_energy)
133 |
134 | def _mo_without_core(rpa, mo):
135 | moidx = get_frozen_mask(rpa)
136 | mo = (mo[0][:,moidx[0]], mo[1][:,moidx[1]])
137 | return np.asarray(mo)
138 |
139 | def as_scanner(rpa):
140 | '''Generating a scanner/solver for RPA PES.'''
141 | if isinstance(rpa, lib.SinglePointScanner):
142 | return rpa
143 |
144 | logger.info(rpa, 'Set %s as a scanner', rpa.__class__)
145 |
146 | class RPA_Scanner(rpa.__class__, lib.SinglePointScanner):
147 | def __init__(self, rpa):
148 | self.__dict__.update(rpa.__dict__)
149 | self._scf = rpa._scf.as_scanner()
150 | def __call__(self, mol_or_geom, **kwargs):
151 | if isinstance(mol_or_geom, gto.Mole):
152 | mol = mol_or_geom
153 | else:
154 | mol = self.mol.set_geom_(mol_or_geom, inplace=False)
155 |
156 | self.reset(mol)
157 |
158 | mf_scanner = self._scf
159 | mf_scanner(mol)
160 | self.mo_coeff = mf_scanner.mo_coeff
161 | self.mo_occ = mf_scanner.mo_occ
162 | self.kernel(**kwargs)
163 | return self.e_tot
164 | return RPA_Scanner(rpa)
165 |
166 |
167 | class URPA(RPA):
168 |
169 | def dump_flags(self, verbose=None):
170 | log = logger.Logger(self.stdout, self.verbose)
171 | log.info('')
172 | log.info('******** %s ********', self.__class__)
173 | log.info('method = %s', self.__class__.__name__)
174 | nocca, noccb = self.nocc
175 | nmoa, nmob = self.nmo
176 | nvira = nmoa - nocca
177 | nvirb = nmob - noccb
178 | log.info('RPA (nocca, noccb) = (%d, %d), (nvira, nvirb) = (%d, %d)',
179 | nocca, noccb, nvira, nvirb)
180 | if self.frozen is not None:
181 | log.info('frozen orbitals = %s', str(self.frozen))
182 | return self
183 |
184 | get_nocc = get_nocc
185 | get_nmo = get_nmo
186 | get_frozen_mask = get_frozen_mask
187 |
188 | as_scanner = as_scanner
189 |
190 | def kernel(self, mo_energy=None, mo_coeff=None, Lpq=None, nw=40):
191 | """
192 | Args:
193 | mo_energy : 2D array (2, nmo), mean-field mo energy
194 | mo_coeff : 3D array (2, nmo, nmo), mean-field mo coefficient
195 | Lpq : 4D array (2, naux, nmo, nmo), 3-index ERI
196 | nw: interger, grid number
197 |
198 | Returns:
199 | self.e_tot : RPA total eenrgy
200 | self.e_hf : EXX energy
201 | self.e_corr : RPA correlation energy
202 | """
203 | if mo_coeff is None:
204 | mo_coeff = _mo_without_core(self, self._scf.mo_coeff)
205 | if mo_energy is None:
206 | mo_energy = _mo_energy_without_core(self, self._scf.mo_energy)
207 |
208 | cput0 = (time.process_time(), time.perf_counter())
209 | self.dump_flags()
210 | self.e_tot, self.e_hf, self.e_corr = \
211 | kernel(self, mo_energy, mo_coeff, Lpq=Lpq, nw=nw, verbose=self.verbose)
212 |
213 | logger.timer(self, 'RPA', *cput0)
214 | return self.e_corr
215 |
216 | def ao2mo(self, mo_coeff=None):
217 | nmoa, nmob = self.nmo
218 | nao = self.mo_coeff[0].shape[0]
219 | naux = self.with_df.get_naoaux()
220 | mem_incore = (nmoa**2*naux + nmob**2*naux + nao**2*naux) * 8/1e6
221 | mem_now = lib.current_memory()[0]
222 |
223 | moa = np.asarray(mo_coeff[0], order='F')
224 | mob = np.asarray(mo_coeff[1], order='F')
225 | ijslicea = (0, nmoa, 0, nmoa)
226 | ijsliceb = (0, nmob, 0, nmob)
227 | Lpqa = None
228 | Lpqb = None
229 | if (mem_incore + mem_now < 0.99*self.max_memory) or self.mol.incore_anyway:
230 | Lpqa = _ao2mo.nr_e2(self.with_df._cderi, moa, ijslicea, aosym='s2', out=Lpqa)
231 | Lpqb = _ao2mo.nr_e2(self.with_df._cderi, mob, ijsliceb, aosym='s2', out=Lpqb)
232 | return np.asarray((Lpqa.reshape(naux,nmoa,nmoa),Lpqb.reshape(naux,nmob,nmob)))
233 | else:
234 | logger.warn(self, 'Memory may not be enough!')
235 | raise NotImplementedError
236 |
237 |
238 | if __name__ == '__main__':
239 | from pyscf import gto, dft, scf
240 | mol = gto.Mole()
241 | mol.verbose = 5
242 | mol.atom = 'F 0 0 0'
243 | mol.basis = 'def2-svp'
244 | mol.spin = 1
245 | mol.build()
246 |
247 | mf = dft.UKS(mol)
248 | mf.xc = 'pbe0'
249 | mf.kernel()
250 |
251 | rpa = URPA(mf)
252 | rpa.kernel()
253 | print ('RPA e_tot, e_hf, e_corr = ', rpa.e_tot, rpa.e_hf, rpa.e_corr)
254 | assert(abs(rpa.e_corr- -0.20980646878974454) < 1e-6)
255 | assert(abs(rpa.e_tot- -99.49292565821425) < 1e-6)
256 |
--------------------------------------------------------------------------------
/fcdmft/rpa/pbc/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZhuGroup-Yale/fcdmft/98d93f863bc1ad9dc9d17982de4f5e89581a811c/fcdmft/rpa/pbc/__init__.py
--------------------------------------------------------------------------------
/fcdmft/rpa/pbc/rpa.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2014-2021 The PySCF Developers. All Rights Reserved.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 | # Author: Tianyu Zhu
17 | #
18 |
19 | """
20 | Periodic spin-restricted random phase approximation
21 | (direct RPA/dRPA in chemistry) with N^4 scaling (Gamma only)
22 |
23 | Method:
24 | Main routines are based on GW-AC method descirbed in:
25 | T. Zhu and G.K.-L. Chan, J. Chem. Theory. Comput. 17, 727-741 (2021)
26 | X. Ren et al., New J. Phys. 14, 053020 (2012)
27 | """
28 |
29 | import time, h5py, os
30 | from functools import reduce
31 | import numpy as np
32 |
33 | from pyscf import lib
34 | from pyscf.lib import logger
35 | from pyscf.ao2mo import _ao2mo
36 | from pyscf.pbc import df, dft, scf
37 | from pyscf.mp.mp2 import get_nocc, get_nmo, get_frozen_mask
38 | from pyscf import __config__
39 | from fcdmft.rpa.mol.rpa import RPA, get_rpa_ecorr, _get_scaled_legendre_roots, \
40 | get_rho_response, _mo_energy_without_core, _mo_without_core
41 |
42 | einsum = lib.einsum
43 |
44 | def kernel(rpa, mo_energy, mo_coeff, Lpq=None, nw=None, verbose=logger.NOTE):
45 | """
46 | RPA correlation and total energy
47 |
48 | Args:
49 | Lpq : density fitting 3-center integral in MO basis.
50 | nw : number of frequency point on imaginary axis.
51 | vhf_df : using density fitting integral to compute HF exchange.
52 |
53 | Returns:
54 | e_tot : RPA total energy
55 | e_hf : EXX energy
56 | e_corr : RPA correlation energy
57 | """
58 | mf = rpa._scf
59 | assert(rpa.frozen is None)
60 |
61 | if Lpq is None:
62 | Lpq = rpa.ao2mo(mo_coeff)
63 |
64 | # Grids for integration on imaginary axis
65 | freqs, wts = _get_scaled_legendre_roots(nw)
66 |
67 | # Compute HF exchange energy (EXX)
68 | dm = mf.make_rdm1()
69 | rhf = scf.RHF(rpa.mol, exxdiv=mf.exxdiv)
70 | rhf.with_df = mf.with_df
71 | rhf.with_df._cderi = mf.with_df._cderi
72 | e_hf = rhf.energy_elec(dm=dm)[0]
73 | e_hf += mf.energy_nuc()
74 |
75 | # Compute RPA correlation energy
76 | e_corr = get_rpa_ecorr(rpa, Lpq, freqs, wts)
77 |
78 | # Compute totol energy
79 | e_tot = e_hf + e_corr
80 |
81 | logger.debug(rpa, ' RPA total energy = %s', e_tot)
82 | logger.debug(rpa, ' EXX energy = %s, RPA corr energy = %s', e_hf, e_corr)
83 |
84 | return e_tot, e_hf, e_corr
85 |
86 |
87 | class RPA(RPA):
88 |
89 | @property
90 | def nocc(self):
91 | return self.get_nocc()
92 | @nocc.setter
93 | def nocc(self, n):
94 | self._nocc = n
95 |
96 | @property
97 | def nmo(self):
98 | return self.get_nmo()
99 | @nmo.setter
100 | def nmo(self, n):
101 | self._nmo = n
102 |
103 | get_nocc = get_nocc
104 | get_nmo = get_nmo
105 | get_frozen_mask = get_frozen_mask
106 |
107 | def kernel(self, mo_energy=None, mo_coeff=None, Lpq=None, nw=40):
108 | """
109 | Args:
110 | mo_energy : 1D array (nmo), mean-field mo energy
111 | mo_coeff : 2D array (nmo, nmo), mean-field mo coefficient
112 | Lpq : 3D array (naux, nmo, nmo), 3-index ERI
113 | nw: interger, grid number
114 |
115 | Returns:
116 | self.e_tot : RPA total eenrgy
117 | self.e_hf : EXX energy
118 | self.e_corr : RPA correlation energy
119 | """
120 | if mo_coeff is None:
121 | mo_coeff = _mo_without_core(self, self._scf.mo_coeff)
122 | if mo_energy is None:
123 | mo_energy = _mo_energy_without_core(self, self._scf.mo_energy)
124 |
125 | cput0 = (time.process_time(), time.perf_counter())
126 | self.dump_flags()
127 | self.e_tot, self.e_hf, self.e_corr = \
128 | kernel(self, mo_energy, mo_coeff, Lpq=Lpq, nw=nw, verbose=self.verbose)
129 |
130 | logger.timer(self, 'RPA', *cput0)
131 | return self.e_corr
132 |
133 | def ao2mo(self, mo_coeff=None):
134 | nmo = self.nmo
135 | nao = self.mo_coeff.shape[0]
136 | naux = self.with_df.get_naoaux()
137 | kpts = self._scf.with_df.kpts
138 | mem_incore = (2 * nmo**2*naux) * 8 /1e6
139 | mem_now = lib.current_memory()[0]
140 |
141 | mo = np.asarray(mo_coeff, order='F')
142 | ijslice = (0, nmo, 0, nmo)
143 | Lpq = None
144 |
145 | eri_3d_kpts = []
146 | for i, kpti in enumerate(kpts):
147 | eri_3d_kpts.append([])
148 | for j, kptj in enumerate(kpts):
149 | eri_3d = []
150 | for LpqR, LpqI, sign in self._scf.with_df.sr_loop([kpti,kptj], max_memory=mem_now, compact=False):
151 | eri_3d.append(LpqR+LpqI*1j)
152 | eri_3d = np.vstack(eri_3d).reshape(-1,nao,nao)
153 | eri_3d_kpts[i].append(eri_3d)
154 |
155 | if (mem_incore+mem_now < self.max_memory) or self.mol.incore_anyway:
156 | tao = []
157 | ao_loc = None
158 | Lpq = _ao2mo.r_e2(np.array(eri_3d_kpts[0][0]), mo, ijslice, tao, ao_loc, out=Lpq)
159 | return Lpq.real.reshape(naux,nmo,nmo)
160 | else:
161 | logger.warn(self, 'Memory not enough!')
162 | raise NotImplementedError
163 |
164 | if __name__ == '__main__':
165 | from pyscf.pbc import gto, scf, dft, df, tools
166 | from pyscf.pbc.lib import chkfile
167 |
168 | ucell = gto.Cell()
169 | ucell.build(unit = 'angstrom',
170 | a = '''
171 | 0.000000 1.783500 1.783500
172 | 1.783500 0.000000 1.783500
173 | 1.783500 1.783500 0.000000
174 | ''',
175 | atom = 'C 1.337625 1.337625 1.337625; C 2.229375 2.229375 2.229375',
176 | dimension = 3,
177 | max_memory = 64000,
178 | verbose = 5,
179 | pseudo = 'gth-pbe',
180 | basis='gth-dzv',
181 | precision=1e-12)
182 |
183 | kmesh = [3,1,1]
184 | cell = tools.super_cell(ucell, kmesh)
185 | cell.verbose = 5
186 |
187 | gdf = df.GDF(cell)
188 | gdf_fname = 'gdf_ints.h5'
189 | gdf._cderi_to_save = gdf_fname
190 | if not os.path.isfile(gdf_fname):
191 | gdf.build()
192 |
193 | chkfname = 'diamond_hf.chk'
194 | if os.path.isfile(chkfname):
195 | kmf = scf.RHF(cell).density_fit()
196 | kmf.with_df = gdf
197 | kmf.with_df._cderi = gdf_fname
198 | kmf.conv_tol = 1e-12
199 | data = chkfile.load(chkfname, 'scf')
200 | kmf.__dict__.update(data)
201 | else:
202 | kmf = scf.RHF(cell).density_fit()
203 | kmf.with_df = gdf
204 | kmf.with_df._cderi = gdf_fname
205 | kmf.conv_tol = 1e-12
206 | kmf.chkfile = chkfname
207 | kmf.kernel()
208 |
209 | rpa = RPA(kmf)
210 | rpa.kernel()
211 | assert(abs(rpa.e_corr- -0.5558316165999143) < 1e-6)
212 | assert(abs(rpa.e_tot- -32.08317615664809) < 1e-6)
213 |
--------------------------------------------------------------------------------
/fcdmft/rpa/pbc/urpa.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2014-2021 The PySCF Developers. All Rights Reserved.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 | # Author: Tianyu Zhu
17 | #
18 |
19 | """
20 | Periodic spin-unrestricted random phase approximation
21 | (direct RPA/dRPA in chemistry) with N^4 scaling (Gamma only)
22 |
23 | Method:
24 | Main routines are based on GW-AC method descirbed in:
25 | T. Zhu and G.K.-L. Chan, J. Chem. Theory. Comput. 17, 727-741 (2021)
26 | X. Ren et al., New J. Phys. 14, 053020 (2012)
27 | """
28 |
29 | import time, h5py, os
30 | from functools import reduce
31 | import numpy as np
32 |
33 | from pyscf import lib
34 | from pyscf.lib import logger
35 | from pyscf.ao2mo import _ao2mo
36 | from pyscf import df, dft, scf
37 | from pyscf.mp.ump2 import get_nocc, get_nmo, get_frozen_mask
38 | from pyscf import __config__
39 | from fcdmft.rpa.mol.urpa import URPA, get_rpa_ecorr, \
40 | get_rho_response, _mo_energy_without_core, _mo_without_core
41 | from fcdmft.rpa.mol.rpa import _get_scaled_legendre_roots
42 |
43 | einsum = lib.einsum
44 |
45 | def kernel(rpa, mo_energy, mo_coeff, Lpq=None, nw=None, verbose=logger.NOTE):
46 | """
47 | RPA correlation and total energy
48 |
49 | Args:
50 | Lpq : density fitting 3-center integral in MO basis.
51 | nw : number of frequency point on imaginary axis.
52 | vhf_df : using density fitting integral to compute HF exchange.
53 |
54 | Returns:
55 | e_tot : RPA total energy
56 | e_hf : EXX energy
57 | e_corr : RPA correlation energy
58 | """
59 | mf = rpa._scf
60 | assert(rpa.frozen is None)
61 |
62 | if Lpq is None:
63 | Lpq = rpa.ao2mo(mo_coeff)
64 |
65 | # Grids for integration on imaginary axis
66 | freqs, wts = _get_scaled_legendre_roots(nw)
67 |
68 | # Compute HF exchange energy (EXX)
69 | dm = mf.make_rdm1()
70 | uhf = scf.UHF(rpa.mol, exxdiv=mf.exxdiv)
71 | uhf.with_df = mf.with_df
72 | uhf.with_df._cderi = mf.with_df._cderi
73 | e_hf = uhf.energy_elec(dm=dm)[0]
74 | e_hf += mf.energy_nuc()
75 |
76 | # Compute RPA correlation energy
77 | e_corr = get_rpa_ecorr(rpa, Lpq, freqs, wts)
78 |
79 | # Compute totol energy
80 | e_tot = e_hf + e_corr
81 |
82 | logger.debug(rpa, ' RPA total energy = %s', e_tot)
83 | logger.debug(rpa, ' EXX energy = %s, RPA corr energy = %s', e_hf, e_corr)
84 |
85 | return e_tot, e_hf, e_corr
86 |
87 | class URPA(URPA):
88 |
89 | get_nocc = get_nocc
90 | get_nmo = get_nmo
91 | get_frozen_mask = get_frozen_mask
92 |
93 | def kernel(self, mo_energy=None, mo_coeff=None, Lpq=None, nw=40):
94 | """
95 | Args:
96 | mo_energy : 2D array (2, nmo), mean-field mo energy
97 | mo_coeff : 3D array (2, nmo, nmo), mean-field mo coefficient
98 | Lpq : 4D array (2, naux, nmo, nmo), 3-index ERI
99 | nw: interger, grid number
100 |
101 | Returns:
102 | self.e_tot : RPA total eenrgy
103 | self.e_hf : EXX energy
104 | self.e_corr : RPA correlation energy
105 | """
106 | if mo_coeff is None:
107 | mo_coeff = _mo_without_core(self, self._scf.mo_coeff)
108 | if mo_energy is None:
109 | mo_energy = _mo_energy_without_core(self, self._scf.mo_energy)
110 |
111 | cput0 = (time.process_time(), time.perf_counter())
112 | self.dump_flags()
113 | self.e_tot, self.e_hf, self.e_corr = \
114 | kernel(self, mo_energy, mo_coeff, Lpq=Lpq, nw=nw, verbose=self.verbose)
115 |
116 | logger.timer(self, 'RPA', *cput0)
117 | return self.e_corr
118 |
119 | def ao2mo(self, mo_coeff=None):
120 | nmoa, nmob = self.nmo
121 | nao = self.mo_coeff[0].shape[0]
122 | naux = self.with_df.get_naoaux()
123 | kpts = self._scf.with_df.kpts
124 | mem_incore = (nmoa**2*naux + nmob**2*naux + nao**2*naux) * 8/1e6
125 | mem_now = lib.current_memory()[0]
126 |
127 | moa = np.asarray(mo_coeff[0], order='F')
128 | mob = np.asarray(mo_coeff[1], order='F')
129 | ijslicea = (0, nmoa, 0, nmoa)
130 | ijsliceb = (0, nmob, 0, nmob)
131 | Lpqa = None
132 | Lpqb = None
133 |
134 | eri_3d_kpts = []
135 | for i, kpti in enumerate(kpts):
136 | eri_3d_kpts.append([])
137 | for j, kptj in enumerate(kpts):
138 | eri_3d = []
139 | for LpqR, LpqI, sign in self._scf.with_df.sr_loop([kpti,kptj], max_memory=mem_now, compact=False):
140 | eri_3d.append(LpqR+LpqI*1j)
141 | eri_3d = np.vstack(eri_3d).reshape(-1,nao,nao)
142 | eri_3d_kpts[i].append(eri_3d)
143 |
144 | if (mem_incore+mem_now < self.max_memory) or self.mol.incore_anyway:
145 | tao = []
146 | ao_loc = None
147 | Lpqa = _ao2mo.r_e2(np.array(eri_3d_kpts[0][0]), moa, ijslicea, tao, ao_loc, out=Lpqa)
148 | tao = []
149 | ao_loc = None
150 | Lpqb = _ao2mo.r_e2(np.array(eri_3d_kpts[0][0]), mob, ijsliceb, tao, ao_loc, out=Lpqb)
151 | return np.asarray((Lpqa.real.reshape(naux,nmoa,nmoa),Lpqb.real.reshape(naux,nmob,nmob)))
152 | else:
153 | logger.warn(self, 'Memory not enough!')
154 | raise NotImplementedError
155 |
156 | if __name__ == '__main__':
157 | from pyscf.pbc import gto, scf, dft, df, tools
158 | from pyscf.pbc.lib import chkfile
159 |
160 | ucell = gto.Cell()
161 | ucell.build(
162 | unit = 'B',
163 | a = [[ 0., 6.74027466, 6.74027466],
164 | [ 6.74027466, 0., 6.74027466],
165 | [ 6.74027466, 6.74027466, 0. ]],
166 | atom = '''H 0 0 0
167 | H 1.68506866 1.68506866 1.68506866
168 | H 3.37013733 3.37013733 3.37013733''',
169 | basis = 'gth-dzvp',
170 | pseudo = 'gth-pade',
171 | verbose = 5,
172 | charge = 0,
173 | spin = 1)
174 |
175 | kmesh = [3,1,1]
176 | cell = tools.super_cell(ucell, kmesh)
177 | cell.verbose = 5
178 | cell.spin = ucell.spin * 3
179 |
180 | gdf = df.GDF(cell)
181 | gdf_fname = 'gdf_ints.h5'
182 | gdf._cderi_to_save = gdf_fname
183 | if not os.path.isfile(gdf_fname):
184 | gdf.build()
185 |
186 | chkfname = 'h3_hf.chk'
187 | if os.path.isfile(chkfname):
188 | kmf = scf.UHF(cell).density_fit()
189 | kmf.with_df = gdf
190 | kmf.with_df._cderi = gdf_fname
191 | kmf.conv_tol = 1e-12
192 | data = chkfile.load(chkfname, 'scf')
193 | kmf.__dict__.update(data)
194 | else:
195 | kmf = scf.UHF(cell).density_fit()
196 | kmf.with_df = gdf
197 | kmf.with_df._cderi = gdf_fname
198 | kmf.conv_tol = 1e-12
199 | kmf.chkfile = chkfname
200 | kmf.kernel()
201 |
202 | rpa = URPA(kmf)
203 | rpa.kernel()
204 | assert(abs(rpa.e_corr- -0.12865054702442688) < 1e-6)
205 | assert(abs(rpa.e_tot- -4.767926645428772) < 1e-6)
206 |
--------------------------------------------------------------------------------
/fcdmft/solver/ccgf.py:
--------------------------------------------------------------------------------
1 | import time
2 | import sys
3 |
4 | import numpy as np
5 | import scipy
6 | from fcdmft.solver import gmres
7 |
8 | import pyscf
9 | import pyscf.cc
10 | from pyscf.lib import logger
11 | from pyscf.cc.eom_rccsd import amplitudes_to_vector_ip, amplitudes_to_vector_ea
12 |
13 | '''
14 | CCSD Green's function
15 | '''
16 |
17 |
18 | def greens_b_singles_ea_rhf(t1, p):
19 | nocc, nvir = t1.shape
20 | ds_type = t1.dtype
21 | if p < nocc:
22 | return -t1[p,:]
23 | else:
24 | p = p-nocc
25 | result = np.zeros((nvir,), dtype=ds_type)
26 | result[p] = 1.0
27 | return result
28 |
29 |
30 | def greens_b_doubles_ea_rhf(t2, p):
31 | nocc, _, nvir, _ = t2.shape
32 | ds_type = t2.dtype
33 | if p < nocc:
34 | return -t2[p,:,:,:]
35 | else:
36 | return np.zeros((nocc,nvir,nvir), dtype=ds_type)
37 |
38 |
39 | def greens_b_vector_ea_rhf(cc, p):
40 | return amplitudes_to_vector_ea(
41 | greens_b_singles_ea_rhf(cc.t1, p),
42 | greens_b_doubles_ea_rhf(cc.t2, p),
43 | )
44 |
45 |
46 | def greens_e_singles_ea_rhf(t1, t2, l1, l2, p):
47 | nocc, nvir = t1.shape
48 | ds_type = t1.dtype
49 | if p < nocc:
50 | return l1[p, :]
51 | else:
52 | p = p-nocc
53 | result = np.zeros((nvir,), dtype=ds_type)
54 | result[p] = -1.0
55 | result += np.einsum('ia,i->a', l1, t1[:,p])
56 | result += 2*np.einsum('klca,klc->a', l2, t2[:,:,:,p])
57 | result -= np.einsum('klca,lkc->a', l2, t2[:,:,:,p])
58 | return result
59 |
60 |
61 | def greens_e_doubles_ea_rhf(t1, l1, l2, p):
62 | nocc, nvir = t1.shape
63 | ds_type = t1.dtype
64 | if p < nocc:
65 | return 2*l2[p,:,:,:] - l2[:,p,:,:]
66 | else:
67 | p = p-nocc
68 | result = np.zeros((nocc,nvir,nvir), dtype=ds_type)
69 | result[:,p,:] += -2*l1
70 | result[:,:,p] += l1
71 | result += 2*np.einsum('k,jkba->jab', t1[:,p], l2)
72 | result -= np.einsum('k,jkab->jab', t1[:,p], l2)
73 | return result
74 |
75 |
76 | def greens_e_vector_ea_rhf(cc, p):
77 | return amplitudes_to_vector_ea(
78 | greens_e_singles_ea_rhf(cc.t1, cc.t2, cc.l1, cc.l2, p),
79 | greens_e_doubles_ea_rhf(cc.t1, cc.l1, cc.l2, p),
80 | )
81 |
82 |
83 | def greens_b_singles_ip_rhf(t1, p):
84 | nocc, nvir = t1.shape
85 | ds_type = t1.dtype
86 | if p < nocc:
87 | result = np.zeros((nocc,), dtype=ds_type)
88 | result[p] = 1.0
89 | return result
90 | else:
91 | p = p-nocc
92 | return t1[:,p]
93 |
94 |
95 | def greens_b_doubles_ip_rhf(t2, p):
96 | nocc, _, nvir, _ = t2.shape
97 | ds_type = t2.dtype
98 | if p < nocc:
99 | return np.zeros((nocc,nocc,nvir), dtype=ds_type)
100 | else:
101 | p = p-nocc
102 | return t2[:,:,p,:]
103 |
104 |
105 | def greens_b_vector_ip_rhf(cc, p):
106 | return amplitudes_to_vector_ip(
107 | greens_b_singles_ip_rhf(cc.t1, p),
108 | greens_b_doubles_ip_rhf(cc.t2, p),
109 | )
110 |
111 |
112 | def greens_e_singles_ip_rhf(t1, t2, l1, l2, p):
113 | nocc, nvir = t1.shape
114 | ds_type = t1.dtype
115 | if p < nocc:
116 | result = np.zeros((nocc,), dtype=ds_type)
117 | result[p] = -1.0
118 | result += np.einsum('ia,a->i', l1, t1[p,:])
119 | result += 2*np.einsum('ilcd,lcd->i', l2, t2[p,:,:,:])
120 | result -= np.einsum('ilcd,ldc->i', l2, t2[p,:,:,:])
121 | return result
122 | else:
123 | p = p-nocc
124 | return -l1[:,p]
125 |
126 |
127 | def greens_e_doubles_ip_rhf(t1, l1, l2, p):
128 | nocc, nvir = t1.shape
129 | ds_type = t1.dtype
130 | if p < nocc:
131 | result = np.zeros((nocc, nocc, nvir), dtype=ds_type)
132 | result[p, :, :] += -2*l1
133 | result[:, p, :] += l1
134 | result += 2*np.einsum('c,ijcb->ijb', t1[p,:], l2)
135 | result -= np.einsum('c,jicb->ijb', t1[p,:], l2)
136 | return result
137 | else:
138 | p = p-nocc
139 | return -2*l2[:,:,p,:] + l2[:,:,:,p]
140 |
141 |
142 | def greens_e_vector_ip_rhf(cc, p):
143 | return amplitudes_to_vector_ip(
144 | greens_e_singles_ip_rhf(cc.t1, cc.t2, cc.l1, cc.l2, p),
145 | greens_e_doubles_ip_rhf(cc.t1, cc.l1, cc.l2, p),
146 | )
147 |
148 |
149 | def greens_func_multiply(ham, vector, linear_part, **kwargs):
150 | return np.array(ham(vector, **kwargs) + linear_part * vector)
151 |
152 |
153 | def ip_shape(cc):
154 | nocc, nvir = cc.t1.shape
155 | return nocc + nocc*nocc*nvir
156 |
157 |
158 | def ea_shape(cc):
159 | nocc, nvir = cc.t1.shape
160 | return nvir + nocc*nvir*nvir
161 |
162 |
163 | class CCGF(object):
164 | def __init__(self, mycc, tol=1e-4, verbose=None):
165 | self._cc = mycc
166 | self.tol = tol
167 | if verbose:
168 | self.verbose = verbose
169 | else:
170 | self.verbose = self._cc.verbose
171 | self.stdout = sys.stdout
172 |
173 | def ipccsd_ao(self, ps, omega_list, mo_coeff, broadening, qs=None):
174 | '''
175 | Compute IP-CCSD-GF in AO basis
176 | '''
177 | eomip = pyscf.cc.eom_rccsd.EOMIP(self._cc)
178 | eomip_imds = eomip.make_imds()
179 | diag = eomip.get_diag()
180 |
181 | if qs is None:
182 | qs = ps
183 | nmo = mo_coeff.shape[1]
184 | e_vector_mo = np.zeros([nmo, ip_shape(self._cc)], dtype=np.complex128)
185 | for i in range(nmo):
186 | e_vector_mo[i,:] = greens_e_vector_ip_rhf(self._cc, i)
187 | e_vector_ao = np.einsum("pi,ix->px", mo_coeff[qs,:], e_vector_mo)
188 | b_vector_mo = np.zeros([ip_shape(self._cc), nmo], dtype=np.complex128)
189 | for i in range(nmo):
190 | b_vector_mo[:,i] = greens_b_vector_ip_rhf(self._cc, i)
191 | b_vector_ao = np.einsum("xi,ip->xp", b_vector_mo, mo_coeff.T[:,ps])
192 |
193 | gf_ao = np.zeros((len(ps), len(qs), len(omega_list)), dtype=np.complex128)
194 | for ip, p in enumerate(ps):
195 | x0 = None
196 | for iomega in range(len(omega_list))[::-1]:
197 | curr_omega = omega_list[iomega]
198 |
199 | def matr_multiply(vector, args=None):
200 | return greens_func_multiply(eomip.matvec, vector, curr_omega - 1j * broadening, imds=eomip_imds)
201 |
202 | diag_w = diag + curr_omega-1j*broadening
203 | if x0 is None:
204 | x0 = b_vector_ao[:,ip]/diag_w
205 | solver = gmres.GMRES(matr_multiply, b_vector_ao[:,ip], x0, diag_w, tol=self.tol)
206 | cput1 = (time.process_time(), time.perf_counter())
207 | sol = solver.solve().reshape(-1)
208 | cput1 = logger.timer(self, 'IPGF GMRES orbital p = %d/%d, freq w = %d/%d (%d iterations)'%(
209 | ip+1,len(ps),iomega+1,len(omega_list),solver.niter), *cput1)
210 | x0 = sol
211 | for iq, q in enumerate(qs):
212 | gf_ao[ip,iq,iomega] = -np.dot(e_vector_ao[iq,:], sol)
213 | return gf_ao
214 |
215 | def eaccsd_ao(self, ps, omega_list, mo_coeff, broadening, qs=None):
216 | '''
217 | Compute EA-CCSD-GF in AO basis
218 | '''
219 | eomea = pyscf.cc.eom_rccsd.EOMEA(self._cc)
220 | eomea_imds = eomea.make_imds()
221 | diag = eomea.get_diag()
222 |
223 | if qs is None:
224 | qs = ps
225 | nmo = mo_coeff.shape[1]
226 | e_vector_mo = np.zeros([nmo, ea_shape(self._cc)], dtype=np.complex128)
227 | for i in range(nmo):
228 | e_vector_mo[i,:] = greens_e_vector_ea_rhf(self._cc, i)
229 | e_vector_ao = np.einsum("pi,ix->px", mo_coeff[qs,:], e_vector_mo)
230 | b_vector_mo = np.zeros([ea_shape(self._cc), nmo], dtype=np.complex128)
231 | for i in range(nmo):
232 | b_vector_mo[:,i] = greens_b_vector_ea_rhf(self._cc, i)
233 | b_vector_ao = np.einsum("xi,ip->xp", b_vector_mo, mo_coeff.T[:,ps])
234 |
235 | gf_ao = np.zeros((len(qs), len(ps), len(omega_list)), dtype=np.complex128)
236 | for iq, q in enumerate(ps):
237 | x0 = None
238 | for iomega in range(len(omega_list)):
239 | curr_omega = omega_list[iomega]
240 |
241 | def matr_multiply(vector, args=None):
242 | return greens_func_multiply(eomea.matvec, vector, -curr_omega - 1j * broadening, imds=eomea_imds)
243 |
244 | diag_w = diag + (-curr_omega-1j*broadening)
245 | if x0 is None:
246 | x0 = b_vector_ao[:,iq]/diag_w
247 | solver = gmres.GMRES(matr_multiply, b_vector_ao[:,iq], x0, diag_w, tol=self.tol)
248 | cput1 = (time.process_time(), time.perf_counter())
249 | sol = solver.solve().reshape(-1)
250 | cput1 = logger.timer(self, 'EAGF GMRES orbital q = %d/%d, freq w = %d/%d (%d iterations)'%(
251 | iq+1,len(ps),iomega+1,len(omega_list),solver.niter), *cput1)
252 | x0 = sol
253 | for ip, p in enumerate(qs):
254 | gf_ao[ip,iq,iomega] = np.dot(e_vector_ao[ip,:], sol)
255 | return gf_ao
256 |
257 | def ipccsd_mo(self, ps, qs, omega_list, broadening):
258 | '''
259 | Compute IP-CCSD-GF in MO basis
260 | '''
261 | eomip = pyscf.cc.eom_rccsd.EOMIP(self._cc)
262 | eomip_imds = eomip.make_imds()
263 | diag = eomip.get_diag()
264 | e_vector = list()
265 | for q in qs:
266 | e_vector.append(greens_e_vector_ip_rhf(self._cc, q))
267 | gfvals = np.zeros((len(ps), len(qs), len(omega_list)), dtype=complex)
268 | for ip, p in enumerate(ps):
269 | b_vector = greens_b_vector_ip_rhf(self._cc, p)
270 | for iomega in range(len(omega_list)):
271 | curr_omega = omega_list[iomega]
272 |
273 | def matr_multiply(vector, args=None):
274 | return greens_func_multiply(eomip.matvec, vector, curr_omega - 1j * broadening, imds=eomip_imds)
275 |
276 | diag_w = diag + curr_omega-1j*broadening
277 | x0 = b_vector/diag_w
278 | solver = gmres.GMRES(matr_multiply, b_vector, x0, diag_w, tol=self.tol)
279 | cput1 = (time.process_time(), time.perf_counter())
280 | sol = solver.solve().reshape(-1)
281 | cput1 = logger.timer(self, 'IPGF GMRES orbital p = %d/%d, freq w = %d/%d (%d iterations)'%(
282 | ip+1,len(ps),iomega+1,len(omega_list),solver.niter), *cput1)
283 | x0 = sol
284 | for iq, q in enumerate(qs):
285 | gfvals[ip,iq,iomega] = -np.dot(e_vector[iq], sol)
286 | return gfvals
287 |
288 | def eaccsd_mo(self, ps, qs, omega_list, broadening):
289 | '''
290 | Compute EA-CCSD-GF in MO basis
291 | '''
292 | eomea = pyscf.cc.eom_rccsd.EOMEA(self._cc)
293 | eomea_imds = eomea.make_imds()
294 | diag = eomea.get_diag()
295 | e_vector = list()
296 | for p in ps:
297 | e_vector.append(greens_e_vector_ea_rhf(self._cc, p))
298 | gfvals = np.zeros((len(ps), len(qs), len(omega_list)), dtype=complex)
299 | for iq, q in enumerate(qs):
300 | b_vector = greens_b_vector_ea_rhf(self._cc, q)
301 | for iomega in range(len(omega_list)):
302 | curr_omega = omega_list[iomega]
303 |
304 | def matr_multiply(vector, args=None):
305 | return greens_func_multiply(eomea.matvec, vector, -curr_omega - 1j * broadening, imds=eomea_imds)
306 |
307 | diag_w = diag + (-curr_omega-1j*broadening)
308 | x0 = b_vector/diag_w
309 | solver = gmres.GMRES(matr_multiply, b_vector, x0, diag_w, tol=self.tol)
310 | cput1 = (time.process_time(), time.perf_counter())
311 | sol = solver.solve().reshape(-1)
312 | cput1 = logger.timer(self, 'EAGF GMRES orbital q = %d/%d, freq w = %d/%d (%d iterations)'%(
313 | iq+1,len(ps),iomega+1,len(omega_list),solver.niter), *cput1)
314 | x0 = sol
315 | for ip, p in enumerate(ps):
316 | gfvals[ip,iq,iomega] = np.dot(e_vector[ip], sol)
317 | return gfvals
318 |
319 | def get_gf(self, p, q, omega_list, broadening):
320 | return (self.ipccsd_mo(p, q, omega_list, broadening),
321 | self.eaccsd_mo(p, q, omega_list, broadening))
322 |
323 |
--------------------------------------------------------------------------------
/fcdmft/solver/gmres.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import scipy.sparse.linalg as spla
3 |
4 | '''
5 | GMRES/GCROT(m,k) for solving Green's function linear equations
6 | '''
7 |
8 | class GMRES(object):
9 | def __init__(self, A, b, x0, diag=None, tol=1e-3):
10 | n = max(b.shape)
11 | self.A = spla.LinearOperator((n,n), matvec=A)
12 | self.b = b.reshape(-1)
13 | self.x0 = x0.reshape(-1)
14 | self.tol = tol
15 | self.niter = 0
16 | if diag is None:
17 | self.M = None
18 | else:
19 | diag = diag.reshape(-1)
20 | Mx = lambda x: x/diag
21 | self.M = spla.LinearOperator((n,n), matvec=Mx)
22 |
23 | def solve(self):
24 | callback = None
25 | self.niter = 0
26 | def callback(rk):
27 | #print ("residual =", rk)
28 | self.niter += 1
29 | #self.x, self.info = spla.gmres(self.A, self.b, x0=self.x0, M=self.M,
30 | # maxiter=200, callback=callback, restart=40, tol=self.tol)
31 | self.x, self.info = spla.gcrotmk(self.A, self.b, x0=self.x0, M=self.M,
32 | maxiter=200, callback=callback, m=40, tol=self.tol)
33 | self.x = self.x.reshape(-1)
34 | if self.info > 0:
35 | print ("convergence to tolerance not achieved in", self.info, "iterations")
36 | return self.x
37 |
38 |
39 | def setA(size, plus):
40 | A = np.zeros(shape=(size,size),dtype=complex)
41 | diag = np.zeros(shape=(size),dtype=complex)
42 | fac = 1.0
43 | for i in xrange(size):
44 | A[i,i] = 1.0 * fac + 6.0 * 1j * fac + plus + 30.*np.random.random()
45 | diag[i] = A[i,i]
46 | if i+2 < size:
47 | A[i,i+2] = 1.0 * fac
48 | if i+3 < size:
49 | A[i,i+3] = 0.7 * fac
50 | if i+1 < size:
51 | A[i+1,i] = 3.0*1j * fac
52 | return A, diag
53 |
54 |
55 | def main():
56 | size = 300
57 | A, diag = setA(size, 0.0+1j*0.0)
58 | b = np.random.rand(size) + 0j*np.random.rand(size)
59 | b /= np.linalg.norm(b)
60 |
61 | x0 = np.dot(np.linalg.inv(A),b)
62 | x0 += 1./1.*(np.random.rand(size) + 0j*np.random.rand(size))
63 | condition_number = np.linalg.cond(A)
64 | res = np.linalg.norm(b-np.dot(A,x0))
65 | finalx = np.dot(np.linalg.inv(A), b)
66 | print (" ::: Making A,b matrix :::")
67 | print (" - condition number = %12.8f" % condition_number)
68 | print (" - x0 residual = %12.8f" % np.real(res))
69 |
70 | def multiplyA(vector, args=None):
71 | return np.dot(A,vector)
72 |
73 | gmin = GMRES(multiplyA, b, x0, diag)
74 | sol = gmin.solve()
75 |
76 | print ("|Ax-b| = ", np.linalg.norm(np.dot(A,sol) - b))
77 |
78 | if __name__ == '__main__':
79 | main()
80 |
--------------------------------------------------------------------------------
/fcdmft/solver/mpiccgf.py:
--------------------------------------------------------------------------------
1 | import time
2 | import sys
3 |
4 | import numpy as np
5 | import scipy
6 | from fcdmft.solver import gmres
7 |
8 | import pyscf
9 | import pyscf.cc
10 | from pyscf.lib import logger
11 | from pyscf.cc.eom_rccsd import amplitudes_to_vector_ip, amplitudes_to_vector_ea
12 |
13 | from mpi4py import MPI
14 |
15 |
16 | '''
17 | MPI CCSD Green's function
18 | '''
19 |
20 | rank = MPI.COMM_WORLD.Get_rank()
21 | size = MPI.COMM_WORLD.Get_size()
22 | comm = MPI.COMM_WORLD
23 |
24 | def greens_b_singles_ea_rhf(t1, p):
25 | nocc, nvir = t1.shape
26 | ds_type = t1.dtype
27 | if p < nocc:
28 | return -t1[p,:]
29 | else:
30 | p = p-nocc
31 | result = np.zeros((nvir,), dtype=ds_type)
32 | result[p] = 1.0
33 | return result
34 |
35 |
36 | def greens_b_doubles_ea_rhf(t2, p):
37 | nocc, _, nvir, _ = t2.shape
38 | ds_type = t2.dtype
39 | if p < nocc:
40 | return -t2[p,:,:,:]
41 | else:
42 | return np.zeros((nocc,nvir,nvir), dtype=ds_type)
43 |
44 |
45 | def greens_b_vector_ea_rhf(cc, p):
46 | return amplitudes_to_vector_ea(
47 | greens_b_singles_ea_rhf(cc.t1, p),
48 | greens_b_doubles_ea_rhf(cc.t2, p),
49 | )
50 |
51 |
52 | def greens_e_singles_ea_rhf(t1, t2, l1, l2, p):
53 | nocc, nvir = t1.shape
54 | ds_type = t1.dtype
55 | if p < nocc:
56 | return l1[p, :]
57 | else:
58 | p = p-nocc
59 | result = np.zeros((nvir,), dtype=ds_type)
60 | result[p] = -1.0
61 | result += np.einsum('ia,i->a', l1, t1[:,p])
62 | result += 2*np.einsum('klca,klc->a', l2, t2[:,:,:,p])
63 | result -= np.einsum('klca,lkc->a', l2, t2[:,:,:,p])
64 | return result
65 |
66 |
67 | def greens_e_doubles_ea_rhf(t1, l1, l2, p):
68 | nocc, nvir = t1.shape
69 | ds_type = t1.dtype
70 | if p < nocc:
71 | return 2*l2[p,:,:,:] - l2[:,p,:,:]
72 | else:
73 | p = p-nocc
74 | result = np.zeros((nocc,nvir,nvir), dtype=ds_type)
75 | result[:,p,:] += -2*l1
76 | result[:,:,p] += l1
77 | result += 2*np.einsum('k,jkba->jab', t1[:,p], l2)
78 | result -= np.einsum('k,jkab->jab', t1[:,p], l2)
79 | return result
80 |
81 |
82 | def greens_e_vector_ea_rhf(cc, p):
83 | return amplitudes_to_vector_ea(
84 | greens_e_singles_ea_rhf(cc.t1, cc.t2, cc.l1, cc.l2, p),
85 | greens_e_doubles_ea_rhf(cc.t1, cc.l1, cc.l2, p),
86 | )
87 |
88 |
89 | def greens_b_singles_ip_rhf(t1, p):
90 | nocc, nvir = t1.shape
91 | ds_type = t1.dtype
92 | if p < nocc:
93 | result = np.zeros((nocc,), dtype=ds_type)
94 | result[p] = 1.0
95 | return result
96 | else:
97 | p = p-nocc
98 | return t1[:,p]
99 |
100 |
101 | def greens_b_doubles_ip_rhf(t2, p):
102 | nocc, _, nvir, _ = t2.shape
103 | ds_type = t2.dtype
104 | if p < nocc:
105 | return np.zeros((nocc,nocc,nvir), dtype=ds_type)
106 | else:
107 | p = p-nocc
108 | return t2[:,:,p,:]
109 |
110 |
111 | def greens_b_vector_ip_rhf(cc, p):
112 | return amplitudes_to_vector_ip(
113 | greens_b_singles_ip_rhf(cc.t1, p),
114 | greens_b_doubles_ip_rhf(cc.t2, p),
115 | )
116 |
117 |
118 | def greens_e_singles_ip_rhf(t1, t2, l1, l2, p):
119 | nocc, nvir = t1.shape
120 | ds_type = t1.dtype
121 | if p < nocc:
122 | result = np.zeros((nocc,), dtype=ds_type)
123 | result[p] = -1.0
124 | result += np.einsum('ia,a->i', l1, t1[p,:])
125 | result += 2*np.einsum('ilcd,lcd->i', l2, t2[p,:,:,:])
126 | result -= np.einsum('ilcd,ldc->i', l2, t2[p,:,:,:])
127 | return result
128 | else:
129 | p = p-nocc
130 | return -l1[:,p]
131 |
132 |
133 | def greens_e_doubles_ip_rhf(t1, l1, l2, p):
134 | nocc, nvir = t1.shape
135 | ds_type = t1.dtype
136 | if p < nocc:
137 | result = np.zeros((nocc, nocc, nvir), dtype=ds_type)
138 | result[p, :, :] += -2*l1
139 | result[:, p, :] += l1
140 | result += 2*np.einsum('c,ijcb->ijb', t1[p,:], l2)
141 | result -= np.einsum('c,jicb->ijb', t1[p,:], l2)
142 | return result
143 | else:
144 | p = p-nocc
145 | return -2*l2[:,:,p,:] + l2[:,:,:,p]
146 |
147 |
148 | def greens_e_vector_ip_rhf(cc, p):
149 | return amplitudes_to_vector_ip(
150 | greens_e_singles_ip_rhf(cc.t1, cc.t2, cc.l1, cc.l2, p),
151 | greens_e_doubles_ip_rhf(cc.t1, cc.l1, cc.l2, p),
152 | )
153 |
154 |
155 | def greens_func_multiply(ham, vector, linear_part, **kwargs):
156 | return np.array(ham(vector, **kwargs) + linear_part * vector)
157 |
158 |
159 | def ip_shape(cc):
160 | nocc, nvir = cc.t1.shape
161 | return nocc + nocc*nocc*nvir
162 |
163 |
164 | def ea_shape(cc):
165 | nocc, nvir = cc.t1.shape
166 | return nvir + nocc*nvir*nvir
167 |
168 |
169 | class CCGF(object):
170 | def __init__(self, mycc, tol=1e-4, verbose=None):
171 | self._cc = mycc
172 | self.tol = tol
173 | if verbose:
174 | self.verbose = verbose
175 | else:
176 | self.verbose = self._cc.verbose
177 | self.stdout = sys.stdout
178 |
179 | def ipccsd_ao(self, ps, omega_list, mo_coeff, broadening):
180 | '''
181 | Compute IP-CCSD-GF in AO basis (parallelize over orbitals)
182 | '''
183 | eomip = pyscf.cc.eom_rccsd.EOMIP(self._cc)
184 | eomip_imds = eomip.make_imds()
185 | diag = eomip.get_diag()
186 |
187 | nmo = mo_coeff.shape[1]
188 | e_vector_mo = np.zeros([nmo, ip_shape(self._cc)], dtype=np.complex128)
189 | b_vector_mo = np.zeros([ip_shape(self._cc), nmo], dtype=np.complex128)
190 | for i in range(nmo):
191 | e_vector_mo[i,:] = greens_e_vector_ip_rhf(self._cc, i)
192 | e_vector_ao = np.einsum("pi,ix->px", mo_coeff[ps,:], e_vector_mo)
193 | for i in range(nmo):
194 | b_vector_mo[:,i] = greens_b_vector_ip_rhf(self._cc, i)
195 | b_vector_ao = np.einsum("xi,ip->xp", b_vector_mo, mo_coeff.T[:,ps])
196 | comm.Barrier()
197 |
198 | segsize = len(ps) // size
199 | if rank >= size-(len(ps)-segsize*size):
200 | start = rank * segsize + rank-(size-(len(ps)-segsize*size))
201 | stop = min(len(ps), start+segsize+1)
202 | else:
203 | start = rank * segsize
204 | stop = min(len(ps), start+segsize)
205 |
206 | gf_ao = np.zeros((stop-start, len(ps), len(omega_list)), dtype=np.complex128)
207 | for ip in range(start,stop):
208 | p = ps[ip]
209 | x0 = None
210 | for iomega in range(len(omega_list))[::-1]:
211 | curr_omega = omega_list[iomega]
212 |
213 | def matr_multiply(vector, args=None):
214 | return greens_func_multiply(eomip.matvec, vector, curr_omega - 1j * broadening, imds=eomip_imds)
215 |
216 | diag_w = diag + curr_omega-1j*broadening
217 | if x0 is None:
218 | x0 = b_vector_ao[:,ip]/diag_w
219 | solver = gmres.GMRES(matr_multiply, b_vector_ao[:,ip], x0, diag_w, tol=self.tol)
220 | cput1 = (time.process_time(), time.perf_counter())
221 | sol = solver.solve().reshape(-1)
222 | cput1 = logger.timer(self, 'IPGF orbital p = %d/%d, freq w = %d/%d (%d iterations) @ Rank %d'%(
223 | ip+1,len(ps),iomega+1,len(omega_list),solver.niter,rank), *cput1)
224 | x0 = sol
225 | for iq, q in enumerate(ps):
226 | gf_ao[ip-start,iq,iomega] = -np.dot(e_vector_ao[iq,:], sol)
227 | comm.Barrier()
228 | gf_ao_gather = comm.gather(gf_ao)
229 | if rank == 0:
230 | gf_ao_gather = np.vstack(gf_ao_gather)
231 | comm.Barrier()
232 | gf_ao_gather = comm.bcast(gf_ao_gather,root=0)
233 | return gf_ao_gather
234 |
235 | def eaccsd_ao(self, ps, omega_list, mo_coeff, broadening):
236 | '''
237 | Compute EA-CCSD-GF in AO basis (parallelize over orbitals)
238 | '''
239 | eomea = pyscf.cc.eom_rccsd.EOMEA(self._cc)
240 | eomea_imds = eomea.make_imds()
241 | diag = eomea.get_diag()
242 |
243 | nmo = mo_coeff.shape[1]
244 | e_vector_mo = np.zeros([nmo, ea_shape(self._cc)], dtype=np.complex128)
245 | b_vector_mo = np.zeros([ea_shape(self._cc), nmo], dtype=np.complex128)
246 | for i in range(nmo):
247 | e_vector_mo[i,:] = greens_e_vector_ea_rhf(self._cc, i)
248 | e_vector_ao = np.einsum("pi,ix->px", mo_coeff[ps,:], e_vector_mo)
249 | for i in range(nmo):
250 | b_vector_mo[:,i] = greens_b_vector_ea_rhf(self._cc, i)
251 | b_vector_ao = np.einsum("xi,ip->xp", b_vector_mo, mo_coeff.T[:,ps])
252 | comm.Barrier()
253 |
254 | segsize = len(ps) // size
255 | if rank < len(ps)-segsize*size:
256 | start = rank * segsize + rank
257 | stop = min(len(ps), start+segsize+1)
258 | else:
259 | start = rank * segsize + len(ps)-segsize*size
260 | stop = min(len(ps), start+segsize)
261 |
262 | gf_ao = np.zeros((len(ps), stop-start, len(omega_list)), dtype=np.complex128)
263 | for iq in range(start,stop):
264 | q = ps[iq]
265 | x0 = None
266 | for iomega in range(len(omega_list)):
267 | curr_omega = omega_list[iomega]
268 |
269 | def matr_multiply(vector, args=None):
270 | return greens_func_multiply(eomea.matvec, vector, -curr_omega - 1j * broadening, imds=eomea_imds)
271 |
272 | diag_w = diag + (-curr_omega-1j*broadening)
273 | if x0 is None:
274 | x0 = b_vector_ao[:,iq]/diag_w
275 | solver = gmres.GMRES(matr_multiply, b_vector_ao[:,iq], x0, diag_w, tol=self.tol)
276 | cput1 = (time.process_time(), time.perf_counter())
277 | sol = solver.solve().reshape(-1)
278 | cput1 = logger.timer(self, 'EAGF orbital q = %d/%d, freq w = %d/%d (%d iterations) @ Rank %d'%(
279 | iq+1,len(ps),iomega+1,len(omega_list),solver.niter,rank), *cput1)
280 | x0 = sol
281 | for ip, p in enumerate(ps):
282 | gf_ao[ip,iq-start,iomega] = np.dot(e_vector_ao[ip,:], sol)
283 | comm.Barrier()
284 | gf_ao_gather = comm.gather(gf_ao.transpose(1,0,2))
285 | if rank == 0:
286 | gf_ao_gather = np.vstack(gf_ao_gather).transpose(1,0,2)
287 | comm.Barrier()
288 | gf_ao_gather = comm.bcast(gf_ao_gather,root=0)
289 | return gf_ao_gather
290 |
291 | def ipccsd_mo(self, ps, qs, omega_list, broadening):
292 | '''
293 | Compute IP-CCSD-GF in MO basis
294 | '''
295 | eomip = pyscf.cc.eom_rccsd.EOMIP(self._cc)
296 | eomip_imds = eomip.make_imds()
297 | diag = eomip.get_diag()
298 | e_vector = list()
299 | for q in qs:
300 | e_vector.append(greens_e_vector_ip_rhf(self._cc, q))
301 |
302 | segsize = len(ps) // size
303 | if rank < len(ps)-segsize*size:
304 | start = rank * segsize + rank
305 | stop = min(len(ps), start+segsize+1)
306 | else:
307 | start = rank * segsize + len(ps)-segsize*size
308 | stop = min(len(ps), start+segsize)
309 |
310 | gfvals = np.zeros((stop-start, len(qs), len(omega_list)), dtype=np.complex128)
311 | for ip in range(start,stop):
312 | p = ps[ip]
313 | b_vector = greens_b_vector_ip_rhf(self._cc, p)
314 | for iomega in range(len(omega_list)):
315 | curr_omega = omega_list[iomega]
316 |
317 | def matr_multiply(vector, args=None):
318 | return greens_func_multiply(eomip.matvec, vector, curr_omega - 1j * broadening, imds=eomip_imds)
319 |
320 | diag_w = diag + curr_omega-1j*broadening
321 | x0 = b_vector/diag_w
322 | solver = gmres.GMRES(matr_multiply, b_vector, x0, diag_w, tol=self.tol)
323 | cput1 = (time.process_time(), time.perf_counter())
324 | sol = solver.solve().reshape(-1)
325 | cput1 = logger.timer(self, 'IPGF orbital p = %d/%d, freq w = %d/%d (%d iterations) @ Rank %d'%(
326 | ip+1,len(ps),iomega+1,len(omega_list),solver.niter,rank), *cput1)
327 | x0 = sol
328 | for iq, q in enumerate(qs):
329 | gfvals[ip-start,iq,iomega] = -np.dot(e_vector[iq], sol)
330 | comm.Barrier()
331 | gfvals_gather = comm.gather(gfvals)
332 | if rank == 0:
333 | gfvals_gather = np.vstack(gfvals_gather)
334 | comm.Barrier()
335 | gfvals_gather = comm.bcast(gfvals_gather,root=0)
336 | return gfvals_gather
337 |
338 | def eaccsd_mo(self, ps, qs, omega_list, broadening):
339 | '''
340 | Compute EA-CCSD-GF in MO basis
341 | '''
342 | eomea = pyscf.cc.eom_rccsd.EOMEA(self._cc)
343 | eomea_imds = eomea.make_imds()
344 | diag = eomea.get_diag()
345 | e_vector = list()
346 | for p in ps:
347 | e_vector.append(greens_e_vector_ea_rhf(self._cc, p))
348 |
349 | segsize = len(qs) // size
350 | if rank < len(qs)-segsize*size:
351 | start = rank * segsize + rank
352 | stop = min(len(qs), start+segsize+1)
353 | else:
354 | start = rank * segsize + len(qs)-segsize*size
355 | stop = min(len(qs), start+segsize)
356 |
357 | gfvals = np.zeros((len(ps), stop-start, len(omega_list)), dtype=np.complex128)
358 | for iq in range(start,stop):
359 | q = qs[iq]
360 | b_vector = greens_b_vector_ea_rhf(self._cc, q)
361 | for iomega in range(len(omega_list)):
362 | curr_omega = omega_list[iomega]
363 |
364 | def matr_multiply(vector, args=None):
365 | return greens_func_multiply(eomea.matvec, vector, -curr_omega - 1j * broadening, imds=eomea_imds)
366 |
367 | diag_w = diag + (-curr_omega-1j*broadening)
368 | x0 = b_vector/diag_w
369 | solver = gmres.GMRES(matr_multiply, b_vector, x0, diag_w, tol=self.tol)
370 | cput1 = (time.process_time(), time.perf_counter())
371 | sol = solver.solve().reshape(-1)
372 | cput1 = logger.timer(self, 'EAGF orbital q = %d/%d, freq w = %d/%d (%d iterations) @ Rank %d'%(
373 | iq+1,len(qs),iomega+1,len(omega_list),solver.niter,rank), *cput1)
374 | x0 = sol
375 | for ip, p in enumerate(ps):
376 | gfvals[ip,iq-start,iomega] = np.dot(e_vector[ip], sol)
377 | comm.Barrier()
378 | gfvals_gather = comm.gather(gfvals.transpose(1,0,2))
379 | if rank == 0:
380 | gfvals_gather = np.vstack(gfvals_gather).transpose(1,0,2)
381 | comm.Barrier()
382 | gfvals_gather = comm.bcast(gfvals_gather,root=0)
383 | return gfvals_gather
384 |
385 | def get_gf(self, p, q, omega_list, broadening):
386 | return (self.ipccsd_mo(p, q, omega_list, broadening),
387 | self.eaccsd_mo(p, q, omega_list, broadening))
388 |
389 |
--------------------------------------------------------------------------------
/fcdmft/solver/scf_mu.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import numpy
4 | from pyscf.lib import logger
5 | import pyscf.scf as scf
6 | import numpy as np
7 | from pyscf import ao2mo
8 |
9 | '''
10 | HF with fluctuating occupantion and smearing
11 | '''
12 |
13 | class RHF(scf.hf.RHF):
14 | __doc__ = scf.hf.SCF.__doc__
15 |
16 | def __init__(self, mol, mu, smearing=None):
17 | self.mu = mu
18 | self.smearing = smearing
19 | scf.hf.SCF.__init__(self, mol)
20 |
21 | def get_occ(self, mo_energy=None, mo_coeff=None):
22 | mo_occ = numpy.zeros_like(mo_energy)
23 | if self.smearing:
24 | for n,e in enumerate(mo_energy):
25 | mo_occ[n] = 2./(numpy.exp((e-self.mu)/self.smearing)+1)
26 | else:
27 | mo_occ[mo_energy<=self.mu] = 2.
28 | nmo = mo_energy.size
29 | nocc = int(numpy.sum(mo_occ) // 2)
30 | if self.verbose >= logger.INFO and nocc < nmo:
31 | if mo_energy[nocc-1]+1e-3 > mo_energy[nocc]:
32 | logger.warn(self, 'HOMO %.15g == LUMO %.15g',
33 | mo_energy[nocc-1], mo_energy[nocc])
34 | else:
35 | logger.info(self, ' nelec = %d', nocc*2)
36 | logger.info(self, ' HOMO = %.15g LUMO = %.15g',
37 | mo_energy[nocc-1], mo_energy[nocc])
38 |
39 | if self.verbose >= logger.DEBUG:
40 | numpy.set_printoptions(threshold=nmo)
41 | logger.debug(self, ' mo_energy =\n%s', mo_energy)
42 | numpy.set_printoptions(threshold=1000)
43 | return mo_occ
44 |
45 | class UHF(scf.uhf.UHF):
46 | __doc__ = scf.uhf.UHF.__doc__
47 |
48 | def __init__(self, mol, mu, smearing=None):
49 | self.mu = mu
50 | self.smearing = smearing
51 | scf.uhf.UHF.__init__(self, mol)
52 | self._keys = self._keys.union(['h1e', 'ovlp'])
53 | self.h1e = None
54 | self.ovlp = None
55 |
56 | def get_occ(self, mo_energy=None, mo_coeff=None):
57 | mo_occ = numpy.zeros_like(mo_energy)
58 | if self.smearing:
59 | for i in range(2):
60 | for n,e in enumerate(mo_energy[i]):
61 | mo_occ[i][n] = 1./(numpy.exp((e-self.mu)/self.smearing)+1)
62 | else:
63 | for i in range(2):
64 | mo_occ[i][mo_energy[i]<=self.mu] = 1.
65 | nmo = mo_energy[0].size
66 | nocca = int(numpy.sum(mo_occ[0]))
67 | noccb = int(numpy.sum(mo_occ[1]))
68 |
69 | if self.verbose >= logger.INFO and nocca < nmo and noccb > 0 and noccb < nmo:
70 | if mo_energy[0][nocca-1]+1e-3 > mo_energy[0][nocca]:
71 | logger.warn(self, 'alpha HOMO %.15g == LUMO %.15g',
72 | mo_energy[0][nocca-1], mo_energy[0][nocca])
73 | else:
74 | logger.info(self, ' alpha nelec = %d', nocca)
75 | logger.info(self, ' alpha HOMO = %.15g LUMO = %.15g',
76 | mo_energy[0][nocca-1], mo_energy[0][nocca])
77 |
78 | if mo_energy[1][noccb-1]+1e-3 > mo_energy[1][noccb]:
79 | logger.warn(self, 'beta HOMO %.15g == LUMO %.15g',
80 | mo_energy[1][noccb-1], mo_energy[1][noccb])
81 | else:
82 | logger.info(self, ' beta nelec = %d', noccb)
83 | logger.info(self, ' beta HOMO = %.15g LUMO = %.15g',
84 | mo_energy[1][noccb-1], mo_energy[1][noccb])
85 |
86 | if self.verbose >= logger.DEBUG:
87 | numpy.set_printoptions(threshold=nmo)
88 | logger.debug(self, ' mo_energy =\n%s', mo_energy)
89 | numpy.set_printoptions(threshold=1000)
90 |
91 | if mo_coeff is not None and self.verbose >= logger.DEBUG:
92 | ss, s = self.spin_square((mo_coeff[0][:,mo_occ[0]>0],
93 | mo_coeff[1][:,mo_occ[1]>0]), self.get_ovlp())
94 | logger.debug(self, 'multiplicity = %.8g 2S+1 = %.8g', ss, s)
95 | return mo_occ
96 |
97 | def get_jk(self, mol=None, dm=None, hermi=1, with_j=True, with_k=True):
98 | '''Coulomb (J) and exchange (K)
99 |
100 | Args:
101 | dm : a list of 2D arrays or a list of 3D arrays
102 | (alpha_dm, beta_dm) or (alpha_dms, beta_dms)
103 | '''
104 | if mol is None: mol = self.mol
105 | if dm is None: dm = self.make_rdm1()
106 | if self._eri is not None or mol.incore_anyway or self._is_mem_enough():
107 | if self._eri is None:
108 | log.error("SCF eri is not initialized.")
109 | self._eri = mol.intor('int2e', aosym='s8')
110 |
111 | #vj, vk = hf.dot_eri_dm(self._eri, dm, hermi, with_j, with_k)
112 | vj, vk = _get_jk(dm, self._eri)
113 | else:
114 | log.error("Direct SCF not implemented")
115 | vj, vk = hf.SCF.get_jk(self, mol, dm, hermi, with_j, with_k)
116 | return vj, vk
117 |
118 | def energy_elec(self, dm=None, h1e=None, vhf=None):
119 | if dm is None: dm = self.make_rdm1()
120 | if h1e is None:
121 | h1e = self.get_hcore()
122 | if isinstance(dm, numpy.ndarray) and dm.ndim == 2:
123 | dm = numpy.array((dm*.5, dm*.5))
124 | if vhf is None:
125 | vhf = self.get_veff(self.mol, dm)
126 | e1 = numpy.einsum('ij,ji', h1e[0], dm[0])
127 | e1+= numpy.einsum('ij,ji', h1e[1], dm[1])
128 | e_coul =(numpy.einsum('ij,ji', vhf[0], dm[0]) +
129 | numpy.einsum('ij,ji', vhf[1], dm[1])) * .5
130 | logger.debug(self, 'E1 = %s Ecoul = %s', e1, e_coul.real)
131 | return (e1+e_coul).real, e_coul
132 |
133 | def get_hcore(self, *args):
134 | return self.h1e
135 |
136 | def get_ovlp(self, *args):
137 | return self.ovlp
138 |
139 | class UHFNOMU(scf.uhf.UHF):
140 | __doc__ = scf.uhf.UHF.__doc__
141 |
142 | def __init__(self, mol, smearing=None):
143 | scf.uhf.UHF.__init__(self, mol)
144 | self._keys = self._keys.union(['h1e', 'ovlp'])
145 | self.h1e = None
146 | self.ovlp = None
147 |
148 | def get_jk(self, mol=None, dm=None, hermi=1, with_j=True, with_k=True):
149 | '''Coulomb (J) and exchange (K)
150 |
151 | Args:
152 | dm : a list of 2D arrays or a list of 3D arrays
153 | (alpha_dm, beta_dm) or (alpha_dms, beta_dms)
154 | '''
155 | if mol is None: mol = self.mol
156 | if dm is None: dm = self.make_rdm1()
157 | if self._eri is not None or mol.incore_anyway or self._is_mem_enough():
158 | if self._eri is None:
159 | log.error("SCF eri is not initialized.")
160 | self._eri = mol.intor('int2e', aosym='s8')
161 |
162 | #vj, vk = hf.dot_eri_dm(self._eri, dm, hermi, with_j, with_k)
163 | vj, vk = _get_jk(dm, self._eri)
164 | else:
165 | log.error("Direct SCF not implemented")
166 | vj, vk = hf.SCF.get_jk(self, mol, dm, hermi, with_j, with_k)
167 | return vj, vk
168 |
169 | def energy_elec(self, dm=None, h1e=None, vhf=None):
170 | if dm is None: dm = self.make_rdm1()
171 | if h1e is None:
172 | h1e = self.get_hcore()
173 | if isinstance(dm, numpy.ndarray) and dm.ndim == 2:
174 | dm = numpy.array((dm*.5, dm*.5))
175 | if vhf is None:
176 | vhf = self.get_veff(self.mol, dm)
177 | e1 = numpy.einsum('ij,ji', h1e[0], dm[0])
178 | e1+= numpy.einsum('ij,ji', h1e[1], dm[1])
179 | e_coul =(numpy.einsum('ij,ji', vhf[0], dm[0]) +
180 | numpy.einsum('ij,ji', vhf[1], dm[1])) * .5
181 | logger.debug(self, 'E1 = %s Ecoul = %s', e1, e_coul.real)
182 | return (e1+e_coul).real, e_coul
183 |
184 | def get_hcore(self, *args):
185 | return self.h1e
186 |
187 | def get_ovlp(self, *args):
188 | return self.ovlp
189 |
190 | def _get_jk(dm, eri):
191 | """
192 | Get J and K potential from rdm and ERI.
193 | vj00 = np.tensordot(dm[0], eri[0], ((0,1), (0,1))) # J a from a
194 | vj11 = np.tensordot(dm[1], eri[1], ((0,1), (0,1))) # J b from b
195 | vj10 = np.tensordot(dm[0], eri[2], ((0,1), (0,1))) # J b from a
196 | vj01 = np.tensordot(dm[1], eri[2], ((1,0), (3,2))) # J a from b
197 | vk00 = np.tensordot(dm[0], eri[0], ((0,1), (0,3))) # K a from a
198 | vk11 = np.tensordot(dm[1], eri[1], ((0,1), (0,3))) # K b from b
199 | JK = np.asarray([vj00 + vj01 - vk00, vj11 + vj10 - vk11])
200 | """
201 | dm = np.asarray(dm, dtype=np.double)
202 | eri = np.asarray(eri, dtype=np.double)
203 | if len(dm.shape) == 2:
204 | dm = dm[np.newaxis, ...]
205 | if len(eri.shape) == 4:
206 | eri = eri[np.newaxis, ...]
207 | spin = dm.shape[0]
208 | norb = dm.shape[-1]
209 | if spin == 1:
210 | eri = ao2mo.restore(8, eri, norb)
211 | vj, vk = scf.hf.dot_eri_dm(eri, dm, hermi=1)
212 | else:
213 | eri_aa = ao2mo.restore(8, eri[0], norb)
214 | eri_bb = ao2mo.restore(8, eri[1], norb)
215 | eri_ab = ao2mo.restore(4, eri[2], norb)
216 | vj00, vk00 = scf.hf.dot_eri_dm(eri_aa, dm[0], hermi=1)
217 | vj11, vk11 = scf.hf.dot_eri_dm(eri_bb, dm[1], hermi=1)
218 | vj01, _ = scf.hf.dot_eri_dm(eri_ab, dm[1], hermi=1, with_j=True, with_k=False)
219 | # ZHC NOTE the transpose, since the dot_eri_dm uses the convention ijkl, kl -> ij
220 | vj10, _ = scf.hf.dot_eri_dm(eri_ab.T, dm[0], hermi=1, with_j=True, with_k=False)
221 | # ZHC NOTE explicit write down vj, without broadcast
222 | vj = np.asarray([[vj00, vj11], [vj01, vj10]])
223 | vk = np.asarray([vk00, vk11])
224 | return vj, vk
225 |
226 | def _get_veff(dm, eri):
227 | """
228 | Get HF effective potential from rdm and ERI.
229 | """
230 | dm = np.asarray(dm, dtype=np.double)
231 | if len(dm.shape) == 2:
232 | dm = dm[np.newaxis, ...]
233 | spin = dm.shape[0]
234 | vj, vk = _get_jk(dm, eri)
235 | if spin == 1:
236 | JK = vj - vk*0.5
237 | else:
238 | JK = vj[0] + vj[1] - vk
239 | return JK
240 |
241 |
242 |
--------------------------------------------------------------------------------
/fcdmft/solver/ucc_eri.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """
3 | CC impurity solver.
4 | """
5 |
6 | import numpy as np
7 | import scipy.linalg as la
8 | import h5py
9 |
10 | from pyscf import cc
11 | import time
12 | from pyscf import lib
13 | from pyscf import ao2mo
14 | from pyscf.cc.uccsd import _ChemistsERIs
15 |
16 | def _make_eris_incore(mycc, mo_coeff=None, ao2mofn=None):
17 | """
18 | Hacked CC make eri function. NOTE the order.
19 | """
20 | cput0 = (time.process_time(), time.perf_counter())
21 | eris = _ChemistsERIs()
22 | eris._common_init_(mycc, mo_coeff)
23 |
24 | nocca, noccb = mycc.nocc
25 | nmoa, nmob = mycc.nmo
26 | nvira, nvirb = nmoa-nocca, nmob-noccb
27 |
28 | moa = eris.mo_coeff[0]
29 | mob = eris.mo_coeff[1]
30 | nmoa = moa.shape[1]
31 | nmob = mob.shape[1]
32 |
33 | if callable(ao2mofn):
34 | eri_aa = ao2mofn(moa).reshape([nmoa]*4)
35 | eri_bb = ao2mofn(mob).reshape([nmob]*4)
36 | eri_ab = ao2mofn((moa,moa,mob,mob))
37 | else:
38 | # ZHC NOTE the order, aa, bb, ab
39 | #if len(self._scf._eri.shape) :
40 | # mycc._scf._eri = np.asarray((mycc._scf._eri, )*3)
41 | eri_aa = ao2mo.restore(1, ao2mo.full(mycc._scf._eri[0], moa), nmoa)
42 | eri_bb = ao2mo.restore(1, ao2mo.full(mycc._scf._eri[1], mob), nmob)
43 | eri_ab = ao2mo.general(mycc._scf._eri[2], (moa,moa,mob,mob), compact=False)
44 | eri_ba = eri_ab.reshape(nmoa,nmoa,nmob,nmob).transpose(2,3,0,1)
45 |
46 | eri_aa = eri_aa.reshape(nmoa,nmoa,nmoa,nmoa)
47 | eri_ab = eri_ab.reshape(nmoa,nmoa,nmob,nmob)
48 | eri_ba = eri_ba.reshape(nmob,nmob,nmoa,nmoa)
49 | eri_bb = eri_bb.reshape(nmob,nmob,nmob,nmob)
50 | eris.oooo = eri_aa[:nocca,:nocca,:nocca,:nocca].copy()
51 | eris.ovoo = eri_aa[:nocca,nocca:,:nocca,:nocca].copy()
52 | eris.ovov = eri_aa[:nocca,nocca:,:nocca,nocca:].copy()
53 | eris.oovv = eri_aa[:nocca,:nocca,nocca:,nocca:].copy()
54 | eris.ovvo = eri_aa[:nocca,nocca:,nocca:,:nocca].copy()
55 | eris.ovvv = eri_aa[:nocca,nocca:,nocca:,nocca:].copy()
56 | eris.vvvv = eri_aa[nocca:,nocca:,nocca:,nocca:].copy()
57 | eri_aa = None
58 |
59 | eris.OOOO = eri_bb[:noccb,:noccb,:noccb,:noccb].copy()
60 | eris.OVOO = eri_bb[:noccb,noccb:,:noccb,:noccb].copy()
61 | eris.OVOV = eri_bb[:noccb,noccb:,:noccb,noccb:].copy()
62 | eris.OOVV = eri_bb[:noccb,:noccb,noccb:,noccb:].copy()
63 | eris.OVVO = eri_bb[:noccb,noccb:,noccb:,:noccb].copy()
64 | eris.OVVV = eri_bb[:noccb,noccb:,noccb:,noccb:].copy()
65 | eris.VVVV = eri_bb[noccb:,noccb:,noccb:,noccb:].copy()
66 | eri_bb = None
67 |
68 | eris.ooOO = eri_ab[:nocca,:nocca,:noccb,:noccb].copy()
69 | eris.ovOO = eri_ab[:nocca,nocca:,:noccb,:noccb].copy()
70 | eris.ovOV = eri_ab[:nocca,nocca:,:noccb,noccb:].copy()
71 | eris.ooVV = eri_ab[:nocca,:nocca,noccb:,noccb:].copy()
72 | eris.ovVO = eri_ab[:nocca,nocca:,noccb:,:noccb].copy()
73 | eris.ovVV = eri_ab[:nocca,nocca:,noccb:,noccb:].copy()
74 | eris.vvVV = eri_ab[nocca:,nocca:,noccb:,noccb:].copy()
75 |
76 | #eris.OOoo = eri_ba[:noccb,:noccb,:nocca,:nocca].copy()
77 | eris.OVoo = eri_ba[:noccb,noccb:,:nocca,:nocca].copy()
78 | #eris.OVov = eri_ba[:noccb,noccb:,:nocca,nocca:].copy()
79 | eris.OOvv = eri_ba[:noccb,:noccb,nocca:,nocca:].copy()
80 | eris.OVvo = eri_ba[:noccb,noccb:,nocca:,:nocca].copy()
81 | eris.OVvv = eri_ba[:noccb,noccb:,nocca:,nocca:].copy()
82 | #eris.VVvv = eri_ba[noccb:,noccb:,nocca:,nocca:].copy()
83 | eri_ab = None
84 |
85 | if not callable(ao2mofn):
86 | ovvv = eris.ovvv.reshape(nocca*nvira,nvira,nvira)
87 | eris.ovvv = lib.pack_tril(ovvv).reshape(nocca,nvira,nvira*(nvira+1)//2)
88 | eris.vvvv = ao2mo.restore(4, eris.vvvv, nvira)
89 |
90 | OVVV = eris.OVVV.reshape(noccb*nvirb,nvirb,nvirb)
91 | eris.OVVV = lib.pack_tril(OVVV).reshape(noccb,nvirb,nvirb*(nvirb+1)//2)
92 | eris.VVVV = ao2mo.restore(4, eris.VVVV, nvirb)
93 |
94 | ovVV = eris.ovVV.reshape(nocca*nvira,nvirb,nvirb)
95 | eris.ovVV = lib.pack_tril(ovVV).reshape(nocca,nvira,nvirb*(nvirb+1)//2)
96 | vvVV = eris.vvVV.reshape(nvira**2,nvirb**2)
97 | idxa = np.tril_indices(nvira)
98 | idxb = np.tril_indices(nvirb)
99 | eris.vvVV = lib.take_2d(vvVV, idxa[0]*nvira+idxa[1], idxb[0]*nvirb+idxb[1])
100 |
101 | OVvv = eris.OVvv.reshape(noccb*nvirb,nvira,nvira)
102 | eris.OVvv = lib.pack_tril(OVvv).reshape(noccb,nvirb,nvira*(nvira+1)//2)
103 | return eris
104 |
105 | cc.uccsd._make_eris_incore = _make_eris_incore
106 |
--------------------------------------------------------------------------------
/fcdmft/utils/cholesky.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import math
3 |
4 | LINEAR_DEP_THR = 1e-12
5 |
6 | def mat_loop_2d(ni,nj, i0=0, istep=1, j0=0, jstep=1):
7 |
8 | '''Loop over the full 2d matrix
9 | '''
10 |
11 | for i in range(i0, ni, istep):
12 | for j in range(j0, nj, jstep):
13 | yield i,j
14 |
15 |
16 | def get_eri_diag(eri):
17 |
18 | nao = eri.shape[0]
19 | out = np.empty([nao,nao], dtype=np.double)
20 | for mu in range(nao):
21 | for nu in range(nao):
22 | out[mu,nu] = eri[mu,nu,mu,nu]
23 |
24 | return out
25 |
26 |
27 | class AOPair():
28 |
29 | def __init__(self,mu,nu):
30 |
31 | self.mu = mu
32 | self.nu = nu
33 | self.Bmask = 0
34 | self.Dmask = 0
35 | self.eri_diag = -999999.0
36 | self.eri_off_ioff = 0
37 | self.Lpq = None
38 |
39 |
40 | class AOPairs():
41 |
42 | def __init__(self, nao):
43 |
44 | self.nao = nao
45 | self.n_aopairs = nao*nao
46 | self.eri_diag = None
47 | self.sorted_ind = None
48 |
49 | self.data = None
50 |
51 | def init_aopairs(self):
52 |
53 | ni = self.nao
54 | nj = self.nao
55 |
56 | self.data = np.empty([ni,nj], dtype = object)
57 | for i,j in mat_loop_2d(ni,nj):
58 | self.data[i,j] = AOPair(i,j)
59 |
60 | def get_eri_diag(self, eri):
61 |
62 | self.eri_diag = get_eri_diag(eri)
63 | for i, j in self.ijloop():
64 | ao_pair = self.get_aopair(i,j)
65 | ao_pair.eri_diag = self.eri_diag[i,j]
66 |
67 | def print_eri_diag(self):
68 | for i, j in self.ijloop():
69 | ao_pair = self.get_aopair(i,j)
70 | print(i,j, ao_pair.eri_diag)
71 |
72 | def get_aopair(self, i, j):
73 |
74 | return self.data[i,j]
75 |
76 |
77 | def ijloop(self):
78 |
79 | for i,j in mat_loop_2d(self.nao, self.nao):
80 | yield i,j
81 |
82 | def reorder_aopairs(self):
83 |
84 | max_diag_values = np.zeros([self.n_aopairs])
85 | ind = 0
86 | for i,j in self.ijloop():
87 | max_diag_values[ind] = self.eri_diag[i,j]
88 | ind += 1
89 | self.sorted_ind = np.argsort(-max_diag_values)
90 |
91 | def sorted_ijloop(self):
92 |
93 | if self.sorted_ind is None:
94 | self.reorder_aopairs()
95 |
96 | nj = self.nao
97 | for ind in self.sorted_ind:
98 | i = ind//nj
99 | j = ind % nj
100 | yield i,j
101 |
102 | def sorted_aopairs(self):
103 |
104 | for i, j in self.sorted_ijloop():
105 | yield self.get_aopair(i,j)
106 |
107 |
108 |
109 | def make_eri_offdiag(self,eri, p_aopair_ind, q_aopair_ind):
110 |
111 | nij = p_aopair_ind.shape[0]
112 | nkl = q_aopair_ind.shape[0]
113 | out = np.empty([nij*nkl], dtype=np.double)
114 | ind = 0
115 | for ij in range(nij):
116 | i = p_aopair_ind[ij,0]
117 | j = p_aopair_ind[ij,1]
118 | for kl in range(nkl):
119 | k = q_aopair_ind[kl,0]
120 | l = q_aopair_ind[kl,1]
121 | out[ind] = eri[i,j,k,l]
122 | ind += 1
123 |
124 | return out, nij, nkl
125 |
126 | def make_eri_ao_aopair(self, eri, kl_ind):
127 |
128 | nao = self.nao
129 | nao_r = len(kl_ind)
130 | nao_l = nao * nao
131 | out = np.empty([nao_l, nao_r], dtype = np.double)
132 | ind = 0
133 | eri = eri.reshape(nao_l, nao, nao)
134 | for kl in kl_ind:
135 | k = kl[0]
136 | l = kl[1]
137 | out[:,ind] = eri[:,k,l]
138 | ind += 1
139 |
140 | return out, nao_l, nao_r
141 |
142 |
143 | class cholesky():
144 |
145 | def __init__(self, eri, tau=1e-8, sigma=1e-2, dimQ=10):
146 |
147 | self.eri = eri
148 | self.tau = tau
149 | self.sigma = sigma
150 | self.dimQ = dimQ
151 |
152 | nao = self.eri.shape[0]
153 | self.ao_pairs = AOPairs(nao)
154 | self.ao_pairs.init_aopairs()
155 |
156 | def kernel(self):
157 |
158 | self.step1()
159 | return self.step2()
160 |
161 | def step1(self):
162 |
163 | self.ao_pairs.get_eri_diag(self.eri)
164 |
165 | it = 0
166 | while True:
167 |
168 | it += 1
169 | if it > 200:
170 | print("decomposition is likely to fail!!!!")
171 | exit()
172 |
173 | Dmax = 0.0
174 | D = []
175 | Q = []
176 | nq = 0
177 | ioff = 0
178 | self.ao_pairs.sorted_ind = None
179 | for ind, ao_pair in enumerate(self.ao_pairs.sorted_aopairs()):
180 |
181 | max_diag = ao_pair.eri_diag
182 | if max_diag < self.tau:
183 | ao_pair.Dmask = 0
184 | ao_pair.Lpq = None
185 | continue
186 |
187 | if ind == 0: Dmax = max_diag
188 |
189 | i = ao_pair.mu
190 | j = ao_pair.nu
191 |
192 | ao_pair.Dmask = 1
193 | D.append((i,j))
194 |
195 | ao_pair.eri_off_ioff = ioff
196 | ioff += 1
197 |
198 | if nq < self.dimQ:
199 | if ao_pair.eri_diag > self.sigma * Dmax:
200 | ao_pair.Dmask = 2
201 | Q.append((i,j))
202 | nq += 1
203 |
204 | if nq == 0: break
205 | p_aopair_ind = np.asarray(D)
206 | q_aopair_ind = np.asarray(Q)
207 |
208 | eri_offdiag, nao_ij, nao_kl = self.ao_pairs.make_eri_offdiag(self.eri, p_aopair_ind, q_aopair_ind)
209 | eri_offdiag = eri_offdiag.reshape((nao_ij, nao_kl))
210 |
211 | tmp = []
212 | for q in Q:
213 | i = q[0]
214 | j = q[1]
215 | ao_pair = self.ao_pairs.get_aopair(i,j)
216 | Dq = -999999.0
217 | if ao_pair.Dmask == 2:
218 | Dq = ao_pair.eri_diag
219 | tmp.append((i, j, 0, Dq))
220 |
221 | tmp1=np.asarray(tmp)[:,-1]
222 | sorted_q = np.argsort(-tmp1)
223 |
224 | for p in D:
225 | ao_pair = self.ao_pairs.get_aopair(p[0],p[1])
226 | if ao_pair.Lpq is None: continue
227 | ioff = ao_pair.eri_off_ioff
228 | size = 1
229 |
230 | LL = np.zeros([size, nao_kl], dtype=np.double)
231 | for ind, q in enumerate(tmp):
232 | if q[-1] < -9999: continue
233 | ao_pair_q = self.ao_pairs.get_aopair(q[0],q[1])
234 | if ao_pair_q.Lpq is None: continue
235 |
236 | LL[:,ind:ind+1] = np.dot(ao_pair.Lpq, ao_pair_q.Lpq[q[2]:q[2]+1,:].T)
237 | eri_offdiag[ioff:ioff+size,:] -= LL
238 |
239 |
240 | Lpq = np.empty([nao_ij, nq], dtype=np.double)
241 | iq = 0
242 | for ind in sorted_q:
243 | q = tmp[ind]
244 | if q[-1] < -9999: break
245 |
246 | Mpq = eri_offdiag[:,ind]
247 | Mqq = -1.0
248 | ao_pair = self.ao_pairs.get_aopair(q[0],q[1])
249 | ioff = ao_pair.eri_off_ioff
250 | q_left = ioff + q[2]
251 | Mqq = eri_offdiag[q_left,ind]
252 |
253 | Ltmp = np.zeros([nao_ij], dtype=np.double)
254 | for J in range(0,iq):
255 | Ltmp += Lpq[:,J] * Lpq[q_left, J]
256 |
257 | Lpq[:,iq] = (Mpq - Ltmp)/math.sqrt(Mqq)
258 |
259 |
260 | ao_pair.Dmask = 1 #remove q from Q
261 | ao_pair.Bmask = 1
262 |
263 |
264 | for p in D:
265 | ao_pair = self.ao_pairs.get_aopair(p[0],p[1])
266 | ioff = ao_pair.eri_off_ioff
267 | size = 1
268 | ao_pair.eri_diag -= Lpq[ioff:ioff+size,iq]**2
269 |
270 | iq += 1
271 |
272 | for p in D:
273 | ao_pair = self.ao_pairs.get_aopair(p[0],p[1])
274 | ioff = ao_pair.eri_off_ioff
275 | size = 1
276 | if ao_pair.Lpq is None:
277 | ao_pair.Lpq = Lpq[ioff:ioff+size,:].copy()
278 | else:
279 | ao_pair.Lpq = np.append(ao_pair.Lpq, Lpq[ioff:ioff+size,:], axis=1)
280 |
281 |
282 | def step2(self):
283 |
284 | aopair_ind = []
285 | for i, j in self.ao_pairs.ijloop():
286 | ao_pair = self.ao_pairs.get_aopair(i,j)
287 | if ao_pair.Bmask == 1:
288 | aopair_ind.append((i,j))
289 |
290 | aopair_ind = np.asarray(aopair_ind)
291 |
292 | eri_S, nao_ij, nao_kl = self.ao_pairs.make_eri_offdiag(self.eri, aopair_ind, aopair_ind)
293 | eri_S = eri_S.reshape(nao_ij,nao_kl)
294 | eri_S_ao = eri_S
295 |
296 | try:
297 | L = np.linalg.cholesky(eri_S_ao)
298 | tag = 'cd'
299 | except np.linalg.LinAlgError:
300 | w, v = np.linalg.eigh(eri_S_ao)
301 | idx = w > LINEAR_DEP_THR
302 | L = v[:,idx]/np.sqrt(w[idx])
303 | tag = 'eig'
304 | #print(w)
305 |
306 | if tag == 'cd':
307 | L = np.linalg.inv(L).T
308 |
309 | #print("L.shape = ", L.shape)
310 | #L = np.insert(L, insert_loc, 0.0, axis = 0)
311 | #print(L.shape)
312 |
313 | eri, nao_ij, nao_kl = self.ao_pairs.make_eri_ao_aopair(self.eri, aopair_ind)
314 | eri = eri.reshape(nao_ij, nao_kl)
315 | cderi = np.dot(eri,L).T
316 |
317 | return cderi
318 |
319 |
--------------------------------------------------------------------------------
/fcdmft/utils/write.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 | def write_dos(filename, freqs, ldos, occupancy=None):
4 | spin = ldos.shape[0]
5 | if spin == 1:
6 | with open(filename+'.dat', 'w') as f:
7 | if occupancy:
8 | f.write('# n = %0.12g\n'%(occupancy))
9 | for w,freq in enumerate(freqs):
10 | f.write('%0.12g %.12g\n'%(freq, ldos[0][w]))
11 | else:
12 | with open(filename+'.dat', 'w') as f:
13 | if occupancy:
14 | f.write('# n = %0.12g\n'%(occupancy))
15 | for w,freq in enumerate(freqs):
16 | f.write('%0.12g %.12g %.12g %.12g\n'%(freq, ldos[0][w], ldos[1][w],
17 | 0.5*(ldos[0][w]+ldos[1][w])))
18 |
19 | def write_gf_to_dos(filename, freqs, gf):
20 | ldos = -1./np.pi * np.trace(gf.imag,axis1=1,axis2=2)
21 | spin = ldos.shape[0]
22 | if spin == 1:
23 | with open(filename+'.dat', 'w') as f:
24 | for w,freq in enumerate(freqs):
25 | f.write('%0.12g %.12g\n'%(freq, ldos[0][w]))
26 | else:
27 | with open(filename+'.dat', 'w') as f:
28 | for w,freq in enumerate(freqs):
29 | f.write('%0.12g %.12g %.12g %.12g\n'%(freq, ldos[0][w], ldos[1][w],
30 | 0.5*(ldos[0][w]+ldos[1][w])))
31 |
32 | def write_sigma(filename, freqs, sigma):
33 | sig = np.trace(sigma.imag,axis1=1,axis2=2)
34 | spin = sig.shape[0]
35 | if spin == 1:
36 | with open(filename+'.dat', 'w') as f:
37 | for w,freq in enumerate(freqs):
38 | f.write('%0.12g %.12g\n'%(freq, sig[0][w]))
39 | else:
40 | with open(filename+'.dat', 'w') as f:
41 | for w,freq in enumerate(freqs):
42 | f.write('%0.12g %.12g %.12g %.12g\n'%(freq, sig[0][w], sig[1][w],
43 | 0.5*(sig[0][w]+sig[1][w])))
44 |
45 | def write_sigma_elem(filename, freqs, sigma):
46 | spin = sigma.shape[0]
47 | if spin == 1:
48 | with open(filename+'.dat', 'w') as f:
49 | for w,freq in enumerate(freqs):
50 | f.write('%0.12g %0.12g %.12g\n'%(freq, sigma[0][w].real, sigma[0][w].imag))
51 | else:
52 | with open(filename+'.dat', 'w') as f:
53 | for w,freq in enumerate(freqs):
54 | f.write('%0.12g %0.12g %.12g %.12g %.12g\n'%(freq, sigma[0][w].real, sigma[0][w].imag,
55 | sigma[1][w].real, sigma[1][w].imag))
56 |
57 |
--------------------------------------------------------------------------------