AICCM aiccm2026dev-a follow-on — derivation document

Math + validation record for the three follow-on features on the aiccm2026dev-a cyclic-cluster line: (1) localization, (2) DLPNO natural orbitals, (3) space-group symmetry. Each sits behind its own option and does not change existing behavior. Decisions + open-questions log: handovers/HANDOVER_AICCM_FOLLOWON.md.

Every numerical claim here is grounded in a real run (test file named per section). SI/atomic units (bohr, hartree).


Interaction-range parameterization — the real-space dual of k-point sampling

A.1 The object

Historically the cluster is given as an explicit supercell mesh nrep = (N₁, N₂, N₃). The physically meaningful knob, however, is how far the interactions reach — a real-space cutoff R_c. Because CCM ≡ SCM-Γ, the cyclic cluster of size nrep is a Born–von-Kármán torus that samples exactly a Γ-centred (N₁,N₂,N₃) Monkhorst–Pack mesh; so choosing the cluster by a real-space radius is the exact dual of choosing a k-mesh by density. We let the user supply the unit cell + R_c and derive the minimal nrep.

A.2 What “reach R_c” means geometrically — the WS inscribed sphere

In the CCM, atom A interacts with the minimum image of atom B inside A’s Wigner–Seitz supercell (WSSC). The set of displacements captured at full weight, in every direction is the largest sphere inscribed in the WS cell. So “the interactions reach R_c around every atom” is precisely

r_in(L_c) ≥ R_c ,   L_c = {N_i a_i} the cluster lattice.

The inscribed-sphere radius equals half the shortest lattice vector, r_in = λ₁/2. Proof: x lies in the WS (Voronoi) cell iff x·R |R|²/2 for every lattice vector R; for |x| = r the binding constraint is along , giving r |R|/2, minimised by the shortest R. The nearest Voronoi face is the perpendicular bisector of the shortest lattice vector. Hence the condition is

λ₁(L_c) ≥ 2 R_c .

A.3 The per-direction formula and why it is rigorous (not a guess)

Let d_i = V/|a_j × a_k| be the unit-cell interplanar spacing along a_i (the spacing between successive (a_j,a_k) planes; d_i = 1/|b_i| with b_i the 2π-free reciprocal vector). The cluster interplanar spacing is D_i = N_i d_i. Project any nonzero cluster vector R = Σ_i m_i N_i a_i onto the unit reciprocal direction b̂_i: since a_i·b̂_i = d_i and a_j·b̂_i = 0 (j≠i),

|R| ≥ |R·b̂_i| = |m_i| D_i   ⟹   λ₁(L_c) = min_{R≠0}|R| ≥ min_i D_i .

Therefore choosing

N_i = ⌈ 2 R_c / d_i ⌉      ⟹   D_i ≥ 2R_c ∀i   ⟹   λ₁ ≥ 2R_c   ⟹   r_in ≥ R_c .   ✓

The bound λ₁ min_i D_i makes the per-direction formula a sufficient condition for the inscribed-sphere guarantee — it can never under-shoot. It is tight (equality λ₁ = min_i D_i) for orthogonal cells, and conservative for oblique cells (where λ₁ can exceed min_i D_i, so the achieved r_in is slightly larger than R_c — never smaller). This is the rigorous content behind the heuristic N_i ⌈2R_c/d_i⌉.

A.4 The duality constant

A cyclic cluster of WS “diameter” 2 R_c is a BvK torus, so its allowed k-points are spaced by Δk = 2π/(2R_c) = π/R_c (2π reciprocal convention). Equivalently, per direction, N_i = ⌈2R_c/d_i⌉ = ⌈|b_i|/(π/R_c)⌉ = ⌈|b_i|/Δk⌉ — exactly the uniform-k-density rule. So:

real-space cutoff R_c   ⟺   k-spacing Δk = π/R_c   ⟺   cluster (N₁,N₂,N₃) ≡ MP mesh (N₁,N₂,N₃).

