22function dynmat_red_to_cart (model:: Model , dynmat)
33 inv_lattice = model. inv_lattice
44
5- # The dynamical matrix `D` acts on vectors `dr` and gives a covector `dF`:
6- # dF = D · dr.
7- # Thus the transformation between reduced and Cartesian coordinates is not a comatrix.
8- # To transform `dynamical_matrix` from reduced coordinates to `dynmat_cart` in Cartesian
9- # coordinates, we write
10- # dr_cart = lattice · dr_red,
11- # ⇒ dr_redᵀ · D_red · dr_red = dr_cartᵀ · lattice⁻ᵀ · D_red · lattice⁻¹ · dr_cart
12- # = dr_cartᵀ · D_cart · dr_cart
13- # ⇒ D_cart = lattice⁻ᵀ · D_red · lattice⁻¹.
14-
5+ # The dynamical matrix `D` acts on vectors `δr` and gives a covector `δF`:
6+ # δF = D δr
7+ # We have δr_cart = lattice * δr_red, δF_cart = lattice⁻ᵀ δF_red, so
8+ # δF_cart = lattice⁻ᵀ D_red lattice⁻¹ δr_cart
159 dynmat_cart = zero .(dynmat)
16- for s = 1 : size (dynmat_cart, 2 ), α = 1 : size (dynmat_cart, 4 )
10+ for s in axes (dynmat_cart, 2 ), α in axes (dynmat_cart, 4 )
1711 dynmat_cart[:, α, :, s] = inv_lattice' * dynmat[:, α, :, s] * inv_lattice
1812 end
1913 dynmat_cart
2014end
2115
22- # Create a ``3×n_{\rm atoms}×3×n_{\rm atoms}`` tensor (for consistency with the format of
23- # dynamical matrices) equivalent to a diagonal matrix with the atomic masses of the atoms in
24- # a.u. on the diagonal.
16+ # Create a ``3×n_{\rm atoms}×3×n_{\rm atoms}`` tensor equivalent to a diagonal matrix with
17+ # the atomic masses of the atoms in a.u. on the diagonal.
2518function mass_matrix (T, atoms)
2619 n_atoms = length (atoms)
2720 atoms_mass = atomic_mass .(atoms)
@@ -34,26 +27,42 @@ function mass_matrix(T, atoms)
3427end
3528mass_matrix (model:: Model{T} ) where {T} = mass_matrix (T, model. atoms)
3629
37- @doc raw """
38- Solve the eigenproblem for a dynamical matrix: returns the `frequencies` and eigenvectors
39- (`vectors`).
4030"""
41- function phonon_modes (basis:: PlaneWaveBasis{T} , dynmat) where {T}
31+ Get phonon quantities. We return the frequencies, the mass matrix and reduced and Cartesian
32+ eigenvectors and dynamical matrices.
33+ """
34+ function phonon_modes (basis:: PlaneWaveBasis{T} , ψ, occupation; kwargs... ) where {T}
35+ dynmat = compute_dynmat (basis:: PlaneWaveBasis , ψ, occupation; kwargs... )
36+ dynmat_cart = dynmat_red_to_cart (basis. model, dynmat)
37+
38+ modes = _phonon_modes (basis, dynmat_cart)
39+ vectors = similar (modes. vectors_cart)
40+ for s in axes (vectors, 2 ), t in axes (vectors, 4 )
41+ vectors[:, s, :, t] = vector_cart_to_red (basis. model, modes. vectors_cart[:, s, :, t])
42+ end
43+
44+ (; modes. mass_matrix, modes. frequencies, dynmat, dynmat_cart, vectors, modes. vectors_cart)
45+ end
46+ # Compute the frequencies and vectors. Internal because of the potential misuse:
47+ # the diagonalization of the phonon modes has to be done in Cartesian coordinates.
48+ function _phonon_modes (basis:: PlaneWaveBasis{T} , dynmat_cart) where {T}
4249 n_atoms = length (basis. model. positions)
4350 M = reshape (mass_matrix (T, basis. model. atoms), 3 * n_atoms, 3 * n_atoms)
4451
45- res = eigen (reshape (dynmat , 3 * n_atoms, 3 * n_atoms), M)
52+ res = eigen (reshape (dynmat_cart , 3 * n_atoms, 3 * n_atoms), M)
4653 maximum (abs, imag (res. values)) > sqrt (eps (T)) &&
47- @warn " Some eigenvalues of the dynamical matrix have a large imaginary part"
54+ @warn " Some eigenvalues of the dynamical matrix have a large imaginary part. "
4855
4956 signs = sign .(real (res. values))
5057 frequencies = signs .* sqrt .(abs .(real (res. values)))
5158
52- (; frequencies, res. vectors)
59+ vectors_cart =
60+ (; mass_matrix= M, frequencies, vectors_cart= reshape (res. vectors, 3 , n_atoms, 3 , n_atoms))
5361end
54- function phonon_modes_cart (basis:: PlaneWaveBasis{T} , dynmat) where {T}
55- dynmat_cart = dynmat_red_to_cart (basis. model, dynmat)
56- phonon_modes (basis, dynmat_cart)
62+ # For convenience
63+ function phonon_modes (scfres:: NamedTuple ; kwargs... )
64+ phonon_modes (scfres. basis, scfres. ψ, scfres. occupation; scfres. ρ, scfres. ham,
65+ scfres. occupation_threshold, scfres. εF, scfres. eigenvalues, kwargs... )
5766end
5867
5968@doc raw """
@@ -69,44 +78,27 @@ in reduced coordinates.
6978 δoccupations = [zero .(occupation) for _ = 1 : 3 , _ = 1 : n_atoms]
7079 δψs = [zero .(ψ) for _ = 1 : 3 , _ = 1 : n_atoms]
7180 for s = 1 : n_atoms, α = 1 : basis. model. n_dim
81+ # Get δH ψ
7282 δHψs_αs = compute_δHψ_αs (basis, ψ, α, s, q)
7383 isnothing (δHψs_αs) && continue
84+ # Response solver to get δψ
7485 (; δψ, δρ, δoccupation) = solve_ΩplusK_split (ham, ρ, ψ, occupation, εF, eigenvalues,
7586 - δHψs_αs; q, kwargs... )
7687 δoccupations[α, s] = δoccupation
7788 δρs[α, s] = δρ
7889 δψs[α, s] = δψ
7990 end
80-
91+ # Query each energy term for their contribution to the dynamical matrix.
8192 dynmats_per_term = [compute_dynmat (term, basis, ψ, occupation; ρ, δψs, δρs,
8293 δoccupations, q)
8394 for term in basis. terms]
8495 sum (filter (! isnothing, dynmats_per_term))
8596end
8697
8798"""
88- Cartesian form of [`compute_dynmat`](@ref).
89- """
90- function compute_dynmat_cart (basis:: PlaneWaveBasis , ψ, occupation; kwargs... )
91- dynmats_reduced = compute_dynmat (basis, ψ, occupation; kwargs... )
92- dynmat_red_to_cart (basis. model, dynmats_reduced)
93- end
94-
95- function compute_dynmat (scfres:: NamedTuple ; kwargs... )
96- compute_dynmat (scfres. basis, scfres. ψ, scfres. occupation; scfres. ρ, scfres. ham,
97- scfres. occupation_threshold, scfres. εF, scfres. eigenvalues, kwargs... )
98- end
99-
100- function compute_dynmat_cart (scfres; kwargs... )
101- compute_dynmat_cart (scfres. basis, scfres. ψ, scfres. occupation; scfres. ρ, scfres. ham,
102- scfres. occupation_threshold, scfres. εF, scfres. eigenvalues, kwargs... )
103- end
104-
105- # TODO : Document relation to non-local potential in future phonon PR.
106- """
107- Assemble the right-hand side term for the Sternheimer equation for all relevant quantities:
108- Compute the perturbation of the Hamiltonian with respect to a variation of the local
109- potential produced by a displacement of the atom s in the direction α.
99+ Get ``δH·ψ``, with ``δH`` the perturbation of the Hamiltonian with respect to a position
100+ displacement ``e^{iq·r}`` of the ``α`` coordinate of atom ``s``.
101+ `δHψ[ik]` is ``δH·ψ_{k-q}``, expressed in `basis.kpoints[ik]`.
110102"""
111103@timing function compute_δHψ_αs (basis:: PlaneWaveBasis , ψ, α, s, q)
112104 δHψ_per_term = [compute_δHψ_αs (term, basis, ψ, α, s, q) for term in basis. terms]
0 commit comments