Symmetries in Fourier space

From version 0.8, AtomicSymmetries.jl provided the possibility to apply symmetries to vector and matrices directly in Fourier space. This is implemented now for force-constant dynamical matrices and vectors (displacements, forces, ...).

A vector is transformed from real to q-space with the following convention:

\[\tilde v_k(\vec q) = \frac{1}{\sqrt{N_q}} \sum_{R} e^{-i 2\pi \vec R\cdot \vec q} v_k(\vec R)\]

\[v_k(\vec R) = \frac{1}{\sqrt{N_q}} \sum_{R} e^{i 2\pi \vec R\cdot \vec q} \tilde v_k(\vec q)\]

Note the sign of the Fourier and the normalization prefactor. This convention allows for correctly transforming the matrices, however, it introduces a size inconsistency on the vectors. If we have a periodic vector in the cell, its $q$ fourier transformed counterpart will be $\sqrt {N_q}$ times the value in the primitive cell. So be carefull when extracting $\Gamma$ point data from periodic vectors.

With this convention, we recover the standard rule for the matrices.

\[\tilde \Phi_{ab}(\vec q) = \sum_{\vec R} e^{2\pi i \vec q\cdot \vec R}\Phi_{a;b + \vec R}\]

\[\Phi_{ab} = \frac{1}{N_q} \sum_{\vec q} \tilde\Phi_{ab}(\vec q) e^{2i\pi \vec q\cdot[\vec R(a) - \vec R(b)]}\]

Note that these transformation of matrices and vector are consistent so that matrices and vector written as outer product can be consistently transformed

\[\Phi(\vec R) = \sum_i\sum_{\vec R} \vec v_i(\vec R_1) \otimes \vec v_i(\vec R_1 + \vec R)\]

\[\tilde \Phi(\vec q) = \sum_i \vec {\tilde v}_i(\vec q) \otimes \vec {\tilde v_i}(-\vec q)\]

Notably, this convention introduces two main properties that must be handled with care. The $\Gamma$ value of the fourier transform is not the average over the supercell of the same quantity. If you want to obtain the average, you must divide by $\sqrt {N_q}$ (the number of q-points). If the R_lat is not centered around zero, and the coordinates passed as v_sc are absolute values of positions, then the $\Gamma$ value of the fourier transform will be shifted by a total translation which is the average of the translations of the supercell lattice vectors. This can be avoided by either removing the corner of the supercell from the positions before performing the fourier transform, by centering Rlat around 0, or by removing this translational average a posteriori using the method `shiftposition_origin!`.

Fourier transform

The API to perform the fourier transform occur mainly with vector_r2q!, vector_q2r! which, respectively, trasform a vector from real to q space and vice-versa. Transformation of matrices occur with matrix_r2q!, matrix_q2r!. All these operations are inplace. The matrices are assumed in crystal coordinates, but in this case it should not matter.

To shift the origin for the fourier transformed absolute positions, use the method shift_position_origin! as

The detailed API calls are

AtomicSymmetries.vector_r2q!Function
vector_r2q!(
    v_q :: AbstractArray{Complex{T}, 3},
    v_sc :: AbstractMatrix{T},
    q_tot :: Matrix{T})
vector_r2q!(v_q :: AbstractArray{Complex{T}, 2},
    v_sc :: AbstractVector{T},
    q :: Matrix{T},
    itau :: Vector{I},
    R_lat :: Matrix{T}
) where {T <: AbstractFloat, I <: Integer}

Fourier transform a vector from real space and q space.

$\displaystyle v_k(\vec q) = \frac{1}{\sqrt{N_q}} \sum_{R} e^{-i 2\pi \vec R\cdot \vec q} v_k(\vec R)$

It works both on a single vector and on a series of vector. NOTE: In the latter case, the number of configurations must be in the first column. This is not standard, but implemented in this way for performance reasons as it is the most convenient memory rapresentation for vectorizing the average calculation.

Notably, this convention introduces two main properties:

The $\Gamma$ value of the fourier transform is not the average over the supercell of the same quantity. If you want to obtain the average, you must divide by √nq (the number of q-points).

