freepaths 2.1.2__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.
Files changed (43) hide show
  1. {freepaths-2.1.2 → freepaths-2.2}/PKG-INFO +3 -3
  2. {freepaths-2.1.2 → freepaths-2.2}/README.md +1 -1
  3. {freepaths-2.1.2 → freepaths-2.2}/freepaths/__main__.py +12 -4
  4. {freepaths-2.1.2 → freepaths-2.2}/freepaths/config.py +32 -7
  5. {freepaths-2.1.2 → freepaths-2.2}/freepaths/data.py +86 -28
  6. {freepaths-2.1.2 → freepaths-2.2}/freepaths/default_config.py +18 -4
  7. freepaths-2.2/freepaths/electron.py +77 -0
  8. {freepaths-2.1.2 → freepaths-2.2}/freepaths/flight.py +44 -19
  9. freepaths-2.2/freepaths/interface_smmm.py +143 -0
  10. {freepaths-2.1.2 → freepaths-2.2}/freepaths/main_mfp_sampling.py +16 -10
  11. {freepaths-2.1.2 → freepaths-2.2}/freepaths/main_tracing.py +75 -42
  12. {freepaths-2.1.2 → freepaths-2.2}/freepaths/maps.py +23 -24
  13. {freepaths-2.1.2 → freepaths-2.2}/freepaths/materials.py +144 -23
  14. freepaths-2.2/freepaths/move.py +23 -0
  15. {freepaths-2.1.2 → freepaths-2.2}/freepaths/output_info.py +23 -12
  16. freepaths-2.2/freepaths/output_plots.py +1125 -0
  17. {freepaths-2.1.2 → freepaths-2.2}/freepaths/output_structure.py +11 -5
  18. freepaths-2.2/freepaths/particle.py +94 -0
  19. freepaths-2.2/freepaths/particle_types.py +5 -0
  20. {freepaths-2.1.2 → freepaths-2.2}/freepaths/phonon.py +15 -26
  21. freepaths-2.2/freepaths/post_computations.py +177 -0
  22. {freepaths-2.1.2 → freepaths-2.2}/freepaths/progress.py +2 -2
  23. freepaths-2.2/freepaths/run_particle.py +86 -0
  24. {freepaths-2.1.2 → freepaths-2.2}/freepaths/scatterers.py +397 -117
  25. {freepaths-2.1.2 → freepaths-2.2}/freepaths/scattering.py +64 -47
  26. freepaths-2.2/freepaths/scattering_interfaces.py +265 -0
  27. {freepaths-2.1.2 → freepaths-2.2}/freepaths/scattering_primitives.py +84 -82
  28. {freepaths-2.1.2 → freepaths-2.2}/freepaths/scattering_semicircle.py +176 -234
  29. {freepaths-2.1.2 → freepaths-2.2}/freepaths/scattering_types.py +26 -5
  30. {freepaths-2.1.2 → freepaths-2.2}/freepaths/sources.py +8 -8
  31. {freepaths-2.1.2 → freepaths-2.2}/freepaths.egg-info/PKG-INFO +3 -3
  32. {freepaths-2.1.2 → freepaths-2.2}/freepaths.egg-info/SOURCES.txt +7 -1
  33. freepaths-2.1.2/freepaths/move.py +0 -23
  34. freepaths-2.1.2/freepaths/output_plots.py +0 -553
  35. freepaths-2.1.2/freepaths/run_phonon.py +0 -71
  36. {freepaths-2.1.2 → freepaths-2.2}/freepaths/animation.py +0 -0
  37. {freepaths-2.1.2 → freepaths-2.2}/freepaths.egg-info/dependency_links.txt +0 -0
  38. {freepaths-2.1.2 → freepaths-2.2}/freepaths.egg-info/entry_points.txt +0 -0
  39. {freepaths-2.1.2 → freepaths-2.2}/freepaths.egg-info/requires.txt +0 -0
  40. {freepaths-2.1.2 → freepaths-2.2}/freepaths.egg-info/top_level.txt +0 -0
  41. {freepaths-2.1.2 → freepaths-2.2}/pyproject.toml +0 -0
  42. {freepaths-2.1.2 → freepaths-2.2}/setup.cfg +0 -0
  43. {freepaths-2.1.2 → freepaths-2.2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: freepaths
3
- Version: 2.1.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.1.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.main(args.input_file)
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.number_of_phonons = NUMBER_OF_PHONONS
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.ignore_faulty_phonons = IGNORE_FAULTY_PHONONS
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
@@ -93,9 +105,10 @@ class Config:
93
105
  self.hot_side_position_bottom = HOT_SIDE_POSITION_BOTTOM
94
106
  self.hot_side_position_right = HOT_SIDE_POSITION_RIGHT
95
107
  self.hot_side_position_left = HOT_SIDE_POSITION_LEFT
108
+ self.rethermalization_on_hot_sides = RETHERMALIZATION_ON_HOT_SIDES
96
109
 
97
110
  # Sources:
98
- self.phonon_sources = PHONON_SOURCES
111
+ self.particles_sources = PARTICLE_SOURCES
99
112
 
100
113
  # Cold side positions:
101
114
  self.cold_side_position_top = COLD_SIDE_POSITION_TOP
@@ -116,6 +129,7 @@ class Config:
116
129
  self.holes = HOLES
117
130
  self.pillars = PILLARS
118
131
  self.interfaces = INTERFACES
132
+ self.bulks = BULKS
119
133
 
120
134
  # Multiprocessing:
121
135
  self.num_workers = NUMBER_OF_PROCESSES
@@ -125,7 +139,7 @@ class Config:
125
139
 
126
140
  # Distributions:
127
141
  valid_distributions =[member.name.lower() for member in Distributions]
128
- for source in self.phonon_sources:
142
+ for source in self.particles_sources:
129
143
  if source.angle_distribution in valid_distributions:
130
144
  source.angle_distribution = Distributions[source.angle_distribution.upper()]
131
145
  else:
@@ -135,8 +149,8 @@ class Config:
135
149
 
136
150
  def check_parameter_validity(self):
137
151
  """Check if various parameters are valid"""
138
- if self.number_of_phonons < self.output_trajectories_of_first:
139
- self.output_trajectories_of_first = self.number_of_phonons
152
+ if self.number_of_particles < self.output_trajectories_of_first:
153
+ self.output_trajectories_of_first = self.number_of_particles
140
154
 
141
155
  if self.number_of_timeframes <= self.number_of_stabilization_timeframes:
142
156
  logging.error("Parameter NUMBER_OF_STABILIZATION_TIMEFRAMES exceeds or equal to NUMBER_OF_TIMEFRAMES.\n" +
@@ -144,7 +158,7 @@ class Config:
144
158
  f"See the documentation at {WEBSITE}")
145
159
  sys.exit()
146
160
 
147
- for source in self.phonon_sources:
161
+ for source in self.particles_sources:
148
162
  if source.y > self.length:
149
163
  logging.error("Y coordinate of a source exceeded LENGHT")
150
164
  sys.exit()
@@ -231,7 +245,18 @@ class Config:
231
245
  f"See the documentation at {WEBSITE}")
