Density of States (DOS) and Projected DOS
The density of states (DOS) describes how many electronic states exist at each energy level. sci-form computes DOS from EHT orbital energies using Gaussian smearing.
DOS via Gaussian Smearing
Total DOS Formula
Given a set of orbital energies
where
Parameters
| Parameter | Symbol | Typical Range | Default |
|---|---|---|---|
| Smearing width | 0.1–0.5 eV | 0.3 eV | |
| Energy grid points | 500–2000 | 1000 | |
| Energy range | Auto from eigenvalues ± 5σ | Auto |
Properties
- Integral:
- Non-negative:
for all - σ dependence: Smaller σ → sharper peaks near eigenvalue positions
Projected DOS (PDOS)
PDOS decomposes the total DOS into contributions from individual atoms, revealing which atoms contribute to states at each energy.
PDOS Formula
The projected density of states for atom
where the Mulliken weight for atom
PDOS Sum Rule
The atom-projected contributions always sum to the total DOS:
This is guaranteed because
Energy Grid
The energy grid is constructed automatically:
Grid points are evenly spaced:
API
Rust
use sci_form::compute_dos;
let result = compute_dos("O", 0.3, 1000, None);
// result.energies: Vec<f64> — energy grid points
// result.total_dos: Vec<f64> — D(E) values
// result.pdos: Vec<Vec<f64>> — per-atom PDOS
// result.eigenvalues: Vec<f64> — orbital energiesCLI
sci-form dos "O" --sigma 0.3 --grid-points 1000
# Output: JSON with energies, total_dos, pdos arraysPython
import sci_form
result = sci_form.dos("O", sigma=0.3, grid_points=1000)
print(len(result.energies)) # 1000
print(len(result.total_dos)) # 1000Validation
- Grid match:
len(energies)=len(total_dos)=grid_points - Non-negative: All DOS values ≥ 0
- PDOS sum: Sum of PDOS arrays equals total DOS at each energy point
- σ effect: Narrower σ produces sharper, taller peaks
- Energy range: Grid spans all eigenvalues with sufficient margin
DOS Comparison (MSE)
Two DOS curves can be quantitatively compared using the Mean Squared Error:
This is used for benchmarking and to compare computed DOS against reference spectra. Both curves must be on the same energy grid (same length).
use sci_form::dos::{compute_dos, dos_mse};
let res_a = compute_dos("O", 0.3, 1000, None)?;
let res_b = compute_dos("O", 0.5, 1000, None)?; // different sigma
let mse = dos_mse(&res_a.total_dos, &res_b.total_dos);
println!("MSE = {mse:.6}");JSON Export for Web Visualization
The export_dos_json function serializes a DosResult into a compact JSON string suitable for sending to a browser or plotting library:
{
"energies": [-35.2, -34.8, ..., 5.0],
"total_dos": [0.0, 0.12, ..., 0.0],
"sigma": 0.3,
"pdos": {
"0": [0.0, 0.08, ...],
"1": [0.0, 0.04, ...]
}
}use sci_form::dos::{compute_dos, export_dos_json};
let result = compute_dos("c1ccccc1", 0.3, 1000, None)?;
let json = export_dos_json(&result);
// Send to frontend over WebSocket or WASM callThe PDOS dictionary keys are atom indices (0-based). This format is consumed directly by the TypeScript WASM API:
const result = JSON.parse(compute_dos("c1ccccc1", 0.3, 1000));
// result.energies: number[]
// result.total_dos: number[]
// result.pdos: { [atomIndex: string]: number[] }