freepaths 2.3.2__tar.gz → 2.3.4__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.3.2 → freepaths-2.3.4}/PKG-INFO +1 -1
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/__main__.py +5 -5
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/config.py +7 -1
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/data.py +35 -48
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/default_config.py +4 -1
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/electron.py +3 -5
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/flight.py +0 -26
- freepaths-2.3.4/freepaths/main_mfp_sampling.py +231 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/main_tracing.py +52 -32
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/maps.py +10 -45
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/materials.py +73 -2
- freepaths-2.3.4/freepaths/options.py +10 -0
- freepaths-2.3.4/freepaths/output_electron_plots.py +239 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/output_info.py +41 -12
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/output_plots.py +116 -558
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/phonon.py +1 -1
- freepaths-2.3.4/freepaths/post_computations.py +199 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/run_particle.py +3 -2
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/scatterers.py +0 -16
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/scattering_interfaces.py +1 -1
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/scattering_primitives.py +1 -1
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths.egg-info/PKG-INFO +1 -1
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths.egg-info/SOURCES.txt +2 -1
- freepaths-2.3.2/freepaths/main_mfp_sampling.py +0 -135
- freepaths-2.3.2/freepaths/particle_types.py +0 -5
- freepaths-2.3.2/freepaths/post_computations.py +0 -177
- {freepaths-2.3.2 → freepaths-2.3.4}/README.md +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/animation.py +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/interface_smmm.py +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/move.py +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/output_structure.py +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/particle.py +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/progress.py +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/scattering.py +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/scattering_semicircle.py +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/scattering_types.py +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths/sources.py +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths.egg-info/dependency_links.txt +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths.egg-info/entry_points.txt +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths.egg-info/requires.txt +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/freepaths.egg-info/top_level.txt +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/pyproject.toml +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/setup.cfg +0 -0
- {freepaths-2.3.2 → freepaths-2.3.4}/setup.py +0 -0
|
@@ -5,9 +5,9 @@ import argparse
|
|
|
5
5
|
import colorama
|
|
6
6
|
from colorama import Fore, Style
|
|
7
7
|
|
|
8
|
-
from freepaths.
|
|
8
|
+
from freepaths.options import SimulationMode
|
|
9
9
|
|
|
10
|
-
__version__ = "2.3.
|
|
10
|
+
__version__ = "2.3.4"
|
|
11
11
|
|
|
12
12
|
colorama.init()
|
|
13
13
|
|
|
@@ -45,15 +45,15 @@ def run():
|
|
|
45
45
|
try:
|
|
46
46
|
if args.sampling:
|
|
47
47
|
import freepaths.main_mfp_sampling
|
|
48
|
-
freepaths.main_mfp_sampling.main(args.input_file,
|
|
48
|
+
freepaths.main_mfp_sampling.main(args.input_file, SimulationMode.PHONON_MFP_SAMPLING)
|
|
49
49
|
|
|
50
50
|
elif args.electron:
|
|
51
51
|
import freepaths.main_tracing
|
|
52
|
-
freepaths.main_tracing.main(args.input_file,
|
|
52
|
+
freepaths.main_tracing.main(args.input_file, SimulationMode.ELECTRON)
|
|
53
53
|
|
|
54
54
|
else:
|
|
55
55
|
import freepaths.main_tracing
|
|
56
|
-
freepaths.main_tracing.main(args.input_file,
|
|
56
|
+
freepaths.main_tracing.main(args.input_file, SimulationMode.PHONON_TRACING)
|
|
57
57
|
|
|
58
58
|
except KeyboardInterrupt:
|
|
59
59
|
print(f"\n{Fore.RED}Simulation interrupted by user.{Style.RESET_ALL}")
|
|
@@ -3,6 +3,7 @@ Module that reads the user input file, provides default values,
|
|
|
3
3
|
checks the validity of the parameters and converts the variables into enums
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
import os
|
|
6
7
|
import sys
|
|
7
8
|
import argparse
|
|
8
9
|
import logging
|
|
@@ -32,8 +33,11 @@ args = parser.parse_args()
|
|
|
32
33
|
|
|
33
34
|
# If a file is provided, overwrite the default values:
|
|
34
35
|
if args.input_file:
|
|
36
|
+
input_path = args.input_file
|
|
37
|
+
if not os.path.isfile(input_path) and not input_path.endswith('.py') and os.path.isfile(input_path + '.py'):
|
|
38
|
+
input_path = input_path + '.py'
|
|
35
39
|
try:
|
|
36
|
-
exec(open(
|
|
40
|
+
exec(open(input_path, encoding='utf-8').read(), globals())
|
|
37
41
|
except FileNotFoundError:
|
|
38
42
|
logging.error("Input file does not exist. Check if you are in the right folder and the file name is correct.")
|
|
39
43
|
sys.exit()
|
|
@@ -69,6 +73,8 @@ class Config:
|
|
|
69
73
|
self.electron_mfp = ELECTRON_MFP
|
|
70
74
|
self.mean_mapping_constant = MEAN_MAPPING_CONSTANT
|
|
71
75
|
self.is_carrier_electron = IS_CARRIER_ELECTRON
|
|
76
|
+
self.fermi_level_lower_bound = FERMI_LEVEL_LOWER_BOUND
|
|
77
|
+
self.fermi_level_upper_bound = FERMI_LEVEL_UPPER_BOUND
|
|
72
78
|
|
|
73
79
|
# Animation:
|
|
74
80
|
self.output_path_animation = OUTPUT_PATH_ANIMATION
|
|
@@ -66,59 +66,53 @@ class GeneralData(Data):
|
|
|
66
66
|
self.travel_times = []
|
|
67
67
|
self.mean_free_paths = []
|
|
68
68
|
self.thermal_conductivity = []
|
|
69
|
-
|
|
70
|
-
self.interfaces_transmission_factor = []
|
|
71
|
-
self.interfaces_wavelength = []
|
|
72
|
-
self.interfaces_frequency = []
|
|
73
|
-
self.interfaces_mode = []
|
|
74
|
-
|
|
75
|
-
def save_particle_data(self, pt):
|
|
69
|
+
def save_particle_data(self, pt, mode=None):
|
|
76
70
|
"""Add information about the particle to the dataset"""
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
71
|
+
from freepaths.options import SimulationMode
|
|
72
|
+
if mode is SimulationMode.ELECTRON:
|
|
73
|
+
self.initial_energies.append(pt.energy)
|
|
74
|
+
else:
|
|
75
|
+
self.frequencies.append(pt.f)
|
|
76
|
+
self.group_velocities.append(pt.speed)
|
|
77
|
+
|
|
78
|
+
def save_flight_data(self, flight, mode=None):
|
|
82
79
|
"""Add information about the particle flight to the dataset"""
|
|
80
|
+
from freepaths.options import SimulationMode
|
|
83
81
|
if not cf.low_memory_usage:
|
|
84
82
|
self.free_paths.extend(flight.free_paths)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
if mode is SimulationMode.PHONON_TRACING:
|
|
84
|
+
self.initial_angles.append(flight.initial_theta)
|
|
85
|
+
self.exit_angles.append(flight.exit_theta)
|
|
86
|
+
self.hole_diff_scattering_angles.extend(flight.hole_diff_scattering_angles)
|
|
87
|
+
self.hole_spec_scattering_angles.extend(flight.hole_spec_scattering_angles)
|
|
89
88
|
self.travel_times.append(flight.travel_time)
|
|
90
89
|
self.mean_free_paths.append(flight.mean_free_path)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
self.interfaces_transmission_factor.extend(flight.interfaces_transmission_factor)
|
|
94
|
-
self.interfaces_wavelength.extend(flight.interfaces_wavelength)
|
|
95
|
-
self.interfaces_frequency.extend(flight.interfaces_frequency)
|
|
96
|
-
self.interfaces_mode.extend(flight.interfaces_mode)
|
|
97
|
-
|
|
90
|
+
if mode is SimulationMode.PHONON_MFP_SAMPLING:
|
|
91
|
+
self.thermal_conductivity.append(flight.thermal_conductivity)
|
|
98
92
|
|
|
99
|
-
def write_into_files(self):
|
|
93
|
+
def write_into_files(self, mode=None):
|
|
100
94
|
import os
|
|
95
|
+
from freepaths.options import SimulationMode
|
|
101
96
|
if not os.path.exists("Data"):
|
|
102
97
|
os.makedirs("Data")
|
|
103
98
|
"""Write all the data into files"""
|
|
104
99
|
if not cf.low_memory_usage:
|
|
105
100
|
np.savetxt("Data/All free paths.csv", self.free_paths, fmt='%2.4e', header="L [m]", encoding='utf-8')
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
101
|
+
if mode is SimulationMode.ELECTRON:
|
|
102
|
+
np.savetxt("Data/All initial energies.csv", self.initial_energies, fmt='%2.4e', header="Energy [J]", encoding='utf-8')
|
|
103
|
+
else:
|
|
104
|
+
np.savetxt("Data/All initial frequencies.csv", self.frequencies, fmt='%2.4e', header="f [Hz]", encoding='utf-8')
|
|
105
|
+
np.savetxt("Data/All group velocities.csv", self.group_velocities, fmt='%.4f', header="Vg [m//s]", encoding='utf-8')
|
|
106
|
+
if mode is SimulationMode.PHONON_TRACING:
|
|
107
|
+
np.savetxt("Data/All exit angles.csv", self.exit_angles, fmt='%.4f', header="Angle [rad]", encoding='utf-8')
|
|
108
|
+
np.savetxt("Data/All initial angles.csv", self.initial_angles, fmt='%.4f', header="Angle [rad]", encoding='utf-8')
|
|
109
|
+
if cf.holes:
|
|
110
|
+
np.savetxt("Data/All hole diffuse scattering angles.csv", self.hole_diff_scattering_angles, fmt='%.4f', header="Angle [rad]", encoding='utf-8')
|
|
111
|
+
np.savetxt("Data/All hole specular scattering angles.csv", self.hole_spec_scattering_angles, fmt='%.4f', header="Angle [rad]", encoding='utf-8')
|
|
112
112
|
np.savetxt("Data/All travel times.csv", self.travel_times, fmt='%2.4e', header="Travel time [s]", encoding='utf-8')
|
|
113
113
|
np.savetxt("Data/All mean free paths.csv", self.mean_free_paths, fmt='%2.4e', header="MFPs [m]", encoding='utf-8')
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
np.savetxt("Data/All interfaces angles.csv", self.interfaces_angles, fmt='%.4f', header="Angle [rad]", encoding='utf-8')
|
|
117
|
-
np.savetxt("Data/All interfaces transmission factor.csv", self.interfaces_transmission_factor, fmt='%2.4e', header="Transmission factor [%]", encoding='utf-8')
|
|
118
|
-
np.savetxt("Data/All interfaces wavelength.csv", self.interfaces_wavelength, fmt='%.18f', header="Interfaces wavelength [m]", encoding='utf-8')
|
|
119
|
-
np.savetxt("Data/All interfaces frequency.csv", self.interfaces_frequency, fmt='%.18f', header="Interfaces frequency [THz]", encoding='utf-8')
|
|
120
|
-
np.savetxt("Data/All interfaces mode.csv", self.interfaces_mode, fmt='%d', header="Interfaces mode", encoding='utf-8')
|
|
121
|
-
|
|
114
|
+
if mode is SimulationMode.PHONON_MFP_SAMPLING:
|
|
115
|
+
np.savetxt("Data/All thermal conductivities.csv", self.thermal_conductivity, fmt='%2.4e', header="K [W/mK]", encoding='utf-8')
|
|
122
116
|
def dump_data(self):
|
|
123
117
|
"""Return data of a process in the form of a dictionary to be attached to the global data"""
|
|
124
118
|
return {
|
|
@@ -133,11 +127,6 @@ class GeneralData(Data):
|
|
|
133
127
|
'mean_free_paths': self.mean_free_paths,
|
|
134
128
|
'thermal_conductivity': self.thermal_conductivity,
|
|
135
129
|
'initial_energies': self.initial_energies,
|
|
136
|
-
'interfaces_angles': self.interfaces_angles,
|
|
137
|
-
'interfaces_transmission_factor': self.interfaces_transmission_factor,
|
|
138
|
-
'interfaces_wavelength': self.interfaces_wavelength,
|
|
139
|
-
'interfaces_frequency': self.interfaces_frequency,
|
|
140
|
-
'interfaces_mode': self.interfaces_mode,
|
|
141
130
|
}
|
|
142
131
|
|
|
143
132
|
|
|
@@ -298,11 +287,9 @@ class SegmentData(Data):
|
|
|
298
287
|
|
|
299
288
|
def record_time_in_segment(self, coordinate):
|
|
300
289
|
"""Record how long particle stays in different segments"""
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if segment_beginning <= coordinate < segment_end:
|
|
305
|
-
self.time_spent[segment_number] += cf.timestep * 1e6
|
|
290
|
+
segment = int(coordinate // (cf.length / cf.number_of_length_segments))
|
|
291
|
+
if 0 <= segment < cf.number_of_length_segments:
|
|
292
|
+
self.time_spent[segment] += cf.timestep * 1e9
|
|
306
293
|
|
|
307
294
|
def write_into_files(self):
|
|
308
295
|
"""Write data into files"""
|
|
@@ -25,13 +25,16 @@ NUMBER_OF_STABILIZATION_TIMEFRAMES = 5
|
|
|
25
25
|
|
|
26
26
|
# Electron parameters [eV]
|
|
27
27
|
IS_CARRIER_ELECTRON = True
|
|
28
|
-
ENERGY_UPPER_BOUND =
|
|
28
|
+
ENERGY_UPPER_BOUND = 350e-3
|
|
29
29
|
ENERGY_LOWER_BOUND = 0
|
|
30
30
|
ENERGY_STEP = 5e-3
|
|
31
31
|
|
|
32
32
|
ELECTRON_MFP = 10e-9 # [m]
|
|
33
33
|
MEAN_MAPPING_CONSTANT = 5e-6 # [m²]
|
|
34
34
|
|
|
35
|
+
FERMI_LEVEL_LOWER_BOUND = -0.2 # [eV] lower end of post-processing Fermi level sweep
|
|
36
|
+
FERMI_LEVEL_UPPER_BOUND = 0.2 # [eV] upper end of post-processing Fermi level sweep
|
|
37
|
+
|
|
35
38
|
|
|
36
39
|
# Animation:
|
|
37
40
|
OUTPUT_PATH_ANIMATION = False
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""This module provides electron class which generates and moves an electron"""
|
|
2
2
|
|
|
3
|
-
from random import choice
|
|
3
|
+
from random import choice, random
|
|
4
4
|
from scipy.constants import h, electron_volt
|
|
5
5
|
from freepaths.config import cf
|
|
6
6
|
from freepaths.particle import Particle
|
|
7
|
-
from freepaths.
|
|
7
|
+
from freepaths.options import ParticleType
|
|
8
8
|
|
|
9
9
|
import numpy as np
|
|
10
10
|
|
|
@@ -72,6 +72,4 @@ class Electron(Particle):
|
|
|
72
72
|
Considering only elasctic scattering between electrons and phonons and thus a constant MFP.
|
|
73
73
|
"""
|
|
74
74
|
mfp = cf.electron_mfp
|
|
75
|
-
self.time_of_internal_scattering = mfp / self.speed
|
|
76
|
-
|
|
77
|
-
# self.time_of_internal_scattering = -np.log(random()) * (mfp/self.speed)
|
|
75
|
+
self.time_of_internal_scattering = -np.log(random()) * (mfp / self.speed)
|
|
@@ -43,12 +43,6 @@ class Flight:
|
|
|
43
43
|
self.hole_diff_scattering_angles = []
|
|
44
44
|
self.hole_spec_scattering_angles = []
|
|
45
45
|
self.thermal_conductivity = 0.0
|
|
46
|
-
self.interfaces_angles = []
|
|
47
|
-
self.interfaces_transmission_factor = []
|
|
48
|
-
self.interfaces_wavelength = []
|
|
49
|
-
self.interfaces_frequency = []
|
|
50
|
-
self.interfaces_mode = []
|
|
51
|
-
|
|
52
46
|
@property
|
|
53
47
|
def mean_free_path(self):
|
|
54
48
|
"""Mean value of all free flights"""
|
|
@@ -74,26 +68,6 @@ class Flight:
|
|
|
74
68
|
"""Save angle of specular scattering from the hole"""
|
|
75
69
|
self.hole_spec_scattering_angles.append(angle)
|
|
76
70
|
|
|
77
|
-
def save_interfaces_angles(self, angle):
|
|
78
|
-
"""Save a transmission event angle"""
|
|
79
|
-
self.interfaces_angles.append(angle)
|
|
80
|
-
|
|
81
|
-
def save_interfaces_transmission_factor(self, alpha_total):
|
|
82
|
-
"""Save a transmission event"""
|
|
83
|
-
self.interfaces_transmission_factor.append(alpha_total)
|
|
84
|
-
|
|
85
|
-
def save_interfaces_wavelength(self):
|
|
86
|
-
"""Save a wavelength event"""
|
|
87
|
-
self.interfaces_wavelength.append(self.particle.wavelength)
|
|
88
|
-
|
|
89
|
-
def save_interfaces_frequency(self):
|
|
90
|
-
"""Save a frequency event"""
|
|
91
|
-
self.interfaces_frequency.append(self.particle.f)
|
|
92
|
-
|
|
93
|
-
def save_interfaces_mode (self):
|
|
94
|
-
"""Save mode"""
|
|
95
|
-
self.interfaces_mode.append(self.particle.branch_number)
|
|
96
|
-
|
|
97
71
|
def restart(self):
|
|
98
72
|
"""Restart the flight after a scattering event"""
|
|
99
73
|
self.time_since_previous_scattering = 0.0
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"""Module to run thermal conductivity calculations by integrating the phonon dispersion"""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import numpy as np
|
|
5
|
+
import sys
|
|
6
|
+
import time
|
|
7
|
+
import shutil
|
|
8
|
+
import scipy
|
|
9
|
+
import math
|
|
10
|
+
import logging
|
|
11
|
+
import signal
|
|
12
|
+
import traceback
|
|
13
|
+
import multiprocessing
|
|
14
|
+
from colorama import Fore, Style
|
|
15
|
+
|
|
16
|
+
# Modules:
|
|
17
|
+
from freepaths.animation import create_animation
|
|
18
|
+
from freepaths.config import cf
|
|
19
|
+
from freepaths.run_particle import run_particle
|
|
20
|
+
from freepaths.phonon import Phonon
|
|
21
|
+
from freepaths.flight import Flight
|
|
22
|
+
from freepaths.options import SimulationMode
|
|
23
|
+
from freepaths.data import ScatteringData, GeneralData, SegmentData, PathData, TriangleScatteringData
|
|
24
|
+
from freepaths.materials import Si, SiC, Graphite, SiGe
|
|
25
|
+
from freepaths.maps import ScatteringMap
|
|
26
|
+
from freepaths.output_info import output_general_information, output_scattering_information, output_parameter_warnings
|
|
27
|
+
from freepaths.materials import get_media_class
|
|
28
|
+
from freepaths.output_plots import plot_data
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def display_all_progress(shared_progress, finished_branches, branch_names):
|
|
32
|
+
"""Render a live progress percentage for each branch on its own line."""
|
|
33
|
+
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
|
34
|
+
n = len(branch_names)
|
|
35
|
+
width = max(len(name) for name in branch_names)
|
|
36
|
+
try:
|
|
37
|
+
for name in branch_names:
|
|
38
|
+
sys.stdout.write(f' {name.ljust(width)}: 0%\n')
|
|
39
|
+
sys.stdout.flush()
|
|
40
|
+
while True:
|
|
41
|
+
sys.stdout.write(f'\033[{n}A')
|
|
42
|
+
for i, name in enumerate(branch_names):
|
|
43
|
+
sys.stdout.write(f'\r {name.ljust(width)}: {shared_progress[i]:3d}%\n')
|
|
44
|
+
sys.stdout.flush()
|
|
45
|
+
if finished_branches.value == n:
|
|
46
|
+
break
|
|
47
|
+
time.sleep(0.1)
|
|
48
|
+
except Exception:
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _branch_worker(branch_number, shared_list, finished_branches, shared_progress):
|
|
53
|
+
"""Entry point for each worker process. Catches exceptions so they are logged
|
|
54
|
+
rather than silently swallowed by the multiprocessing machinery."""
|
|
55
|
+
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
|
56
|
+
try:
|
|
57
|
+
_run_branch(branch_number, shared_list, shared_progress)
|
|
58
|
+
shared_progress[branch_number] = 100
|
|
59
|
+
finished_branches.value += 1
|
|
60
|
+
except Exception:
|
|
61
|
+
logging.exception("Branch worker %d crashed", branch_number)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _run_branch(branch_number, shared_list, shared_progress):
|
|
65
|
+
"""Run all phonons for one polarization branch and push results to shared_list.
|
|
66
|
+
|
|
67
|
+
Each call processes NUMBER_OF_PARTICLES phonons sampled uniformly across the
|
|
68
|
+
dispersion of the given branch. The k-vector integration weight (d_k_vector)
|
|
69
|
+
is the width of the k-space interval assigned to each phonon, so the sum of
|
|
70
|
+
flight.thermal_conductivity over all phonons approximates the branch integral
|
|
71
|
+
in Phys. Rev. 132 2461 (1963).
|
|
72
|
+
|
|
73
|
+
Branch 2 (TA) drives the shared progress bar; the other two run silently.
|
|
74
|
+
Results are appended to shared_list as a dict of dump_data() payloads so that
|
|
75
|
+
the main process can merge them with the standard read_data() mechanism.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
# Each worker builds its own material instance so the dispersion is
|
|
79
|
+
# sampled with the correct number of points (number_of_particles + 1
|
|
80
|
+
# intervals → number_of_particles midpoints):
|
|
81
|
+
if cf.media == "Si":
|
|
82
|
+
material = Si(cf.temp, num_points=cf.number_of_particles + 1)
|
|
83
|
+
elif cf.media == "SiGe":
|
|
84
|
+
material = SiGe(cf.temp, num_points=cf.number_of_particles + 1)
|
|
85
|
+
elif cf.media == "SiC":
|
|
86
|
+
material = SiC(cf.temp, num_points=cf.number_of_particles + 1)
|
|
87
|
+
elif cf.media == "Graphite":
|
|
88
|
+
material = Graphite(cf.temp, num_points=cf.number_of_particles + 1)
|
|
89
|
+
else:
|
|
90
|
+
logging.error(f"Material {cf.media} is not supported")
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
# Local data structures — merged into the global ones after all workers finish:
|
|
94
|
+
scatter_stats = ScatteringData()
|
|
95
|
+
general_stats = GeneralData()
|
|
96
|
+
segment_stats = SegmentData()
|
|
97
|
+
places_stats = TriangleScatteringData()
|
|
98
|
+
path_stats = PathData()
|
|
99
|
+
scatter_maps = ScatteringMap()
|
|
100
|
+
|
|
101
|
+
total_thermal_conductivity = 0.0
|
|
102
|
+
last_pct = -1
|
|
103
|
+
|
|
104
|
+
for index in range(cf.number_of_particles):
|
|
105
|
+
pct = 100 * index // cf.number_of_particles
|
|
106
|
+
if pct > last_pct:
|
|
107
|
+
shared_progress[branch_number] = pct
|
|
108
|
+
last_pct = pct
|
|
109
|
+
|
|
110
|
+
# Mid-point k-vector and integration weight for this phonon:
|
|
111
|
+
k_vector = (material.dispersion[index + 1, 0] + material.dispersion[index, 0]) / 2
|
|
112
|
+
d_k_vector = material.dispersion[index + 1, 0] - material.dispersion[index, 0]
|
|
113
|
+
|
|
114
|
+
# Initialise phonon at this k-point and run it through the geometry:
|
|
115
|
+
phonon = Phonon(material, branch_number, index)
|
|
116
|
+
flight = Flight(phonon)
|
|
117
|
+
run_particle(phonon, flight, scatter_stats, places_stats, segment_stats, None, scatter_maps, material)
|
|
118
|
+
|
|
119
|
+
# Mode heat capacity (Ref. PRB 88 155318, 2013):
|
|
120
|
+
omega = 2 * math.pi * phonon.f
|
|
121
|
+
part = scipy.constants.hbar * omega / (scipy.constants.k * cf.temp)
|
|
122
|
+
c_p = scipy.constants.k * part**2 * math.exp(part) / (math.exp(part) - 1)**2
|
|
123
|
+
|
|
124
|
+
# Thermal conductivity contribution from this k-point (Ref. Phys. Rev. 132 2461, 1963):
|
|
125
|
+
mean_relax_time = flight.mean_free_path / phonon.speed
|
|
126
|
+
flight.thermal_conductivity = (1 / (6 * math.pi**2)) * c_p * phonon.speed**2 * mean_relax_time * k_vector**2 * d_k_vector
|
|
127
|
+
total_thermal_conductivity += flight.thermal_conductivity
|
|
128
|
+
|
|
129
|
+
general_stats.save_particle_data(phonon, SimulationMode.PHONON_MFP_SAMPLING)
|
|
130
|
+
general_stats.save_flight_data(flight, SimulationMode.PHONON_MFP_SAMPLING)
|
|
131
|
+
|
|
132
|
+
if index < cf.output_trajectories_of_first:
|
|
133
|
+
path_stats.save_particle_path(flight)
|
|
134
|
+
|
|
135
|
+
# Push this branch's results to the shared list for the main process to collect:
|
|
136
|
+
shared_list.append({
|
|
137
|
+
'total_thermal_conductivity': total_thermal_conductivity,
|
|
138
|
+
'scatter_stats': scatter_stats.dump_data(),
|
|
139
|
+
'general_stats': general_stats.dump_data(),
|
|
140
|
+
'segment_stats': segment_stats.dump_data(),
|
|
141
|
+
'places_stats': places_stats.dump_data(),
|
|
142
|
+
'path_stats': path_stats.dump_data(),
|
|
143
|
+
'scatter_maps': scatter_maps.dump_data(),
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def main(input_file, mode: SimulationMode):
|
|
148
|
+
"""Integrate the phonon dispersion over all three branches in parallel to get
|
|
149
|
+
the bulk thermal conductivity via the MFP-sampling method."""
|
|
150
|
+
|
|
151
|
+
print(f'Mean free path sampling of {Fore.GREEN}{cf.output_folder_name}{Style.RESET_ALL}')
|
|
152
|
+
start_time = time.time()
|
|
153
|
+
|
|
154
|
+
branch_names = get_media_class(cf.media).branch_names
|
|
155
|
+
n_branches = len(branch_names)
|
|
156
|
+
|
|
157
|
+
# Spawn one worker process per polarization branch, all running concurrently:
|
|
158
|
+
manager = multiprocessing.Manager()
|
|
159
|
+
shared_list = manager.list()
|
|
160
|
+
finished_branches = manager.Value('i', 0)
|
|
161
|
+
shared_progress = manager.list([0] * n_branches)
|
|
162
|
+
|
|
163
|
+
processes = [
|
|
164
|
+
multiprocessing.Process(target=_branch_worker, args=(branch_number, shared_list, finished_branches, shared_progress))
|
|
165
|
+
for branch_number in range(n_branches - 1, -1, -1)
|
|
166
|
+
]
|
|
167
|
+
for process in processes:
|
|
168
|
+
process.start()
|
|
169
|
+
|
|
170
|
+
display_process = multiprocessing.Process(target=display_all_progress, args=(shared_progress, finished_branches, branch_names))
|
|
171
|
+
display_process.start()
|
|
172
|
+
|
|
173
|
+
try:
|
|
174
|
+
for process in processes:
|
|
175
|
+
process.join()
|
|
176
|
+
except KeyboardInterrupt:
|
|
177
|
+
for process in processes:
|
|
178
|
+
process.terminate()
|
|
179
|
+
raise
|
|
180
|
+
|
|
181
|
+
display_process.join(timeout=3)
|
|
182
|
+
display_process.terminate()
|
|
183
|
+
|
|
184
|
+
# Merge per-branch results into single data structures:
|
|
185
|
+
scatter_stats = ScatteringData()
|
|
186
|
+
general_stats = GeneralData()
|
|
187
|
+
segment_stats = SegmentData()
|
|
188
|
+
places_stats = TriangleScatteringData()
|
|
189
|
+
path_stats = PathData()
|
|
190
|
+
scatter_maps = ScatteringMap()
|
|
191
|
+
total_thermal_conductivity = 0.0
|
|
192
|
+
|
|
193
|
+
for result in shared_list:
|
|
194
|
+
total_thermal_conductivity += result['total_thermal_conductivity']
|
|
195
|
+
scatter_stats.read_data(result['scatter_stats'])
|
|
196
|
+
general_stats.read_data(result['general_stats'])
|
|
197
|
+
segment_stats.read_data(result['segment_stats'])
|
|
198
|
+
places_stats.read_data(result['places_stats'])
|
|
199
|
+
path_stats.read_data(result['path_stats'])
|
|
200
|
+
scatter_maps.read_data(result['scatter_maps'])
|
|
201
|
+
|
|
202
|
+
# Create the output folder and copy input file:
|
|
203
|
+
if not os.path.exists("Results/" + cf.output_folder_name):
|
|
204
|
+
os.makedirs("Results/" + cf.output_folder_name)
|
|
205
|
+
os.makedirs("Results/" + cf.output_folder_name + '/Data')
|
|
206
|
+
if input_file:
|
|
207
|
+
shutil.copy(input_file, "Results/" + cf.output_folder_name)
|
|
208
|
+
os.chdir("Results/" + cf.output_folder_name)
|
|
209
|
+
|
|
210
|
+
# Save data and generate plots:
|
|
211
|
+
general_stats.write_into_files(mode)
|
|
212
|
+
scatter_stats.write_into_files()
|
|
213
|
+
segment_stats.write_into_files()
|
|
214
|
+
if cf.output_scattering_map:
|
|
215
|
+
scatter_maps.write_into_files()
|
|
216
|
+
path_stats.write_into_files()
|
|
217
|
+
|
|
218
|
+
if cf.output_path_animation:
|
|
219
|
+
create_animation()
|
|
220
|
+
|
|
221
|
+
np.savetxt("Data/Thermal conductivity from MFP.csv", np.array([total_thermal_conductivity]), fmt='%2.4e', header="K [W/mK]", encoding='utf-8')
|
|
222
|
+
|
|
223
|
+
sys.stdout.write("\rAnalyzing the data...")
|
|
224
|
+
plot_data(mode, cf)
|
|
225
|
+
|
|
226
|
+
output_general_information(start_time)
|
|
227
|
+
output_scattering_information(scatter_stats)
|
|
228
|
+
output_parameter_warnings(mode)
|
|
229
|
+
sys.stdout.write(f'\rSee the results in {Fore.GREEN}Results/{cf.output_folder_name}{Style.RESET_ALL}\n')
|
|
230
|
+
sys.stdout.write(f"\rThermal conductivity = {Fore.GREEN}{total_thermal_conductivity:.5f}{Style.RESET_ALL} W/m·K\n")
|
|
231
|
+
sys.stdout.write(f"\r{Fore.BLUE}Thank you for using FreePATHS{Style.RESET_ALL}\n\n")
|