232
246
  sys.exit()
233
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
+
234
258
  cf = Config()
235
259
  cf.convert_to_enums()
236
260
  cf.check_parameter_validity()
237
261
  cf.check_depricated_parameters()
262
+
@@ -15,26 +15,30 @@ class Data:
15
15
 
16
16
 
17
17
  class PathData(Data):
18
- """Paths of phonons in space"""
18
+ """Paths of particles in space"""
19
19
 
20
20
  def __init__(self):
21
- """Initialize arrays to save phonon paths"""
22
- self.phonon_paths = []
21
+ """Initialize arrays to save particle paths"""
22
+ self.particle_paths = []
23
23
 
24
- def save_phonon_path(self, flight):
24
+ def save_particle_path(self, flight):
25
25
  """Save the path to list of all paths"""
26
- self.phonon_paths.append(flight.path)
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.phonon_paths])
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
- filename = "Data/Phonon paths.csv"
36
- data = np.zeros((self.length_of_longest_path, 3*len(self.phonon_paths)))
37
- for index, path in enumerate(self.phonon_paths):
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 {'phonon_paths': self.phonon_paths}
50
+ return {'particle_paths': self.particle_paths}
47
51
 
48
52
 
49
53
  class GeneralData(Data):
50
- """General statistics of various phonon properties"""
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
- def save_phonon_data(self, ph):
67
- """Add information about the phonon to the dataset"""
68
- self.frequencies.append(ph.f)
69
- self.group_velocities.append(ph.speed)
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 phonon flight to the dataset"""
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
- np.savetxt("Data/All free paths.csv", self.free_paths, fmt='%2.4e', header="L [m]", encoding='utf-8')
86
- np.savetxt("Data/All free paths in plane.csv", self.free_paths_along_y, fmt='%2.4e', header="Ly [m]", encoding='utf-8')
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 phonon scattering events"""
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)).T
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
- header = header1 + header2
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 phonon scattering events on triangular holes"""
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 phonon stays in different segments"""
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
- NUMBER_OF_PHONONS = 5000
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
- IGNORE_FAULTY_PHONONS = False
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
@@ -58,9 +70,10 @@ HOT_SIDE_POSITION_TOP = False
58
70
  HOT_SIDE_POSITION_BOTTOM = True
59
71
  HOT_SIDE_POSITION_RIGHT = False
60
72
  HOT_SIDE_POSITION_LEFT = False
73
+ RETHERMALIZATION_ON_HOT_SIDES = True
61
74
 
62
- # Phonon source:
63
- PHONON_SOURCES = [Source(x=0, y=0, z=0, size_x=0, size_y=0, size_z=0, angle_distribution="random", angle=0)]
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)]
64
77
 
65
78
  # Roughness [m]:
66
79
  SIDE_WALL_ROUGHNESS = 2e-9
@@ -75,6 +88,7 @@ INTERFACE_ROUGHNESS = 0.2e-9
75
88
  HOLES = []
76
89
  PILLARS = []
77
90
  INTERFACES = []
91
+ BULKS = []
78
92
 
79
93
  # Multiprocessing:
80
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)