3a_tensor_conductivity_save.py — Per-q Conductivity Tensor

Computes the Allen-Feldman conductivity tensor contribution for a single irreducible q-point iq and a block of mode indices [num_start, num_stop). Saves the result as a partial HDF5 file postprocessed by 3b_tensor_conductivity_save_process.py.

This script is not run directly; it is dispatched in a loop by 3c_launch_serial.py, which iterates over all q-points and mode batches.

# Called internally by 3c_launch_serial.py:
python 3a_tensor_conductivity_save.py <iq> <num_start> <num_stop> <gamma_min_plateau_cmm1>
  1# import needed libraries
  2import numpy as np
  3import os, sys
  4import h5py
  5from typing import List
  6
  7# CONSTANTS
  8rY_TO_CMM1 = 109737.315701113
  9hARTREE_SI = 4.35974394E-18
 10rYDBERG_SI = hARTREE_SI / 2.0
 11H_PLANCK_SI = 6.62606896E-34
 12ryau_sec = H_PLANCK_SI / rYDBERG_SI
 13k_BOLTZMANN_SI = 1.3806504E-23  # J K^-1
 14aU_SEC = H_PLANCK_SI / (2. * np.pi) / hARTREE_SI
 15aU_TERAHERTZ = aU_SEC * 1.0E+12
 16rY_TO_THZ = 1.0 / aU_TERAHERTZ / (4 * np.pi)
 17k_BOLTZMANN_RY = k_BOLTZMANN_SI / rYDBERG_SI
 18BOHR_TO_M = 0.52917720859E-10
 19ryvel_si = BOHR_TO_M / ryau_sec
 20SpeedOfLight = 299792458  # [m/s]
 21THzToCm = 1.0e12 / (SpeedOfLight * 100)  # [cm^-1] 33.356410
 22Angstrom = 1.0e-10  # [m]
 23THz = 1.0e12  # [/s]
 24tpi = 2.0 * np.pi
 25
 26if len(sys.argv) > 1:
 27    iq, num_start, num_stop, gamma_min_plateau_cmm1 = (int(sys.argv[1]), int(sys.argv[2]),
 28                                                        int(sys.argv[3]), float(sys.argv[4]))
 29else:
 30    print('error: iq, num_start, num_stop, gamma_min_plateau_cmm1 not given')
 31    exit()
 32
 33temperature_list = np.arange(50, 2001, 50).tolist()
 34n_temp = len(temperature_list)
 35
 36gamma_min_plateau_Ry = gamma_min_plateau_cmm1 / rY_TO_CMM1
 37sigma_Gauss_Ry = np.sqrt(np.pi / 2.0) * gamma_min_plateau_Ry
 38
 39
 40# -------------------------------------------------------------
 41# define function for calculating the conductivity
 42def is_acoustic_mode_at_Gamma(iq, im):
 43    res = False
 44    if (iq == 0 and im < 3):
 45        res = True
 46    return res
 47
 48
 49def conductivity_q(iq: int = iq,
 50                   num_start: int = num_start,
 51                   num_stop: int = num_stop,
 52                   sigma_Gauss: float = sigma_Gauss_Ry,
 53                   temp_list: List = temperature_list):
 54    """
 55    Saves and returns specific heat, Allen conductivity and diffusivity, weight, temperatures and q-point.
 56    Quantities are resolved w.r.t. temperature and mode.
 57
 58    :param iq: q-point for calculation
 59    :param num_start: mode to start - used for parallelisation
 60    :param num_stop: mode to stop (not inclusive) - used for parallelisation
 61    :param sigma_Gauss: sigma which broadens the delta function into a Gaussian [Rydberg]
 62    :param temp_list: list of temperatures for which to calculate conductivities
 63
 64    :return: specific_heat_q,             shape: (num_stop-num_start, n_temp)
 65             thermal_conductivity_Allen_q, shape: (num_stop-num_start, n_temp, 3, 3)
 66             diffusivity_Allen_q,          shape: (num_stop-num_start, 3, 3)
 67             weight,
 68             np.asarray(temp_list),        shape: (n_temp,)
 69             iq
 70    """
 71    smearing = sigma_Gauss * rY_TO_CMM1 / np.sqrt(np.pi / 2.0)  # value of the eta parameter used here
 72
 73    # read frequencies and velocities
 74    filename_vel = './velocity_operators/save_%d.hdf5' % (iq)
 75    f_vel = h5py.File(filename_vel, 'r')
 76
 77    # read velocity operator in phonopy format and convert to QE atomic units
 78    array_V_operator = np.asarray(f_vel['velocity_operator'][:]) * (THz * Angstrom / (2.0 * np.pi * ryvel_si))
 79    array_frequency = np.asarray(f_vel['frequency'])
 80    weight = int(np.copy(f_vel['weight']))
 81
 82    # read frequencies
 83    num_modes = len(array_frequency)
 84    n_temp = len(temp_list)
 85
 86    # setting up arrays for thermal conductivity dataset
 87    array_modes = num_stop - num_start
 88    specific_heat_q = np.zeros((array_modes, n_temp))  # after conversion should be in SI units
 89
 90    thermal_conductivity_Allen_q = np.zeros((array_modes, n_temp, 3, 3))
 91    diffusivity_Allen_q = np.zeros([array_modes, 3, 3])
 92
 93    conv_diffusivity = ((tpi * ryvel_si) ** 2) * ryau_sec / tpi
 94    conv_spec_heat = (1.0 / k_BOLTZMANN_SI) * (rYDBERG_SI) ** 2
 95
 96    # -----------------
 97    # MAIN FOR-LOOP
 98    # -----------------
 99
