Single Point Calculations¶
Single-point calculations compute the energy, forces, and stress of a structure at its current geometry without any optimization.
Basic Usage¶
from mace_inference import MACEInference
from ase.io import read
calc = MACEInference(model="medium", device="auto")
atoms = read("structure.cif")
result = calc.single_point(atoms)
Return Values¶
The single_point() method returns a dictionary:
| Key | Type | Description |
|---|---|---|
energy |
float |
Total potential energy (eV) |
energy_per_atom |
float |
Energy divided by number of atoms (eV) |
forces |
ndarray |
Forces on each atom, shape (N, 3) (eV/Å) |
max_force |
float |
Maximum force magnitude (eV/Å) |
stress |
ndarray |
Stress tensor in Voigt notation (eV/ų) |
Examples¶
Basic Energy Calculation¶
result = calc.single_point(atoms)
print(f"Total energy: {result['energy']:.6f} eV")
print(f"Energy per atom: {result['energy_per_atom']:.6f} eV")
print(f"Number of atoms: {len(atoms)}")
Force Analysis¶
import numpy as np
result = calc.single_point(atoms)
forces = result['forces']
print(f"Force shape: {forces.shape}")
print(f"Max force: {result['max_force']:.4f} eV/Å")
print(f"Mean force magnitude: {np.linalg.norm(forces, axis=1).mean():.4f} eV/Å")
# Check if structure is relaxed
if result['max_force'] < 0.05:
print("Structure appears to be well-relaxed")
else:
print("Structure may need optimization")
Stress Analysis¶
result = calc.single_point(atoms)
stress = result['stress'] # Voigt notation: xx, yy, zz, yz, xz, xy
print("Stress tensor (eV/ų):")
print(f" σxx = {stress[0]:.6f}")
print(f" σyy = {stress[1]:.6f}")
print(f" σzz = {stress[2]:.6f}")
# Calculate pressure (negative trace / 3)
pressure = -np.mean(stress[:3])
print(f"Pressure: {pressure:.6f} eV/ų")
print(f"Pressure: {pressure * 160.2:.2f} GPa") # Convert to GPa
Comparing Structures¶
from ase.io import read
structures = [read(f"structure_{i}.cif") for i in range(5)]
print("Structure comparison:")
print("-" * 50)
print(f"{'File':<20} {'E (eV)':<12} {'E/atom (eV)':<12}")
print("-" * 50)
for i, atoms in enumerate(structures):
result = calc.single_point(atoms)
print(f"structure_{i}.cif {result['energy']:<12.4f} {result['energy_per_atom']:<12.4f}")
With D3 Correction¶
For systems where dispersion interactions are important:
# Without D3
calc_no_d3 = MACEInference(model="medium", enable_d3=False)
result_no_d3 = calc_no_d3.single_point(atoms)
# With D3
calc_d3 = MACEInference(model="medium", enable_d3=True, d3_xc="pbe")
result_d3 = calc_d3.single_point(atoms)
d3_contribution = result_d3['energy'] - result_no_d3['energy']
print(f"MACE energy: {result_no_d3['energy']:.4f} eV")
print(f"MACE + D3 energy: {result_d3['energy']:.4f} eV")
print(f"D3 contribution: {d3_contribution:.4f} eV")
Performance Tips¶
Batch Calculations¶
For many structures, reuse the calculator:
calc = MACEInference(model="medium", device="auto")
results = []
for atoms in structure_list:
result = calc.single_point(atoms)
results.append(result)
GPU Acceleration¶
For large systems, GPU provides significant speedup:
Lower Precision for Screening¶
For quick screening, use float32:
calc = MACEInference(
model="medium",
device="auto",
default_dtype="float32" # Faster but less accurate
)
Common Use Cases¶
- Quick energy check before expensive calculations
- Screening many candidate structures
- Validation of ML model predictions
- Force verification to check if structure is relaxed
- Stress analysis for pressure calculations