Larger R_c ⇔ denser k-mesh. A radius scan is the CCM analogue of a k-point convergence study.

A.5 Implementation + validation

Geometry (vibeqc.periodic.ccm.wigner_seitz): interplanar_spacings, shortest_lattice_vector_length, wsc_inscribed_radius, nrep_for_interaction_range, kspacing_for_interaction_range. API (CCMSystem): interaction_range= (bohr) / interaction_range_ang= (Å), the from_interaction_range(unit, R_c, basis, units=...) constructor, and the stored diagnostics interaction_range, wsc_inscribed_radius, kspacing_equiv; explicit nrep remains the advanced override. Scan helper (ccm_interaction_range_scan) → InteractionRangeScan (radius → energy/atom, with converged_radius(tol) and JSON as_records()).

Validated (tests/test_ccm_interaction_range.py):

  • shortest_lattice_vector_length / wsc_inscribed_radius match a brute-force ±6-shell oracle to ≤1e-9 on cubic / ortho / tetragonal / fcc-prim / bcc-prim / hexagonal / triclinic / vacuum-chain lattices.

  • Inscribed-sphere gate r_in(L_c) R_c and the per-direction bound min_i N_i d_i 2R_c hold for every (lattice, R_c) in the battery above — the numerical proof of A.3, not an assertion.

  • Orthogonal bound is tight: ortho(3,5,7) at R_c=7 → nrep=(5,3,2).

  • from_interaction_range and explicit nrep give bit-identical S^CCM and HF energy; the Å convenience matches bohr; ambiguous specs raise.

  • H₂-chain (6-bohr cell, STO-3G) radius scan converges monotonically; the dual k-mesh per point equals the cluster mesh.


Task 1 — Localization of the canonical crystalline orbitals (Wannier)

1.1 The object

A converged CCM SCF returns the canonical crystalline orbitals ψ. By the CCM ≡ SCM-Γ identity (AICCM_ALGORITHM.md §1, §13.1) the cyclic cluster is the finite Born–von-Kármán torus and ψ are its Γ-point occupied MOs on the supercell of N = N₁N₂N₃ cells — S^CCM-orthonormal: Σ_{μν} C†_{μi} S^CCM_{μν} C_{νj} = δ_{ij}.

1.2 Localization is a unitary rotation within the occupied space

The textbook cell-periodic Wannier construction is the discrete back-transform over the cluster net,

w_n(r − R) = (1/N) Σ_k e^{−i k·R} ψ_{n,k}(r),     k ∈ equivalent net,  R ∈ L_c,

which produces N translationally-equivalent Wannier functions per band. The block-Fourier matrix U_{(nk),(mR)} = (1/√N) e^{−ik·R} δ_{nm} is unitary, so the Wannier set spans the same occupied space as {ψ_{n,k}}. Under CCM ≡ SCM-Γ the supercell already carries those N images: the supercell-Γ occupied set {ψ_i}, i = 1…N·n_occ^cell is exactly {ψ_{n,k}} over the net, related by the same unitary. Localizing the supercell-Γ occupieds by a unitary rotation therefore is the (maximally-localized) Wannier gauge, obtained directly in the picture the CCM produces — no explicit k-sum.

Because the rotation C_loc = C_occ U stays inside the occupied space, the one-particle density P = Σ_i^{occ} C_i C_i† is invariant, and with it every ground-state observable, including the total energy. This is the hard correctness gate.

1.3 Gauge fixing (spread minimization)

The Marzari–Vanderbilt spread functional is Ω = Σ_i [⟨w_i|r²|w_i⟩ ⟨w_i|r|w_i⟩²]. Two gauges are offered, reusing the validated molecular/periodic localizer (vibeqc.periodic_localise.localise_periodic_gamma):

  • Pipek–Mezey — maximize Σ_i Σ_A (Q_i^A)² (Mulliken populations). No position operator ⇒ PBC-safe in every regime, including orbitals that wrap the cluster boundary. Default.

  • Foster–Boys — maximize Σ_i ⟨w_i|r|w_i⟩² via the home-cell dipole integrals. Faithful (with the reported centroids/spreads) only for orbitals that do not wrap the boundary (molecule-in-a-box / dilute / large cell).

