|
| 1 | +r"""3D face-centered cubic (fcc) lattice. |
| 2 | +
|
| 3 | +The dispersion of the 3D face-centered cubic lattice is given by |
| 4 | +
|
| 5 | +.. math:: |
| 6 | +
|
| 7 | + ϵ_{k_x,k_y,k_z} = 4t [\cos(k_x/2)\cos(k_y/2) + \cos(k_x/2)\cos(k_z/2) + \cos(k_y/2) \cos(k_z/2)] |
| 8 | +
|
| 9 | +which takes values in :math:`ϵ_{k_x, k_y, k_z} ∈ [-4t, +12t] = [-0.5D, +1.5D]`. |
| 10 | +
|
| 11 | +:half_bandwidth: The half_bandwidth corresponds to a nearest neighbor hopping |
| 12 | + of `t=D/8`. |
| 13 | +
|
| 14 | +""" |
| 15 | +import numpy as np |
| 16 | + |
| 17 | +from mpmath import mp |
| 18 | + |
| 19 | +from gftool._util import _u_ellipk |
| 20 | + |
| 21 | + |
| 22 | +def _signed_sqrt(z): |
| 23 | + """Square root with correct sign for fcc lattice.""" |
| 24 | + # sign = np.where((z.real < 0) & (z.imag < 0), -1, 1) |
| 25 | + sign = np.where(z.real < 0, -1, 1) |
| 26 | + factor = np.where(sign == 1, 1, -1j) |
| 27 | + return factor * np.lib.scimath.sqrt(sign*z) |
| 28 | + |
| 29 | + |
| 30 | +def gf_z(z, half_bandwidth): |
| 31 | + r"""Local Green's function of the 3D face-centered cubic (fcc) lattice. |
| 32 | +
|
| 33 | + Note, that the spectrum is asymmetric and in :math:`[-D/2, 3D/2]`, |
| 34 | + where :math:`D` is the half-bandwidth. |
| 35 | +
|
| 36 | + Has a van Hove singularity at `z=-half_bandwidth/2` (divergence) and at |
| 37 | + `z=0` (continuous but not differentiable). |
| 38 | +
|
| 39 | + Implements equations (2.16), (2.17) and (2.11) from [morita1971]_. |
| 40 | +
|
| 41 | + Parameters |
| 42 | + ---------- |
| 43 | + z : complex np.ndarray or complex |
| 44 | + Green's function is evaluated at complex frequency `z`. |
| 45 | + half_bandwidth : float |
| 46 | + Half-bandwidth of the DOS of the face-centered cubic lattice. |
| 47 | + The `half_bandwidth` corresponds to the nearest neighbor hopping `t=D/8`. |
| 48 | +
|
| 49 | + Returns |
| 50 | + ------- |
| 51 | + gf_z : complex np.ndarray or complex |
| 52 | + Value of the face-centered cubic lattice Green's function |
| 53 | +
|
| 54 | + References |
| 55 | + ---------- |
| 56 | + .. [morita1971] Morita, T., Horiguchi, T., 1971. Calculation of the Lattice |
| 57 | + Green’s Function for the bcc, fcc, and Rectangular Lattices. Journal of |
| 58 | + Mathematical Physics 12, 986–992. https://doi.org/10.1063/1.1665693 |
| 59 | +
|
| 60 | + Examples |
| 61 | + -------- |
| 62 | + >>> ww = np.linspace(-1.6, 1.6, num=501, dtype=complex) |
| 63 | + >>> gf_ww = gt.lattice.fcc.gf_z(ww, half_bandwidth=1) |
| 64 | +
|
| 65 | + >>> import matplotlib.pyplot as plt |
| 66 | + >>> _ = plt.axvline(-0.5, color='black', linewidth=0.8) |
| 67 | + >>> _ = plt.axvline(0, color='black', linewidth=0.8) |
| 68 | + >>> _ = plt.axhline(0, color='black', linewidth=0.8) |
| 69 | + >>> _ = plt.plot(ww.real, gf_ww.real, label=r"$\Re G$") |
| 70 | + >>> _ = plt.plot(ww.real, gf_ww.imag, '--', label=r"$\Im G$") |
| 71 | + >>> _ = plt.ylabel(r"$G*D$") |
| 72 | + >>> _ = plt.xlabel(r"$\omega/D$") |
| 73 | + >>> _ = plt.xlim(left=ww.real.min(), right=ww.real.max()) |
| 74 | + >>> _ = plt.legend() |
| 75 | + >>> plt.show() |
| 76 | +
|
| 77 | + """ |
| 78 | + D = half_bandwidth / 2 |
| 79 | + z = np.asarray(1 / D * z) |
| 80 | + retarded = z.imag > 0 |
| 81 | + z = np.where(retarded, np.conj(z), z) # calculate advanced only, and use symmetry |
| 82 | + zp1 = z + 1 |
| 83 | + zp1_pow = _signed_sqrt(zp1)**-3 |
| 84 | + sum1 = 4 * _signed_sqrt(z) * zp1_pow |
| 85 | + sum2 = (z - 1) * _signed_sqrt(z - 3) * zp1_pow |
| 86 | + m_p = 0.5*(1 + sum1 - sum2) # eq. (2.11) |
| 87 | + m_m = 0.5*(1 - sum1 - sum2) # eq. (2.11) |
| 88 | + kii = np.asarray(_u_ellipk(m_p)) |
| 89 | + kii[m_p.imag < 0] += 2j*_u_ellipk(1 - m_p[m_p.imag < 0]) # eq (2.17) |
| 90 | + gf = 4 / (np.pi**2 * D * zp1) * _u_ellipk(m_m) * kii # eq (2.16) |
| 91 | + return np.where(retarded, np.conj(gf), gf) # return to retarded by symmetry |
| 92 | + |
| 93 | + |
| 94 | +def hilbert_transform(xi, half_bandwidth): |
| 95 | + r"""Hilbert transform of non-interacting DOS of the face-centered cubic lattice. |
| 96 | +
|
| 97 | + The Hilbert transform is defined |
| 98 | +
|
| 99 | + .. math:: \tilde{D}(ξ) = ∫_{-∞}^{∞}dϵ \frac{DOS(ϵ)}{ξ − ϵ} |
| 100 | +
|
| 101 | + The lattice Hilbert transform is the same as the non-interacting Green's |
| 102 | + function. |
| 103 | +
|
| 104 | + Parameters |
| 105 | + ---------- |
| 106 | + xi : complex np.ndarray or complex |
| 107 | + Point at which the Hilbert transform is evaluated |
| 108 | + half_bandwidth : float |
| 109 | + half-bandwidth of the DOS of the 3D face-centered cubic lattice |
| 110 | +
|
| 111 | + Returns |
| 112 | + ------- |
| 113 | + hilbert_transform : complex np.ndarray or complex |
| 114 | + Hilbert transform of `xi`. |
| 115 | +
|
| 116 | + Notes |
| 117 | + ----- |
| 118 | + Relation between nearest neighbor hopping `t` and half-bandwidth `D` |
| 119 | +
|
| 120 | + .. math:: 8t = D |
| 121 | +
|
| 122 | + See Also |
| 123 | + -------- |
| 124 | + gftool.lattice.fcc.gf_z |
| 125 | +
|
| 126 | + """ |
| 127 | + return gf_z(xi, half_bandwidth) |
| 128 | + |
| 129 | + |
| 130 | +def dos(eps, half_bandwidth): |
| 131 | + r"""DOS of non-interacting 3D face-centered cubic lattice. |
| 132 | +
|
| 133 | + Has a van Hove singularity at `z=-half_bandwidth/2` (divergence) and at |
| 134 | + `z=0` (continuous but not differentiable). |
| 135 | +
|
| 136 | + Parameters |
| 137 | + ---------- |
| 138 | + eps : float np.ndarray or float |
| 139 | + DOS is evaluated at points `eps`. |
| 140 | + half_bandwidth : float |
| 141 | + Half-bandwidth of the DOS, DOS(`eps` < -0.5*`half_bandwidth`) = 0, |
| 142 | + DOS(1.5*`half_bandwidth` < `eps`) = 0. |
| 143 | + The `half_bandwidth` corresponds to the nearest neighbor hopping `t=D/8` |
| 144 | +
|
| 145 | + Returns |
| 146 | + ------- |
| 147 | + dos : float np.ndarray or float |
| 148 | + The value of the DOS. |
| 149 | +
|
| 150 | + See Also |
| 151 | + -------- |
| 152 | + gftool.lattice.fcc.dos_mp : multi-precision version suitable for integration |
| 153 | +
|
| 154 | + References |
| 155 | + ---------- |
| 156 | + .. [morita1971] Morita, T., Horiguchi, T., 1971. Calculation of the Lattice |
| 157 | + Green’s Function for the bcc, fcc, and Rectangular Lattices. Journal of |
| 158 | + Mathematical Physics 12, 986–992. https://doi.org/10.1063/1.1665693 |
| 159 | +
|
| 160 | + Examples |
| 161 | + -------- |
| 162 | + >>> eps = np.linspace(-1.6, 1.6, num=501) |
| 163 | + >>> dos = gt.lattice.fcc.dos(eps, half_bandwidth=1) |
| 164 | +
|
| 165 | + >>> import matplotlib.pyplot as plt |
| 166 | + >>> _ = plt.axvline(0, color='black', linewidth=0.8) |
| 167 | + >>> _ = plt.axvline(-0.5, color='black', linewidth=0.8) |
| 168 | + >>> _ = plt.plot(eps, dos) |
| 169 | + >>> _ = plt.xlabel(r"$\epsilon/D$") |
| 170 | + >>> _ = plt.ylabel(r"DOS * $D$") |
| 171 | + >>> _ = plt.ylim(bottom=0) |
| 172 | + >>> _ = plt.xlim(left=eps.min(), right=eps.max()) |
| 173 | + >>> plt.show() |
| 174 | +
|
| 175 | + """ |
| 176 | + eps = np.asarray(eps) |
| 177 | + singular = eps == -0.5*half_bandwidth |
| 178 | + finite = (-0.5*half_bandwidth < eps) & (eps < 1.5*half_bandwidth) & ~singular |
| 179 | + dos_ = np.zeros_like(eps) |
| 180 | + dos_[finite] = 1 / np.pi * gf_z(eps[finite], half_bandwidth=half_bandwidth).imag |
| 181 | + dos_[singular] = np.infty |
| 182 | + return abs(dos_) # at 0.5D wrong sign |
| 183 | + |
| 184 | + |
| 185 | +# ∫dϵ ϵ^m DOS(ϵ) for half-bandwidth D=1 |
| 186 | +# from: integral of dos_mp with mp.workdps(100) |
| 187 | +# for m in range(0, 21, 1): |
| 188 | +# with mp.workdps(100): |
| 189 | +# print(mp.quad(lambda eps: eps**m * dos_mp(eps), [mp.mpf('-0.5'), 0, 1]) |
| 190 | +# rational numbers obtained by mp.identify |
| 191 | +dos_moment_coefficients = { |
| 192 | + 0: 1, |
| 193 | + 1: 0, |
| 194 | + 2: 3/16, |
| 195 | + 3: 3/32, |
| 196 | + 4: 135/1024, |
| 197 | + 5: 135/1024, |
| 198 | + 6: 0.1611328125, |
| 199 | + 7: 0.1922607421875, |
| 200 | + 8: 0.24070143699646, |
| 201 | + 9: 0.305163860321045, |
| 202 | + 10: 0.394462153315544, |
| 203 | + 11: 0.516299419105052, |
| 204 | + 12: 0.683690124191343, |
| 205 | + 13: 0.913928582333027, |
| 206 | + 14: 1.23181895411108, |
| 207 | + 15: 1.67210463207448, |
| 208 | + 16: 2.28395076888283, |
| 209 | + 17: 3.13686893977359, |
| 210 | + 18: 4.32941325997849, |
| 211 | + 19: 6.00152324929046, |
| 212 | + 20: 8.35226611969712, |
| 213 | +} |
| 214 | + |
| 215 | + |
| 216 | +def dos_moment(m, half_bandwidth): |
| 217 | + """Calculate the `m` th moment of the face-centered cubic DOS. |
| 218 | +
|
| 219 | + The moments are defined as :math:`∫dϵ ϵ^m DOS(ϵ)`. |
| 220 | +
|
| 221 | + Parameters |
| 222 | + ---------- |
| 223 | + m : int |
| 224 | + The order of the moment. |
| 225 | + half_bandwidth : float |
| 226 | + Half-bandwidth of the DOS of the 3D face-centered cubic lattice. |
| 227 | +
|
| 228 | + Returns |
| 229 | + ------- |
| 230 | + dos_moment : float |
| 231 | + The `m` th moment of the 3D face-centered cubic DOS. |
| 232 | +
|
| 233 | + Raises |
| 234 | + ------ |
| 235 | + NotImplementedError |
| 236 | + Currently only implemented for a few specific moments `m`. |
| 237 | +
|
| 238 | + See Also |
| 239 | + -------- |
| 240 | + gftool.lattice.fcc.dos |
| 241 | +
|
| 242 | + """ |
| 243 | + try: |
| 244 | + return dos_moment_coefficients[m] * half_bandwidth**m |
| 245 | + except KeyError as keyerr: |
| 246 | + raise NotImplementedError('Calculation of arbitrary moments not implemented.') from keyerr |
| 247 | + |
| 248 | + |
| 249 | +def _signed_mp_sqrt(eps): |
| 250 | + """Square root with correct sign for fcc lattice.""" |
| 251 | + if eps >= 0: |
| 252 | + return mp.sqrt(eps) |
| 253 | + return -1j*mp.sqrt(-eps) |
| 254 | + |
| 255 | + |
| 256 | +def dos_mp(eps, half_bandwidth=1): |
| 257 | + r"""Multi-precision DOS of non-interacting 3D face-centered cubic lattice. |
| 258 | +
|
| 259 | + Has a van Hove singularity at `z=-half_bandwidth/2` (divergence) and at |
| 260 | + `z=0` (continuous but not differentiable). |
| 261 | +
|
| 262 | + This function is particularity suited to calculate integrals of the form |
| 263 | + :math:`∫dϵ DOS(ϵ)f(ϵ)`. If you have problems with the convergence, |
| 264 | + consider using :math:`∫dϵ DOS(ϵ)[f(ϵ)-f(-1/2)] + f(-1/2)` to avoid the |
| 265 | + singularity. |
| 266 | +
|
| 267 | + Parameters |
| 268 | + ---------- |
| 269 | + eps : mpmath.mpf or mpf_like |
| 270 | + DOS is evaluated at points `eps`. |
| 271 | + half_bandwidth : mpmath.mpf or mpf_like |
| 272 | + Half-bandwidth of the DOS, DOS(`eps` < -0.5*`half_bandwidth`) = 0, |
| 273 | + DOS(1.5*`half_bandwidth` < `eps`) = 0. |
| 274 | + The `half_bandwidth` corresponds to the nearest neighbor hopping `t=D/8` |
| 275 | +
|
| 276 | + Returns |
| 277 | + ------- |
| 278 | + dos_mp : mpmath.mpf |
| 279 | + The value of the DOS. |
| 280 | +
|
| 281 | + See Also |
| 282 | + -------- |
| 283 | + gftool.lattice.fcc.dos : vectorized version suitable for array evaluations |
| 284 | +
|
| 285 | + References |
| 286 | + ---------- |
| 287 | + .. [morita1971] Morita, T., Horiguchi, T., 1971. Calculation of the Lattice |
| 288 | + Green’s Function for the bcc, fcc, and Rectangular Lattices. Journal of |
| 289 | + Mathematical Physics 12, 986–992. https://doi.org/10.1063/1.1665693 |
| 290 | +
|
| 291 | + Examples |
| 292 | + -------- |
| 293 | + Calculate integrals: |
| 294 | +
|
| 295 | + >>> from mpmath import mp |
| 296 | + >>> unit = mp.quad(gt.lattice.fcc.dos_mp, [-0.5, 0, 1.5]) |
| 297 | + >>> mp.identify(unit) |
| 298 | + '1' |
| 299 | +
|
| 300 | + >>> eps = np.linspace(-1.6, 1.6, num=501) |
| 301 | + >>> dos_mp = [gt.lattice.fcc.dos_mp(ee, half_bandwidth=1) for ee in eps] |
| 302 | + >>> dos_mp = np.array(dos_mp, dtype=np.float64) |
| 303 | +
|
| 304 | + >>> import matplotlib.pyplot as plt |
| 305 | + >>> _ = plt.axvline(0, color='black', linewidth=0.8) |
| 306 | + >>> _ = plt.axvline(-0.5, color='black', linewidth=0.8) |
| 307 | + >>> _ = plt.plot(eps, dos_mp) |
| 308 | + >>> _ = plt.xlabel(r"$\epsilon/D$") |
| 309 | + >>> _ = plt.ylabel(r"DOS * $D$") |
| 310 | + >>> _ = plt.ylim(bottom=0) |
| 311 | + >>> _ = plt.xlim(left=eps.min(), right=eps.max()) |
| 312 | + >>> plt.show() |
| 313 | +
|
| 314 | + """ |
| 315 | + D = mp.mpf(half_bandwidth) * mp.mpf('1/2') |
| 316 | + eps = mp.mpf(eps) / D |
| 317 | + if 3 < eps < -1: |
| 318 | + return mp.mpf('0') |
| 319 | + if eps == -1: |
| 320 | + return mp.inf |
| 321 | + epsp1 = eps + 1 |
| 322 | + epsp1_pow = _signed_mp_sqrt(epsp1)**-3 |
| 323 | + sum1 = 4 * _signed_mp_sqrt(eps) * epsp1_pow |
| 324 | + sum2 = (eps - 1) * _signed_mp_sqrt(eps - 3) * epsp1_pow |
| 325 | + m_p = mp.mpf('0.5')*(1 + sum1 - sum2) # eq. (2.11) |
| 326 | + m_m = mp.mpf('0.5')*(1 - sum1 - sum2) # eq. (2.11) |
| 327 | + kii = mp.ellipk(m_p) |
| 328 | + if m_p.imag < 0: |
| 329 | + kii += 2j * mp.ellipk(1 - m_p) # eq (2.17) |
| 330 | + return abs(4 / (mp.pi**3 * D * epsp1) * (_u_ellipk(m_m) * kii).imag) # eq (2.16) |
0 commit comments