freepaths 2.1.3__tar.gz → 2.2__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.1.3 → freepaths-2.2}/PKG-INFO +2 -2
- {freepaths-2.1.3 → freepaths-2.2}/README.md +1 -1
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/__main__.py +12 -4
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/config.py +31 -7
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/data.py +86 -28
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/default_config.py +17 -4
- freepaths-2.2/freepaths/electron.py +77 -0
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/flight.py +44 -19
- freepaths-2.2/freepaths/interface_smmm.py +143 -0
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/main_mfp_sampling.py +16 -10
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/main_tracing.py +75 -42
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/maps.py +23 -24
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/materials.py +144 -23
- freepaths-2.2/freepaths/move.py +23 -0
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/output_info.py +23 -12
- freepaths-2.2/freepaths/output_plots.py +1125 -0
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/output_structure.py +11 -5
- freepaths-2.2/freepaths/particle.py +94 -0
- freepaths-2.2/freepaths/particle_types.py +5 -0
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/phonon.py +15 -45
- freepaths-2.2/freepaths/post_computations.py +177 -0
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/progress.py +2 -2
- freepaths-2.2/freepaths/run_particle.py +86 -0
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/scatterers.py +397 -117
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/scattering.py +64 -47
- freepaths-2.2/freepaths/scattering_interfaces.py +265 -0
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/scattering_primitives.py +84 -82
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/scattering_semicircle.py +176 -234
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/scattering_types.py +26 -5
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/sources.py +8 -8
- {freepaths-2.1.3 → freepaths-2.2}/freepaths.egg-info/PKG-INFO +2 -2
- {freepaths-2.1.3 → freepaths-2.2}/freepaths.egg-info/SOURCES.txt +7 -1
- freepaths-2.1.3/freepaths/move.py +0 -23
- freepaths-2.1.3/freepaths/output_plots.py +0 -553
- freepaths-2.1.3/freepaths/run_phonon.py +0 -78
- {freepaths-2.1.3 → freepaths-2.2}/freepaths/animation.py +0 -0
- {freepaths-2.1.3 → freepaths-2.2}/freepaths.egg-info/dependency_links.txt +0 -0
- {freepaths-2.1.3 → freepaths-2.2}/freepaths.egg-info/entry_points.txt +0 -0
- {freepaths-2.1.3 → freepaths-2.2}/freepaths.egg-info/requires.txt +0 -0
- {freepaths-2.1.3 → freepaths-2.2}/freepaths.egg-info/top_level.txt +0 -0
- {freepaths-2.1.3 → freepaths-2.2}/pyproject.toml +0 -0
- {freepaths-2.1.3 → freepaths-2.2}/setup.cfg +0 -0
- {freepaths-2.1.3 → freepaths-2.2}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: freepaths
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2
|
|
4
4
|
Summary: Phonon Monte Carlo simulator
|
|
5
5
|
Home-page: https://github.com/anufrievroman/freepaths
|
|
6
6
|
Author: Roman Anufriev
|
|
@@ -95,7 +95,7 @@ The code is still in development and provided as is. It likely contains bugs or
|
|
|
95
95
|
|
|
96
96
|
## References and acknowledgments
|
|
97
97
|
|
|
98
|
-
The code is developed by [Roman Anufriev](https://anufrievroman.com), Philipp Gassmann, and other contributors in [Nomura lab](https://www.nlab.iis.u-tokyo.ac.jp/index-e.html) at the University of Tokyo since 2018.
|
|
98
|
+
The code is developed by [Roman Anufriev](https://anufrievroman.com), Philipp Gassmann, Simon Defradas and other contributors in [Nomura lab](https://www.nlab.iis.u-tokyo.ac.jp/index-e.html) at the University of Tokyo since 2018.
|
|
99
99
|
If you would like to use this code for your research, please see the disclaimer above and consider citing the papers below, if it is appropriate.
|
|
100
100
|
Details of the code and examples of the output can be found in the following papers:
|
|
101
101
|
|
|
@@ -59,7 +59,7 @@ The code is still in development and provided as is. It likely contains bugs or
|
|
|
59
59
|
|
|
60
60
|
## References and acknowledgments
|
|
61
61
|
|
|
62
|
-
The code is developed by [Roman Anufriev](https://anufrievroman.com), Philipp Gassmann, and other contributors in [Nomura lab](https://www.nlab.iis.u-tokyo.ac.jp/index-e.html) at the University of Tokyo since 2018.
|
|
62
|
+
The code is developed by [Roman Anufriev](https://anufrievroman.com), Philipp Gassmann, Simon Defradas and other contributors in [Nomura lab](https://www.nlab.iis.u-tokyo.ac.jp/index-e.html) at the University of Tokyo since 2018.
|
|
63
63
|
If you would like to use this code for your research, please see the disclaimer above and consider citing the papers below, if it is appropriate.
|
|
64
64
|
Details of the code and examples of the output can be found in the following papers:
|
|
65
65
|
|
|
@@ -4,10 +4,8 @@ import argparse
|
|
|
4
4
|
import colorama
|
|
5
5
|
from colorama import Fore, Style
|
|
6
6
|
|
|
7
|
-
import freepaths.main_tracing
|
|
8
|
-
import freepaths.main_mfp_sampling
|
|
9
7
|
|
|
10
|
-
__version__ = "2.
|
|
8
|
+
__version__ = "2.2"
|
|
11
9
|
|
|
12
10
|
colorama.init()
|
|
13
11
|
|
|
@@ -19,6 +17,7 @@ parser = argparse.ArgumentParser(
|
|
|
19
17
|
)
|
|
20
18
|
parser.add_argument('input_file', nargs='?', default=None, help='The input file')
|
|
21
19
|
parser.add_argument("-s", "--sampling", help="Run in MFP sampling mode", action="store_true")
|
|
20
|
+
parser.add_argument("-e", "--electron", help="Run simulation for electrons", action="store_true")
|
|
22
21
|
args = parser.parse_args()
|
|
23
22
|
|
|
24
23
|
|
|
@@ -26,9 +25,18 @@ def run():
|
|
|
26
25
|
"""Run the program depending on the mode"""
|
|
27
26
|
print(f"\n{Fore.BLUE}FreePATHS v{__version__}{Style.RESET_ALL}")
|
|
28
27
|
if args.sampling:
|
|
28
|
+
import freepaths.main_mfp_sampling
|
|
29
29
|
freepaths.main_mfp_sampling.main(args.input_file)
|
|
30
|
+
|
|
31
|
+
elif args.electron:
|
|
32
|
+
import freepaths.main_tracing
|
|
33
|
+
from freepaths.particle_types import ParticleType
|
|
34
|
+
freepaths.main_tracing.main(args.input_file, ParticleType.ELECTRON)
|
|
35
|
+
|
|
30
36
|
else:
|
|
31
|
-
freepaths.main_tracing
|
|
37
|
+
import freepaths.main_tracing
|
|
38
|
+
from freepaths.particle_types import ParticleType
|
|
39
|
+
freepaths.main_tracing.main(args.input_file, ParticleType.PHONON)
|
|
32
40
|
|
|
33
41
|
|
|
34
42
|
if __name__ == "__main__":
|
|
@@ -6,6 +6,7 @@ checks the validity of the parameters and converts the variables into enums
|
|
|
6
6
|
import sys
|
|
7
7
|
import argparse
|
|
8
8
|
import logging
|
|
9
|
+
import builtins #24/06
|
|
9
10
|
from colorama import Fore, Style
|
|
10
11
|
|
|
11
12
|
from freepaths.sources import Distributions
|
|
@@ -24,6 +25,7 @@ parser = argparse.ArgumentParser(prog='FreePATHS', description='Monte Carlo simu
|
|
|
24
25
|
epilog=f'For more information, visit: {WEBSITE}')
|
|
25
26
|
parser.add_argument('input_file', nargs='?', default=None, help='The input file')
|
|
26
27
|
parser.add_argument("-s", "--sampling", help="Run in MFP sampling mode", action="store_true")
|
|
28
|
+
parser.add_argument("-e", "--electron", help="Run with electrons", action="store_true")
|
|
27
29
|
args = parser.parse_args()
|
|
28
30
|
|
|
29
31
|
|
|
@@ -46,13 +48,14 @@ class Config:
|
|
|
46
48
|
|
|
47
49
|
# General parameters:
|
|
48
50
|
self.output_folder_name = str(OUTPUT_FOLDER_NAME)
|
|
49
|
-
self.
|
|
51
|
+
self.number_of_particles = NUMBER_OF_PARTICLES
|
|
50
52
|
self.number_of_nodes = NUMBER_OF_NODES
|
|
51
53
|
self.temp = T
|
|
52
54
|
self.output_scattering_map = OUTPUT_SCATTERING_MAP
|
|
53
55
|
self.output_trajectories_of_first = OUTPUT_TRAJECTORIES_OF_FIRST
|
|
54
56
|
self.output_structure_color = OUTPUT_STRUCTURE_COLOR
|
|
55
57
|
self.number_of_length_segments = NUMBER_OF_LENGTH_SEGMENTS
|
|
58
|
+
self.low_memory_usage = LOW_MEMORY_USAGE
|
|
56
59
|
|
|
57
60
|
# Time parameters:
|
|
58
61
|
self.timestep = TIMESTEP
|
|
@@ -60,6 +63,14 @@ class Config:
|
|
|
60
63
|
self.number_of_timeframes = NUMBER_OF_TIMEFRAMES
|
|
61
64
|
self.number_of_stabilization_timeframes = NUMBER_OF_STABILIZATION_TIMEFRAMES
|
|
62
65
|
|
|
66
|
+
# Electron parameters:
|
|
67
|
+
self.energy_upper_bound = ENERGY_UPPER_BOUND
|
|
68
|
+
self.energy_lower_bound = ENERGY_LOWER_BOUND
|
|
69
|
+
self.energy_step = ENERGY_STEP
|
|
70
|
+
self.electron_mfp = ELECTRON_MFP
|
|
71
|
+
self.mean_mapping_constant = MEAN_MAPPING_CONSTANT
|
|
72
|
+
self.is_carrier_electron = IS_CARRIER_ELECTRON
|
|
73
|
+
|
|
63
74
|
# Animation:
|
|
64
75
|
self.output_path_animation = OUTPUT_PATH_ANIMATION
|
|
65
76
|
self.output_animation_fps = OUTPUT_ANIMATION_FPS
|
|
@@ -68,10 +79,11 @@ class Config:
|
|
|
68
79
|
self.number_of_pixels_x = NUMBER_OF_PIXELS_X
|
|
69
80
|
self.number_of_pixels_y = NUMBER_OF_PIXELS_Y
|
|
70
81
|
self.number_of_virtual_timesteps = NUMBER_OF_VIRTUAL_TIMESTEPS
|
|
71
|
-
self.
|
|
82
|
+
self.ignore_faulty_particles = IGNORE_FAULTY_PARTICLES
|
|
72
83
|
|
|
73
84
|
# Material parameters:
|
|
74
85
|
self.media = MEDIA
|
|
86
|
+
self.media_fermi_level = MEDIA_FERMI_LEVEL
|
|
75
87
|
|
|
76
88
|
# Internal scattering:
|
|
77
89
|
self.include_internal_scattering = INCLUDE_INTERNAL_SCATTERING
|
|
@@ -96,7 +108,7 @@ class Config:
|
|
|
96
108
|
self.rethermalization_on_hot_sides = RETHERMALIZATION_ON_HOT_SIDES
|
|
97
109
|
|
|
98
110
|
# Sources:
|
|
99
|
-
self.
|
|
111
|
+
self.particles_sources = PARTICLE_SOURCES
|
|
100
112
|
|
|
101
113
|
# Cold side positions:
|
|
102
114
|
self.cold_side_position_top = COLD_SIDE_POSITION_TOP
|
|
@@ -117,6 +129,7 @@ class Config:
|
|
|
117
129
|
self.holes = HOLES
|
|
118
130
|
self.pillars = PILLARS
|
|
119
131
|
self.interfaces = INTERFACES
|
|
132
|
+
self.bulks = BULKS
|
|
120
133
|
|
|
121
134
|
# Multiprocessing:
|
|
122
135
|
self.num_workers = NUMBER_OF_PROCESSES
|
|
@@ -126,7 +139,7 @@ class Config:
|
|
|
126
139
|
|
|
127
140
|
# Distributions:
|
|
128
141
|
valid_distributions =[member.name.lower() for member in Distributions]
|
|
129
|
-
for source in self.
|
|
142
|
+
for source in self.particles_sources:
|
|
130
143
|
if source.angle_distribution in valid_distributions:
|
|
131
144
|
source.angle_distribution = Distributions[source.angle_distribution.upper()]
|
|
132
145
|
else:
|
|
@@ -136,8 +149,8 @@ class Config:
|
|
|
136
149
|
|
|
137
150
|
def check_parameter_validity(self):
|
|
138
151
|
"""Check if various parameters are valid"""
|
|
139
|
-
if self.
|
|
140
|
-
self.output_trajectories_of_first = self.
|
|
152
|
+
if self.number_of_particles < self.output_trajectories_of_first:
|
|
153
|
+
self.output_trajectories_of_first = self.number_of_particles
|
|
141
154
|
|
|
142
155
|
if self.number_of_timeframes <= self.number_of_stabilization_timeframes:
|
|
143
156
|
logging.error("Parameter NUMBER_OF_STABILIZATION_TIMEFRAMES exceeds or equal to NUMBER_OF_TIMEFRAMES.\n" +
|
|
@@ -145,7 +158,7 @@ class Config:
|
|
|
145
158
|
f"See the documentation at {WEBSITE}")
|
|
146
159
|
sys.exit()
|
|
147
160
|
|
|
148
|
-
for source in self.
|
|
161
|
+
for source in self.particles_sources:
|
|
149
162
|
if source.y > self.length:
|
|
150
163
|
logging.error("Y coordinate of a source exceeded LENGHT")
|
|
151
164
|
sys.exit()
|
|
@@ -232,7 +245,18 @@ class Config:
|
|
|
232
245
|
f"See the documentation at {WEBSITE}")
|
|
233
246
|
sys.exit()
|
|
234
247
|
|
|
248
|
+
if any([
|
|
249
|
+
'NUMBER_OF_PHONONS' in globals(),
|
|
250
|
+
'IGNORE_FAULTY_PHONONS' in globals(),
|
|
251
|
+
'PHONON_SOURCES' in globals(),
|
|
252
|
+
]):
|
|
253
|
+
logging.error("Parameters NUMBER_OF_PHONONS, PHONON_SOURCES and IGNORE_FAULTY_PHONONS were deprecated.\n" +
|
|
254
|
+
"Replace PHONONS with PARTICLES.\n" +
|
|
255
|
+
f"See the documentation at {WEBSITE}")
|
|
256
|
+
sys.exit()
|
|
257
|
+
|
|
235
258
|
cf = Config()
|
|
236
259
|
cf.convert_to_enums()
|
|
237
260
|
cf.check_parameter_validity()
|
|
238
261
|
cf.check_depricated_parameters()
|
|
262
|
+
|
|
@@ -15,26 +15,30 @@ class Data:
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class PathData(Data):
|
|
18
|
-
"""Paths of
|
|
18
|
+
"""Paths of particles in space"""
|
|
19
19
|
|
|
20
20
|
def __init__(self):
|
|
21
|
-
"""Initialize arrays to save
|
|
22
|
-
self.
|
|
21
|
+
"""Initialize arrays to save particle paths"""
|
|
22
|
+
self.particle_paths = []
|
|
23
23
|
|
|
24
|
-
def
|
|
24
|
+
def save_particle_path(self, flight):
|
|
25
25
|
"""Save the path to list of all paths"""
|
|
26
|
-
|
|
26
|
+
if cf.low_memory_usage:
|
|
27
|
+
return
|
|
28
|
+
self.particle_paths.append(flight.path)
|
|
27
29
|
|
|
28
30
|
@property
|
|
29
31
|
def length_of_longest_path(self):
|
|
30
32
|
"""Calculate the number of points in the longest path"""
|
|
31
|
-
return max([path.number_of_path_points for path in self.
|
|
33
|
+
return max([path.number_of_path_points for path in self.particle_paths])
|
|
32
34
|
|
|
33
35
|
def write_into_files(self):
|
|
34
36
|
"""Write all the path coordinates into a file"""
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
if cf.low_memory_usage:
|
|
38
|
+
return
|
|
39
|
+
filename = "Data/Particle paths.csv"
|
|
40
|
+
data = np.zeros((self.length_of_longest_path, 3*len(self.particle_paths)))
|
|
41
|
+
for index, path in enumerate(self.particle_paths):
|
|
38
42
|
for point_n, (x, y, z) in enumerate(zip(path.x, path.y, path.z)):
|
|
39
43
|
data[point_n, 0 + index*3] = x*1e6
|
|
40
44
|
data[point_n, 1 + index*3] = y*1e6
|
|
@@ -43,11 +47,11 @@ class PathData(Data):
|
|
|
43
47
|
|
|
44
48
|
def dump_data(self):
|
|
45
49
|
"""Return data of a process in the form of a dictionary to be attached to the global data"""
|
|
46
|
-
return {'
|
|
50
|
+
return {'particle_paths': self.particle_paths}
|
|
47
51
|
|
|
48
52
|
|
|
49
53
|
class GeneralData(Data):
|
|
50
|
-
"""General statistics of various
|
|
54
|
+
"""General statistics of various particle properties"""
|
|
51
55
|
|
|
52
56
|
def __init__(self):
|
|
53
57
|
"""Initialize arrays for writing various properties"""
|
|
@@ -56,34 +60,50 @@ class GeneralData(Data):
|
|
|
56
60
|
self.hole_diff_scattering_angles = []
|
|
57
61
|
self.hole_spec_scattering_angles = []
|
|
58
62
|
self.free_paths = []
|
|
59
|
-
self.free_paths_along_y = []
|
|
60
63
|
self.frequencies = []
|
|
64
|
+
self.initial_energies = []
|
|
61
65
|
self.group_velocities = []
|
|
62
66
|
self.travel_times = []
|
|
63
67
|
self.mean_free_paths = []
|
|
64
68
|
self.thermal_conductivity = []
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
self.
|
|
69
|
-
self.
|
|
69
|
+
self.interfaces_angles = []
|
|
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):
|
|
76
|
+
"""Add information about the particle to the dataset"""
|
|
77
|
+
self.frequencies.append(pt.f)
|
|
78
|
+
self.group_velocities.append(pt.speed)
|
|
79
|
+
self.initial_energies.append(pt.energy)
|
|
70
80
|
|
|
71
81
|
def save_flight_data(self, flight):
|
|
72
|
-
"""Add information about the
|
|
82
|
+
"""Add information about the particle flight to the dataset"""
|
|
83
|
+
if not cf.low_memory_usage:
|
|
84
|
+
self.free_paths.extend(flight.free_paths)
|
|
73
85
|
self.initial_angles.append(flight.initial_theta)
|
|
74
86
|
self.exit_angles.append(flight.exit_theta)
|
|
75
|
-
self.free_paths.extend(flight.free_paths)
|
|
76
87
|
self.hole_diff_scattering_angles.extend(flight.hole_diff_scattering_angles)
|
|
77
88
|
self.hole_spec_scattering_angles.extend(flight.hole_spec_scattering_angles)
|
|
78
|
-
self.free_paths_along_y.extend(flight.free_paths_along_y)
|
|
79
89
|
self.travel_times.append(flight.travel_time)
|
|
80
90
|
self.mean_free_paths.append(flight.mean_free_path)
|
|
81
91
|
self.thermal_conductivity.append(flight.thermal_conductivity)
|
|
92
|
+
self.interfaces_angles.extend(flight.interfaces_angles)
|
|
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
|
+
|
|
98
|
+
|
|
82
99
|
|
|
83
100
|
def write_into_files(self):
|
|
101
|
+
import os
|
|
102
|
+
if not os.path.exists("Data"):
|
|
103
|
+
os.makedirs("Data")
|
|
84
104
|
"""Write all the data into files"""
|
|
85
|
-
|
|
86
|
-
|
|
105
|
+
if not cf.low_memory_usage:
|
|
106
|
+
np.savetxt("Data/All free paths.csv", self.free_paths, fmt='%2.4e', header="L [m]", encoding='utf-8')
|
|
87
107
|
np.savetxt("Data/All initial frequencies.csv", self.frequencies, fmt='%2.4e', header="f [Hz]", encoding='utf-8')
|
|
88
108
|
np.savetxt("Data/All exit angles.csv", self.exit_angles, fmt='%.4f', header="Angle [rad]", encoding='utf-8')
|
|
89
109
|
np.savetxt("Data/All hole diffuse scattering angles.csv", self.hole_diff_scattering_angles, fmt='%.4f', header="Angle [rad]", encoding='utf-8')
|
|
@@ -93,6 +113,12 @@ class GeneralData(Data):
|
|
|
93
113
|
np.savetxt("Data/All travel times.csv", self.travel_times, fmt='%2.4e', header="Travel time [s]", encoding='utf-8')
|
|
94
114
|
np.savetxt("Data/All mean free paths.csv", self.mean_free_paths, fmt='%2.4e', header="MFPs [m]", encoding='utf-8')
|
|
95
115
|
np.savetxt("Data/All thermal conductivities.csv", self.thermal_conductivity, fmt='%2.4e', header="K [W/mK]", encoding='utf-8')
|
|
116
|
+
np.savetxt("Data/All initial energies.csv", self.initial_energies, fmt='%2.4e', header="Energy [J]", encoding='utf-8')
|
|
117
|
+
np.savetxt("Data/All interfaces angles.csv", self.interfaces_angles, fmt='%.4f', header="Angle [rad]", encoding='utf-8')
|
|
118
|
+
np.savetxt("Data/All interfaces transmission factor.csv", self.interfaces_transmission_factor, fmt='%2.4e', header="Transmission factor [%]", encoding='utf-8')
|
|
119
|
+
np.savetxt("Data/All interfaces wavelength.csv", self.interfaces_wavelength, fmt='%.18f', header="Interfaces wavelength [m]", encoding='utf-8')
|
|
120
|
+
np.savetxt("Data/All interfaces frequency.csv", self.interfaces_frequency, fmt='%.18f', header="Interfaces frequency [THz]", encoding='utf-8')
|
|
121
|
+
np.savetxt("Data/All interfaces mode.csv", self.interfaces_mode, fmt='%d', header="Interfaces mode", encoding='utf-8')
|
|
96
122
|
|
|
97
123
|
def dump_data(self):
|
|
98
124
|
"""Return data of a process in the form of a dictionary to be attached to the global data"""
|
|
@@ -102,17 +128,23 @@ class GeneralData(Data):
|
|
|
102
128
|
'hole_diff_scattering_angles': self.hole_diff_scattering_angles,
|
|
103
129
|
'hole_spec_scattering_angles': self.hole_spec_scattering_angles,
|
|
104
130
|
'free_paths': self.free_paths,
|
|
105
|
-
'free_paths_along_y': self.free_paths_along_y,
|
|
106
131
|
'frequencies': self.frequencies,
|
|
107
132
|
'group_velocities': self.group_velocities,
|
|
108
133
|
'travel_times': self.travel_times,
|
|
109
134
|
'mean_free_paths': self.mean_free_paths,
|
|
110
135
|
'thermal_conductivity': self.thermal_conductivity,
|
|
136
|
+
'initial_energies': self.initial_energies,
|
|
137
|
+
'interfaces_angles': self.interfaces_angles,
|
|
138
|
+
'interfaces_transmission_factor': self.interfaces_transmission_factor,
|
|
139
|
+
'interfaces_wavelength': self.interfaces_wavelength,
|
|
140
|
+
'interfaces_frequency': self.interfaces_frequency,
|
|
141
|
+
'interfaces_mode': self.interfaces_mode,
|
|
111
142
|
}
|
|
112
143
|
|
|
113
144
|
|
|
145
|
+
|
|
114
146
|
class ScatteringData(Data):
|
|
115
|
-
"""Statistics of
|
|
147
|
+
"""Statistics of particle scattering events"""
|
|
116
148
|
|
|
117
149
|
def __init__(self):
|
|
118
150
|
"""Initialize arrays according to the number of segments"""
|
|
@@ -129,6 +161,15 @@ class ScatteringData(Data):
|
|
|
129
161
|
self.interfaces_diffuse = np.zeros(cf.number_of_length_segments+1)
|
|
130
162
|
self.interfaces_specular = np.zeros(cf.number_of_length_segments+1)
|
|
131
163
|
self.total = np.zeros(cf.number_of_length_segments+1)
|
|
164
|
+
self.interfaces_transmission_specular= np.zeros(cf.number_of_length_segments + 1)
|
|
165
|
+
self.interfaces_transmission_diffuse = np.zeros(cf.number_of_length_segments + 1)
|
|
166
|
+
self.interfaces_angles = np.zeros(cf.number_of_length_segments + 1)
|
|
167
|
+
self.interfaces_transmission_factor = np.zeros(cf.number_of_length_segments + 1)
|
|
168
|
+
self.interfaces_wavelength = np.zeros(cf.number_of_length_segments+1)
|
|
169
|
+
self.interfaces_frequency = np.zeros(cf.number_of_length_segments+1)
|
|
170
|
+
self.interfaces_mode = np.zeros(cf.number_of_length_segments+1)
|
|
171
|
+
|
|
172
|
+
|
|
132
173
|
|
|
133
174
|
def save_scattering_events(self, y, scattering_types):
|
|
134
175
|
"""Analyze types of scattering at the current timestep and add it to the statistics"""
|
|
@@ -161,6 +202,10 @@ class ScatteringData(Data):
|
|
|
161
202
|
# Internal scattering and rethermalization on hot side:
|
|
162
203
|
self.hot_side[segment] += 1 if scattering_types.hot_side == Scattering.DIFFUSE else 0
|
|
163
204
|
self.internal[segment] += 1 if scattering_types.internal == Scattering.DIFFUSE else 0
|
|
205
|
+
|
|
206
|
+
# Interfaces transmission events:
|
|
207
|
+
self.interfaces_transmission_specular[segment] += 1 if scattering_types.interfaces_transmission== Scattering.SPECULAR else 0
|
|
208
|
+
self.interfaces_transmission_diffuse[segment] += 1 if scattering_types.interfaces_transmission == Scattering.DIFFUSE else 0
|
|
164
209
|
except:
|
|
165
210
|
pass
|
|
166
211
|
|
|
@@ -168,10 +213,16 @@ class ScatteringData(Data):
|
|
|
168
213
|
"""Write data into a file"""
|
|
169
214
|
filename = "Data/Scattering events statistics.csv"
|
|
170
215
|
data = np.vstack((self.wall_diffuse, self.wall_specular, self.top_diffuse, self.top_specular, self.hole_diffuse,
|
|
171
|
-
self.hole_specular, self.hot_side, self.internal, self.pillar_diffuse, self.pillar_specular
|
|
216
|
+
self.hole_specular, self.hot_side, self.internal, self.pillar_diffuse, self.pillar_specular,
|
|
217
|
+
self.interfaces_diffuse, self.interfaces_specular,
|
|
218
|
+
self.interfaces_transmission_diffuse, self.interfaces_transmission_specular,
|
|
219
|
+
self.interfaces_transmission_factor, self.interfaces_angles,
|
|
220
|
+
self.interfaces_wavelength, self.interfaces_mode)).T
|
|
172
221
|
header1 = "Sidewalls diffuse, Sidewalls specular, Top & bottom diffuse, Top & bottom specular, "
|
|
173
222
|
header2 = "Holes diffuse, Holes specular, Hot side, Internal, Pillars diffuse, Pillars specular"
|
|
174
|
-
|
|
223
|
+
header3 = "Interfaces diffuse, Interfaces specular, Interfaces transmission diffuse, Interfaces transmission specular, " \
|
|
224
|
+
"Interfaces transmission factor, Interfaces angles, Interfaces wavelength, Interfaces frequency, Interfaces mode"
|
|
225
|
+
header = header1 + header2 + header3
|
|
175
226
|
np.savetxt(filename, data, fmt='%1.3e', delimiter=",", header=header, encoding='utf-8')
|
|
176
227
|
|
|
177
228
|
def dump_data(self):
|
|
@@ -189,12 +240,19 @@ class ScatteringData(Data):
|
|
|
189
240
|
'internal': self.internal,
|
|
190
241
|
'interfaces_diffuse': self.interfaces_diffuse,
|
|
191
242
|
'interfaces_specular': self.interfaces_specular,
|
|
243
|
+
'interfaces_transmission_specular': self.interfaces_transmission_specular,
|
|
244
|
+
'interfaces_transmission_diffuse': self.interfaces_transmission_diffuse,
|
|
245
|
+
'interfaces_angles': self.interfaces_angles,
|
|
246
|
+
'interfaces_transmission_factor': self.interfaces_transmission_factor,
|
|
247
|
+
'interfaces_wavelength': self.interfaces_wavelength,
|
|
248
|
+
'interfaces_frequency': self.interfaces_frequency,
|
|
249
|
+
'interfaces_mode' : self.interfaces_mode,
|
|
192
250
|
'total': self.total
|
|
193
251
|
}
|
|
194
252
|
|
|
195
253
|
|
|
196
254
|
class TriangleScatteringData(Data):
|
|
197
|
-
"""Statistics of
|
|
255
|
+
"""Statistics of particle scattering events on triangular holes"""
|
|
198
256
|
|
|
199
257
|
def __init__(self):
|
|
200
258
|
"""Initialize arrays according to the number of segments"""
|
|
@@ -255,7 +313,7 @@ class SegmentData(Data):
|
|
|
255
313
|
return segments
|
|
256
314
|
|
|
257
315
|
def record_time_in_segment(self, coordinate):
|
|
258
|
-
"""Record how long
|
|
316
|
+
"""Record how long particle stays in different segments"""
|
|
259
317
|
for segment_number in range(cf.number_of_length_segments):
|
|
260
318
|
segment_beginning = segment_number * (cf.length / cf.number_of_length_segments)
|
|
261
319
|
segment_end = (segment_number + 1)*(cf.length / cf.number_of_length_segments)
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
"""Default config file"""
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
|
+
from scipy.constants import k, electron_volt
|
|
4
5
|
from freepaths.sources import Source
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
# General parameters:
|
|
8
9
|
OUTPUT_FOLDER_NAME = "Si nanowire at 300 K"
|
|
9
|
-
|
|
10
|
+
NUMBER_OF_PARTICLES = 5000
|
|
10
11
|
NUMBER_OF_NODES = 400
|
|
11
12
|
T = 300
|
|
12
13
|
OUTPUT_SCATTERING_MAP = False
|
|
13
14
|
OUTPUT_TRAJECTORIES_OF_FIRST = 50
|
|
14
15
|
OUTPUT_STRUCTURE_COLOR = "#F0F0F0"
|
|
15
16
|
NUMBER_OF_LENGTH_SEGMENTS = 10
|
|
17
|
+
LOW_MEMORY_USAGE = False
|
|
16
18
|
|
|
17
19
|
# Time parameters:
|
|
18
20
|
TIMESTEP = 1e-12
|
|
@@ -21,6 +23,15 @@ NUMBER_OF_VIRTUAL_TIMESTEPS = NUMBER_OF_TIMESTEPS * 3
|
|
|
21
23
|
NUMBER_OF_TIMEFRAMES = 8
|
|
22
24
|
NUMBER_OF_STABILIZATION_TIMEFRAMES = 5
|
|
23
25
|
|
|
26
|
+
# Electron parameters [eV]
|
|
27
|
+
IS_CARRIER_ELECTRON = True
|
|
28
|
+
ENERGY_UPPER_BOUND = 3*k*T / electron_volt
|
|
29
|
+
ENERGY_LOWER_BOUND = 0
|
|
30
|
+
ENERGY_STEP = 5e-3
|
|
31
|
+
|
|
32
|
+
ELECTRON_MFP = 15e-9 # [m]
|
|
33
|
+
MEAN_MAPPING_CONSTANT = 5e-6 # [m²]
|
|
34
|
+
|
|
24
35
|
|
|
25
36
|
# Animation:
|
|
26
37
|
OUTPUT_PATH_ANIMATION = False
|
|
@@ -29,10 +40,11 @@ OUTPUT_ANIMATION_FPS = 24
|
|
|
29
40
|
# Map & profiles parameters:
|
|
30
41
|
NUMBER_OF_PIXELS_X = 25
|
|
31
42
|
NUMBER_OF_PIXELS_Y = 100
|
|
32
|
-
|
|
43
|
+
IGNORE_FAULTY_PARTICLES = False
|
|
33
44
|
|
|
34
45
|
# Material parameters:
|
|
35
46
|
MEDIA = "Si"
|
|
47
|
+
MEDIA_FERMI_LEVEL = None
|
|
36
48
|
|
|
37
49
|
# Internal scattering:
|
|
38
50
|
INCLUDE_INTERNAL_SCATTERING = True
|
|
@@ -60,8 +72,8 @@ HOT_SIDE_POSITION_RIGHT = False
|
|
|
60
72
|
HOT_SIDE_POSITION_LEFT = False
|
|
61
73
|
RETHERMALIZATION_ON_HOT_SIDES = True
|
|
62
74
|
|
|
63
|
-
#
|
|
64
|
-
|
|
75
|
+
# Particle source:
|
|
76
|
+
PARTICLE_SOURCES = [Source(x=0, y=0, z=0, size_x=0, size_y=0, size_z=0, angle_distribution="random", angle=0)]
|
|
65
77
|
|
|
66
78
|
# Roughness [m]:
|
|
67
79
|
SIDE_WALL_ROUGHNESS = 2e-9
|
|
@@ -76,6 +88,7 @@ INTERFACE_ROUGHNESS = 0.2e-9
|
|
|
76
88
|
HOLES = []
|
|
77
89
|
PILLARS = []
|
|
78
90
|
INTERFACES = []
|
|
91
|
+
BULKS = []
|
|
79
92
|
|
|
80
93
|
# Multiprocessing:
|
|
81
94
|
NUMBER_OF_PROCESSES = 10
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""This module provides electron class which generates and moves an electron"""
|
|
2
|
+
|
|
3
|
+
from random import choice
|
|
4
|
+
from scipy.constants import h, electron_volt
|
|
5
|
+
from freepaths.config import cf
|
|
6
|
+
from freepaths.particle import Particle
|
|
7
|
+
from freepaths.particle_types import ParticleType
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
class Electron(Particle):
|
|
12
|
+
"""An electron particle"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, material):
|
|
15
|
+
super().__init__()
|
|
16
|
+
|
|
17
|
+
# Assign particle type
|
|
18
|
+
self.type = ParticleType.ELECTRON
|
|
19
|
+
self.is_electron_carrier = cf.is_carrier_electron # assign electron or hole behavior
|
|
20
|
+
|
|
21
|
+
source = choice(cf.particles_sources)
|
|
22
|
+
while True:
|
|
23
|
+
self.x, self.y, self.z = source.generate_coordinates()
|
|
24
|
+
is_in_hole = any(hole.is_inside(self.x, self.y, None, cf) for hole in cf.holes)
|
|
25
|
+
if not is_in_hole:
|
|
26
|
+
break
|
|
27
|
+
|
|
28
|
+
# Assign initial angles
|
|
29
|
+
self.theta, self.phi = source.generate_angles()
|
|
30
|
+
self.correct_angle()
|
|
31
|
+
if cf.is_two_dimensional_material:
|
|
32
|
+
self.phi, self.z = 0.0, 0.0
|
|
33
|
+
|
|
34
|
+
self.assign_energy()
|
|
35
|
+
self.assign_frequency(material)
|
|
36
|
+
self.assign_speed(material)
|
|
37
|
+
self.assign_internal_scattering_time(material)
|
|
38
|
+
|
|
39
|
+
def assign_energy(self):
|
|
40
|
+
"""
|
|
41
|
+
Assign energy uniformly to an electron based on temperature.
|
|
42
|
+
Conduction minimum is considered at 0 energy by convention.
|
|
43
|
+
"""
|
|
44
|
+
num_energy_points = int((cf.energy_upper_bound-cf.energy_lower_bound)/cf.energy_step)
|
|
45
|
+
# Keep energy in J for other computations
|
|
46
|
+
self.energy = np.random.choice(np.linspace(cf.energy_lower_bound, cf.energy_upper_bound - cf.energy_step, num_energy_points)) * electron_volt + cf.energy_step * electron_volt
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def wavelength(self):
|
|
51
|
+
raise Exception("Electron wavelength undefined")
|
|
52
|
+
|
|
53
|
+
def assign_frequency(self, material):
|
|
54
|
+
"""
|
|
55
|
+
Conduction minimum is 0 by convention
|
|
56
|
+
"""
|
|
57
|
+
self.f = self.energy / h
|
|
58
|
+
|
|
59
|
+
def assign_speed(self, material):
|
|
60
|
+
"""
|
|
61
|
+
Assign speed to an electron using group velocity and considering parabolic energy-k relation and conduction minimum at 0
|
|
62
|
+
"""
|
|
63
|
+
if self.is_electron_carrier:
|
|
64
|
+
effective_mass = material.effective_electron_dos_mass
|
|
65
|
+
else:
|
|
66
|
+
effective_mass = material.effective_hole_dos_mass
|
|
67
|
+
self.speed = (2*self.energy/(effective_mass))**(0.5)
|
|
68
|
+
|
|
69
|
+
def assign_internal_scattering_time(self, material):
|
|
70
|
+
"""
|
|
71
|
+
Determine relaxation time after which this particle will undergo internal scattering.
|
|
72
|
+
Considering only elasctic scattering between electrons and phonons and thus a constant MFP.
|
|
73
|
+
"""
|
|
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)
|