The reported centroids = ⟨w_i|r|w_i⟩ and spreads = ⟨w_i|r²⟩ ⟨w_i|r⟩² use the plain (home-cell) position operator, so for a dense cell they fold into the home cell (a Wannier on cell R reports its in-cell center). The Resta periodic operator ⟨μ|e^{−iG·r}|ν⟩ that would unwrap them is an open item (§ decisions log); Pipek–Mezey localization itself is unaffected.

1.4 Implementation + validation

vibeqc.periodic.ccm.localise_ccm(ccm_result, ccm, method=...)PeriodicWannierResult (C_loc, U, centers, centroids, spreads, charges, localization). localization_density_residual(ccm_result, w) is the gate ‖P_loc P_canonical‖_F.

Validated (tests/test_ccm_localize.py), dense 1-D H₂ chain (6-bohr cell, STO-3G, nrep (3,1,1), 3 occupied):

quantity

Pipek–Mezey

Boys

density residual ‖P_loc−P_can‖

2.4e-16

3.0e-16

unitarity ‖C_locᵀ S C_loc I‖

6.7e-16

4.9e-16

objective (initial → final)

0.644 → 1.500

109.5 → 181.5

spreads Ω_i (bohr²)

~2.39

~2.39

Wannier center z (bohr)

0.7 (H₂ bond midpoint)

0.7

real C_loc (centrosymmetric)

yes

yes

So the rotation is exactly density/energy-preserving (machine ε), genuinely localizes, gives real orbitals for the centrosymmetric cell, and places the Wannier centers on the H₂ bond midpoint — the expected Wyckoff/bond position.

1.5 Open (M2–M4, see decisions log)

Explicit multi-k U(k)/M(k,b) route; Resta operator (unwrapped centroids/spreads for dense crystals); IAO/IBO path (Knizia); aliasing diagnostics + spread-vs-cluster-size convergence; emit in the exact rep Task 2 (DLPNO) consumes.


Task 3 — Space-group symmetry (spglib)

3.1 The cluster-invariant subgroup

spglib analyzes the crystal (unit cell) space group G, giving operations {W|w} (integer rotation W in the unit-cell fractional basis + fractional translation w). Each op is converted to Cartesian, R = L_u W L_u⁻¹, t = L_u w (L_u = unit lattice, columns aⱼ). The operations usable on the cyclic cluster are the cluster-invariant subgroup G_c G: those (R,t) that map the cluster lattice L_c = {N_j a_j} onto itself modulo L_c. For a point op, R(N_j a_j) = N_j Σ_k W_{kj} a_k L_c iff N_j W_{kj}/N_k — so for equal nrep in symmetry-related directions all crystal point ops survive; unequal nrep keeps the compatible subset. Tested operationally by symmetry_ao.atom_permutation_under_op on the supercell (it raises iff (R,t) is not a cluster symmetry).

3.2 AO representation

For each g G_c the AO matrix is P = (atom permutation) × (Wigner-D blocks) from symmetry_ao.build_ao_permutation_matrix(basis, R, perm) — real solid harmonics, wigner_d_real(ℓ, R) per shell, with improper rotations factored through the -parity. At Γ the fractional translation contributes phase 1, so P (permutation + rotation) is the full cluster-AO representation.

3.3 Validation + a proven finding (tests/test_ccm_symmetry.py)

The AO maps are correct: S^CCM and T^CCM are invariant Pᵀ M P = M to machine precision under every g G_c, including the non-symmorphic glide/screw ops of diamond (Fd-3m):

system

SG