If the R_lat is not centered around zero, and the coordinates passed as v_sc are absolute values of positions, then the $\Gamma$ value of the fourier transform will be shifted by a total translation which is the average of the translations of the supercell lattice vectors.

To avoid this behaviour (which is wrong), you can use the option absolute_positions, which automatically rescales the v_sc to be coordinates relative to the respective cell origin identified by R_lat. Indeed, in this case, R_lat and v_sc must be of the same units, and coordinate types (you cannot mix crystalline and cartesian).

Parameters

  • v_q : (nconfigs, 3nat, nq) The target vector in Fourier space. Optionally, nconfigs could be omitted if transforming only 1 vector
  • v_sc : (nconfigs, 3*natsc) The original vector in real space. Optionally, n_configs could be omitted if transforming only 1 vector
  • q_tot : (3, nq) The list of q vectors
  • itau : (nat_sc) The correspondance for each atom in the supercell with the atom in the primitive cell.
  • R_lat : (3, nat_sc) The origin coordinates of the supercell in which the atom is
  • absolute_positions : Bool If true [default false], removes from vsc the value of Rlat.
source
AtomicSymmetries.vector_q2r!Function
vector_q2r!(
    v_sc :: AbstractMatrix{T},
    v_q :: AbstractArray{Complex{T}, 3},
    q_tot :: Matrix{T},
    itau :: Vector{I},
    R_lat :: Matrix{T};
    absolute_positions :: Bool = false
    ) where {T <: AbstractFloat, I <: Integer}
function vector_q2r!(
    v_sc :: AbstractVector{T},
    v_q :: AbstractMatrix{Complex{T}},
    q :: Matrix{T},
    itau :: Vector{I},
    R_lat :: Matrix{T};
    absolute_positions :: Bool = false
) where {T <: AbstractFloat, I <: Integer}

Fourier transform a vector from q space to real space.

$\displaystyle v_k(\vec R) = \frac{1}{\sqrt{N_q}} \sum_{R} e^{+i 2\pi \vec R\cdot \vec q} v_k(\vec q)$

It can be applied both to a single vector and in an ensemble. NOTE: In the latter case, the configurations must be stored as the first index. This choice is made for performance reason in computing averages (exploiting vectorization).

Parameters

  • v_sc : (nconfigs, 3*natsc) The target vector in real space. Optionally, n_configs can be omitted
  • v_q : (nconfigs, nq, 3*nat) The original vector in Fourier space. Optionally, nconfigs can be omitted
  • q_tot : (3, nq) The list of q vectors
  • itau : (nat_sc) The correspondance for each atom in the supercell with the atom in the primitive cell.
  • R_lat : (3, nat_sc) The origin coordinates of the supercell in which the atom is
  • absolute_positions : Bool If true, add the absolute position of the cell to the transformed v_sc
source
AtomicSymmetries.matrix_r2q!Function
matrix_r2q!(
    matrix_q :: Array{Complex{T}, 3},
    matrix_r :: AbstractMatrix{T},
    q :: Matrix{T},
    itau :: Vector{I},
    R_lat :: Matrix{T})

Fourier transform a matrix from real to q space

\[M_{ab}(\vec q) = \sum_{\vec R} e^{2\pi i \vec q\cdot \vec R}\Phi_{a;b + \vec R}\]

Where $\Phi_{ab}$ is the real space matrix, the $b+\vec R$ indicates the corresponding atom in the supercell displaced by $\vec R$.

Parameters

  • matrix_q : (3nat, 3nat, nq) The target matrix in Fourier space.
  • matrix_r : (3nat_sc, 3nat) The original matrix in real space (supercell)
  • q_tot : (3, nq) The list of q vectors
  • itau : (nat_sc) The correspondance for each atom in the supercell with the atom in the primitive cell.
  • R_lat : (3, nat_sc) The origin coordinates of the supercell in which the corresponding atom is