100    for id_temp in range(0, n_temp):
101        temperature = temp_list[id_temp]
102        tempm1 = 1. / (temperature * k_BOLTZMANN_RY)
103
104        frequencies_Ry = (array_frequency * THzToCm) / rY_TO_CMM1
105        bose_all = 1.0 / (np.exp(frequencies_Ry * tempm1) - 1.0)
106        f_bose_all = bose_all * (bose_all + 1.0)
107        spec_heat_all = (1.0 / (temperature ** 2)) * np.square(frequencies_Ry) * f_bose_all
108
109        specific_heat_q[:, id_temp] = spec_heat_all[num_start:num_stop]
110
111        for im1 in range(num_start, num_stop):  # loop maintained so the memory requirements for large models are not huge
112
113            if is_acoustic_mode_at_Gamma(iq, im1):
114                continue
115
116            omega_1_Ry = frequencies_Ry[im1]
117            spec_heat_s1 = spec_heat_all[im1]
118
119            # vectorisation over second mode
120            local_frequencies = frequencies_Ry
121            local_spec_heat = spec_heat_all
122            n_skip = 3 if iq == 0 else 0  # used for skipping zero modes
123            local_velocity_operator = array_V_operator[im1]
124
125            # distributions
126            Gaussian = (1.0 / (np.sqrt(2.0 * np.pi) * sigma_Gauss)) * np.exp(
127                -0.5 * ((local_frequencies - omega_1_Ry) / sigma_Gauss) ** 2)
128
129            # calculate v_alpha v_beta tensor
130            local_velocity_tensor = np.zeros((3, 3, len(local_velocity_operator)))
131            for alpha in range(3):
132                for beta in range(3):
133                    local_velocity_tensor[alpha, beta, :] = (local_velocity_operator[:,
134                                                            alpha] * local_velocity_operator.conj()[:, beta]).real
135
136            # prefactors
137            prefactor_conductivity_tensor = (((omega_1_Ry + local_frequencies) / 4.0) *
138                                      ((spec_heat_s1 / omega_1_Ry) + (local_spec_heat / local_frequencies)) *
139                                      np.pi * local_velocity_tensor)
140
141            prefactor_diffusivity_tensor = (
142                    ((omega_1_Ry + local_frequencies) / (2.0 * (spec_heat_s1 + local_spec_heat))) *
143                    ((spec_heat_s1 / omega_1_Ry) + (local_spec_heat / local_frequencies)) *
144                    local_velocity_tensor *
145                    np.pi)
146
147            thermal_conductivity_Allen_q[im1 - num_start, id_temp, :, :] = (prefactor_conductivity_tensor * Gaussian)[:, :, n_skip:].sum(axis=2)
148
149            # diffusivity is temperature-independent; compute once at the last temperature step
150            if id_temp == n_temp - 1:
151                diffusivity_Allen_q[im1 - num_start] = (prefactor_diffusivity_tensor * Gaussian)[:, :, n_skip:].sum(axis=2)
152
153    result = (specific_heat_q * conv_spec_heat,
154             thermal_conductivity_Allen_q * conv_spec_heat * conv_diffusivity,
155             diffusivity_Allen_q * conv_diffusivity,
156             weight,
157             np.asarray(temp_list),
158             iq)
159
160    os.makedirs('data_save/interpolation_conductivity_dataset', exist_ok=True)
161    np.save(
162        f'./data_save/interpolation_conductivity_dataset/results_iq_{iq}_start_{num_start}_stop_{num_stop}_gamma_{int(np.round(smearing * 1000))}.npy',
163        np.array(result, dtype=object))
164
165    return result
166
167result = conductivity_q()