QE_utils

libra_py.QE_utils.get_value(params, key, default, typ)[source]

Function to extract parameter from the dictionary

Parameters
  • params (dict) – A dictionary containing important simulation parameters

  • key (string) – The name of the variable that we wish to extract from the params dictionary

  • default (various types) – The default value assigned to a dictionary key

  • typ (string) – The data type assigned to a value that is extracted from the dictionary

Returns

a value from the params dictionary that is of type typ

Return type

various types

libra_py.QE_utils.merge_orbitals(Ca, Cb)[source]

This function puts two matrices together into a single matrix

param[in] Ca Coefficient matrix corresponding to alpha orbitals of size N_pw x N_Mo param[in] Cb Coefficient matrix corresponding to beta orbitals of size N_pw x N_Mo

Returns: A single matrix of size N_pw x 2*N_Mo

libra_py.QE_utils.orthogonalize_orbitals(C)[source]

This function takes an input of orbitals (C), which may not be rigorously orthogonal, finds a suitable transformation (U) and converts them into rigorously orthogonal orbitals (C_tilda)

C_tilda = C * U, so if you want

C_tilda^+ * C_tilda = I, you’ll find that

U = S^{-1/2}, where S = C^+ * C

Parameters

C (CMATRIX(N_pw, N_mo)) – just alpha or beta orbitals

Returns

just alpha or beta orbitals, where

the overlap matrix constructed using this matrix is the identity matrix

Return type

CMATRIX(N_pw, N_mo)

libra_py.QE_utils.orthogonalize_orbitals2(Ca, Cb)[source]

Ca and Cb = N_pw x N_mo - represent the spin-components of the adiabatic states

This function takes an input of orbitals (C), which may not be rigorously orthogonal, finds a suitable transformation (U) and converts them into rigorously orthogonal orbitals (C_tilda)

For each channel:

C_tilda = C * U, so if you want

C_tilda^+ * C_tilda = I, you’ll find that

U = S^{-1/2}, where $S = Ca^+ * Ca + Cb^+ * Cb$

Parameters
  • Ca (CMATRIX(N_pw, N_mo)) – alpha-component of the adiabatic states

  • Cb (CMATRIX(N_pw, N_mo)) – beta-component of the adiabatic states

Returns

Two matricies where the overlap matrix

constructed using this matrix is the identity matrix

Return type

( CMATRIX(N_pw, N_mo) , CMATRIX(N_pw, N_mo) )

libra_py.QE_utils.post_process(coeff, ene, issoc)[source]

Post-processing of the data extracted from QE output files

Parameters
  • coeff (list of CMATRIX) – PW coefficients for orbitals, potentially spin-resolved

  • ene (list of CMATRIX) – energies of KS orbitals, potentially spin-resolved

  • issoc (int) –

    flag to indicate whether the orbitals are 2-component spinors (with SOC) or regular KS orbitals, one per spin channel

    • 0 : no SOC

    • 1 : yes SOC

Returns:

(list[0], list[1]), where :

No-SOC case: list[0] = list[1] SOC case: 2 lists, where list[0] = alpha components, list[1] = beta components

Notes

In SOC case (spinor):

coeff[0] - a N_pw x 2*N matrix of type: (psi_0^alp, psi_0^bet, … psi_{N-1}^alp, psi_{N-1}^bet)

where each psi is a colum of the PW coefficients for given KS orbital (spatial component for each spin)

ene[0] - a 2*N x 2*N matrix of energies coming in pairs: e_{2*i} = e_{2*i+1}, because these are the

energies of the same orbital, just its different spin components

We then split the coeff[0] matrix into a pair of N_pw x N matrices that represent alpha and beta spatial components of the wavefunction, separately

However, the number of <b>spin<>-orbitals will be twice that of the N, so we need to construct new matrices with spin-orbitals.

So that we have both psi_i = (psi_i_alp, psi_i_bet) and psi_{i+N} = (psi_i_bet, psi_i_alp) pairs of spin-orbitals (this is needed to represent the indistinguishable nature of electrons) i = 0,…N-1, where N - is the number of pairs of read spinors = N_adi_ks_orb

In non-SOC case (spin-polarized):

We directly get a pair of N_pw x N_mo_dia matrices that represent alpha and beta spatial components of the wavefunction

coeff[0] - a N_pw x N matrix of type: (psi_0^alp, … psi_{N-1}^alp) coeff[1] - a N_pw x N matrix of type: (psi_0^bet, … psi_{N-1}^bet)

where each psi is a colum of the PW coefficients for given KS orbital (spatial component for each spin)

ene[0] - a N x N matrix of alpha KS orbital energies ene[1] - a N x N matrix of beta KS orbital energies

Eventually:

“alpha-block” “beta-block”

C_adi[0] = (psi_0^alp,… psi_{N-1}^alp, psi_N^alp, … psi_{2N-1}^alp) alpha-components of spinors C_adi[1] = (psi_0^bet,… psi_{N-1}^bet, psi_N^bet, … psi_{2N-1}^bet) beta-components of spinors

same energies in SOC case or non-polarized non-SOC different energies in spin-polarized non-SOC

Also: psi_0^alp = psi_N^bet and psi_0^bet = psi_N^alp, and so on

E^alpha-block 0 |

E_adi = | | | 0 E^beta-block |

E^alpha-block = E^beta-block (SOC or non-polarized non-SOC) E^alpha-block != E^beta-block (spin-polarized non-SOC)

libra_py.QE_utils.split_orbitals_energies(C, E)[source]
In SOC, non-collinear case, the orbitals are 2-component spinors:
psi_i^alp | | E_i_alp |
psi_i = | |, so E = | |
psi_i^bet | | E_i_bet |

So, the wfc we read from the QE calculations, in this case is composed of such pairs, going in this order, so:

psi_i^alp, psi_i^bet, psi_{i+1}^alp, psi_{i+1}^bet, …

Thus, there are 2*N_mo_adi columns, so we need to extract spin-components into 2 matrices

param[in] C Coefficient matrix of size N_pw x 2*N_Mo param[in] E Eigenvalue matrix of size 2*N_mo x 2*N_Mo

Returns: Matricies for the alpha and beta components of the input matricies