source
AtomicSymmetries.matrix_q2r!Function
matrix_q2r!(
    matrix_r :: AbstractMatrix{T},
    matrix_q :: Array{Complex{T}, 3},
    q :: Matrix{T},
    itau :: Vector{Int},
    R_lat :: Matrix{T})

Fourier transform a matrix from q space into r space

$\displaystyle \Phi_{ab} = \frac{1}{N_q} \sum_{\vec q} M_{ab}(\vec q) e^{2i\pi \vec q\cdot[\vec R(a) - \vec R(b)]}$

Where $\Phi_{ab}$ is the real space matrix, $M_{ab}(\vec q)$ is the q space matrix.

Parameters

  • matrixr : (3*natsc, 3*nat) The target matrix in real space (supercell). If the second dimension is 3nat_sc, we also apply the translations
  • matrix_q : (3nat, 3nat, nq) The original matrix in Fourier space.
  • q_tot : (3, nq) The list of q vectors
  • itau : (nat_sc) The correspondance for each atom in the supercell with the atom in the primitive cell.
  • Rlat : (3, natsc) The origin coordinates of the supercell in which the corresponding atom is
  • translations : Vector{Vector{Int}} The itau correspondance for each translational vector. Its size must be equal to the number of q point and contain all possible translations. This can be obtained from the get_translations subroutine.
source
AtomicSymmetries.shift_position_origin!Function
shift_position_origin!(r_vector::AbstractVector{Complex{T}}, cell::AbstractMatrix{T}, R_lat::AbstractMatrix{T}; buffer) where T
shift_position_origin!(r_vectors::AbstractMatrix{Complex{T}}, cell::AbstractMatrix{T}, R_lat::AbstractMatrix{T}; buffer) where T

Shifts a set of position vectors (r_vector or r_vectors) such that the average position (center of mass) of the reference lattice (R_lat) is moved to the origin. The function operates in-place. This can be employed after performing a Fourier Transform of absolute positions, to correct for non centered R_lat.

This is typically used to remove the lattice translation from displacement vectors before calculating quantities that are invariant to rigid body translations.

The average position vector of the reference lattice $\mathbf{r}_{\text{avg}}$ is calculated in Cartesian coordinates, and then subtracted from the input vectors $\mathbf{r}$.

\[\mathbf{r}_{\text{avg}} = \frac{1}{N_{\text{atoms}}} \sum_{k=1}^{N_{\text{atoms}}} \mathbf{r}_{\text{lat}, k}\]

The position vectors are then shifted:

