7a_workflow_precompute_quantities.py — Precompute Phonon Quantities

This script covers the precomputation phase of the Disorder Linewidth pipeline (mirrors Notebooks 1-4). It must be run first; its HDF5 outputs are consumed by scripts 7b and 7c.

What it computes

  1. Band structure — phonon dispersion of reference crystal graphite along a Γ-A-L-M-Γ-K-H path; saved as dl_workflow/crystal_band_structure.png.

  2. Phonon mesh — frequencies and group velocities on a [128, 128, 32] Γ-centred BZ mesh; saved to dl_workflow/mesh_data.hdf5.

  3. Crystal VDOS and mean group speed — Lorentzian-broadened (half-width η = 0.6 cm⁻¹); saved to dl_workflow/crystal_vdos_group_vel.hdf5.

  4. Disordered VDOS — Lorentzian-broadened from pre-computed frequencies in 2_irg_t2/irg_t2_frequencies.hdf5; saved to dl_workflow/disordered_vdos.hdf5.

  5. Density-shifted crystal VDOS and speed — frequencies scaled by (ρ_dis/ρ_crys)^(1/3) to align with the disordered system; saved to dl_workflow/reduced_density_crystal_vdos_group_vel.hdf5.

Prerequisites: BNE + DL installation (see setup_dl.sh).

cd tutorials/disorder_linewidth
python 7a_workflow_precompute_quantities.py
  1import os
  2import sys
  3
  4import h5py
  5import numpy as np
  6import matplotlib
  7import matplotlib.pyplot as plt
  8import ase
  9from ase.io import read
 10
 11from tqdm import tqdm
 12
 13
 14from phonopy import Phonopy
 15from phonopy import file_IO as phonopy_file_IO
 16
 17from phonopy.interface.calculator import read_crystal_structure
 18from phonopy.phonon.band_structure import get_band_qpoints_and_path_connections
 19
 20
 21from smooth_disorder.structural import obtain_density, THzToCm, THz, Angstrom
 22from smooth_disorder.vis.interactive import *
 23
 24from smooth_disorder.disorder_linewidth import run_band_structure_manual
 25from smooth_disorder.disorder_linewidth import run_phonon_mesh, save_mesh_data_to_files
 26
 27from smooth_disorder.disorder_linewidth import lorentzian_numpy, flatten_arrays_freq_only
 28from smooth_disorder.disorder_linewidth import calculate_vdos_with_frequency
 29from smooth_disorder.disorder_linewidth import save_vdos_data_to_files
 30
 31from smooth_disorder.disorder_linewidth import flatten_arrays
 32from smooth_disorder.disorder_linewidth import calculate_vdos_and_average_speed_with_frequency
 33from smooth_disorder.disorder_linewidth import save_vdos_speed_data_to_files
 34
 35
 36
 37CRYSTAL_POSCAR   = "./1_graphite/POSCAR"
 38CRYSTAL_FC2      = "./1_graphite/fc2.hdf5"
 39SUPERCELL_MATRIX = np.diag([8, 8, 2])
 40MESH             = [128, 128, 32]
 41GAMMA_CENTER     = True
 42
 43WORK_DIR = "./dl_workflow"
 44os.makedirs(WORK_DIR, exist_ok=True)
 45
 46MESH_SAVE        = f"{WORK_DIR}/mesh_data"
 47CRYSTAL_VEL_SAVE      = f"{WORK_DIR}/crystal_vdos_group_vel"
 48SHIFTED_SAVE          = f"{WORK_DIR}/reduced_density_crystal_vdos_group_vel"
 49
 50
 51DISORDERED_POSCAR      = "./2_irg_t2/irg_t2_14009.vasp"
 52DISORDERED_FREQUENCIES = "./2_irg_t2/irg_t2_frequencies.hdf5"
 53DISORDERED_DIFFUSIVITY = "./2_irg_t2/diffusivity.hdf5"
 54
 55DISORDERED_VDOS_SAVE  = f"{WORK_DIR}/disordered_vdos"
 56
 57# Lorentzian half-width η for VDOS broadening [cm⁻¹].
 58# Controls spectral resolution — value used for graphite: 0.6 cm⁻¹.
 59GAMMA_BROADENING = 0.6
 60
 61
 62
 63################################
 64# BAND STRUCTURE VISUALIZATION #
 65################################
 66
 67# Special BZ points for hexagonal graphite — fractional reciprocal-lattice coordinates
 68atoms_ase = ase.io.read(CRYSTAL_POSCAR)
 69print(f"Special points in the BZ")
 70print(ase.dft.kpoints.get_special_points(atoms_ase.cell))
 71
 72# Preferred path chosen from the BZ
 73path = [[[0, 0, 0], [0. , 0. , 0.5], [0.5, 0. , 0.5], [0.5, 0. , 0. ],
 74         [0., 0., 0.], [0.33333333, 0.33333333, 0.], [0.33333333, 0.33333333, 0.5]]]
 75labels = ["$\\Gamma$", "A", "L", "M", "$\\Gamma$", "K", "H"]
 76
 77print(f"Running the band structure calculation")
 78frequencies, distances, qpoints = run_band_structure_manual(CRYSTAL_POSCAR, CRYSTAL_FC2, SUPERCELL_MATRIX, path, labels)
 79
 80num_paths = len(distances)
 81num_modes = frequencies[0].shape[1]
 82
 83
 84# visualization
 85plt.figure(figsize=(16, 8))
 86
 87for path in range(num_paths):
 88    for mode in range(num_modes):
 89        plt.plot(distances[path], frequencies[path][:, mode]*THzToCm, color=Colors[3])
 90
 91y_min, y_max = 0, 1600
 92plt.vlines(0.0, y_min, y_max, color="black", lw=1)
 93plt.text(0.0-0.003, -50, labels[0])
 94
 95for path in range(num_paths):
 96    plt.vlines(distances[path][-1], y_min, y_max, color="black", lw=1)
 97    plt.text(distances[path][-1]-0.003, -50, labels[path+1])
 98
 99plt.ylabel("Frequencies [cm-1]")
