|
| 1 | +# PyABACUS |
| 2 | + |
| 3 | +PyABACUS is the official Python interface for ABACUS, providing a convenient way to run DFT calculations directly from Python scripts. |
| 4 | + |
| 5 | +## Installation |
| 6 | + |
| 7 | +### From Source (Recommended) |
| 8 | + |
| 9 | +```bash |
| 10 | +cd /path/to/abacus-develop/python/pyabacus |
| 11 | +pip install -e . |
| 12 | +``` |
| 13 | + |
| 14 | +### With C++ Driver Support |
| 15 | + |
| 16 | +For full functionality including direct library calls (faster than subprocess), build ABACUS with Python bindings: |
| 17 | + |
| 18 | +```bash |
| 19 | +cmake -B build -DENABLE_PYABACUS=ON -DENABLE_LCAO=ON |
| 20 | +cmake --build build -j8 |
| 21 | +pip install -e python/pyabacus |
| 22 | +``` |
| 23 | + |
| 24 | +**Note:** The `pyabacus` package on PyPI is a different project and is NOT related to ABACUS. Please install from source as shown above. |
| 25 | + |
| 26 | +## Quick Start |
| 27 | + |
| 28 | +### Basic SCF Calculation |
| 29 | + |
| 30 | +```python |
| 31 | +import pyabacus |
| 32 | + |
| 33 | +# Run calculation from a directory containing INPUT, STRU, KPT files |
| 34 | +result = pyabacus.abacus("./Si_scf/") |
| 35 | + |
| 36 | +# Check results |
| 37 | +print(f"Converged: {result.converged}") |
| 38 | +print(f"Total energy: {result.etot_ev:.6f} eV") |
| 39 | +print(result.summary()) |
| 40 | +``` |
| 41 | + |
| 42 | +### Calculate Forces and Stress |
| 43 | + |
| 44 | +```python |
| 45 | +result = pyabacus.abacus( |
| 46 | + "./Si_relax/", |
| 47 | + calculate_force=True, |
| 48 | + calculate_stress=True, |
| 49 | +) |
| 50 | + |
| 51 | +# Access forces (in eV/Angstrom) |
| 52 | +if result.has_forces: |
| 53 | + forces = result.forces_ev_ang |
| 54 | + print(f"Max force: {forces.max():.6f} eV/Ang") |
| 55 | + |
| 56 | +# Access stress tensor (in kbar) |
| 57 | +if result.has_stress: |
| 58 | + print(f"Stress tensor:\n{result.stress}") |
| 59 | +``` |
| 60 | + |
| 61 | +### Parallel Calculation |
| 62 | + |
| 63 | +```python |
| 64 | +# Run with MPI and OpenMP parallelization |
| 65 | +result = pyabacus.abacus( |
| 66 | + "./Si_scf/", |
| 67 | + nprocs=4, # 4 MPI processes (mpirun -np 4) |
| 68 | + nthreads=2, # 2 OpenMP threads (OMP_NUM_THREADS=2) |
| 69 | +) |
| 70 | +``` |
| 71 | + |
| 72 | +This is equivalent to running: |
| 73 | +```bash |
| 74 | +OMP_NUM_THREADS=2 mpirun -np 4 abacus |
| 75 | +``` |
| 76 | + |
| 77 | +### Silent Mode |
| 78 | + |
| 79 | +```python |
| 80 | +# Run without output |
| 81 | +result = pyabacus.abacus("./Si_scf/", verbosity=0) |
| 82 | +``` |
| 83 | + |
| 84 | +## API Reference |
| 85 | + |
| 86 | +### `pyabacus.abacus()` |
| 87 | + |
| 88 | +Main function for running ABACUS calculations. |
| 89 | + |
| 90 | +```python |
| 91 | +def abacus( |
| 92 | + input_dir: str = None, |
| 93 | + *, |
| 94 | + input_file: str = None, |
| 95 | + stru_file: str = None, |
| 96 | + kpt_file: str = None, |
| 97 | + pseudo_dir: str = None, |
| 98 | + orbital_dir: str = None, |
| 99 | + output_dir: str = None, |
| 100 | + calculate_force: bool = True, |
| 101 | + calculate_stress: bool = False, |
| 102 | + verbosity: int = 1, |
| 103 | + nprocs: int = 1, |
| 104 | + nthreads: int = 1, |
| 105 | +) -> CalculationResult |
| 106 | +``` |
| 107 | + |
| 108 | +**Parameters:** |
| 109 | + |
| 110 | +| Parameter | Type | Default | Description | |
| 111 | +|-----------|------|---------|-------------| |
| 112 | +| `input_dir` | str | `"."` | Directory containing INPUT, STRU, KPT files | |
| 113 | +| `input_file` | str | None | Explicit path to INPUT file | |
| 114 | +| `stru_file` | str | None | Explicit path to STRU file | |
| 115 | +| `kpt_file` | str | None | Explicit path to KPT file | |
| 116 | +| `pseudo_dir` | str | None | Directory containing pseudopotentials | |
| 117 | +| `orbital_dir` | str | None | Directory containing orbital files (LCAO) | |
| 118 | +| `output_dir` | str | `"OUT.PYABACUS"` | Directory for output files | |
| 119 | +| `calculate_force` | bool | True | Whether to calculate forces | |
| 120 | +| `calculate_stress` | bool | False | Whether to calculate stress tensor | |
| 121 | +| `verbosity` | int | 1 | Output level (0=silent, 1=normal, 2=verbose) | |
| 122 | +| `nprocs` | int | 1 | Number of MPI processes | |
| 123 | +| `nthreads` | int | 1 | Number of OpenMP threads | |
| 124 | + |
| 125 | +**Returns:** `CalculationResult` object |
| 126 | + |
| 127 | +### `CalculationResult` |
| 128 | + |
| 129 | +Container for calculation results. |
| 130 | + |
| 131 | +**Attributes:** |
| 132 | + |
| 133 | +| Attribute | Type | Description | |
| 134 | +|-----------|------|-------------| |
| 135 | +| `converged` | bool | Whether SCF converged | |
| 136 | +| `niter` | int | Number of SCF iterations | |
| 137 | +| `drho` | float | Final charge density difference | |
| 138 | +| `etot` | float | Total energy (Ry) | |
| 139 | +| `etot_ev` | float | Total energy (eV) | |
| 140 | +| `forces` | ndarray | Forces on atoms (nat, 3) in Ry/Bohr | |
| 141 | +| `forces_ev_ang` | ndarray | Forces in eV/Angstrom | |
| 142 | +| `stress` | ndarray | Stress tensor (3, 3) in kbar | |
| 143 | +| `fermi_energy` | float | Fermi energy (eV) | |
| 144 | +| `bandgap` | float | Band gap (eV) | |
| 145 | +| `nat` | int | Number of atoms | |
| 146 | +| `ntype` | int | Number of atom types | |
| 147 | +| `nbands` | int | Number of bands | |
| 148 | +| `nks` | int | Number of k-points | |
| 149 | +| `output_dir` | str | Path to output directory (OUT.$suffix) | |
| 150 | +| `log_file` | str | Path to the main log file | |
| 151 | +| `output_files` | dict | Dictionary of output files (filename -> path) | |
| 152 | + |
| 153 | +**Methods:** |
| 154 | + |
| 155 | +| Method | Description | |
| 156 | +|--------|-------------| |
| 157 | +| `summary()` | Return a formatted summary string | |
| 158 | +| `energies` | Dictionary of all energy components | |
| 159 | +| `has_forces` | Whether forces are available | |
| 160 | +| `has_stress` | Whether stress is available | |
| 161 | +| `has_output_dir` | Whether output directory exists | |
| 162 | +| `get_output_file(name)` | Get full path to specific output file | |
| 163 | +| `list_output_files()` | List all output file names | |
| 164 | + |
| 165 | +## Output File Tracking |
| 166 | + |
| 167 | +PyABACUS automatically tracks output files generated during calculations: |
| 168 | + |
| 169 | +```python |
| 170 | +result = pyabacus.abacus("./Si_scf/") |
| 171 | + |
| 172 | +# Check output directory |
| 173 | +print(f"Output directory: {result.output_dir}") |
| 174 | +print(f"Log file: {result.log_file}") |
| 175 | + |
| 176 | +# List all output files |
| 177 | +print("Output files:") |
| 178 | +for filename in result.list_output_files(): |
| 179 | + print(f" {filename}") |
| 180 | + |
| 181 | +# Get path to specific file |
| 182 | +bands_file = result.get_output_file("BANDS_1.dat") |
| 183 | +if bands_file: |
| 184 | + # Read and process band structure data |
| 185 | + import numpy as np |
| 186 | + bands = np.loadtxt(bands_file) |
| 187 | +``` |
| 188 | + |
| 189 | +### Common Output Files |
| 190 | + |
| 191 | +| File | Description | |
| 192 | +|------|-------------| |
| 193 | +| `running_scf.log` | Main calculation log | |
| 194 | +| `BANDS_1.dat` | Band structure data | |
| 195 | +| `PDOS` | Projected density of states | |
| 196 | +| `CHARGE.cube` | Charge density in cube format | |
| 197 | +| `SPIN1_CHG.cube` | Spin-up charge density | |
| 198 | +| `SPIN2_CHG.cube` | Spin-down charge density | |
| 199 | +| `istate.info` | Band eigenvalues and occupations | |
| 200 | +| `kpoints` | K-point information | |
| 201 | + |
| 202 | +## Convenience Functions |
| 203 | + |
| 204 | +### `run_scf()` |
| 205 | + |
| 206 | +Alias for `abacus()` with default SCF parameters: |
| 207 | + |
| 208 | +```python |
| 209 | +result = pyabacus.run_scf("./Si_scf/") |
| 210 | +``` |
| 211 | + |
| 212 | +### `run_relax()` |
| 213 | + |
| 214 | +Alias for `abacus()` with force calculation enabled: |
| 215 | + |
| 216 | +```python |
| 217 | +result = pyabacus.run_relax("./Si_relax/") |
| 218 | +``` |
| 219 | + |
| 220 | +## Examples |
| 221 | + |
| 222 | +### Energy vs. Lattice Constant |
| 223 | + |
| 224 | +```python |
| 225 | +import pyabacus |
| 226 | +import numpy as np |
| 227 | + |
| 228 | +lattice_constants = np.linspace(5.0, 5.5, 11) |
| 229 | +energies = [] |
| 230 | + |
| 231 | +for a in lattice_constants: |
| 232 | + # Modify STRU file with new lattice constant |
| 233 | + # ... (file modification code) |
| 234 | + |
| 235 | + result = pyabacus.abacus("./Si_eos/", verbosity=0) |
| 236 | + energies.append(result.etot_ev) |
| 237 | + |
| 238 | +# Plot equation of state |
| 239 | +import matplotlib.pyplot as plt |
| 240 | +plt.plot(lattice_constants, energies, 'o-') |
| 241 | +plt.xlabel("Lattice constant (Ang)") |
| 242 | +plt.ylabel("Energy (eV)") |
| 243 | +plt.savefig("eos.png") |
| 244 | +``` |
| 245 | + |
| 246 | +### Parallel Batch Calculations |
| 247 | + |
| 248 | +```python |
| 249 | +import pyabacus |
| 250 | +from pathlib import Path |
| 251 | + |
| 252 | +# Run calculations for multiple systems with parallelization |
| 253 | +systems = ["Si", "Ge", "C"] |
| 254 | +results = {} |
| 255 | + |
| 256 | +for system in systems: |
| 257 | + input_dir = Path(f"./{system}_scf/") |
| 258 | + if input_dir.exists(): |
| 259 | + result = pyabacus.abacus( |
| 260 | + str(input_dir), |
| 261 | + nprocs=4, |
| 262 | + nthreads=2, |
| 263 | + ) |
| 264 | + results[system] = { |
| 265 | + "energy": result.etot_ev, |
| 266 | + "converged": result.converged, |
| 267 | + "bandgap": result.bandgap, |
| 268 | + } |
| 269 | + |
| 270 | +# Print summary |
| 271 | +for system, data in results.items(): |
| 272 | + print(f"{system}: E={data['energy']:.4f} eV, gap={data['bandgap']:.2f} eV") |
| 273 | +``` |
| 274 | + |
| 275 | +## Troubleshooting |
| 276 | + |
| 277 | +### ABACUS executable not found |
| 278 | + |
| 279 | +If you see "ABACUS executable not found", ensure: |
| 280 | +1. ABACUS is installed and in your PATH |
| 281 | +2. Or build with C++ driver support (see Installation) |
| 282 | + |
| 283 | +### MPI not found |
| 284 | + |
| 285 | +If you see "mpirun/mpiexec not found" when using `nprocs > 1`: |
| 286 | +1. Install MPI (OpenMPI or MPICH) |
| 287 | +2. Ensure `mpirun` or `mpiexec` is in your PATH |
| 288 | +3. Or set `nprocs=1` to run without MPI |
| 289 | + |
| 290 | +### Import errors |
| 291 | + |
| 292 | +If `import pyabacus` fails: |
| 293 | +1. Ensure pyabacus is installed: `pip install pyabacus` |
| 294 | +2. Check Python version compatibility (Python 3.8+) |
| 295 | + |
| 296 | +### Calculation not converging |
| 297 | + |
| 298 | +Check the log file for details: |
| 299 | +```python |
| 300 | +result = pyabacus.abacus("./problem_case/") |
| 301 | +if not result.converged: |
| 302 | + log_path = result.get_output_file("running_scf.log") |
| 303 | + if log_path: |
| 304 | + with open(log_path) as f: |
| 305 | + print(f.read()[-2000:]) # Print last 2000 chars |
| 306 | +``` |
| 307 | + |
| 308 | +### Forces or stress not available |
| 309 | + |
| 310 | +Forces and stress are parsed from the ABACUS output log. Ensure: |
| 311 | +1. `cal_force` is set in your INPUT file for forces |
| 312 | +2. `cal_stress` is set in your INPUT file for stress |
| 313 | +3. The calculation completed successfully |
0 commit comments