\[\mathbf{r}' = \mathbf{r} - \mathbf{r}_{\text{avg}}\]

Arguments

  • r_vector/r_vectors : The position vector(s) (of type Complex{T}) to be shifted in-place.
  • cell : The $N_{dims} \times N_{dims}$ matrix defining the unit cell (lattice vectors).
  • R_lat : The reference lattice positions (fractional/lattice coordinates, $N_{dims} \times N_{atoms}$) whose average position determines the shift.
  • buffer : An optional buffer for temporary memory allocation (Bumer.jl)

Details on r_vectors Matrix Method

The matrix method assumes that the input r_vectors has the dimensions $(N_{\text{configs}}, N_{\text{dims}} \times N_{\text{atoms,v}})$, where $N_{\text{configs}}$ is the number of configurations, and $N_{\text{atoms,v}}$ is the number of atoms in the vectors being shifted.

The shift is applied simultaneously to all configurations using broadcasting (@views ... .-=).

Example

An example of usage after the fourier transform

# Define positions_r as a n_configs, 3n_atoms_sc vector
# Perform the fourier transform in q space
# Here, we assume that R_lat and q_points are expressed in crystal coordinates.
# Otherwise, just pass the identity to the cell below.
vector_r2q!(positions_q, positions_r, q_points, itau, R_lat)

# Remove the translations
shift_position_origin!(positions_q, cell, R_lat)
source

Symmetries in Q space

The application of symmetries in Fourier space must also account how points in q space are mapped by the symmetry operations.

For this, the important information about how q points are related by symmetries needs to be computed and stored. This identification is performed by the helper function get_irt_q!, which identifies, for a given symmetry operation, the i->j mapping between q points. Q points mapped into themselves by the same set of symmetry operations form the socalled small-group of $q$, while the set of $q$ points mapped by all the symmetries of a crystal is called the star of the $q$ point. Due to time-inversion symmetry, the dynamical matrix must also satisfy the condition

$D(q) = D^\dagger(-q + G)$

therefore it is necessary also to keep track, for each q point, which one is the corresponding $-q + G$ in the mesh. This mapping is computed by the helper function get_minus_q!. All these information needs to be stored when applying symmetries. Therefore we defined a new Symmetries struct that ihnerits from the GenericSymmetries called SymmetriesQSpace. Note that, to initialize the symmetries in q-space, we must use the symmetries object (Symmetries) evaluated in the primitive cell. The correct initialization of symmetries could be checked with the subroutine check_symmetries, which will spot if a different cell has been employed when initializing the symmetries.

Since the q points must be passed in crystal coordinates, it may be useful to get the reciprocal lattice, which can be done with $get_reciprocal_lattice!$ (see section on crystal coordinates for the API)

Application of symmetries

Applying a symmetry means transforming a vector or a matrix (already in q-space) into a new vector (matrix). If the vector (matrix) is invariant under that transformation, then that transformation belong to the symmetry group.

Notably, the symmetries in the supercell are always the symmetries in the primitive cell times all possible translations operated by the lattice vectors compatible with the chosen supercell. On the contrary, the symmetries in q space are always only equal to the symmetries in the primitive cell. The reason is that translations are automatically incorporated in the q space representation by the block theorem:

\[D(q, q') = D(q)\delta(q - q')\]

This means that applying each symmetry operation in $q$ space is equivalent to averaging the result of the same symmetry operation in the supercell averaging among all possible translations.

The application of a symmetry in q space can be performed by considering how the force-constant matrix transform in real space under a symmetry operation $S$.

\[S[\tilde\Phi_{ab}(\bm q)] = \sum_{\bm R} e^{2\pi i \bm q\cdot \bm R}S^\dagger\Phi_{S\bm a, S(\bm b + \bm R)}S\]

The transformation also changes which atoms are considered. However, we must be careful with the convention adopted for the Fourier transform. In fact, we have that $\bm a$ and $\bm b$ are the positions on the atom in the primitive cell considered. The vectors $S\bm a$ and $S(\bm b + \bm R)$ may not correspond to atoms in the primitive cell, but rather folded in the supercell. To solve this issue, we need to define, for each symmetry operation, which atom in the primitive cell is mapped into which other atom in the primitive cell. This is indicated with $s(a)$ and $s(b)$. Also, we need to consider what is the translation vector $\bm t_{s,a}$ that brings the vector $S\bm a$ inside the primitive cell. With this information, we can rewrite the transformation as

\[\bm t_{s,a} = S\bm a - \bm{s(a)}\]

\[S[\tilde\Phi_{ab}(\bm q)] = \sum_{\bm R} e^{2\pi i \bm q\cdot \bm R}S^\dagger\Phi_{s(a) + \bm t_{s,a}, s(b) + \bm t_{s, b} + S\bm R}S\]

Exploiting the translational invariance, we can remove the $\bm t_{s,a}$ vector from the first index of the supercell force constant matrix, and rewrite the expression as

\[S[\tilde\Phi_{ab}(\bm q)] = \sum_{\bm R} e^{2\pi i \bm q\cdot \bm R}S^\dagger\Phi_{s(a), s(b) + \bm t_{s, b} - \bm t_{s, a} + S\bm R}S\]

By defining $\bm R' = \bm t_{s, b} - \bm t_{s, a} + S\bm R$, we can rewrite the summation in $\bm R'$ as

\[S[\tilde\Phi_{ab}(\bm q)] = \sum_{\bm R'} e^{2\pi i \bm q\cdot S^{-1} (\bm R' + \bm t_{s,a} - \bm t_{s,b})}S^\dagger\Phi_{s(a), s(b) + \bm R'}S\]

Since we work in crystal coordinates and reciprocal vectors, $S^{-1}\neq S^\dagger$. Therefore, we have

\[S[\tilde\Phi_{ab}(\bm q)] = \sum_{\bm R'} e^{2\pi i [(\bm S^{-1})^\dagger\bm q]\cdot(\bm R' + \bm t_{s,a} - \bm t_{s,b})}S^\dagger\Phi_{s(a), s(b) + \bm R'}S\]

Which is equivalent to the Fourier transform of the dynamical matrix at the transformed q-point $(\bm S^{-1})^\dagger\bm q$, times a phase factor. This is how symmetries operates in q space:

\[\bm S_\text{recip} = \left(\bm S^{-1}\right)^\dagger\]

\[S[\tilde\Phi_{ab}(\bm q)] = S^\dagger \tilde\Phi_{s(a)s(b)}(S_\text{recip}\bm q) S e^{2\pi i (S_\text{recip}\bm q)\cdot ( \bm t_{s,a} - \bm t_{s,b})}\]

Note that the $S_\text{recip}q$ vector in the phase factor and in the dynamical matrix can be always folded back into the first Brilluin zone. In fact the dynamical matrix is periodic in the reciprocal vector, while the phase factor is multiplied by a direct lattice vector. Thus, by adding a reciprocal lattice vector $\bm G$ to $S_\text{recip}\bm q$, the phase factor is multiplied by $e^{2\pi i \bm G\cdot ( \bm t_{s,a} - \bm t_{s,b})}$, which is always equal to 1.

The application of symmetries is handled by the general function rotate_vector! and rotate_dynamical_matrix! or rotate_matrix! that works exactly like for real space symmetries, with the same general interface. However, we also provide specific q-space only functions. Note that, while the rotate_* functions works in cartesian space, the following one expects symmetries in real space.

This transformation for each q point is operated by the subroutine apply_symmetry_matrixq!. Both these function modify in-place the first argument, storing the result of the transformation there. Note that, since symmetries are stored in crystalline components, both the vector and the matrix must be in crystalline components. This makes it also important that the $\bm q$ points are provided in crystalline coordinates, to correctly compute the phase factor and the transformed $S\bm q$.

AtomicSymmetries.SymmetriesQSpaceType
SymmetriesQSpace(symmetries :: Symmetries{T}, q_points :: AbstractMatrix{T}) :: SymmetriesQSpace{T} where T

struct SymmetriesQSpace{T} <: GenericSymmetries where T
    symmetries :: Symmetries{T}
    irt_q :: Vector{Vector{Int}}
    minus_q_index :: Vector{Int}
end

This structure contains the information to perform the symmetrization of a dynamical matrix directly in q space.

Note that the q_points needs to be in crystal coordinates,

and the symmetries must be of the primitive cell.

Parameters

  • symmetries : The symmetries of the primitive cell (Symmetries{T})
  • q_points : The q points where the symmetries must be applied (in crystal coordinates)
  • irt_q : A vector (one for each symmetry) of the correspondances of q points. For each symmetry can be obtained from get_irt_q! Q points linked in this way are related by the symmetry operation in reciprocal space, and belong to the same star of q.
  • minus_q_index : A vector containing for each q the corresponding $\vec {q'} = -\vec q + \vec G$, where $\vec G$ is a generic reciprocal lattice vector.
source
AtomicSymmetries.apply_symmetry_vectorq!Function
apply_symmetry_vectorq!(target_vector :: AbstractMatrix{Complex{T}}, original_vector :: AbstractMatrix{Complex{T}}, symmetry_operation :: AbstractMatrix{U}, irt :: Vector{Int}, irt_q:: AbstractVector{Int})

Apply the symmetry on the original vector in q space

Parameters

  • target_vector : The result (modified inplace) (3n x nq)
  • original_vector : The original vector (3n x nq)
  • symmetry_operation : The 3x3 symmetry
  • irt : The atom-atom association by symmetry
  • irt_q : The q-q association by symmetry
source
AtomicSymmetries.apply_symmetry_matrixq!Function
apply_symmetry_matrixq!(target_matrix :: AbstractArray{Complex{T}, 3},
    original_matrix :: AbstractArray{Complex{T}, 3},
    sym :: AbstractMatrix{U},
    irt :: AbstractVector{Int},
    irt_q :: AbstractVector{Int},
    unit_cell_translations :: AbstractMatrix{T},
    ; buffer = default_buffer()) where {T, U}

Apply the symmetry on the matrix in q space This subroutine assumes the convention that the phase factor is for each supercell, not atoms. In other words, all the atoms coordinates are computed from the same origin of the supercell they are associated with.

Parameters

  • target_vector : The result (modified inplace) (3n x nq)
  • original_vector : The original vector (3n x nq)
  • symmetry_operation : The 3x3 symmetry
  • irt : The atom-atom association by symmetry
  • irt_q : The q-q association by symmetry
  • unit_cell_translations : The translation vectors to move the transformed atom in the primitive cell
  • buffer : The Bumper.jl buffer for caching memory allocations [Optional]
source
AtomicSymmetries.get_irt_q!Function
get_irt_q!(irt_q :: AbstractVector{Int}, q_points :: AbstractVector{T}, sym_mat :: AbstractMatrix)

Get the correspondance $q' = S_\text{recip} q$ on the provided q grid. Always assume everything is in crystal coordinates.

Note that in reciprocal space (crystal coordinates) the symmetry operation is the inverse transpose.

\[S_\text{recip} = (S_\text{direct})^{-T}\]

The provided sym_mat is assumed to be in direct space.

This is needed for the correct application of the symmetries

source
AtomicSymmetries.get_minus_q!Function
get_minus_q!(minus_q_index :: AbstractVector{Int}, q_points :: AbstractMatrix{T}; buffer = default_buffer()) where T
get_minus_q!(minus_q_index :: AbstractVector{Int}, q_points :: AbstractMatrix{T}, reciprocal_lattice :: AbstractMatrix{T}; buffer = default_buffer()) where T

Identify for each q point what is the corresponding -q:

$\vec q \longrightarrow -\vec q + \vec G$

where $\vec G$ is a reciprocal vector. Since this is done in crystal coordinates$\vec G$ are all possible integers.

The reciprocal vectors is only needed if the q points are in cartesian coordinates.

Parameters

  • minus_q_index : The result vector (modified inplace)
  • q_points : The q points (in crystal coordinates if no reciprocal_lattice is provided, cartesian otherwise)
  • cell : The primitive cell (column-based). Only if q_points are in cartesian coordinates. [Optional]
  • reciprocal_lattice : The reciprocal lattice vectors (column-based). Only if q_points are in cartesian coordinates. [Optional]
  • buffer : The Bumper.jl buffer for caching memory allocations [Optional, keyword only]
source
AtomicSymmetries.check_symmetriesFunction
check_symmetries(q_symmetries :: SymmetriesQSpace{T}, n_atoms :: Int) :: Bool

Check if the q_symmetries has been correctly initialized in the primitive cell.

Essentially, this subroutine checks the atomic correspondance by symmetry and spots if there are atoms outside the primitive cell (whose index is above n_atoms).

Parameters

  • q_symmetries : The symmetries in q space
  • n_atoms : The number of atoms in the primitive cell

Returns

true if no contraddiction have been detected, false otherwise.

source

Enforcing symmetries

One of the most useful operation to do is enforce a specific matrix or vector in q-space to satisfy a given symmetry group.

This can be implemented by applying the complete irreducible representation of the symmetry group. Symmetrization of an ent \Phi is obtained as

$\Phi = \frac{1}{N}\sum_{i=1}^N S_i(\Phi)$

where $S_i$ is the symmetry operation. The two functions performing the symmetrization are symmetrize_matrix_q! and symmetrize_vector_q!. Also in this case, the dynamical matrix must be provided in crystalline coordinates.

To symmetrize vector and matrices already provided in cartesian coordinates, we must use the appropriate subroutines symmetrize_vector_cartesian_q! and symmetrize_matrix_cartesian_q!. These two subroutines correctly convert the vector/matrix in crystal coordinates before applying the symmetries, and then convert the symmetrized result back in cartesian space. They are the most used subroutines to perform symmetrization in q-space, the equivalent of symmetrize_vector! and symmetrize_fc! for real space.

The Hermitianity is not automatically imposed by the symmetrization procedure. This allows to symmetrize matrices that are not necessarily hermitian, for example, the cross correlation matrices between different quantities. Hermitianity and time-reversal symmetry can be imposed with the subroutine impose_hermitianity_q!, which enforces the condition. The time-reversal symmetry corresponds to the condition that the original matrix in real space is real-valued.

Here the complete API

AtomicSymmetries.symmetrize_vector_q!Function
symmetrize_vector_q!(target_gamma :: AbstractVector{T}, original_q :: AbstractArray{Complex{T}, 2}, symmetries :: Symmetries, irt_q :: Vector{Vector{Int}}; buffer = default_buffer() where T

Impose the symmetrization of a vector in q space. Since the symmetrization also imposes translational symmetries, the result is always a vector only at gamma.

The symmetrized vector is supposed to be a displacement (so no translations are applied)

NOTE: The provided vector must be in crystal coordinates To symmetrize a vector incartesian coordinates, see the routine symmetrize_vector_cartesian_q!.

Parameters

  • target_gamma : The n_at * n_dims output symmetrized vector at $\Gamma$
  • original_q : The original vector in q-space of size nat*n_dims, nq
  • symmetries : The symmetry group
  • irt_q : A vector (one for each symmetry) of the correspondances of q points. For each symmetry can be obtained from get_irt_q!
  • gamma_index : Specify which q vector is $\Gamma$. If not specified, it is assumed to be the first one
source
AtomicSymmetries.symmetrize_matrix_q!Function
symmetrize_matrix_q!(target_q :: AbstractArray{Complex{T}, 3}, original_q :: AbstractArray{Complex{T}, 3}, symmetries :: Symmetries, irt_q :: Vector{Vector{Int}}; buffer = default_buffer() where T
symmetrize_matrix_q!(matrix_q :: AbstractArray{Complex{T}, 3}, q_symmetries :: SymmetriesQSpace; buffer = default_buffer())  where T
symmetrize_matrix_q!(target_q :: AbstractArray{T, 3}, original_q :: AbstractArray{Complex{T}, 3}, q_symmetries :: SymmetriesQSpace; buffer = default_buffer())  where T

Impose the symmetrization of a dynamical matrix in q space. The matrix must be in crystal coordinates.

Parameters

  • target_q : The symmetrized matrix of size n_modes, n_modes, nq (modified in-place).
  • original_q : The original matrix in q-space of size n_modes, n_modes, nq. It could be the same as target_q
  • symmetries : The symmetry group
  • irt_q : A vector (one for each symmetry) of the correspondances of q points. For each symmetry can be obtained from get_irt_q!
  • unit_cell_translations :: Vector{Matrix{T}} : The translations of the unit cell to bring back the atoms in the primitive cell after the symmetry operation. Each vector elements corresponds to one symmetry operation, then the matrix is a ndims x natoms translation. This is usually the same as the content of symmetries.unit_cell_translations.
  • minus_q_index : A vector containing for each q the corresponding $\vec {q'} = -\vec q + \vec G$, where $\vec G$ is a generic reciprocal lattice vector.
  • q_points : The vector containing the actual q points
source
AtomicSymmetries.symmetrize_vector_cartesian_q!Function
symmetrize_vector_cartesian_q!(vector_q_cart:: AbstractArray{Complex{T}, 2}, cell :: Matrix{T}, symmetries :: SymmetriesQSpace; buffer = default_buffer()) where {T}

Perform the symmetrization of a vector (overwriting it) in cartesian coordinates. This is the go-to subroutine for performing symmetrization of vectors in q space.

Parameters

  • vector_q_cart : in-place symmetrize vector (q-space, cartesian coordinates)
  • cell : 3x3 matrix of the primitive cell (column-based)
  • symmetries : Symmetries in Q space
  • buffer : Optional, Bumper stack buffer (caching)
source
AtomicSymmetries.symmetrize_matrix_cartesian_q!Function
symmetrize_matrix_cartesian_q!(matrix_q :: AbstractArray{Complex{T}, 3}, cell :: Matrix{T}, q_symmetries :: SymmetriesQSpace; buffer=default_buffer()) where T

Enforce the symmetries on the provided matrix (q-space), modifying it in-place. The provided matrix must be in Cartesian Coordinates.

Parameters

  • matrix_q : The matrix to be symmetrized. Size (nmodes, nmodes, nq)
  • cell : The 3x3 primitive cell (column ordering)
  • q_symmetries : The symmetry group (q-space)
  • buffer : Optional, stack for Bumper to cache allocations.
source
AtomicSymmetries.impose_hermitianity_q!Function
impose_hermitianity_q!(matrix_q :: AbstractArray{Complex{T}, 3}, minus_q_index; buffer=default_buffer()) where T

Impose the hermitianity and time-reversal symmetry on the dynamical matrix in q space.

Parameters

  • matrix_q : The dynamical matrix in q space (modified inplace)
  • minus_q_index : A vector containing for each q the corresponding $\vec {q'} = -\vec q + \vec G$, where $\vec G$ is a generic reciprocal lattice vector.
source

Manipulating q points

The fourier transform depends on the knowledge of few vectors: q_points, itau, and R_lat (evenutally translations, for inverse fourier transform into a matrix).

All these properties can be evaluated from the core source. For example, to obtain the supercell to which the q points are commensurate, we can use the get_supercell method as

AtomicSymmetries.get_supercell!Function
get_supercell(q_points::AbstractMatrix{T}, cell :: AbstractMatrix{T}) :: Vector{Int}
get_supercell(q_points::AbstractMatrix{T}) :: Vector{Int}
get_supercell!(supercell::AbstractVector{I}, q_points::AbstractMatrix{T}, cell :: AbstractMatrix{T}) where {T, I<:Integer}
get_supercell!(supercell::AbstractVector{I}, q_points::AbstractMatrix{T}) where {T, I<:Integer}

Calculates the minimum supercell dimensions required to fold a set of commensurate wave vectors (q_points) back to the Gamma point (Γ) of the Brillouin zone.

The resulting supercell dimension $S_i$ for each spatial direction is determined by the reciprocal of the smallest non-zero q-point component in that direction. For commensurate grids, this is mathematically equivalent to:

\[S_i = \text{round} \left( \frac{1}{\min(|q_{i}|)} \right)\]

This function is primarily used when performing calculations in a real-space supercell that is commensurate with the input k-point (or q-point) grid.

Arguments

  • q_points: A 2D matrix where each column represents a q-point vector, and each row corresponds to a dimension (x, y, z).
  • supercell: An pre-allocated integer vector to store the result (used by the get_supercell! in-place version).
  • cell : The primitive cell. If not provided, the code assumes that q_points are in fractional coordinates.

Important Note on Coordinates

The q_points must be provided in crystal coordinates (fractional coordinates) if cell is not provided.

Example

# 3 dimensions, 2 q-points
q_points = [0.5 0.0;
            0.0 0.5;
            0.0 0.25]

# The supercell dimensions required are based on (1/0.5, 1/0.5, 1/0.25).
supercell = get_supercell(q_points)
# Result: [2, 2, 4]
source

Analogously, we can get the translations R_lat as

AtomicSymmetries.get_R_lat!Function
get_R_lat!(R_lat :: Matrix{T}, primitive_coords :: Matrix{T}, supercell_coords :: Matrix{T})

Get the R_lat parameter to perform the fourier transform.

Parameters

  • R_lat the result lattice vectors, modified inplace
  • primitive_coords : The coordinates in the primitive cell
  • supercell_coords : The coordinates in the supercell
  • itau : The correspondence for each atom in the supercell with the respective atom in the primitive cell
source