Skip to content

Commit fb9742a

Browse files
kosm6966kosm6966claude
authored
Add Linear Nk OCCRI method + ISDF (#155)
* added OCCRI class to init * finished adding compat for uks, rks, uhf, rhf. todo: check test for uks and write kpt functions. * added optimized get_k for occRI using FFTW, OMP and BLAS. * added comments and docstrings. * made compiled version an option if users don't want to build with optimized liibraries. * minor optimizations and removed lib files from .gitignore * fixed bug in build full k * occRI -> occri * added kpt compat. need to make two get_k for modify for use w/ & w/o kpts * kpts test passing. * added logger calls to get_k * added BLAS, FFTW, & OpenMP version of occRI_get_k_kpts. * added kpt docstrings. * added kpt specific diag function to deal with different dm shapes. * split off kpts functions. * fixing bug in c code. vR_dm and ao_mo from python not byte aligned. * can't do simd aligned on cluster without segfaulting. removed calls in non-kpt code. * added nio example * added test suite and examples. * removed debug test * updated tests and examples. merged get_k with get_k_kpts. * scaled down docstrings * Formatted code with Black, isort, and flake8. * Reduced doc strings further * adding multigrid occri. dummy files generated. * added grids. seem to be working. * maybe bug in pyscf rhf? compare FFTDF times in examples 03 & 04. * added mg tests for grids. * added interpolation functions to occri main * added isdf and thc to occri * added overkill doc to isdfx functions * added unrestricted compat. stop tracking multigrid for now. * removed multigrid examples from tracking * wrote tests for function returns etc. * added tests to ensure energy for large and asymmetric kpts occri have correct energy. * moved some functions into utils files in anticipation of adding multigrid compat. * added examples for isdfx. shows scaling is linear. * removed multigrid tests and occri performance examples * removed performance examples * block compute occri like pyscf for low mem. * Formatted code with Black, isort, and flake8. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * Removed exit() in c code. Return errors to the Python side and raise an exception in Python. Cache FFTW plan. * moved commands to build. updated kmesh from kmesh call. * provided a class method to initialize OCCRI, OCCRI.from_mf(mf). updated tests and examples. * added class methods OCCRI.from_mf(mf) and ISDFX.from_mf(mf) for initialization * deleted run_tests.py * formatted with ruff.toml * added note * fixed cmakelists from merge --------- Co-authored-by: kosm6966 <[email protected]> Co-authored-by: Claude <[email protected]>
1 parent 77f816e commit fb9742a

22 files changed

+4373
-1
lines changed

.gitignore

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ dist/
1414
downloads/
1515
eggs/
1616
.eggs/
17-
lib/
17+
lib*.*
1818
lib64/
1919
parts/
2020
sdist/
@@ -109,6 +109,7 @@ venv/
109109
ENV/
110110
env.bak/
111111
venv.bak/
112+
*code-workspace
112113

113114
# Spyder project settings
114115
.spyderproject
@@ -134,3 +135,9 @@ dmypy.json
134135

135136
# MacOS
136137
.DS_Store
138+
139+
# Multigrid modules (development)
140+
multigrid/
141+
**/multigrid/
142+
examples/occri/multigrid/
143+
pytest.ini
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
OCCRI Gamma Point Examples: Getting Started
5+
6+
This example demonstrates the basic usage of OCCRI (Occupied Orbital Coulomb
7+
Resolution of Identity) for efficient exact exchange evaluation in periodic
8+
systems at the Gamma point (single k-point).
9+
10+
OCCRI provides significant speedup over standard FFTDF while maintaining
11+
chemical accuracy for hybrid DFT and Hartree-Fock calculations.
12+
13+
Key concepts covered:
14+
- Basic OCCRI setup and usage
15+
- Different SCF methods (RHF, UHF, RKS, UKS)
16+
- How to set up periodic systems
17+
- Performance and accuracy considerations
18+
"""
19+
20+
import numpy
21+
from pyscf.occri import OCCRI
22+
from pyscf.pbc import gto, scf
23+
24+
print('=== OCCRI Gamma Point Tutorial ===')
25+
print('This example shows basic OCCRI usage for single k-point calculations.\n')
26+
27+
# =============================================================================
28+
# System Setup
29+
# =============================================================================
30+
print('Setting up diamond structure...')
31+
32+
# Set up diamond structure (2 carbon atoms per unit cell)
33+
cell = gto.Cell()
34+
cell.atom = """
35+
C 0.000000 0.000000 0.000000
36+
C 0.890186 0.890186 0.890186
37+
"""
38+
cell.basis = 'gth-szv' # Compact basis set
39+
cell.pseudo = 'gth-pbe' # Pseudopotentials
40+
cell.a = numpy.eye(3) * 3.5607 # Diamond lattice parameter (Å)
41+
cell.mesh = [20] * 3 # FFT mesh
42+
cell.verbose = 0
43+
cell.build()
44+
45+
print(f'System: {" ".join(cell.atom_symbol(i) for i in range(cell.natm))} ({cell.natm} atoms)')
46+
print(f'Basis: {cell.basis}')
47+
print(f'Lattice parameter: {cell.a[0, 0]:.3f} Å')
48+
print(f'FFT mesh: {cell.mesh} ({numpy.prod(cell.mesh)} total points)')
49+
50+
# =============================================================================
51+
# Example 1: Basic OCCRI usage
52+
# =============================================================================
53+
print('\n' + '=' * 50)
54+
print('Example 1: Basic OCCRI Setup')
55+
print('=' * 50)
56+
57+
print('\n1a. Restricted Hartree-Fock (RHF)')
58+
59+
# Standard syntax: attach OCCRI to mean-field object
60+
mf_rhf = scf.RHF(cell)
61+
mf_rhf.with_df = OCCRI.from_mf(mf_rhf) # This line enables OCCRI
62+
e_rhf = mf_rhf.kernel()
63+
64+
print(f' Energy: {e_rhf:.6f} Hartree')
65+
66+
print('\n1b. Unrestricted Hartree-Fock (UHF)')
67+
mf_uhf = scf.UHF(cell)
68+
mf_uhf.with_df = OCCRI.from_mf(mf_uhf)
69+
e_uhf = mf_uhf.kernel()
70+
print(f' Energy: {e_uhf:.6f} Hartree')
71+
72+
# =============================================================================
73+
# Example 2: Hybrid DFT calculations
74+
# =============================================================================
75+
print('\n' + '=' * 50)
76+
print('Example 2: Hybrid DFT with OCCRI')
77+
print('=' * 50)
78+
79+
print('\n2a. PBE0 (25% exact exchange)')
80+
mf_pbe0 = scf.RKS(cell)
81+
mf_pbe0.xc = 'pbe0'
82+
mf_pbe0.with_df = OCCRI.from_mf(mf_pbe0) # OCCRI handles exact exchange
83+
e_pbe0 = mf_pbe0.kernel()
84+
print(f' PBE0 energy: {e_pbe0:.6f} Hartree')
85+
86+
print('\n2b. HSE06 range-separated hybrid')
87+
mf_hse = scf.RKS(cell)
88+
mf_hse.xc = 'hse06' # 25% short-range exact exchange
89+
mf_hse.with_df = OCCRI.from_mf(mf_hse)
90+
e_hse = mf_hse.kernel()
91+
print(f' HSE06 energy: {e_hse:.6f} Hartree')
92+
93+
# =============================================================================
94+
# Example 3: Configuration options
95+
# =============================================================================
96+
print('\n' + '=' * 50)
97+
print('Example 3: OCCRI Configuration')
98+
print('=' * 50)
99+
100+
print('\n3a. Python implementation')
101+
mf_python = scf.RHF(cell)
102+
mf_python.with_df = OCCRI.from_mf(mf_python, disable_c=True)
103+
e_python = mf_python.kernel()
104+
print(f' Python: {e_python:.6f} Ha')
105+
106+
print('\n3b. C extension')
107+
mf_c = scf.RHF(cell)
108+
mf_c.with_df = OCCRI.from_mf(mf_c, disable_c=False)
109+
e_c = mf_c.kernel()
110+
print(f' C extension: {e_c:.6f} Ha')
111+
print(f' Difference: {abs(e_python - e_c):.2e} Ha')
112+
113+
# =============================================================================
114+
# Example 4: FFT mesh convergence study
115+
# =============================================================================
116+
print('\n' + '=' * 60)
117+
print('Example 4: FFT mesh convergence study')
118+
print('=' * 60)
119+
120+
print('OCCRI accuracy depends on FFT mesh density. This example shows')
121+
print('how to converge the mesh size for reliable results.\n')
122+
123+
# Test different mesh sizes - keep k-points fixed
124+
mesh_sizes = [25, 27, 29, 31] # FFT mesh dimensions
125+
energies = []
126+
127+
for mesh_size in mesh_sizes:
128+
print(f'4.{mesh_size}: [{mesh_size}]³ mesh ({mesh_size**3} total points)')
129+
130+
# Create new cell with different mesh
131+
test_cell = cell.copy()
132+
test_cell.mesh = [mesh_size] * 3
133+
test_cell.build()
134+
135+
mf_test = scf.RHF(test_cell)
136+
mf_test.with_df = OCCRI.from_mf(mf_test)
137+
mf_test.verbose = 1 # Reduce output for cleaner display
138+
139+
e_test = mf_test.kernel()
140+
energies.append(e_test)
141+
print(f' Energy: {e_test:.8f} Ha')
142+
143+
if len(energies) > 1:
144+
diff = e_test - energies[-2]
145+
print(f' Change: {diff:.8f} Ha ({abs(diff) * 1000:.2f} mHa)')
146+
147+
# Check convergence
148+
if abs(diff) < 1e-6:
149+
print(' ✓ Converged to μHa accuracy')
150+
elif abs(diff) < 5e-6:
151+
print(' ✓ Converged to 5 μHa accuracy')
152+
else:
153+
print(' ⚠ Not yet converged')
154+
print()
155+
156+
print('Mesh convergence guidelines:')
157+
print('• Energy differences < 1-5 μHa/atom typically sufficient')
158+
print('• Denser meshes → higher accuracy but slower calculation')
159+
160+
# =============================================================================
161+
# Usage guide
162+
# =============================================================================
163+
print('\n' + '=' * 50)
164+
print('OCCRI Usage Guide')
165+
print('=' * 50)
166+
167+
print(
168+
"""
169+
Quick start:
170+
mf = scf.RHF(cell) # Create SCF object
171+
mf.with_df = OCCRI.from_mf(mf) # Enable OCCRI
172+
energy = mf.kernel() # Run calculation
173+
174+
When to use OCCRI:
175+
• Hartree-Fock calculations (exact exchange)
176+
• Hybrid functionals (PBE0, HSE06, etc.)
177+
• When standard FFTDF is too slow
178+
• Large basis sets
179+
180+
Configuration options:
181+
OCCRI.from_mf(mf) # Default (use C if available)
182+
OCCRI.from_mf(mf, disable_c=True) # Force Python implementation
183+
OCCRI.from_mf(mf, disable_c=False) # Force C implementation
184+
185+
Compatible methods:
186+
• scf.RHF, scf.UHF # Hartree-Fock
187+
• scf.RKS, scf.UKS # DFT (any functional)
188+
• Gamma point calculations (use 02-kpoint for k-points)
189+
190+
Performance tips:
191+
• Converge FFT mesh: start low, increase until energy changes < 1-5 μHa/atom
192+
• OCCRI scaling: O(N_occ²) vs FFTDF O(N_AO²)
193+
• Most beneficial when N_AO >> N_occ (large basis, few electrons)
194+
"""
195+
)
196+
197+
print('Example completed successfully!')
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
OCCRI with k-points: Usage Examples
5+
6+
This example demonstrates how to use OCCRI for k-point calculations.
7+
OCCRI provides efficient exact exchange evaluation for periodic systems
8+
with k-point sampling, making it ideal for band structure calculations
9+
and solid-state systems.
10+
11+
Key features demonstrated:
12+
- Setting up k-point calculations with OCCRI
13+
- Different SCF methods (RHF, UHF, RKS, UKS)
14+
- Configuration options
15+
- Performance considerations and best practices
16+
"""
17+
18+
import numpy
19+
from pyscf.occri import OCCRI
20+
from pyscf.pbc import gto, scf
21+
22+
print('=== OCCRI k-point Usage Examples ===')
23+
print('This example shows how to use OCCRI for different k-point calculations.\n')
24+
25+
# Set up a simple diamond structure
26+
cell = gto.Cell()
27+
cell.atom = """
28+
C 0.000000 0.000000 0.000000
29+
C 0.890186 0.890186 0.890186
30+
"""
31+
cell.basis = 'gth-szv' # Compact basis for faster demonstration
32+
cell.pseudo = 'gth-pbe' # Pseudopotentials for efficiency
33+
cell.a = numpy.eye(3) * 3.5607 # Diamond lattice parameter
34+
cell.mesh = [20] * 3 # FFT mesh
35+
cell.verbose = 0
36+
cell.build()
37+
38+
print(f'System: Diamond structure with {cell.natm} atoms')
39+
print(f'FFT mesh: {cell.mesh} (total {numpy.prod(cell.mesh)} points)')
40+
41+
# =============================================================================
42+
# Example 1: Basic k-point setup
43+
# =============================================================================
44+
print('\n' + '=' * 60)
45+
print('Example 1: Basic k-point Hartree-Fock')
46+
print('=' * 60)
47+
48+
# Define k-point mesh - start with small mesh for demonstration
49+
kmesh = [2, 2, 2]
50+
kpts = cell.make_kpts(kmesh)
51+
52+
print(f'k-point mesh: {kmesh} ({len(kpts)} k-points total)')
53+
print('k-point coordinates:')
54+
for i, kpt in enumerate(kpts):
55+
print(f' k{i + 1}: [{kpt[0]:8.4f}, {kpt[1]:8.4f}, {kpt[2]:8.4f}]')
56+
57+
# Set up KRHF calculation with OCCRI
58+
mf = scf.KRHF(cell, kpts)
59+
mf.with_df = OCCRI.from_mf(mf)
60+
61+
print('\nRunning KRHF calculation...')
62+
energy = mf.kernel()
63+
print(f'KRHF energy: {energy:.6f} Hartree')
64+
65+
66+
mf = scf.KRHF(cell, kpts)
67+
mf.with_df = OCCRI.from_mf(mf, disable_c=True)
68+
69+
print('\nRunning KRHF calculation...')
70+
energy = mf.kernel()
71+
print(f'KRHF energy: {energy:.6f} Hartree')
72+
73+
74+
# =============================================================================
75+
# Example 2: Different SCF methods
76+
# =============================================================================
77+
print('\n' + '=' * 60)
78+
print('Example 2: Different SCF methods with OCCRI')
79+
print('=' * 60)
80+
81+
# RHF - Restricted (closed shell)
82+
print('\n2a. Restricted Hartree-Fock (RHF)')
83+
mf_rhf = scf.KRHF(cell, kpts)
84+
mf_rhf.with_df = OCCRI.from_mf(mf_rhf)
85+
e_rhf = mf_rhf.kernel()
86+
print(f' Energy: {e_rhf:.6f} Ha')
87+
88+
# UHF - Unrestricted (open shell capable)
89+
print('\n2b. Unrestricted Hartree-Fock (UHF)')
90+
mf_uhf = scf.KUHF(cell, kpts)
91+
mf_uhf.with_df = OCCRI.from_mf(mf_uhf)
92+
e_uhf = mf_uhf.kernel()
93+
print(f' Energy: {e_uhf:.6f} Ha')
94+
95+
# DFT with hybrid functional
96+
print('\n2c. DFT with PBE0 hybrid functional')
97+
mf_dft = scf.KRKS(cell, kpts)
98+
mf_dft.xc = 'pbe0' # 25% exact exchange + PBE correlation
99+
mf_dft.with_df = OCCRI.from_mf(mf_dft)
100+
e_dft = mf_dft.kernel()
101+
print(f' Energy: {e_dft:.6f} Ha')
102+
103+
# =============================================================================
104+
# Example 3: Configuration options
105+
# =============================================================================
106+
print('\n' + '=' * 60)
107+
print('Example 3: OCCRI configuration options')
108+
print('=' * 60)
109+
110+
import time
111+
112+
# Force Python implementation
113+
print('\n3a. Python implementation (disable_c=True)')
114+
mf_python = scf.KRHF(cell, kpts)
115+
mf_python.with_df = OCCRI.from_mf(mf_python, disable_c=True)
116+
t0 = time.time()
117+
e_python = mf_python.kernel()
118+
print(f' Energy (Python): {e_python:.6f} Ha')
119+
print(f' Time (Python): {time.time() - t0}')
120+
121+
# Use C extension if available (default)
122+
print('\n3b. C extension (default, disable_c=False)')
123+
mf_c = scf.KRHF(cell, kpts)
124+
mf_c.with_df = OCCRI.from_mf(mf_c, disable_c=False)
125+
t0 = time.time()
126+
e_c = mf_c.kernel()
127+
print(f' Energy (C ext): {e_c:.6f} Ha')
128+
print(f' Time (C ext): {time.time() - t0}')
129+
130+
131+
# =============================================================================
132+
# Example 5: Gamma point vs k-point comparison
133+
# =============================================================================
134+
print('\n' + '=' * 60)
135+
print('Example 5: Gamma point vs k-point comparison')
136+
print('=' * 60)
137+
138+
# Gamma point only (equivalent to molecular calculation)
139+
print('\n5a. Gamma point only')
140+
mf_gamma = scf.RHF(cell) # Note: RHF (not KRHF) for gamma point
141+
mf_gamma.with_df = OCCRI.from_mf(mf_gamma)
142+
e_gamma = mf_gamma.kernel()
143+
print(f' Gamma point energy: {e_gamma:.6f} Ha')
144+
145+
# k-point sampling
146+
print(f'\n5b. k-point sampling ({kmesh})')
147+
print(f' k-point energy: {e_rhf:.6f} Ha')
148+
print(f' k-point correction: {e_rhf - e_gamma:.6f} Ha')

0 commit comments

Comments
 (0)