freepaths 2.4.2__tar.gz → 2.4.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {freepaths-2.4.2 → freepaths-2.4.3}/PKG-INFO +1 -1
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/__main__.py +1 -1
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/data.py +7 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/output_plots.py +76 -32
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths.egg-info/PKG-INFO +1 -1
- {freepaths-2.4.2 → freepaths-2.4.3}/README.md +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/animation.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/config.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/default_config.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/electron.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/flight.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/interface_smmm.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/main_mfp_sampling.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/main_tracing.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/maps.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/materials.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/move.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/options.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/output_electron_plots.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/output_info.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/output_structure.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/particle.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/phonon.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/post_computations.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/progress.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/run_particle.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/scatterers.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/scattering.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/scattering_interfaces.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/scattering_primitives.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/scattering_semicircle.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/scattering_types.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths/sources.py +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths.egg-info/SOURCES.txt +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths.egg-info/dependency_links.txt +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths.egg-info/entry_points.txt +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths.egg-info/requires.txt +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/freepaths.egg-info/top_level.txt +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/pyproject.toml +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/setup.cfg +0 -0
- {freepaths-2.4.2 → freepaths-2.4.3}/setup.py +0 -0
|
@@ -74,6 +74,10 @@ class GeneralData(Data):
|
|
|
74
74
|
# the two channels of the total rate v/MFP resolved as a function of frequency:
|
|
75
75
|
self.internal_scattering_rates = []
|
|
76
76
|
self.boundary_scattering_rates = []
|
|
77
|
+
# Per-phonon dispersion branch index (0=LA, 1=TA1, 2=TA2, ...). In MFP-sampling
|
|
78
|
+
# mode each phonon keeps its launch branch (no rethermalization), so this lets the
|
|
79
|
+
# scattering-rate spectra be resolved per branch. Row-aligned with the arrays above.
|
|
80
|
+
self.branches = []
|
|
77
81
|
def save_particle_data(self, pt, mode=None):
|
|
78
82
|
"""Add information about the particle to the dataset"""
|
|
79
83
|
from freepaths.options import SimulationMode
|
|
@@ -82,6 +86,7 @@ class GeneralData(Data):
|
|
|
82
86
|
else:
|
|
83
87
|
self.final_frequencies.append(pt.f)
|
|
84
88
|
self.group_velocities.append(pt.speed)
|
|
89
|
+
self.branches.append(pt.branch_number)
|
|
85
90
|
|
|
86
91
|
def save_flight_data(self, flight, mode=None):
|
|
87
92
|
"""Add information about the particle flight to the dataset"""
|
|
@@ -129,6 +134,7 @@ class GeneralData(Data):
|
|
|
129
134
|
np.savetxt("Data/All thermal conductivities.csv", self.thermal_conductivity, fmt='%2.4e', header="K [W/mK]", encoding='utf-8')
|
|
130
135
|
np.savetxt("Data/All internal scattering rates.csv", self.internal_scattering_rates, fmt='%2.4e', header="1/tau_internal [1/s]", encoding='utf-8')
|
|
131
136
|
np.savetxt("Data/All boundary scattering rates.csv", self.boundary_scattering_rates, fmt='%2.4e', header="1/tau_boundary [1/s]", encoding='utf-8')
|
|
137
|
+
np.savetxt("Data/All branches.csv", self.branches, fmt='%d', header="Branch index (0=LA, 1=TA1, 2=TA2)", encoding='utf-8')
|
|
132
138
|
def dump_data(self):
|
|
133
139
|
"""Return data of a process in the form of a dictionary to be attached to the global data"""
|
|
134
140
|
return {
|
|
@@ -146,6 +152,7 @@ class GeneralData(Data):
|
|
|
146
152
|
'thermal_conductivity': self.thermal_conductivity,
|
|
147
153
|
'internal_scattering_rates': self.internal_scattering_rates,
|
|
148
154
|
'boundary_scattering_rates': self.boundary_scattering_rates,
|
|
155
|
+
'branches': self.branches,
|
|
149
156
|
'initial_energies': self.initial_energies,
|
|
150
157
|
}
|
|
151
158
|
|
|
@@ -266,62 +266,106 @@ def plot_velocity_distribution():
|
|
|
266
266
|
|
|
267
267
|
|
|
268
268
|
def plot_scattering_rate_vs_frequency():
|
|
269
|
-
"""Plot phonon scattering rate (1/τ = v/MFP) vs frequency, resolved
|
|
270
|
-
|
|
271
|
-
|
|
269
|
+
"""Plot phonon scattering rate (1/τ = v/MFP) vs frequency, resolved per dispersion
|
|
270
|
+
branch (color + marker shape: LA / TA1 / TA2) and per channel (marker fill:
|
|
271
|
+
filled = Total, open = Boundary, small dot = Internal), with the theoretical
|
|
272
|
+
internal rate overlaid. MFP-sampling mode."""
|
|
273
|
+
from matplotlib.lines import Line2D
|
|
274
|
+
|
|
272
275
|
mfps = np.loadtxt("Data/All mean free paths.csv")
|
|
273
276
|
frequencies = np.loadtxt("Data/All final frequencies.csv")
|
|
274
277
|
speeds = np.loadtxt("Data/All group velocities.csv")
|
|
275
278
|
mask = mfps > 0
|
|
276
279
|
scattering_rates = speeds[mask] / mfps[mask]
|
|
280
|
+
f_masked = frequencies[mask]
|
|
277
281
|
|
|
278
|
-
# Per-channel MC rates written by GeneralData in
|
|
279
|
-
# boundary ≈ total). Optional so the plot still
|
|
280
|
-
|
|
282
|
+
# Per-channel MC rates and per-phonon branch index written by GeneralData in
|
|
283
|
+
# MFP-sampling mode (internal + boundary ≈ total). Optional so the plot still
|
|
284
|
+
# works on older result folders:
|
|
285
|
+
internal_rates = boundary_rates = branches = None
|
|
281
286
|
try:
|
|
282
287
|
internal_rates = np.loadtxt("Data/All internal scattering rates.csv")
|
|
283
288
|
boundary_rates = np.loadtxt("Data/All boundary scattering rates.csv")
|
|
284
289
|
except OSError:
|
|
285
290
|
pass
|
|
291
|
+
try:
|
|
292
|
+
branches = np.atleast_1d(np.loadtxt("Data/All branches.csv")).astype(int)
|
|
293
|
+
except OSError:
|
|
294
|
+
pass
|
|
286
295
|
|
|
287
296
|
# Theoretical internal scattering rate from material model:
|
|
288
297
|
material = get_media_class(cf.media)(cf.temp)
|
|
289
|
-
f_range = np.linspace(
|
|
290
|
-
|
|
291
|
-
tau_internal = np.array([material.phonon_relaxation_time(w) for w in omega_range])
|
|
292
|
-
|
|
298
|
+
f_range = np.linspace(f_masked.min(), f_masked.max(), 500)
|
|
299
|
+
tau_internal = np.array([material.phonon_relaxation_time(w) for w in 2 * np.pi * f_range])
|
|
293
300
|
step_rate_ns = 1e-9 / cf.timestep # 1/TIMESTEP in ns⁻¹
|
|
294
301
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
np.savetxt("Data/Distribution of scattering rates.csv", spectra,
|
|
302
|
-
fmt='%2.4e', delimiter=',',
|
|
303
|
-
header="f [Hz], Total (MC) [1/s], Internal (MC) [1/s], Boundary (MC) [1/s]",
|
|
304
|
-
encoding='utf-8')
|
|
302
|
+
branch_names = material.dispersion_branch_names
|
|
303
|
+
branch_colors = ['royalblue', '#5ec962', 'crimson', 'darkorange'] # one per branch
|
|
304
|
+
# Channel -> marker shape (+ a slightly different alpha to help separate overlaps):
|
|
305
|
+
channel_names = ['Total', 'Boundary', 'Internal']
|
|
306
|
+
channel_markers = ['o', 's', '^']
|
|
307
|
+
channel_alphas = [0.9, 0.6, 0.5]
|
|
305
308
|
|
|
306
309
|
fig, ax = plt.subplots()
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
310
|
+
have_channels = internal_rates is not None and boundary_rates is not None
|
|
311
|
+
|
|
312
|
+
if branches is not None and have_channels:
|
|
313
|
+
# Branch-resolved: branch -> color, channel -> marker shape + alpha.
|
|
314
|
+
br = branches[mask]
|
|
315
|
+
intr, bnd = internal_rates[mask], boundary_rates[mask]
|
|
316
|
+
present = [b for b in range(len(branch_names)) if np.any(br == b)]
|
|
317
|
+
for b in present:
|
|
318
|
+
sel = br == b
|
|
319
|
+
color = branch_colors[b % 4]
|
|
320
|
+
fx = f_masked[sel] * 1e-12
|
|
321
|
+
channel_data = [scattering_rates[sel], bnd[sel], intr[sel]]
|
|
322
|
+
for cdata, marker, alpha in zip(channel_data, channel_markers, channel_alphas):
|
|
323
|
+
ax.scatter(fx, cdata * 1e-9, s=8, marker=marker, color=color,
|
|
324
|
+
alpha=alpha, linewidths=0)
|
|
325
|
+
|
|
326
|
+
# Two proxy legends: branch (color), channel (marker shape):
|
|
327
|
+
branch_handles = [Line2D([], [], linestyle='None', marker='o', markersize=4,
|
|
328
|
+
markerfacecolor=branch_colors[b % 4],
|
|
329
|
+
markeredgecolor=branch_colors[b % 4], label=branch_names[b]) for b in present]
|
|
330
|
+
branch_handles.append(Line2D([], [], color='gray', linestyle='--', label='Internal (Theory)'))
|
|
331
|
+
channel_handles = [Line2D([], [], linestyle='None', marker=m, markersize=4,
|
|
332
|
+
markerfacecolor='gray', markeredgecolor='gray', label=n)
|
|
333
|
+
for m, n in zip(channel_markers, channel_names)]
|
|
334
|
+
# Two horizontal legends side by side above the axes (branch on the left,
|
|
335
|
+
# channel on the right), clear of the data:
|
|
336
|
+
leg1 = ax.legend(handles=branch_handles, loc='lower left', bbox_to_anchor=(0, 1.02),
|
|
337
|
+
ncol=len(branch_handles), fontsize=5.5, title='Branch', title_fontsize=6,
|
|
338
|
+
columnspacing=0.8, handletextpad=0.3)
|
|
339
|
+
ax.add_artist(leg1)
|
|
340
|
+
ax.legend(handles=channel_handles, loc='lower right', bbox_to_anchor=(1, 1.02),
|
|
341
|
+
ncol=len(channel_handles), fontsize=5.5, title='Channel', title_fontsize=6,
|
|
342
|
+
columnspacing=0.8, handletextpad=0.3)
|
|
343
|
+
|
|
344
|
+
# Consolidated CSV in long format, sorted by (branch, frequency):
|
|
345
|
+
order = np.lexsort((f_masked, br))
|
|
346
|
+
legend = ", ".join(f"{i}={name}" for i, name in enumerate(branch_names))
|
|
347
|
+
spectra = np.column_stack((br, f_masked, scattering_rates, intr, bnd))[order]
|
|
348
|
+
np.savetxt("Data/Distribution of scattering rates.csv", spectra,
|
|
349
|
+
fmt=['%d', '%2.4e', '%2.4e', '%2.4e', '%2.4e'], delimiter=',',
|
|
350
|
+
header=f"branch ({legend}), f [Hz], Total (MC) [1/s], "
|
|
351
|
+
"Internal (MC) [1/s], Boundary (MC) [1/s]", encoding='utf-8')
|
|
352
|
+
else:
|
|
353
|
+
# Fallback for older result folders without branch/channel data: total only.
|
|
354
|
+
ax.plot(f_masked * 1e-12, scattering_rates * 1e-9, '.', markersize=2, c='black', label='Total (MC)')
|
|
355
|
+
ax.legend(fontsize=7)
|
|
356
|
+
order = np.argsort(f_masked)
|
|
357
|
+
np.savetxt("Data/Distribution of scattering rates.csv",
|
|
358
|
+
np.column_stack((f_masked, scattering_rates))[order],
|
|
359
|
+
fmt='%2.4e', delimiter=',', header="f [Hz], Total (MC) [1/s]", encoding='utf-8')
|
|
360
|
+
|
|
361
|
+
ax.plot(f_range * 1e-12, 1e-9 / tau_internal, '--', linewidth=0.8, c='gray')
|
|
312
362
|
ax.set_xlabel('Frequency (THz)')
|
|
313
363
|
ax.set_ylabel(r'Scattering rate (ns$^{-1}$)')
|
|
314
|
-
ax.legend()
|
|
315
364
|
ax.text(0.98, 0.04, f'Step rate = {step_rate_ns:.1f} ns$^{{-1}}$',
|
|
316
|
-
transform=ax.transAxes, ha='right', va='bottom',
|
|
317
|
-
fontsize=7, color='gray')
|
|
365
|
+
transform=ax.transAxes, ha='right', va='bottom', fontsize=7, color='gray')
|
|
318
366
|
fig.savefig('Distribution of phonon scattering rates.pdf', format='pdf', bbox_inches="tight")
|
|
319
367
|
plt.close(fig)
|
|
320
368
|
|
|
321
|
-
mc_data = np.vstack((frequencies[mask] * 1e-12, scattering_rates * 1e-9)).T
|
|
322
|
-
np.savetxt('Data/Distribution of phonon scattering rates.csv', mc_data, fmt='%1.3e', delimiter=",",
|
|
323
|
-
header="Frequency (THz),MC total scattering rate (1/ns)")
|
|
324
|
-
|
|
325
369
|
|
|
326
370
|
def plot_energy_distribution():
|
|
327
371
|
"""Plot distribution of energy"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|