Skip to content

Commit 6244956

Browse files
committed
Feature: add ModuleESolver in pyabacus, support ks_lcao only
1 parent 43f249a commit 6244956

9 files changed

Lines changed: 2543 additions & 1 deletion

File tree

python/pyabacus/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,5 @@ set(CMAKE_INSTALL_RPATH "${PYTHON_SITE_PACKAGES}/${TARGET_PACK}")
100100
add_subdirectory(${PROJECT_SOURCE_DIR}/src/hsolver)
101101
add_subdirectory(${PROJECT_SOURCE_DIR}/src/ModuleBase)
102102
add_subdirectory(${PROJECT_SOURCE_DIR}/src/ModuleNAO)
103+
add_subdirectory(${PROJECT_SOURCE_DIR}/src/ModuleESolver)
103104

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Example: LCAO workflow with breakpoint support
4+
5+
This example demonstrates how to use the LCAOWorkflow class to run
6+
LCAO calculations with Python-controlled SCF and breakpoint support.
7+
8+
Usage:
9+
python lcao_workflow_example.py
10+
11+
Requirements:
12+
- pyabacus with ESolver support
13+
- Input files (INPUT, STRU, KPT, etc.) in current directory
14+
"""
15+
16+
import numpy as np
17+
from pathlib import Path
18+
19+
20+
def example_basic_scf():
21+
"""
22+
Basic SCF calculation example.
23+
24+
Shows how to run a simple SCF calculation and get results.
25+
"""
26+
from pyabacus.esolver import LCAOWorkflow
27+
28+
print("=" * 60)
29+
print("Example 1: Basic SCF Calculation")
30+
print("=" * 60)
31+
32+
# Initialize workflow
33+
workflow = LCAOWorkflow("./", gamma_only=True)
34+
workflow.initialize()
35+
36+
# Run SCF
37+
result = workflow.run_scf(max_iter=100)
38+
39+
# Print results
40+
print(result.summary())
41+
print(f"\nEnergy breakdown:")
42+
for key, value in result.energy.to_dict().items():
43+
print(f" {key}: {value:.8f} Ry")
44+
45+
46+
def example_with_callbacks():
47+
"""
48+
SCF calculation with callbacks example.
49+
50+
Shows how to register callbacks to monitor SCF progress
51+
and inspect state at breakpoints.
52+
"""
53+
from pyabacus.esolver import LCAOWorkflow
54+
55+
print("\n" + "=" * 60)
56+
print("Example 2: SCF with Callbacks")
57+
print("=" * 60)
58+
59+
# Initialize workflow
60+
workflow = LCAOWorkflow("./", gamma_only=True)
61+
workflow.initialize()
62+
63+
# Define callback for each iteration
64+
def print_iteration_info(wf, iter_num):
65+
energy = wf.energy
66+
drho = wf.drho
67+
print(f" Iter {iter_num:3d}: E = {energy.etot:16.8f} Ry, drho = {drho:.2e}")
68+
69+
# Define callback for breakpoint before after_scf
70+
def save_final_state(wf):
71+
print("\n[Breakpoint] Before after_scf - saving state...")
72+
73+
# Get charge density
74+
charge = wf.charge
75+
if charge.rho.size > 0:
76+
print(f" Charge density shape: {charge.rho.shape}")
77+
print(f" Total charge: {charge.total_charge():.6f}")
78+
# Save to file
79+
np.save("charge_density.npy", charge.rho)
80+
print(" Saved charge density to charge_density.npy")
81+
82+
# Get energy
83+
energy = wf.energy
84+
print(f" Total energy: {energy.etot:.8f} Ry")
85+
86+
# Get Hamiltonian (if available)
87+
hamiltonian = wf.hamiltonian
88+
if hamiltonian.nbasis > 0:
89+
print(f" Number of basis functions: {hamiltonian.nbasis}")
90+
print(f" Number of k-points: {hamiltonian.nks}")
91+
92+
print("[Breakpoint] State inspection complete\n")
93+
94+
# Register callbacks
95+
workflow.register_callback('after_iter', print_iteration_info)
96+
workflow.register_callback('before_after_scf', save_final_state)
97+
98+
# Run SCF
99+
print("\nStarting SCF iterations:")
100+
result = workflow.run_scf(max_iter=100)
101+
102+
print(f"\nFinal result: {'Converged' if result.converged else 'Not converged'}")
103+
104+
105+
def example_manual_control():
106+
"""
107+
Manual SCF control example.
108+
109+
Shows how to manually control the SCF loop for maximum flexibility.
110+
"""
111+
from pyabacus.esolver import LCAOWorkflow
112+
113+
print("\n" + "=" * 60)
114+
print("Example 3: Manual SCF Control")
115+
print("=" * 60)
116+
117+
# Initialize workflow
118+
workflow = LCAOWorkflow("./", gamma_only=True)
119+
workflow.initialize()
120+
121+
# Manual SCF control
122+
workflow.before_scf(istep=0)
123+
124+
print("\nManual SCF loop:")
125+
max_iter = 100
126+
for iter_num in range(1, max_iter + 1):
127+
# Run single iteration
128+
workflow.run_scf_step(iter_num)
129+
130+
# Get current state
131+
energy = workflow.energy
132+
drho = workflow.drho
133+
134+
print(f" Iter {iter_num}: E = {energy.etot:.8f} Ry")
135+
136+
# Custom convergence check or early termination
137+
if workflow.is_converged:
138+
print(f"\n Converged at iteration {iter_num}")
139+
break
140+
141+
# Example: Custom breakpoint at iteration 5
142+
if iter_num == 5:
143+
print("\n [Custom breakpoint at iter 5]")
144+
print(f" Current energy: {energy.etot:.8f} Ry")
145+
print(f" Current drho: {drho:.2e}")
146+
# Could save intermediate state here
147+
148+
# Inspect state before finalization
149+
print("\n[Before after_scf]")
150+
charge = workflow.charge
151+
hamiltonian = workflow.hamiltonian
152+
print(f" Charge nspin: {charge.nspin}")
153+
print(f" Hamiltonian nbasis: {hamiltonian.nbasis}")
154+
155+
# Finalize
156+
workflow.after_scf(istep=0)
157+
print("\nSCF completed.")
158+
159+
160+
def example_multi_k():
161+
"""
162+
Multi-k calculation example.
163+
164+
Shows how to run calculations with multiple k-points.
165+
"""
166+
from pyabacus.esolver import LCAOWorkflow
167+
168+
print("\n" + "=" * 60)
169+
print("Example 4: Multi-k Calculation")
170+
print("=" * 60)
171+
172+
# Initialize workflow with multi-k
173+
workflow = LCAOWorkflow("./", gamma_only=False)
174+
workflow.initialize()
175+
176+
# Run SCF
177+
result = workflow.run_scf(max_iter=100)
178+
179+
print(f"\nNumber of k-points: {workflow.nks}")
180+
print(f"Number of bands: {workflow.nbands}")
181+
182+
# Access k-point specific data
183+
for ik in range(min(workflow.nks, 3)): # Show first 3 k-points
184+
kvec = workflow.get_kvec(ik)
185+
eigenvalues = workflow.get_eigenvalues(ik)
186+
print(f"\nK-point {ik}: ({kvec[0]:.4f}, {kvec[1]:.4f}, {kvec[2]:.4f})")
187+
if eigenvalues.size > 0:
188+
print(f" Eigenvalues (first 5): {eigenvalues[:5]}")
189+
190+
191+
def example_data_extraction():
192+
"""
193+
Data extraction example.
194+
195+
Shows how to extract various data for post-processing.
196+
"""
197+
from pyabacus.esolver import LCAOWorkflow
198+
199+
print("\n" + "=" * 60)
200+
print("Example 5: Data Extraction")
201+
print("=" * 60)
202+
203+
workflow = LCAOWorkflow("./", gamma_only=True)
204+
workflow.initialize()
205+
206+
# Run SCF
207+
result = workflow.run_scf(max_iter=100)
208+
209+
# Extract data
210+
print("\n1. Energy Data:")
211+
energy = result.energy
212+
print(f" Total energy: {energy.etot:.8f} Ry ({energy.etot * 13.6057:.8f} eV)")
213+
energy_ev = energy.to_eV()
214+
print(f" Band energy: {energy_ev.eband:.8f} eV")
215+
216+
print("\n2. Charge Density:")
217+
if result.charge is not None and result.charge.rho.size > 0:
218+
charge = result.charge
219+
print(f" Shape: {charge.rho.shape}")
220+
print(f" Min/Max: {charge.rho.min():.6f} / {charge.rho.max():.6f}")
221+
222+
print("\n3. Hamiltonian Matrices:")
223+
hamiltonian = workflow.hamiltonian
224+
if hamiltonian.nbasis > 0:
225+
print(f" Number of basis: {hamiltonian.nbasis}")
226+
print(f" Number of k-points: {hamiltonian.nks}")
227+
if len(hamiltonian.Hk) > 0:
228+
print(f" H(k=0) shape: {hamiltonian.Hk[0].shape}")
229+
230+
print("\n4. Density Matrix:")
231+
dm = workflow.density_matrix
232+
if dm.nks > 0:
233+
print(f" DM dimensions: {dm.nrow} x {dm.ncol}")
234+
print(f" Number of k-points: {dm.nks}")
235+
236+
237+
def main():
238+
"""Run all examples."""
239+
print("PyABACUS LCAO Workflow Examples")
240+
print("================================\n")
241+
242+
# Check if input files exist
243+
input_file = Path("INPUT")
244+
if not input_file.exists():
245+
print("Note: INPUT file not found in current directory.")
246+
print("These examples require ABACUS input files (INPUT, STRU, etc.)")
247+
print("Please run from a directory with valid input files.\n")
248+
print("Showing example code structure only...\n")
249+
250+
# Show code structure without running
251+
import inspect
252+
for func in [example_basic_scf, example_with_callbacks,
253+
example_manual_control, example_data_extraction]:
254+
print(f"\n{'=' * 60}")
255+
print(f"Function: {func.__name__}")
256+
print("=" * 60)
257+
print(func.__doc__)
258+
return
259+
260+
# Run examples
261+
try:
262+
example_basic_scf()
263+
except Exception as e:
264+
print(f"Example 1 failed: {e}")
265+
266+
try:
267+
example_with_callbacks()
268+
except Exception as e:
269+
print(f"Example 2 failed: {e}")
270+
271+
try:
272+
example_manual_control()
273+
except Exception as e:
274+
print(f"Example 3 failed: {e}")
275+
276+
try:
277+
example_data_extraction()
278+
except Exception as e:
279+
print(f"Example 5 failed: {e}")
280+
281+
282+
if __name__ == "__main__":
283+
main()
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# CMakeLists.txt for ModuleESolver Python bindings
2+
# This module provides Python bindings for ESolver_KS_LCAO
3+
4+
# Set paths for ESolver related sources
5+
set(ESOLVER_PATH "${ABACUS_SOURCE_DIR}/source_esolver")
6+
set(ESTATE_PATH "${ABACUS_SOURCE_DIR}/source_estate")
7+
set(LCAO_PATH "${ABACUS_SOURCE_DIR}/source_lcao")
8+
set(HAMILT_PATH "${ABACUS_SOURCE_DIR}/source_hamilt")
9+
set(CELL_PATH "${ABACUS_SOURCE_DIR}/source_cell")
10+
set(PSI_PATH "${ABACUS_SOURCE_DIR}/source_psi")
11+
set(BASIS_PATH "${ABACUS_SOURCE_DIR}/source_basis")
12+
set(IO_PATH "${ABACUS_SOURCE_DIR}/source_io")
13+
14+
# Python module source files - only the binding code
15+
list(APPEND pymodule_esolver
16+
${PROJECT_SOURCE_DIR}/src/ModuleESolver/py_esolver_lcao.cpp
17+
)
18+
19+
# Create pybind11 module
20+
pybind11_add_module(_esolver_pack MODULE ${pymodule_esolver})
21+
22+
target_include_directories(_esolver_pack PRIVATE
23+
${ABACUS_SOURCE_DIR}
24+
${ESOLVER_PATH}
25+
${ESTATE_PATH}
26+
${ESTATE_PATH}/module_charge
27+
${ESTATE_PATH}/module_dm
28+
${ESTATE_PATH}/potentials
29+
${LCAO_PATH}
30+
${LCAO_PATH}/module_hcontainer
31+
${HAMILT_PATH}
32+
${CELL_PATH}
33+
${PSI_PATH}
34+
${BASIS_PATH}
35+
${BASIS_PATH}/module_ao
36+
${BASIS_PATH}/module_nao
37+
${IO_PATH}
38+
${IO_PATH}/module_parameter
39+
)
40+
41+
# Only link pybind11 headers - the module uses placeholder implementations
42+
# that don't require actual ABACUS libraries
43+
target_link_libraries(_esolver_pack PRIVATE
44+
pybind11::headers
45+
)
46+
47+
target_compile_definitions(_esolver_pack PRIVATE VERSION_INFO=${PROJECT_VERSION})
48+
49+
# Set RPATH for shared libraries
50+
set_target_properties(_esolver_pack PROPERTIES INSTALL_RPATH "$ORIGIN")
51+
52+
# Install targets
53+
install(TARGETS _esolver_pack DESTINATION ${TARGET_PACK}/esolver)

0 commit comments

Comments
 (0)