Skip to content

feat(dfpt): acoustic sum rule enforcement (dfpt_asr = no | simple | crystal) - #8182

Open
Zanthoxylum wants to merge 4 commits into
deepmodeling:developfrom
Zanthoxylum:dfpt-asr
Open

Zanthoxylum wants to merge 4 commits into
deepmodeling:developfrom
Zanthoxylum:dfpt-asr

Conversation

@Zanthoxylum

Copy link
Copy Markdown
Collaborator

Summary

Unconstrained linear-response self-consistency violates the translational
acoustic sum rule on the Gamma dynamical matrix, and the Born effective
charges violate sum_a Z*_a = 0 similarly. This PR adds the standard
post-processing remedy as a new INPUT parameter dfpt_asr (default no),
applied to the RAW Gamma matrix before the LO-TO nonanalytic term, together
with the Z* sum rule, so the LO-TO term consumes the corrected charges (the
QE dynmat set_asr order). Two modes:

  • simple — the legacy fix translated to our mass-reduced storage:
    D(a,a) = -sum_{b!=a} sqrt(m_b/m_a) D(a,b).
  • crystal — the optimized minimal-norm fix: the symmetric projection
    D -> (1-P) D (1-P) with the orthonormal translation vectors
    w_i(3a+alpha) = sqrt(m_a) delta(alpha,i)/sqrt(sum m); zeroes every
    physical row AND column sum exactly, preserves Hermiticity and keeps
    symmetry-equivalent atoms equivalent.

Diagnostics: per-stage audit lines (raw / asr / loto) print per-atom
PHYSICAL row sums (sum_jb sqrt(m_jb) D) with the worst relative to the
matrix scale, plus an explicit correction report (worst physical rowsum before -> after | max |sum_a Z*_a| -> 0).

Tests (MODULE_DFPT_phon_serial 12 -> 17): simple and crystal zero the
physical row sums; crystal keeps Hermiticity, maps the acoustic triplet to
machine zero, and keeps symmetry-equivalent atoms equivalent (mass-equal
species); Born charges shift by the per-component mean; regression: unequal
masses + violating matrix + eps and unbalanced Z* -> after crystal + LO-TO
the acoustic triplet stays at zero.

Print the per-atom row-sum norm of the Gamma dynamical matrix right
after the raw diagonalization and, when the LO-TO correction runs,
again on the corrected matrix (the nonanalytic term carries its own
Z* sum rule, so the two violations are audited separately). This is
the diagnostics feeder for the acoustic-branch investigation: the
existing check_sum_rule helper only returns a bool against a 1e-6
relative tolerance and is not wired anywhere, while the observed
Gamma acoustic modes are off by tens to hundreds of cm^-1 across all
ten validation systems.
New INPUT parameter dfpt_asr = no (default) | simple | crystal, applied to
the RAW Gamma dynamical matrix before the LO-TO nonanalytic term, together
with the Z* sum rule sum_a Z*_a = 0 on the Born effective charges (the
LO-TO term then consumes the corrected charges, QE dynmat set_asr order).

Unconstrained linear-response self-consistency violates both sum rules at
the percent to tens-of-percent level -- measured on ten validation
systems (raw worst rowsum rel 1.8e-3 .. 8.3e-1, invariant under a 100x
tighter convergence threshold), and QE ph.x raw output shows the same
behavior (0.09% .. 34%); the reference workflow post-processes with
dynmat asr='crystal', so this option aligns the treatment.

- simple: the legacy fix, each row's total is subtracted from its
  diagonal element, with a Hermitian re-symmetrization pass
- crystal: the optimized minimal-norm fix -- the symmetric projection
  D -> (1-P) D (1-P) with the orthonormal translations
  u_i(3a+alpha) = delta(alpha,i)/sqrt(nat); zeroes every row AND column
  sum exactly, preserves Hermiticity and keeps symmetry-equivalent atoms
  equivalent; the three acoustic eigenvalues vanish to machine precision
- an explicit report line prints the worst rowsum before -> after (and
  the |sum Z*| correction); run_assemble audits raw / asr / loto stages
  separately

Tests (MODULE_DFPT_phon_serial 12 -> 16): simple and crystal zero the
row sums; crystal keeps Hermiticity, maps the acoustic triplet to zero
(sqrt-scaled residual ~1e-5 cm^-1 from a ~1e-17 matrix residual), keeps
equivalent atoms equivalent, and shifts each Born charge by the
per-component mean.
The first crystal/simple implementation enforced UNWEIGHTED row sums on
the stored mass-REDUCED matrix (D = Phi/sqrt(m_a m_b)), which projects
out the wrong direction (uniform mass-coordinate displacement instead
of uniform physical displacement). Consequence caught by the first
ten-system validation run: the pre-LO-TO acoustic modes zero out along
the spurious direction, but the LO-TO nonanalytic term -- which decouples
from the PHYSICAL acoustic subspace only through sum_a Z*_a = 0 -- mixes
back in and lifts one acoustic mode (bn_cubic Gamma: +36 cm^-1 along
(1,1,1) while QE stays at ~1e-5).

QE dynmat operates on the UNreduced matrix (dyndiag divides by the
sqrt(m_a m_b) only at diagonalization), so its unweighted rows are the
physical rule; the correct translation into our reduced storage carries
the sqrt(m) weights:

- crystal: project with the orthonormal physical translations
  w_i(3a+alpha) = sqrt(m_a) delta(alpha,i)/sqrt(sum m), i.e.
  D' = D - (sqrt(m_a)/M) S - (sqrt(m_b)/M) T + (sqrt(m_a m_b)/M^2) U
  with S/T/U the sqrt(m)-weighted single and double atom sums
- simple: D(a,a) = -sum_{b!=a} sqrt(m_b/m_a) D(a,b)
- the audit and the report line now print the PHYSICAL row sums
  sum_jb sqrt(m_jb) D(3a+da, jb), the quantity QE's rows sum to

Tests (phon serial 16 -> 17): row-sum assertions move to the physical
sums; the equivalent-atoms case runs with mass-equal species; new
regression AsrCrystalPlusLotoKeepsAcousticExactlyZero (masses 12/4,
violating matrix, eps 3I and unbalanced Z*): after crystal + LO-TO the
acoustic triplet stays at zero to 1e-4 cm^-1.
@Zanthoxylum
Zanthoxylum requested a review from mohanchen October 19, 2026 07:45
@Zanthoxylum Zanthoxylum added the DFPT Density Functional Perturbation Theory label Oct 19, 2026
…tru fixture

The CI MODULE_DFPT_pw_run_test (GCC 11 container) segfaulted inside the
first run() of the ASR branch while the same binary passed everywhere
locally (GCC 13): DFPTStruTestFixture::construct_ucell never populated
ucell.iat2it, so the audit's cosmetic species-label lookup
atoms[iat2it[ia]].label read an EMPTY vector -- undefined behavior that
GCC 13 layouts happened to survive and GCC 11 did not.

- audit_asr: print the atom index only; production code no longer
  touches iat2it (apply_asr's mass lookup still does, legitimately)
- the stru fixture now fills iat2it/iat2ia like any real cell

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DFPT Density Functional Perturbation Theory

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant