|
| 1 | +# Phase conventions in `symmetry_eigenvalues`: reconciling with Crystalline.jl |
| 2 | + |
| 3 | +This document explains the phase convention mismatch between the physical derivation in |
| 4 | +[`theory.md`](../theory.md) and Crystalline.jl's `calc_bandreps`, and how |
| 5 | +`symmetry_eigenvalues` in SymmetricTightBinding.jl corrects for it. |
| 6 | + |
| 7 | +## Background: what `theory.md` derives |
| 8 | + |
| 9 | +The derivation in `theory.md` (§ "Transformation properties under symmetry operations") |
| 10 | +gives the **physical** symmetry eigenvalue for band $n$ at $\mathbf{k}$ under a little-group |
| 11 | +operation $g = \{R|\mathbf{v}\}$: |
| 12 | + |
| 13 | +```math |
| 14 | +\langle\psi_{n\mathbf{k}}|\hat{g}|\psi_{n\mathbf{k}}\rangle |
| 15 | += \sum_{IJ} (w_{I,n\mathbf{k}})^* \, e^{+i\mathbf{G}\cdot\mathbf{q}_\alpha} \, [\mathbf{D}_\mathbf{k}(g)]_{IJ} \, w_{J,n\mathbf{k}} |
| 16 | +``` |
| 17 | + |
| 18 | +where: |
| 19 | + |
| 20 | +- $\mathbf{w}_{n\mathbf{k}}$ is the eigenvector of $H(\mathbf{k})$ |
| 21 | +- $\mathbf{G} = g\mathbf{k} - \mathbf{k}$ is a reciprocal lattice vector (since $g$ is in the little group $G_\mathbf{k}$) |
| 22 | +- The factor $e^{+i\mathbf{G}\cdot\mathbf{q}_\alpha}$ arises from the conjugation of $\Theta_\mathbf{G}$, defined as $[\Theta_\mathbf{G}]_{II} = e^{-i\mathbf{G}\cdot\mathbf{q}_\alpha}$ |
| 23 | +- $\mathbf{D}_\mathbf{k}(g) = e^{-i(g\mathbf{k})\cdot\mathbf{v}} \, \rho(h)$ is the site-induced space group representation, with $\rho(h)$ the momentum-independent matrix part |
| 24 | + |
| 25 | +In vectorized form (the boxed formula in `theory.md`): |
| 26 | + |
| 27 | +```math |
| 28 | +\langle\psi_{n\mathbf{k}}|\hat{g}|\psi_{n\mathbf{k}}\rangle |
| 29 | += (\Theta_\mathbf{G} \, \mathbf{w}_{n\mathbf{k}})^\dagger \, (\mathbf{D}_\mathbf{k}(g) \, \mathbf{w}_{n\mathbf{k}}) |
| 30 | +``` |
| 31 | + |
| 32 | +All signs follow consistently from the Convention 1 Fourier transform used throughout the |
| 33 | +package. The `SiteInducedSGRepElement` functor in `site_representations.jl` faithfully |
| 34 | +implements $\mathbf{D}_\mathbf{k}(g)$: |
| 35 | + |
| 36 | +```julia |
| 37 | +Dₖ = cispi(-2dot(gk, v)) * sgrep.ρ # = e^{-2πi(gk)·v} ρ(h) |
| 38 | +``` |
| 39 | + |
| 40 | +## What Crystalline.jl's `calc_bandreps` computes |
| 41 | + |
| 42 | +In `Crystalline/src/calc_bandreps.jl` (line 179): |
| 43 | + |
| 44 | +```julia |
| 45 | +χᴳₖ += cis(2π*dot(kv′, tα′α′)) * χs[site_symmetry_index] |
| 46 | +``` |
| 47 | + |
| 48 | +The phase uses `cis(+2π...)` where the Cano/Elcoro paper[^1] uses `cis(-2π...)`. |
| 49 | +A comment in the source (lines 180–185) explicitly acknowledges this: |
| 50 | + |
| 51 | +> "The sign in this `cis(...)` above is different from in Elcoro's. I think this is |
| 52 | +> consistent with our overall sign convention (see #12), however, and flipping the sign |
| 53 | +> causes problems for the calculation of some subductions to `LGIrrep`s." |
| 54 | +
|
| 55 | +[^1]: B. Bradlyn et al., "Topological quantum chemistry," Nature **547**, 298 (2017); |
| 56 | +L. Elcoro et al., "Double crystallographic groups [...]," J. Appl. Cryst. **50**, 1457 (2017). |
| 57 | + |
| 58 | +This means the band representation characters computed by `calc_bandreps` are **complex |
| 59 | +conjugated** in their global phases relative to the physical convention. However, |
| 60 | +Crystalline.jl is **internally consistent**: its `LGIrrep` matrices also use this conjugated |
| 61 | +convention, so subduction (decomposing characters into irreps) works correctly — the |
| 62 | +conjugation cancels when matching characters against irreps, because both sides are |
| 63 | +conjugated. |
| 64 | + |
| 65 | +## Where the mismatch occurs |
| 66 | + |
| 67 | +The mismatch arises at the **interface** between the two packages: |
| 68 | + |
| 69 | +1. **SymmetricTightBinding.jl** computes symmetry eigenvalues from actual Hamiltonian |
| 70 | + eigenvectors using the **physical** convention (matching `theory.md`) |
| 71 | +2. **Crystalline.jl** expects characters in its **conjugated** convention (matching its |
| 72 | + `LGIrrep`s) |
| 73 | + |
| 74 | +When `collect_compatible` calls `symmetry_eigenvalues` and passes the result to Crystalline's |
| 75 | +`collect_compatible(symeigsv, cbr.brs)`, the conventions disagree. This produced incorrect |
| 76 | +irrep labels at many high-symmetry $\mathbf{k}$-points (the bug tracked in PR #89). |
| 77 | + |
| 78 | +## The two components of the mismatch |
| 79 | + |
| 80 | +The conjugation affects two independent phase factors in the symmetry eigenvalue formula: |
| 81 | + |
| 82 | +### Component 1: the $\Theta_\mathbf{G}$ factor |
| 83 | + |
| 84 | +| | Physical (`theory.md`) | Crystalline convention | |
| 85 | +|---|---|---| |
| 86 | +| Phase on position $\mathbf{q}$ | $e^{+i\mathbf{G}\cdot\mathbf{q}}$ (from $\Theta_\mathbf{G}^\dagger$) | $e^{-i\mathbf{G}\cdot\mathbf{q}}$ (i.e., $\Theta_\mathbf{G}$ unconjugated) | |
| 87 | + |
| 88 | +For operations where $\mathbf{G} = 0$ (when $g\mathbf{k} = \mathbf{k}$ exactly), this |
| 89 | +component is trivially 1 and doesn't matter. It matters at $\mathbf{k}$-points like K in p3, |
| 90 | +where 3-fold rotations give $g\mathbf{k} = \mathbf{k} + \mathbf{G}$ with nonzero |
| 91 | +$\mathbf{G}$. |
| 92 | + |
| 93 | +### Component 2: the global phase from the translation part of $g$ |
| 94 | + |
| 95 | +| | Physical (`theory.md`) | Crystalline convention | |
| 96 | +|---|---|---| |
| 97 | +| Phase on translation $\mathbf{v}$ | $e^{-i(g\mathbf{k})\cdot\mathbf{v}}$ | $e^{+i(g\mathbf{k})\cdot\mathbf{v}}$ | |
| 98 | + |
| 99 | +For operations with $\mathbf{v} = 0$ (pure rotations), this is trivially 1. It matters for |
| 100 | +screw axes and glide planes (e.g., the $4_1$ screw in SG 93, 141, etc.). |
| 101 | + |
| 102 | +### Failure pattern explained |
| 103 | + |
| 104 | +This two-component structure explains the pattern of test failures across space groups: |
| 105 | + |
| 106 | +- **Original code (both components wrong):** All 2D p3/p6 failures at the K-point |
| 107 | + (Component 1), plus all 3D screw/glide failures (Component 2) |
| 108 | +- **$\Theta_\mathbf{G}$ fix only (Component 1 fixed):** 2D fixed, but 3D screw/glide |
| 109 | + operations still fail |
| 110 | +- **Both components fixed:** Everything passes except pre-existing centered-lattice bugs |
| 111 | + (a separate issue, likely in Crystalline.jl) |
| 112 | + |
| 113 | +## The fix |
| 114 | + |
| 115 | +With both corrections, `symmetry_eigenvalues` computes: |
| 116 | + |
| 117 | +```math |
| 118 | +\mathbf{w}_{n\mathbf{k}}^\dagger \, |
| 119 | +\Theta_\mathbf{G} \, |
| 120 | +\tilde{\mathbf{D}}_\mathbf{k}(g) \, |
| 121 | +\mathbf{w}_{n\mathbf{k}} |
| 122 | +``` |
| 123 | + |
| 124 | +where $\tilde{\mathbf{D}}_\mathbf{k}(g) = e^{+2\pi i(g\mathbf{k})\cdot\mathbf{v}} \, \rho(h)$ uses the conjugated global phase but the same (unconjugated) matrix part $\rho$. |
| 125 | + |
| 126 | +Note that only the scalar phases are conjugated, **not** the representation matrix $\rho$. |
| 127 | +This matches what `calc_bandreps` does: it conjugates the exponential phase factor (line 179 |
| 128 | +uses `cis(+2π...)`) but does not conjugate the site-irrep character $\chi_s$. |
| 129 | + |
| 130 | +In the code, this is implemented as: |
| 131 | + |
| 132 | +```julia |
| 133 | +# Component 1: use conj(Θ_G) = Θ_{-G} instead of Θ_G |
| 134 | +Θᴳ_conj = reciprocal_translation_phase(orbital_positions(ptbm), -G) |
| 135 | + |
| 136 | +# Component 2: flip the sign of the global phase e^{-2πi(gk)·v} → e^{+2πi(gk)·v} |
| 137 | +v_g = translation(g) |
| 138 | +phase_correction = cispi(4dot(gk, v_g)) |
| 139 | +ρ = phase_correction * sgrep(k) |
| 140 | + |
| 141 | +# Compute w† Θ_G D̃_k w (matching Crystalline.jl's convention) |
| 142 | +for (n, v) in enumerate(eachcol(vs)) |
| 143 | + v_kpG = Θᴳ_conj * v |
| 144 | + symeigs[j, n] = dot(v_kpG, ρ, v) |
| 145 | +end |
| 146 | +``` |
| 147 | + |
| 148 | +## Should this be fixed in Crystalline.jl instead? |
| 149 | + |
| 150 | +There are three options, each with different trade-offs: |
| 151 | + |
| 152 | +### Option A: Monkey-patch in `symmetry_eigenvalues` (current approach) |
| 153 | + |
| 154 | +The `theory.md` convention is "correct physics" and the code corrects at the interface with |
| 155 | +Crystalline.jl. |
| 156 | + |
| 157 | +- **Pro:** Minimal blast radius; no Crystalline.jl changes |
| 158 | +- **Con:** The code's comments reference the `theory.md` formula but compute something |
| 159 | + different; the correction factor (`cispi(4dot(gk, v_g))`) is a wart that's easy to get |
| 160 | + confused about |
| 161 | + |
| 162 | +### Option B: Fix the root cause in Crystalline.jl |
| 163 | + |
| 164 | +Change `calc_bandreps` to use `cis(-2π*dot(kv′, tα′α′))` (matching the Elcoro paper). |
| 165 | + |
| 166 | +- **Pro:** Everything matches the physics and the literature |
| 167 | +- **Con:** The comment in `calc_bandreps` warns that "flipping the sign causes problems for |
| 168 | + the calculation of some subductions to `LGIrrep`s." This means the `LGIrrep` matrices in |
| 169 | + Crystalline.jl are also in the conjugated convention. Fixing `calc_bandreps` alone would |
| 170 | + break the subduction machinery; you'd need to also fix the `LGIrrep` phase conventions. |
| 171 | + This is a **large, risky change** to a foundational package with high regression risk. |
| 172 | + |
| 173 | +### Option C: Change the `SiteInducedSGRepElement` convention (recommended) |
| 174 | + |
| 175 | +The key observation is that **the functor's global phase is only used in |
| 176 | +`symmetry_analysis.jl`** — the constraint-building code in `tightbinding.jl` uses |
| 177 | +`sgrep_induced_by_siteir_excl_phase`, which returns just $\rho$ without any global phase. |
| 178 | + |
| 179 | +So changing the functor's phase convention from $e^{-i(g\mathbf{k})\cdot\mathbf{v}}$ to |
| 180 | +$e^{+i(g\mathbf{k})\cdot\mathbf{v}}$ would: |
| 181 | + |
| 182 | +- Remove Component 2 of the monkey-patch from `symmetry_eigenvalues` |
| 183 | +- Not affect Hamiltonian construction at all |
| 184 | +- Make the `SiteInducedSGRepElement` explicitly match Crystalline.jl's convention |
| 185 | + |
| 186 | +You'd still need the Component 1 fix (the $\Theta_\mathbf{G}$ sign), but that becomes a more |
| 187 | +natural choice: implement $\mathbf{w}^\dagger \Theta_\mathbf{G} \tilde{\mathbf{D}}_\mathbf{k} \mathbf{w}$ |
| 188 | +instead of $(\Theta_\mathbf{G} \mathbf{w})^\dagger \mathbf{D}_\mathbf{k} \mathbf{w}$, documented clearly |
| 189 | +as "we use $\Theta_\mathbf{G}$ (not $\Theta_\mathbf{G}^\dagger$) to match Crystalline.jl's |
| 190 | +character convention." |
| 191 | + |
| 192 | +In this option, `theory.md` should also gain a note (or a new devdoc section) explaining: |
| 193 | +"The physical formula uses $e^{-i(g\mathbf{k})\cdot\mathbf{v}}$, but Crystalline.jl's |
| 194 | +`calc_bandreps` and `LGIrrep`s use the conjugated phase $e^{+i(g\mathbf{k})\cdot\mathbf{v}}$. |
| 195 | +Since `symmetry_eigenvalues` must match Crystalline.jl's irreps for subduction to work, we |
| 196 | +adopt the conjugated convention for $\mathbf{D}_\mathbf{k}$." |
| 197 | + |
| 198 | +## Test results with the fix |
| 199 | + |
| 200 | +Across all 230 3D space groups (and all 1D and 2D space groups): |
| 201 | + |
| 202 | +- **All 1D:** pass |
| 203 | +- **All 2D:** pass (including p3, p6, which previously failed at the K-point) |
| 204 | +- **3D:** 223/230 pass; 7 fail (SG 68, 88, 141, 142, 214, 220, 230) |
| 205 | +- The 7 remaining failures are **pre-existing** bugs (present in the original code before |
| 206 | + the fix), all in centered lattices (C or I centering). These are a separate class of issue, |
| 207 | + likely originating in Crystalline.jl's orbit/position handling for non-primitive lattices. |
| 208 | + The fix actually *improves* some of these (SG 214: 10→8 failures; SG 220: 6→4; SG 230: 9→4). |
0 commit comments