100plt.xlabel("Brillouin zone special points")
101
102plt.xlim([-0.01, np.max(distances)+0.01])
103plt.xticks([])
104plt.savefig(f"{WORK_DIR}/crystal_band_structure.png", dpi=300)
105
106
107################################################################
108# OBTAIN FREQUENCIES AND GROUP VELOCITIES IN REFERENCE CRYSTAL #
109################################################################
110
111
112print(f"Obtaining the crystal group velocities...")
113mesh_dict = run_phonon_mesh(CRYSTAL_POSCAR, CRYSTAL_FC2, SUPERCELL_MATRIX, MESH, GAMMA_CENTER)
114
115save_mesh_data_to_files(MESH_SAVE,
116                        mesh_dict['frequencies_cm'],
117                        mesh_dict['weights'],
118                        mesh_dict['qpoints'],
119                        mesh_dict['group_velocities_ms'])
120
121with h5py.File(f"{MESH_SAVE}.hdf5", "r") as f:
122    frequencies_cm      = np.asarray(f["frequencies_cm"])       # (N_qpts, N_bands) [cm⁻¹]
123    weights             = np.asarray(f["weights"])              # (N_qpts,)
124    qpoints             = np.asarray(f["qpoints"])              # (N_qpts, 3) fractional
125    group_velocities_ms = np.asarray(f["group_velocities_ms"])  # (N_qpts, N_bands, 3) [m/s]
126
127
128plt.figure(figsize=(16, 8))
129
130speed_2d = np.sqrt(
131    np.square(group_velocities_ms).sum(axis=2) / 3
132)
133
134plt.scatter(frequencies_cm, speed_2d, color=Colors[3], s=0.01)
135
136
137plt.xlabel("Frequency [cm^-1]")
138plt.ylabel("Group Velocity [m/s]")
139
140plt.title("Group Velocity of reference crystal")
141
142plt.savefig(f"{WORK_DIR}/crystal_group_velocities.png", dpi=300)
143
144
145#############################################
146# OBTAIN VDOS AND v(w) IN REFERENCE CRYSTAL #
147#############################################
148
149print(f"Obtaining the crystal VDOS")
150
151frequencies_flat, weights_flat, speed_flat, weights_sum = flatten_arrays(
152    frequencies_cm,
153    weights,
154    group_velocities_ms)
155
156vdos_crystal, speed_crystal, freq_crystal = calculate_vdos_and_average_speed_with_frequency(
157    frequencies_flat,
158    weights_flat,
159    speed_flat,
160    GAMMA_BROADENING,
161    CRYSTAL_POSCAR,
162    weights_sum
163)
164
165save_vdos_speed_data_to_files(CRYSTAL_VEL_SAVE, freq_crystal, vdos_crystal, speed_crystal)
166
167
168plt.figure(figsize=(16, 8))
169
170plt.plot(freq_crystal, vdos_crystal, color=Colors[3])
171
172plt.xlabel(r"Frequency [cm$^{-1}$]")
173plt.ylabel(r"VDOS [THz$^{-1}$ nm$^{-3}$]")
174
175plt.title("Vibrational Density of States of reference crystal")
176
177plt.savefig(f"{WORK_DIR}/crystal_vdos.png", dpi=300)
178
179
180
181plt.figure(figsize=(16, 8))
182
183speed_2d = np.sqrt(
184    np.square(group_velocities_ms).sum(axis=2) / 3
185)
186
187plt.scatter(frequencies_cm, speed_2d, color=Colors[0], s=0.01)
188
189# the average of the group velocities at a given frequency
190plt.plot(freq_crystal, speed_crystal, color=Colors[3])
191
192plt.xlabel("Frequency [cm^-1]")
193plt.ylabel("Group Velocity [m/s]")
194
195plt.title("Group Velocity of reference crystal")
196
197plt.savefig(f"{WORK_DIR}/crystal_group_velocities_vs_frequency.png", dpi=300)
198
199
200
201##############################################################
202# VISUALIZE FREQUENCIES AND DIFFUSIVITY IN DISORDERED SYSTEM #
203##############################################################
204
205
206with h5py.File(DISORDERED_FREQUENCIES, "r") as f:
207    print(f.keys())
208    frequencies = np.asarray(f['frequencies'])  # these are already saved in cm^-1
209    weights = np.asarray(f['weights'])
210
211print(f"Obtaining VDOS of the disordered system")
212frequencies_flat, weights_flat, weights_sum = flatten_arrays_freq_only(frequencies, weights)
213
214vdos_disordered, freq_disordered = calculate_vdos_with_frequency(
215    frequencies_flat,
216    weights_flat,
217    GAMMA_BROADENING,
218    DISORDERED_POSCAR,
219    weights_sum
220)
221
222save_vdos_data_to_files(DISORDERED_VDOS_SAVE, freq_disordered, vdos_disordered)
223
224
225
226
227plt.figure(figsize=(16, 8))
228
229plt.plot(freq_disordered, vdos_disordered, color=Colors[0])
230
231plt.xlabel("Frequency [cm$^{-1}$]")
232plt.ylabel("VDOS [THz$^{-1}$ nm$^{-3}$]")
233
234plt.title("Vibrational Density of States of the disordered system")
235
236plt.xticks(np.arange(0, 1800, 100))
237
238plt.savefig(f"{WORK_DIR}/disordered_system_vdos.png", dpi=300)
239
240
241
242plt.figure(figsize=(16, 8))
243
244plt.plot(freq_crystal, vdos_crystal, color=Colors[3], label="reference crystal")
245plt.plot(freq_disordered, vdos_disordered, color=Colors[0], label='irradiated graphite')
246
247plt.xlabel("Frequency [cm^-1]")
248plt.ylabel("VDOS [THz^-1 nm^-3]")
249
250plt.title("Vibrational Densities of States of reference crystal and the disordered system")
251
252plt.xticks(np.arange(0, 2000, 100))
253
254plt.legend(loc='upper left')
255
256plt.savefig(f"{WORK_DIR}/crystal_vs_disordered_system_vdos.png", dpi=300)
257
258
259
260
261
262# read in the diffusivity
263with h5py.File(DISORDERED_DIFFUSIVITY, "r") as f:
264    print(f.keys())
265    diffusivity_plot = np.asarray(f["diffusivity"])  # in m^2/s
266    frequencies_plot_diff = np.asarray(f["frequencies_plot"])  # in cm^-1
267
268
269
270
271plt.figure(figsize=(16, 8))
272
273plt.plot(frequencies_plot_diff, diffusivity_plot*1e6, color=Colors[0])
274
275plt.xlabel("Frequency [cm$^{-1}$]")
276plt.ylabel("Diffusivity [mm$^2$/s]")
277
278plt.title("Diffusivity of modes in the disordered system")
279
280plt.xticks(np.arange(0, 1800, 100))
281
282plt.savefig(f"{WORK_DIR}/disordered_system_diffusivity.png", dpi=300)
283
284
285
286################################################################
287# INFLUENCE OF DENSITY ON FREQUENCY SHIFTS IN THE CRYSTAL VDOS #
288################################################################
289
290
291density_crystal = obtain_density(read(CRYSTAL_POSCAR))
292density_disordered = obtain_density(read(DISORDERED_POSCAR))
293
294density_factor = np.power(density_disordered/density_crystal, 1/3)
295print(f"  ρ_crystal    = {density_crystal:.4f} g/cm³")
296print(f"  ρ_disordered = {density_disordered:.4f} g/cm³")
297print(f"  Density factor = (ρ_dis/ρ_crys)^(1/3) = {density_factor:.4f}")
298
299
300
301# load the mesh data
302with h5py.File(f"{MESH_SAVE}.hdf5", "r") as f:
303    frequencies_cm      = np.asarray(f["frequencies_cm"])       # (N_qpts, N_bands) [cm⁻¹]
304    weights             = np.asarray(f["weights"])              # (N_qpts,)
305    qpoints             = np.asarray(f["qpoints"])              # (N_qpts, 3) fractional
306    group_velocities_ms = np.asarray(f["group_velocities_ms"])  # (N_qpts, N_bands, 3) [m/s]
307
308
309print(f"Applying frequency shifts and recalculating crystal VDOS")
310
311# flatten the arrays for easier VDOS calculation
312frequencies_flat, weights_flat, speed_flat, weights_sum = flatten_arrays(
313    frequencies_cm,
314    weights,
315    group_velocities_ms)
316
317# we shift the frequencies by the multiplicative factor
318shifted_frequencies_flat = frequencies_flat * density_factor
319
320shifted_vdos_crystal, shifted_speed_crystal, shifted_freq_crystal = calculate_vdos_and_average_speed_with_frequency(
321    shifted_frequencies_flat,
322    weights_flat,
323    speed_flat,
324    GAMMA_BROADENING,
325    CRYSTAL_POSCAR,
326    weights_sum
327)
328
329save_vdos_speed_data_to_files(SHIFTED_SAVE, shifted_freq_crystal, shifted_vdos_crystal, shifted_speed_crystal)
330
331
332
333plt.figure(figsize=(16, 8))
334
335plt.plot(shifted_freq_crystal, shifted_vdos_crystal, color=Colors[3])
336
337plt.xlabel("Frequency [cm^-1]")
338plt.ylabel("VDOS [THz^-1 nm^-3]")
339
340plt.title("shifted Vibrational Density of States of the reference crystal")
341
342plt.savefig(f"{WORK_DIR}/crystal_shifted_vdos.png", dpi=300)
343
344
345plt.figure(figsize=(16, 8))
346
347plt.scatter(shifted_frequencies_flat, speed_flat, color=Colors[0], s=0.01)
348plt.plot(shifted_freq_crystal, shifted_speed_crystal, color=Colors[3])
349
350plt.xlabel("Frequency [cm^-1]")
351plt.ylabel("Group Velocity [m/s]")
352
353plt.title("Group Velocity of the reference crystal with shifted frequencies")
354
355plt.savefig(f"{WORK_DIR}/crystal_shifted_group_velocities.png", dpi=300)
356