crystal/cluster order

‖PᵀSP−S‖

‖PᵀTP−T‖

‖PᵀVP−V‖ (rel)

MgO (Fm-3m)

225

48 / 48

2e-15

1e-14

0.077 (4.6e-4)

C-diamond (Fd-3m, non-symmorphic)

227

48 / 48

2e-15

2e-15

0.44 (7.9e-3)

NaCl (Fm-3m)

225

48 / 48

5e-15

0.044

Finding. The union three-center V^CCM (bare-1/r, weight ω_μν·½(ω_μC+ω_νC)) is not crystal-symmetric — ~5e-4 (MgO) → ~8e-3 (C-diamond) relative. S and T being exactly invariant isolate V as the sole culprit (the maps are validated); the anchor-bridge breaks spatial symmetry just as eq-18 broke permutation symmetry.

Resolution (proven). The neutral Ewald V_ne IS crystal-symmetric (‖PᵀVP−V‖/‖V‖ ≈ 2e-8, lattice-sum tolerance) — last rows below:

nuclear operator

MgO rel breaking

C-diamond rel breaking

union three-center (bare-1/r)

4.6e-4

7.9e-3

neutral Ewald V_ne

2.3e-8

5.0e-9

This is the spatial analogue of the Madelung gap (#16): bare-1/r union weights break both permutation symmetry (four-center, fixed by §13’s ccm_eri_symmetric) and spatial symmetry (three-center V), and the neutral Ewald kernel fixes both. So the symmetric Hamiltonian already exists — h = T + V_ne with the neutral cderi four-center — and is the natural target for symmetry exploitation.

3.4 Plan (M2–M3, decisions log)

Symmetry exploitation rides the neutral / GDF route (symmetric h): petite- list symmetry-unique shell pairs/quartets → representative integrals → scatter via P + symmetrize Fock; fold the k-net to the IBZ with weights; the exact E/Fock == symmetry-off gate then holds because h is symmetric. (The bare-union route stays available but its h is not crystal-symmetric, so its symmetrized energy would differ — a documented limitation, not a target.)

Task 2 — DLPNO natural orbitals (PAO → PNO)

Foundations now in place: localized occupieds (Task 1), the symmetric neutral route + symmetry-unique pair orbits (Task 3).

2.1 Projected atomic orbitals (M1)

The local virtual basis is the AO space projected out of the occupied space (Pulay; Riplinger–Neese §II.D):

C_PAO = (I − C_occ C_occᵀ S^CCM) · A ,

canonical-orthogonalized within a domain (eigenvectors of Q S Q above a linear-dependence floor). The occupied space projector C_occ C_occᵀ is invariant under occupied rotations, so the full-cell PAO set is identical whether the canonical or the localized (Task 1) occupieds are used — the localized occupieds enter at the pair-domain stage (M2). ccm_pao(ccm_result, ccm) reuses vibeqc.dlpno.pao.

Validated (tests/test_ccm_dlpno.py), dense 1-D H₂ chain (STO-3G, nrep (3,1,1)): PAOs S^CCM-orthogonal to the occupied space (max|C_occᵀ S C_pao| = 2.9e-16); n_pao = 3 = nbf n_occ (full virtual, no linear dependence); occupieds + PAOs span the full space (rank 6/6).

2.2 DLPNO-MP2 (M2, DONE)

ccm_dlpno_mp2(ccm, scf_result, *, cderi=, localize=, tcut_pno=, tcut_mkn=, …)CCMDLPNOMP2Result. It mirrors the validated molecular DLPNO-MP2 (vibeqc.dlpno.mp2), reusing its component functions (build_atom_basis_map, build_projection_matrix, select_domain_atoms_mulliken, semicanonical_pao_basis) with S^CCM / F^CCM injected and the (ia|jb) integrals density-fit from the neutral cderi L[P,μν] (B_half[P,i,ν] = Σ_μ C_loc[μ,i] L[P,μν], so K_ab = Σ_P B[P,i,a] B[P,j,b]).

Pipeline per pair (i,j): Mulliken domain (tcut_mkn) → semicanonical PAOs (eigh of F in the domain, S^CCM-orthonormal) → first-order amplitudes T_ab = K_ab/(f_ii+f_jj−ε_a−ε_b) → PNOs (eigvecs of the pair density ½(TTᵀ+TᵀT), occupation-threshold tcut_pno) → quasi-canonicalize → coupled LMP2 residual R_ij = K_ij + (ε_a+ε_b)T_ij Σ_k[F_ik P(T_kj) + F_kj P(T_ik)] with neighbour amplitudes projected via S_pq = V_pᵀ S^CCM V_q. For canonical occupieds F_oo is diagonal and the residual converges in one step; for localized occupieds the S^CCM-link coupling restores the canonical sum.

Reference = neutral (per the -b-critique correction). The Madelung background shifts the occ–virt denominators, so bare-vs-neutral correlation do not agree (§ decision log): the DLPNO-MP2 reference is the neutral SCF (run_ccm_rhf(ccm, eri=ccm_eri_neutral(ccm))) + neutral cderi. No Madelung-robustness is claimed.

Validated (tests/test_ccm_dlpno_mp2.py, 11/11; H₂-chain STO-3G).

gate

result

no-truncation, canonical occupieds

Δ = 0.0 vs canonical CCM MP2 (neutral)

no-truncation, Pipek–Mezey occupieds

Δ = 8.5e-15 (coupled LMP2, 4 iters)

no-truncation, Boys occupieds

Δ = 8.5e-15

no-truncation, (4,1,1) = 10 pairs

Δ 1e-13 (coupled iteration at scale)

PNO truncation tcut_pno 1e-4→1e-8

monotone error 5e-6 → <1e-7; e_pno_correction tracks the gap

The no-truncation limit reproducing canonical CCM MP2 to machine ε — for canonical and localized occupieds — is the hard correctness proof (not an assertion).

2.3 DLPNO-CCSD(T) (M3, DONE)

ccm_dlpno_ccsd(ccm, scf_result, *, cderi=, g_neutral=, localize=, tcut_pno=, tcut_mkn=, compute_triples=, n_frozen=)CCMDLPNOCCSDResult (vibeqc.periodic.ccm.dlpno_ccsd). Subspace-projected DLPNO-CCSD(T): the per-pair PNOs (_build_ccm_pno_pairs, shared with MP2) are merged into a single union virtual space V_trunc, and vibe-qc’s own CCM CCSD engine (ccsd.py _ccsd_iterate + _triples) runs in {occ, V_trunc}.

  • Union space. Stack the pair PNO coefficients into W, canonical-orthogonalize against S^CCM (eigvecs of WᵀS^CCM W above pno_lindep), then semicanonicalize (diagonalize the Fock within the space) → V_trunc, ε_v.

  • Why exact at no truncation. The CCSD engine assumes a diagonal Fock, so we use the canonical occupieds (occ–occ block diagonal) and the semicanonical V_trunc. Every PNO is built from PAOs projected out of the full occupied space, so V_trunc ⊥_S occ and the occ–virt Fock block vanishes: the MO set C_sub = [C_occ | V_trunc] is orthonormal with a block-diagonal Fock. At tcut_pno = tcut_mkn = 0 each pair’s PNOs span the full virtual block, so the union does too — V_trunc is then a unitary rotation of the canonical virtuals, and CCSD(T) (invariant to occ/virt unitary rotations) equals the canonical CCM CCSD(T).

  • Reference = neutral (the g_eff = Σ_P L⊗L four-center, per the decision log): both the SCF reference and the CCSD MO integrals.

Validated (tests/test_ccm_dlpno_ccsd.py, 9/9; H₂-chain STO-3G).

gate

result

no-truncation, canonical occupieds

Δtot = 7e-18; CCSD and (T) each == canonical

no-truncation, Pipek–Mezey

Δtot = 0.0

no-truncation, Boys

Δtot = 7e-18

no-truncation, (4,1,1)

Δtot = 3e-16

PNO truncation

n_vpno n_full; (T)-toggle / total consistency

The no-truncation == canonical CCM CCSD(T) limit (CCSD + (T), all gauges) is the hard correctness proof.

Scope note (honest). The union-PNO space truncates the global virtual space, so it shrinks only when a virtual direction is unimportant to every pair; on the small, well-coupled validation chains the union stays full-dimensional (correct, not a bug). Per-pair-coupled DLPNO-CCSD (separate per-pair PNO spaces, the more aggressive truncation) is the M3b refinement.

2.4 Open (M3b–): per-pair-coupled DLPNO-CCSD; symmetry-unique pairs

(i, jR) from Task 3’s orbit reduction; open-shell U-DLPNO (Task D). Refs: Nejad et al. 2025; periodic DLPNO literature.

Task C — Derivable properties on the BvK torus

vibeqc.periodic.ccm.properties. Which one-particle observables are well defined on a neutral finite Born–von-Kármán torus, and which need care — implemented in priority order of how cleanly they are defined.

C.1 HOMO–LUMO / fundamental gap (well defined)

ccm_homo_lumo_gap(scf_result, ccm)CCMGap. The CCM SCF eigenvalues are the supercell-Γ orbital energies; by CCM ≡ SCM-Γ they are the band energies at the k-points the cluster folds to Γ, so gap = ε[n_occ] ε[n_occ−1] is the gap at that k-sampling, converging to the bulk gap as the cluster (k-mesh) grows. Validated: equals the raw-spectrum gap to machine ε; H₂-chain (3,1,1) gap 1.14 Ha.

C.2 Mulliken / Löwdin populations (well defined)

ccm_mulliken_charges / ccm_lowdin_chargesCCMPopulation. Basis-local partitions of the cluster density with the cyclic overlap S^CCM: q_A = Z_A Σ_{μ∈A}(D S^CCM)_μμ (Mulliken) and the S^{1/2} D S^{1/2} analogue (Löwdin). Charges sum to the cluster charge (≤1e-9). The per-cell charge is the translational image-average; translational_spread (max image-to-image variation) is a symmetry diagnostic — ≈ 6e-4 for the homonuclear H₂ chain, but ~0.3 for the ionic LiH chain on the bare four-center, concrete evidence that ionic systems need the neutral reference (the bare-1/r four-center breaks cyclic symmetry for ionic cells; § 2.0 decision log). LiH per-cell charges have the correct sign (Li⁺ / H⁻).

C.3 Electric dipole (care needed — Resta)

ccm_dipole(scf_result, ccm) returns the finite-cluster electric dipole μ = Σ_A Z_A R_A Tr(D ⟨r⟩). This is not the bulk polarization: the position operator is not legitimate on a torus (Resta 1998) and the plain home-cell ⟨μ|r|ν⟩ wraps for boundary-crossing orbitals (the Wannier-centroid aliasing of § 1.3). Faithful only for non-wrapping (dilute) clusters; for a dense crystal it is a symmetry indicator (≈ 0 for centrosymmetric/neutral — verified ≤1e-8 on the H₂ chain). Bulk polarization needs the Berry-phase / Resta operator (open item).

C.4 Nuclear gradient / forces (numerical; analytic deferred)

ccm_numerical_gradient(ccm, *, runner=, method=, h=)(n_cell_atoms, 3) central-difference dE_total/dR. Displacing a unit-cell atom propagates to every image (the supercell is built by replication), so this is the gradient under the cyclic constraint; the force is −gradient. Well defined and tractable (no analytic WSSC-integral derivatives), 6·n_cell_atoms SCF evaluations.

Validated: (i) the per-cell forces sum to ≈ 0 (translational invariance, exact); (ii) in the isolated limit ((1,1,1), 80-bohr box) it reproduces vibe-qc’s molecular analytic RHF gradient to 8.9e-8 (finite-difference accuracy). The analytic WSSC-weighted gradient (differentiating S^CCM, h^CCM, the neutral four-center) is the open follow-on.

C.5 Open

Resta periodic position operator (bulk polarization + unwrapped dipoles, shared with Task 1 M4); analytic CCM gradient; open-shell (UHF/UKS) gap + populations (Task D — populations/dipole already accept an unrestricted density via the total-density accessor; only the spin-resolved gap needs wiring).

Task D — Open-shell parity

The unrestricted analogues of the RHF-path methods, on the neutral reference.

D.1 UCCSD(T) (run_ccm_uccsd, DONE)

vibeqc.periodic.ccm.uccsd.run_ccm_uccsd(ccm, uhf_result=, *, cderi=, compute_triples=)CCMUCCSDResult. The open-shell sibling of run_ccm_ccsd: it runs vibe-qc’s own spin-orbital UCCSD(T) engine (vibeqc.dlpno._ccsd_ref.run_ref_uccsd, the in-repo anchor for cpp/uccsd.cpp) on the UHF-CCM reference, fed the CCM neutral cderi transformed into the α / β MO bases (B^σ[P,p,q] = Σ_μν C^σ[μ,p] L[P,μν] C^σ[ν,q], so (pq|rs)^{σσ'} = Σ_P B^σ_pq B^{σ'}_rs) plus the diagonal canonical UHF Fock.

The neutral route is the natural one: run_ref_uccsd needs an RI factorization of the four-center, and the neutral g_eff = Σ_P L⊗L is exactly that (the bare-1/r four-center is non-separable), and — per § 2.0 — is the required correlation reference for ionic systems.

Validated (tests/test_ccm_uccsd.py):

  • Closed-shell consistency — on an even-electron closed-shell cluster run_ccm_uccsd reproduces the closed-shell run_ccm_ccsd on the same neutral four-center to ≤1e-8 (CCSD and (T) each; the UHF collapses to RHF, αα = ββ). This exercises the full spin-orbital machinery + the α/β B-tensor transform.

  • Open-shell — a genuine doublet cluster (3-H chain, n_α n_β) converges with negative correlation.

D.2 Unrestricted properties (DONE)

The population (ccm_mulliken_charges / ccm_lowdin_charges) and dipole (ccm_dipole) routines already consume an unrestricted density (the total-density accessor sums density_alpha + density_beta). The spin-resolved gap is now wired in ccm_homo_lumo_gap: for a UHF/UKS result it returns LUMO HOMO with HOMO = max(ε^α[n_α−1], ε^β[n_β−1]), LUMO = min(ε^α[n_α], ε^β[n_β]) (spin="unrestricted"). Validated on the doublet 3-H chain (tests/test_ccm_properties.py).

D.3 Open (next): U-DLPNO

DLPNO-UMP2 / DLPNO-UCCSD(T) on the cyclic cluster, the open-shell analogue of ccm_dlpno_mp2 / ccm_dlpno_ccsd. Plan, mirroring the closed-shell build on the neutral reference: per-spin PAOs (project out the α-occ and β-occ spaces separately with S^CCM); same-spin (αα, ββ) and opposite-spin (αβ) pair domains and PNOs; spin-blocked pair energies (the αα/ββ antisymmetrized exchange, the αβ direct term — as in run_ccm_ump2). No-truncation gate: == canonical CCM UMP2 (run_ccm_ump2 on the neutral four-center) and == run_ccm_uccsd. Reuse the molecular open-shell DLPNO (vibeqc.dlpno.ump2 / .uccsd) component functions with S^CCM injected, exactly as the closed-shell CCM DLPNO reuses vibeqc.dlpno.mp2.