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