Supercells and volume ranges
Public API for HNF, Supercell, and the SupercellSelection family.
Enumlib.HNF — Type
HNF{D}A Hermite Normal Form matrix in D dimensions: a lower-triangular integer matrix with positive diagonal entries and sub-diagonal entries reduced into [0, m[i,i]). The determinant n = ∏ m[i,i] is the supercell index — the number of parent cells fitting inside the supercell B = parent.A * h.matrix.
Construction validates the HNF form (lower-triangular, positive diagonal, sub-diagonal range). Once built, an HNF{D} is guaranteed to satisfy the form; downstream code can rely on that without re-checking.
HNF{D} is parametric on the spatial dimension D. Almost all uses are D=3; the constructor infers D from size(matrix, 1).
Enumlib.Supercell — Type
Supercell{D}A symmetry-inequivalent supercell representative: an HNF{D} plus the cached SNF diagonal and the permutation group induced by the parent space-group operations that fix the superlattice. Carries the per-supercell data the labeling enumeration reuses across all colorings on this supercell.
Cached fields
hnf— the supercell-defining HNF.snf— diagonal of the Smith Normal Form decomposition ofhnf.matrix. LengthD, withs_1 | s_2 | ... | s_D. Used by the labeling enumeration to index supercell sites.n_stabilizer_ops— number ofparent.space_groupoperations whose action fixes the superlattice (the order of the stabilizer subgroup).permutation_group— permutations of then × n_Dsupercell sites induced by the stabilizer's rotations composed with the supercell's translation group. This is what the labeling enumeration consults when crossing out symmetry-equivalent labelings.hnf_degeneracy— the size of this supercell's parent-point-group orbit on the set of volume-nHNFs. Mirrors the Fortran enumlib'shnf_degen. Diagnostic-grade.
Construction
Supercell(hnf::HNF{D}, parent::ParentLattice{D}) builds the SNF, finds the stabilizer subgroup of parent.space_group, and constructs the permutation group via getPermG. The permutation-group construction is cached at construction time — small memory cost (~kB per supercell) for substantial savings during the labeling enumeration loop, which consults permutation_group once per labeling check.
hnf_degeneracy is computed on demand by counting the HNF's parent-point-group orbit at the given volume. For batch construction inside enumerate(...), the degeneracy is precomputed via getSymInequivHNFs_with_degeneracies and passed in to skip the recomputation: Supercell(hnf, parent; hnf_degeneracy = precomputed).
Examples
Building one of FCC's two symmetry-inequivalent volume-2 supercells:
julia> p = ParentLattice([0.0 0.5 0.5; 0.5 0.0 0.5; 0.5 0.5 0.0]);
julia> sc = Supercell(enumerate_hnfs(VolumeRange(2:2), p)[1], p)
Supercell{3} (n = 2, |stabilizer| = 12, |perm group| = 2, hnf_degeneracy = 4)
HNF: 1 0 0 / 0 1 0 / 0 0 2
SNF diag: [1, 1, 2]
julia> volume(sc.hnf)
2
julia> sc.snf
3-element Vector{Int64}:
1
1
2Enumlib.volume — Function
volume(h::HNF) -> IntThe supercell volume / index — the number of parent cells fitting inside the supercell defined by h. Equals the product of the diagonal entries (since h.matrix is lower-triangular, this is also its determinant).
Examples
julia> h = HNF([1 0 0; 0 2 0; 0 0 3]);
julia> volume(h)
6Enumlib.SupercellSelection — Type
abstract type SupercellSelection endUser-facing description of "which supercells should we enumerate over?". Three concrete subtypes:
VolumeRange(range)— enumerate all symmetry-inequivalent HNFs of supercell volume inrange.RadiusBound(; max_radius_ratio, max_volume)— enumerate HNFs whoseavg_cell_radiusis at mostmax_radius_ratiotimes the parent cell's, with amax_volumesafety stop.ExplicitHNFs(hnfs)— pass a hand-curated list of HNFs through; no symmetry reduction happens (the user has already done it).
The dispatcher enumerate_hnfs(::SupercellSelection, parent) turns any selection into a concrete Vector{HNF{D}} that downstream code can iterate over uniformly.
Enumlib.VolumeRange — Type
VolumeRange(range::AbstractRange{Int})Enumerate all symmetry-inequivalent HNFs whose volume det(h) lies in range. The most common selection — covers the "I want all supercells of size 2 through 8" use case.
Enumlib.RadiusBound — Type
RadiusBound(; max_radius_ratio::Real, max_volume::Integer = typemax(Int))Enumerate symmetry-inequivalent HNFs whose Minkowski-reduced cell radius (per avg_cell_radius) is at most max_radius_ratio times the parent cell's own radius. The max_volume is a safety stop — without it, very large max_radius_ratio values would scan unbounded volumes.
The radius measure is the average distance from cell center to the 8 corners of the Minkowski-reduced basis. Average gives finer tie-breaking than max-distance and is more descriptive for elongated cells.
Enumlib.ExplicitHNFs — Type
ExplicitHNFs(hnfs::AbstractVector{HNF{D}})Enumerate over a user-supplied list of HNFs. No symmetry reduction or filtering — the dispatcher passes the list through unchanged, since the user has already curated it.
Useful for: domain-specific HNF filters, regression tests against literature reference cases, hand-picked supercells the user wants to study individually.
Enumlib.enumerate_hnfs — Function
enumerate_hnfs(s::SupercellSelection, parent::ParentLattice{D}) -> Vector{HNF{D}}Turn a SupercellSelection into a concrete Vector{HNF{D}} for the parent lattice. Three methods, one per subtype:
VolumeRange: loop through volumes in the range; concatenate per-volumegetSymInequivHNFsresults.RadiusBound: scan volumes 1..max_volume, compute each candidate'savg_cell_radius, keep those within the bound, then symmetry-reduce.ExplicitHNFs: pass through unchanged.
Downstream code (enumerate(...)) treats the returned vector uniformly regardless of which selection produced it.
Examples
FCC has 2 symmetry-inequivalent HNFs at volume 2:
julia> p = ParentLattice([0.0 0.5 0.5; 0.5 0.0 0.5; 0.5 0.5 0.0]);
julia> hnfs = enumerate_hnfs(VolumeRange(2:2), p);
julia> length(hnfs)
2
julia> volume.(hnfs)
2-element Vector{Int64}:
2
2Enumlib.avg_cell_radius — Function
avg_cell_radius(B) -> Float64Get the average distance from the center of the unit cell B to its 8 corners. Used as a unit-cell size measure for the radius-based supercell selection (RadiusBound). Minkowski-reduces the basis first so the measure is independent of the user's cell representation (e.g., a skewed basis and its Minkowski-reduced equivalent get the same value).
Average distance (rather than max) gives finer tie-breaking — 8 corner distances rarely all match pairwise — and is more descriptive for elongated cells (max gets dominated by the longest direction; avg weights all axes smoothly). For a cube avg ≈ max ≈ side·√3/2 so the difference only shows up for non-cubic cells.
Examples
A unit cube spans [0, 1]^3; its center is at (0.5, 0.5, 0.5), equidistant from all 8 corners at √3/2 ≈ 0.866.
julia> using LinearAlgebra: I
julia> avg_cell_radius(Matrix{Float64}(I, 3, 3))
0.8660254037844385