freepaths 1.9.2__tar.gz → 2.0__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 (34) hide show
  1. {freepaths-1.9.2 → freepaths-2.0}/PKG-INFO +1 -1
  2. {freepaths-1.9.2 → freepaths-2.0}/freepaths/__main__.py +1 -1
  3. {freepaths-1.9.2 → freepaths-2.0}/freepaths/config.py +5 -1
  4. {freepaths-1.9.2 → freepaths-2.0}/freepaths/data.py +55 -0
  5. {freepaths-1.9.2 → freepaths-2.0}/freepaths/flight.py +10 -0
  6. {freepaths-1.9.2 → freepaths-2.0}/freepaths/holes.py +7 -2
  7. {freepaths-1.9.2 → freepaths-2.0}/freepaths/main_tracing.py +7 -2
  8. {freepaths-1.9.2 → freepaths-2.0}/freepaths/maps.py +1 -1
  9. {freepaths-1.9.2 → freepaths-2.0}/freepaths/materials.py +1 -1
  10. {freepaths-1.9.2 → freepaths-2.0}/freepaths/output_info.py +28 -28
  11. {freepaths-1.9.2 → freepaths-2.0}/freepaths/output_plots.py +74 -30
  12. {freepaths-1.9.2 → freepaths-2.0}/freepaths/run_phonon.py +14 -3
  13. {freepaths-1.9.2 → freepaths-2.0}/freepaths/scattering.py +1 -1
  14. {freepaths-1.9.2 → freepaths-2.0}/freepaths/scattering_primitives.py +60 -70
  15. {freepaths-1.9.2 → freepaths-2.0}/freepaths/scattering_types.py +34 -1
  16. {freepaths-1.9.2 → freepaths-2.0}/freepaths.egg-info/PKG-INFO +1 -1
  17. {freepaths-1.9.2 → freepaths-2.0}/README.md +0 -0
  18. {freepaths-1.9.2 → freepaths-2.0}/freepaths/animation.py +0 -0
  19. {freepaths-1.9.2 → freepaths-2.0}/freepaths/default_config.py +0 -0
  20. {freepaths-1.9.2 → freepaths-2.0}/freepaths/main_mfp_sampling.py +0 -0
  21. {freepaths-1.9.2 → freepaths-2.0}/freepaths/move.py +0 -0
  22. {freepaths-1.9.2 → freepaths-2.0}/freepaths/output_structure.py +0 -0
  23. {freepaths-1.9.2 → freepaths-2.0}/freepaths/phonon.py +0 -0
  24. {freepaths-1.9.2 → freepaths-2.0}/freepaths/progress.py +0 -0
  25. {freepaths-1.9.2 → freepaths-2.0}/freepaths/scattering_semicircle.py +0 -0
  26. {freepaths-1.9.2 → freepaths-2.0}/freepaths/sources.py +0 -0
  27. {freepaths-1.9.2 → freepaths-2.0}/freepaths.egg-info/SOURCES.txt +0 -0
  28. {freepaths-1.9.2 → freepaths-2.0}/freepaths.egg-info/dependency_links.txt +0 -0
  29. {freepaths-1.9.2 → freepaths-2.0}/freepaths.egg-info/entry_points.txt +0 -0
  30. {freepaths-1.9.2 → freepaths-2.0}/freepaths.egg-info/requires.txt +0 -0
  31. {freepaths-1.9.2 → freepaths-2.0}/freepaths.egg-info/top_level.txt +0 -0
  32. {freepaths-1.9.2 → freepaths-2.0}/pyproject.toml +0 -0
  33. {freepaths-1.9.2 → freepaths-2.0}/setup.cfg +0 -0
  34. {freepaths-1.9.2 → freepaths-2.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: freepaths
3
- Version: 1.9.2
3
+ Version: 2.0
4
4
  Summary: Phonon Monte Carlo simulator
5
5
  Home-page: https://github.com/anufrievroman/freepaths
6
6
  Author: Roman Anufriev
@@ -7,7 +7,7 @@ from colorama import Fore, Style
7
7
  import freepaths.main_tracing
8
8
  import freepaths.main_mfp_sampling
9
9
 
10
- __version__ = "1.9.2"
10
+ __version__ = "2.0"
11
11
 
12
12
  colorama.init()
13
13
 
@@ -29,7 +29,11 @@ args = parser.parse_args()
29
29
 
30
30
  # If a file is provided, overwrite the default values:
31
31
  if args.input_file:
32
- exec(open(args.input_file, encoding='utf-8').read(), globals())
32
+ try:
33
+ exec(open(args.input_file, encoding='utf-8').read(), globals())
34
+ except FileNotFoundError:
35
+ logging.error("Input file does not exist. Check if you are in the right folder and the file name is correct.")
36
+ sys.exit()
33
37
  else:
34
38
  logging.warning("You provided no input file, so we will run a demo simulation:")
35
39
 
@@ -53,6 +53,8 @@ class GeneralData(Data):
53
53
  """Initialize arrays for writing various properties"""
54
54
  self.initial_angles = []
55
55
  self.exit_angles = []
56
+ self.hole_diff_scattering_angles = []
57
+ self.hole_spec_scattering_angles = []
56
58
  self.free_paths = []
57
59
  self.free_paths_along_y = []
58
60
  self.frequencies = []
@@ -71,6 +73,8 @@ class GeneralData(Data):
71
73
  self.initial_angles.append(flight.initial_theta)
72
74
  self.exit_angles.append(flight.exit_theta)
73
75
  self.free_paths.extend(flight.free_paths)
76
+ self.hole_diff_scattering_angles.extend(flight.hole_diff_scattering_angles)
77
+ self.hole_spec_scattering_angles.extend(flight.hole_spec_scattering_angles)
74
78
  self.free_paths_along_y.extend(flight.free_paths_along_y)
75
79
  self.travel_times.append(flight.travel_time)
76
80
  self.mean_free_paths.append(flight.mean_free_path)
@@ -82,6 +86,8 @@ class GeneralData(Data):
82
86
  np.savetxt("Data/All free paths in plane.csv", self.free_paths_along_y, fmt='%2.4e', header="Ly [m]", encoding='utf-8')
83
87
  np.savetxt("Data/All initial frequencies.csv", self.frequencies, fmt='%2.4e', header="f [Hz]", encoding='utf-8')
84
88
  np.savetxt("Data/All exit angles.csv", self.exit_angles, fmt='%.4f', header="Angle [rad]", encoding='utf-8')
89
+ np.savetxt("Data/All hole diffuse scattering angles.csv", self.hole_diff_scattering_angles, fmt='%.4f', header="Angle [rad]", encoding='utf-8')
90
+ np.savetxt("Data/All hole specular scattering angles.csv", self.hole_spec_scattering_angles, fmt='%.4f', header="Angle [rad]", encoding='utf-8')
85
91
  np.savetxt("Data/All initial angles.csv", self.initial_angles, fmt='%.4f', header="Angle [rad]", encoding='utf-8')
86
92
  np.savetxt("Data/All group velocities.csv", self.group_velocities, fmt='%.4f', header="Vg [m//s]", encoding='utf-8')
87
93
  np.savetxt("Data/All travel times.csv", self.travel_times, fmt='%2.4e', header="Travel time [s]", encoding='utf-8')
@@ -93,6 +99,8 @@ class GeneralData(Data):
93
99
  return {
94
100
  'initial_angles': self.initial_angles,
95
101
  'exit_angles': self.exit_angles,
102
+ 'hole_diff_scattering_angles': self.hole_diff_scattering_angles,
103
+ 'hole_spec_scattering_angles': self.hole_spec_scattering_angles,
96
104
  'free_paths': self.free_paths,
97
105
  'free_paths_along_y': self.free_paths_along_y,
98
106
  'frequencies': self.frequencies,
@@ -177,6 +185,53 @@ class ScatteringData(Data):
177
185
  }
178
186
 
179
187
 
188
+ class TriangleScatteringData(Data):
189
+ """Statistics of phonon scattering events on triangular holes"""
190
+
191
+ def __init__(self):
192
+ """Initialize arrays according to the number of segments"""
193
+ self.right_wall_diffuse = 0
194
+ self.right_wall_specular = 0
195
+ self.left_wall_diffuse = 0
196
+ self.left_wall_specular = 0
197
+ self.floor_diffuse = 0
198
+ self.floor_specular = 0
199
+
200
+ def save_scattering_events(self, y, triangle_scattering_places):
201
+ """Analyze types of scattering at the current timestep and add it to the statistics"""
202
+
203
+ try:
204
+ self.right_wall_diffuse += 1 if triangle_scattering_places.right_wall == Scattering.DIFFUSE else 0
205
+ self.right_wall_specular += 1 if triangle_scattering_places.right_wall == Scattering.SPECULAR else 0
206
+ self.left_wall_diffuse += 1 if triangle_scattering_places.left_wall == Scattering.DIFFUSE else 0
207
+ self.left_wall_specular += 1 if triangle_scattering_places.left_wall == Scattering.SPECULAR else 0
208
+ self.floor_diffuse += 1 if triangle_scattering_places.floor == Scattering.DIFFUSE else 0
209
+ self.floor_specular += 1 if triangle_scattering_places.floor == Scattering.SPECULAR else 0
210
+ except:
211
+ pass
212
+
213
+ def write_into_files(self):
214
+ """Write data into a file"""
215
+ filename = "Data/Triangle scattering statistics.csv"
216
+ data = np.vstack(np.array([self.right_wall_diffuse, self.right_wall_specular,
217
+ self.left_wall_diffuse, self.left_wall_specular,
218
+ self.floor_diffuse, self.floor_specular])).T
219
+ header = "Inclined right diffuse, Inclinded right specular, Inclined left diffuse, Inclinded left specular, Floor diffuse, Floor specular"
220
+ np.savetxt(filename, data, fmt='%1.3e', delimiter=",", header=header, encoding='utf-8')
221
+
222
+ def dump_data(self):
223
+ """Return data of a process in the form of a dictionary to be attached to the global data"""
224
+ return {
225
+ 'right_wall_diffuse': self.right_wall_diffuse,
226
+ 'right_wall_specular': self.right_wall_specular,
227
+ 'left_wall_diffuse': self.left_wall_diffuse,
228
+ 'left_wall_specular': self.left_wall_specular,
229
+ 'floor_diffuse': self.floor_diffuse,
230
+ 'floor_specular': self.floor_specular,
231
+ }
232
+
233
+
234
+
180
235
  class SegmentData(Data):
181
236
  """Statistics of events happening in different segments"""
182
237
 
@@ -40,6 +40,8 @@ class Flight:
40
40
  self.travel_time = 0.0
41
41
  self.time_since_previous_scattering = 0.0
42
42
  self.free_paths = []
43
+ self.hole_diff_scattering_angles = []
44
+ self.hole_spec_scattering_angles = []
43
45
  self.free_paths_along_y = []
44
46
  self.thermal_conductivity = 0.0
45
47
 
@@ -61,6 +63,14 @@ class Flight:
61
63
  self.free_paths.append(self.free_path)
62
64
  self.free_paths_along_y.append(self.free_path_along_y)
63
65
 
66
+ def save_hole_diff_scattering_angle(self, angle):
67
+ """Save angle of diffuse scattering from the hole"""
68
+ self.hole_diff_scattering_angles.append(angle)
69
+
70
+ def save_hole_spec_scattering_angle(self, angle):
71
+ """Save angle of specular scattering from the hole"""
72
+ self.hole_spec_scattering_angles.append(angle)
73
+
64
74
  def restart(self):
65
75
  """Restart the flight after a scattering event"""
66
76
  self.time_since_previous_scattering = 0.0
@@ -103,11 +103,11 @@ class RectangularHole(Hole):
103
103
 
104
104
  # Scattering on the top wall:
105
105
  elif y > self.y0:
106
- scattering_types.holes = horizontal_surface_up_scattering(ph, cf.side_wall_roughness)
106
+ scattering_types.holes = horizontal_surface_up_scattering(ph, cf.hole_roughness)
107
107
 
108
108
  # Scattering on the bottom wall:
109
109
  else:
110
- scattering_types.holes = horizontal_surface_down_scattering(ph, cf.side_wall_roughness)
110
+ scattering_types.holes = horizontal_surface_down_scattering(ph, cf.hole_roughness)
111
111
 
112
112
  def get_patch(self, color_holes, cf):
113
113
  """Create a patch in the shape of the hole to use in the plots"""
@@ -140,11 +140,16 @@ class TriangularUpHole(Hole):
140
140
  # Scattering on the bottom wall of the triangle:
141
141
  if (ph.y < self.y0 - self.size_y / 2) and (abs(ph.theta) < pi / 2):
142
142
  scattering_types.holes = horizontal_surface_down_scattering(ph, cf.hole_roughness)
143
+ # triangle_scattering_places.floor = scattering_types.holes
143
144
 
144
145
  # Scattering on the sidewalls of the triangle:
145
146
  else:
146
147
  beta = atan(0.5 * self.size_x / self.size_y)
147
148
  scattering_types.holes = inclined_surfaces_up_scattering(ph, beta, x, self.x0, cf.hole_roughness)
149
+ # if x > self.x0:
150
+ # triangle_scattering_places.right_wall = scattering_types.holes
151
+ # else:
152
+ # triangle_scattering_places.left_wall = scattering_types.holes
148
153
 
149
154
  def get_patch(self, color_holes, cf):
150
155
  """Create a patch in the shape of the hole to use in the plots"""
@@ -14,7 +14,7 @@ from freepaths.config import cf
14
14
  from freepaths.run_phonon import run_phonon
15
15
  from freepaths.phonon import Phonon
16
16
  from freepaths.flight import Flight
17
- from freepaths.data import ScatteringData, GeneralData, SegmentData, PathData
17
+ from freepaths.data import ScatteringData, GeneralData, SegmentData, PathData, TriangleScatteringData
18
18
  from freepaths.progress import Progress
19
19
  from freepaths.materials import Si, SiC, Graphite
20
20
  from freepaths.maps import ScatteringMap, ThermalMaps
@@ -54,6 +54,7 @@ class PhononSimulator:
54
54
  self.general_stats = GeneralData()
55
55
  self.segment_stats = SegmentData()
56
56
  self.path_stats = PathData()
57
+ self.places_stats = TriangleScatteringData()
57
58
  self.scatter_maps = ScatteringMap()
58
59
  self.thermal_maps = ThermalMaps()
59
60
 
@@ -65,7 +66,7 @@ class PhononSimulator:
65
66
  flight = Flight(phonon)
66
67
 
67
68
  # Run this phonon through the structure:
68
- run_phonon(phonon, flight, self.scatter_stats, self.segment_stats, self.thermal_maps, self.scatter_maps, self.material)
69
+ run_phonon(phonon, flight, self.scatter_stats, self.places_stats, self.segment_stats, self.thermal_maps, self.scatter_maps, self.material)
69
70
 
70
71
  # Record the properties returned for this phonon:
71
72
  self.general_stats.save_phonon_data(phonon)
@@ -97,6 +98,7 @@ class PhononSimulator:
97
98
  collected_data = {
98
99
  'scatter_stats': self.scatter_stats.dump_data(),
99
100
  'general_stats': self.general_stats.dump_data(),
101
+ 'places_stats': self.places_stats.dump_data(),
100
102
  'segment_stats': self.segment_stats.dump_data(),
101
103
  'path_stats': self.path_stats.dump_data(),
102
104
  'scatter_maps': self.scatter_maps.dump_data(),
@@ -180,6 +182,7 @@ def main(input_file):
180
182
  # Initiate data structures to collect the data from the workers:
181
183
  # material = Material(cf.media, num_points=cf.number_of_phonons+1)
182
184
  scatter_stats = ScatteringData()
185
+ places_stats = TriangleScatteringData()
183
186
  general_stats = GeneralData()
184
187
  segment_stats = SegmentData()
185
188
  path_stats = PathData()
@@ -200,6 +203,7 @@ def main(input_file):
200
203
  execution_time_list = []
201
204
  for collected_data in result_list:
202
205
  scatter_stats.read_data(collected_data['scatter_stats'])
206
+ places_stats.read_data(collected_data['places_stats'])
203
207
  general_stats.read_data(collected_data['general_stats'])
204
208
  segment_stats.read_data(collected_data['segment_stats'])
205
209
  path_stats.read_data(collected_data['path_stats'])
@@ -235,6 +239,7 @@ def main(input_file):
235
239
  sys.stdout.write("\rSaving raw data...")
236
240
  general_stats.write_into_files()
237
241
  scatter_stats.write_into_files()
242
+ places_stats.write_into_files()
238
243
  segment_stats.write_into_files()
239
244
  thermal_maps.write_into_files()
240
245
  scatter_maps.write_into_files()
@@ -67,7 +67,7 @@ class ScatteringMap(Maps):
67
67
 
68
68
  # Save into file:
69
69
  header = "Specular X, Specular Y, Diffuse X, Diffuse Y, Internal X, Internal Y"
70
- np.savetxt("Data/Scattering map.csv", data, fmt='%1.2e', delimiter=",", header=header, encoding='utf-8')
70
+ np.savetxt("Data/Scattering map.csv", data, fmt='%1.3e', delimiter=",", header=header, encoding='utf-8')
71
71
 
72
72
  def dump_data(self):
73
73
  """Return data of a process in the form of a dictionary to be attached to the global data"""
@@ -40,7 +40,7 @@ class Si:
40
40
 
41
41
  def assign_heat_capacity(self):
42
42
  """Calculate heat capacity [J/kg/K] in 3 - 300K range using the polynomial fits"""
43
- below_20K_coeffs = np.array([0.00055196, -0.0052611, 0.03086194, -0.05493787])
43
+ below_20K_coeffs = np.array([0.00044801, -0.00239681, 0.00756769])
44
44
  between_20_and_50K_coeffs = np.array([-9.26222400e-04, 1.49879304e-01, -4.37458293e+00, 3.84245589e+01])
45
45
  above_50K_coeffs = np.array([-2.75839317e-06, -5.16662077e-03, 4.66701391e+00, -1.49876958e+02])
46
46
  if self.temp < 20:
@@ -46,55 +46,55 @@ def output_scattering_information(scatter_stats):
46
46
  total_hole = np.sum(scatter_stats.hole_diffuse) + np.sum(scatter_stats.hole_specular)
47
47
  total_pill = np.sum(scatter_stats.pillar_diffuse) + np.sum(scatter_stats.pillar_specular)
48
48
 
49
- scat_on_walls = 100*(np.sum(scatter_stats.wall_diffuse) +
49
+ sc_on_walls = 100*(np.sum(scatter_stats.wall_diffuse) +
50
50
  np.sum(scatter_stats.wall_specular)) / total
51
- scat_on_walls_diff = 100*np.sum(scatter_stats.wall_diffuse) / total_wall
52
- scat_on_walls_spec = 100*np.sum(scatter_stats.wall_specular) / total_wall
51
+ sc_on_walls_diff = 100*np.sum(scatter_stats.wall_diffuse) / total_wall
52
+ sc_on_walls_spec = 100*np.sum(scatter_stats.wall_specular) / total_wall
53
53
 
54
- scat_on_topbot = 100*(np.sum(scatter_stats.top_diffuse) +
54
+ sc_on_topbot = 100*(np.sum(scatter_stats.top_diffuse) +
55
55
  np.sum(scatter_stats.top_specular)) / total
56
56
 
57
57
  if total_topbot != 0:
58
- scat_on_topbot_diff = 100*np.sum(scatter_stats.top_diffuse) / total_topbot
59
- scat_on_topbot_spec = 100*np.sum(scatter_stats.top_specular) / total_topbot
58
+ sc_on_topbot_diff = 100*np.sum(scatter_stats.top_diffuse) / total_topbot
59
+ sc_on_topbot_spec = 100*np.sum(scatter_stats.top_specular) / total_topbot
60
60
  else:
61
- scat_on_topbot_diff = 0
62
- scat_on_topbot_spec = 0
61
+ sc_on_topbot_diff = 0
62
+ sc_on_topbot_spec = 0
63
63
 
64
64
  retherm = 100*np.sum(scatter_stats.hot_side) / total
65
65
  internal = 100*np.sum(scatter_stats.internal) / total
66
66
 
67
67
  info1 = (
68
- f'\n{scat_on_walls:.2f}% - scattering on side walls ',
69
- f'({scat_on_walls_diff:.2f}% - diffuse, ',
70
- f'{scat_on_walls_spec:.2f}% - specular)',
71
- f'\n{scat_on_topbot:.2f}% - scattering on top and bottom walls ',
72
- f'({scat_on_topbot_diff:.2f}% - diffuse, ',
73
- f'{scat_on_topbot_spec:.2f}% - specular)',
68
+ f'\n{sc_on_walls:.2f}% - scattering on side walls ',
69
+ f'({sc_on_walls_diff:.2f}% - diffuse, ',
70
+ f'{sc_on_walls_spec:.2f}% - specular)',
71
+ f'\n{sc_on_topbot:.2f}% - scattering on top and bottom walls ',
72
+ f'({sc_on_topbot_diff:.2f}% - diffuse, ',
73
+ f'{sc_on_topbot_spec:.2f}% - specular)',
74
74
  f'\n{retherm:.2f}% - rethermalization at the hot side',
75
75
  f'\n{internal:.2f}% - internal scattering processes',
76
76
  )
77
77
 
78
78
  if cf.holes:
79
- scat_on_holes = 100*(np.sum(scatter_stats.hole_diffuse) +
79
+ sc_on_holes = 100*(np.sum(scatter_stats.hole_diffuse) +
80
80
  np.sum(scatter_stats.hole_specular)) / total
81
- scat_on_holes_diff = 100*np.sum(scatter_stats.hole_diffuse) / total_hole
82
- scat_on_holes_spec = 100*np.sum(scatter_stats.hole_specular) / total_hole
81
+ sc_on_holes_diff = 100*np.sum(scatter_stats.hole_diffuse) / total_hole
82
+ sc_on_holes_spec = 100*np.sum(scatter_stats.hole_specular) / total_hole
83
83
  info2 = (
84
- f'\n{scat_on_holes:.2f}% - scattering on hole walls ',
85
- f'({scat_on_holes_diff:.2f}% - diffuse, ',
86
- f'{scat_on_holes_spec:.2f}% - specular)',
84
+ f'\n{sc_on_holes:.2f}% - scattering on hole walls ',
85
+ f'({sc_on_holes_diff:.2f}% - diffuse, ',
86
+ f'{sc_on_holes_spec:.2f}% - specular)',
87
87
  )
88
88
 
89
89
  if cf.pillars:
90
- scat_on_pill = 100*(np.sum(scatter_stats.pillar_diffuse) +
90
+ sc_on_pill = 100*(np.sum(scatter_stats.pillar_diffuse) +
91
91
  np.sum(scatter_stats.pillar_specular)) / total
92
- scat_on_pill_diff = 100*np.sum(scatter_stats.pillar_diffuse) / total_pill
93
- scat_on_pill_spec = 100*np.sum(scatter_stats.pillar_specular) / total_pill
92
+ sc_on_pill_diff = 100*np.sum(scatter_stats.pillar_diffuse) / total_pill
93
+ sc_on_pill_spec = 100*np.sum(scatter_stats.pillar_specular) / total_pill
94
94
  info3 = (
95
- f'\n{scat_on_pill:.2f}% - scattering on pillar walls ',
96
- f'({scat_on_pill_diff:.2f}% - diffuse, ',
97
- f'{scat_on_pill_spec:.2f}% - specular)'
95
+ f'\n{sc_on_pill:.2f}% - scattering on pillar walls ',
96
+ f'({sc_on_pill_diff:.2f}% - diffuse, ',
97
+ f'{sc_on_pill_spec:.2f}% - specular)'
98
98
  )
99
99
 
100
100
  # Write info into a text file:
@@ -116,7 +116,7 @@ def output_parameter_warnings():
116
116
  long_travel_times = travel_times[travel_times > time_of_stabilization]
117
117
  percentage = (len(long_travel_times) / len(travel_times)) * 100
118
118
  if percentage > 10:
119
- logging.warning("Travel time of {percentage}% of phonons was longer than the stabilization period.\n" +
119
+ logging.warning(f"Travel time of {percentage}% of phonons was longer than the stabilization period.\n" +
120
120
  "Increase stabilization period as the thermal conductivity might be incorrect.")
121
121
 
122
122
  # Check if pixel size is too small:
@@ -129,4 +129,4 @@ def output_parameter_warnings():
129
129
  # Check how many phonons reached the cold side during simulation:
130
130
  percentage = int(100 * np.count_nonzero(travel_times) / cf.number_of_phonons)
131
131
  if percentage < 95:
132
- logging.warning("Only {percentage}% of phonons reached the cold side. Increase number of timesteps.")
132
+ logging.warning(f"Only {percentage}% of phonons reached the cold side. Increase number of timesteps.")
@@ -1,5 +1,7 @@
1
1
  """Module that calculates and outputs vaious plots and distributions from the saved files"""
2
2
 
3
+ import logging
4
+ import sys
3
5
  import numpy as np
4
6
  import matplotlib.pyplot as plt
5
7
  import matplotlib.patches as patches
@@ -17,7 +19,7 @@ if 'Arial' in all_fonts:
17
19
  plt.rcParams['font.family'] = 'Arial'
18
20
  else:
19
21
  # Use a generic font or specify multiple options
20
- print('Warning: Arial font not available. Falling back on other sans-serif font')
22
+ logging.warning("Arial font not available. Falling back on default sans-serif font")
21
23
  plt.rcParams['font.family'] = ['sans-serif']
22
24
  plt.rcParams['axes.titlesize'] = 10
23
25
  plt.rcParams['axes.labelsize'] = 10
@@ -35,6 +37,7 @@ plt.rcParams['figure.figsize'] = [5, 3.5]
35
37
  plt.rcParams['figure.dpi'] = 300
36
38
  plt.rcParams['savefig.dpi'] = 300
37
39
  plt.rcParams['legend.fontsize'] = 8
40
+ plt.rcParams['grid.linewidth'] = 0.5
38
41
 
39
42
 
40
43
  def distribution_calculation(filename, data_range, number_of_nodes):
@@ -52,6 +55,8 @@ def angle_distribution_calculation():
52
55
  """Analyse measured phonon angles and create their distribution"""
53
56
  all_exit_angles = np.loadtxt("Data/All exit angles.csv", dtype='float', encoding='utf-8')
54
57
  initial_angles = np.loadtxt("Data/All initial angles.csv", dtype='float', encoding='utf-8')
58
+ hole_diff_angles = np.loadtxt("Data/All hole diffuse scattering angles.csv", dtype='float', encoding='utf-8')
59
+ hole_spec_angles = np.loadtxt("Data/All hole specular scattering angles.csv", dtype='float', encoding='utf-8')
55
60
  distribution = np.zeros((360, 3))
56
61
  distribution[:, 0] = range(-180, 180)
57
62
  exit_angles = all_exit_angles[all_exit_angles != 0]
@@ -60,6 +65,17 @@ def angle_distribution_calculation():
60
65
  return distribution
61
66
 
62
67
 
68
+ def scattering_angle_distribution_calculation():
69
+ """Analyse scattering phonon angles and create their distribution"""
70
+ hole_diff_angles = np.loadtxt("Data/All hole diffuse scattering angles.csv", dtype='float', encoding='utf-8')
71
+ hole_spec_angles = np.loadtxt("Data/All hole specular scattering angles.csv", dtype='float', encoding='utf-8')
72
+ distribution = np.zeros((360, 3))
73
+ distribution[:, 0] = range(-180, 180)
74
+ distribution[:, 1], _ = np.histogram(np.degrees(hole_diff_angles), 360, range=(-180, 180))
75
+ distribution[:, 2], _ = np.histogram(np.degrees(hole_spec_angles), 360, range=(-180, 180))
76
+ return distribution
77
+
78
+
63
79
  def wavelength_distribution_calculation(number_of_nodes):
64
80
  """Calculate phonon wavelength distribution from their frequencies and velocities"""
65
81
  frequencies = np.loadtxt("Data/All initial frequencies.csv", encoding='utf-8')
@@ -100,7 +116,7 @@ def plot_cumulative_thermal_conductivity(mfp_sampling):
100
116
 
101
117
 
102
118
  def plot_angle_distribution():
103
- """Plot distribution of angles"""
119
+ """Plot distribution of initial and exit angles"""
104
120
  angle_distributions = angle_distribution_calculation()
105
121
  fig, ax = plt.subplots()
106
122
  ax.plot(angle_distributions[:, 0], angle_distributions[:, 1], 'royalblue')
@@ -114,6 +130,24 @@ def plot_angle_distribution():
114
130
  np.savetxt('Data/Distribution of angles.csv', angle_distributions, fmt='%1.3e', delimiter=",")
115
131
 
116
132
 
133
+ def plot_scattering_angle_distribution():
134
+ """Plot distribution of hole scattering angles"""
135
+ angle_distributions = scattering_angle_distribution_calculation()
136
+ fig, ax = plt.subplots(subplot_kw={'projection': 'polar'})
137
+ ax.grid(zorder=0)
138
+ ax.plot(np.deg2rad(angle_distributions[:, 0]), angle_distributions[:, 1], 'royalblue', label="Diffuse", zorder=2)
139
+ ax.fill_between(np.deg2rad(angle_distributions[:, 0]), angle_distributions[:, 1], 0, alpha=0.2, zorder=2)
140
+ ax.plot(np.deg2rad(angle_distributions[:, 0]), angle_distributions[:, 2], 'deeppink', label="Specular", zorder=3)
141
+ ax.fill_between(np.deg2rad(angle_distributions[:, 0]), angle_distributions[:, 2], 0, alpha=0.2, zorder=3)
142
+ ax.set_theta_zero_location('N')
143
+ ax.set_theta_direction(-1)
144
+ ax.legend(facecolor='white', framealpha=1, ncols=2, loc="lower center", bbox_to_anchor=(0.5, -0.17))
145
+ ax.set_title('Number of scattered phonons per angle')
146
+ fig.savefig("Distribution of hole scattering angles.pdf", format='pdf', bbox_inches="tight")
147
+ plt.close(fig)
148
+ np.savetxt('Data/Distribution of hole scattering angles.csv', angle_distributions, fmt='%1.3e', delimiter=",")
149
+
150
+
117
151
  def plot_free_path_distribution():
118
152
  """Plot distribution of free path"""
119
153
  filename = "Data/All free paths.csv"
@@ -227,16 +261,16 @@ def plot_thermal_conductivity():
227
261
  ax.add_patch(rectangle_mat)
228
262
 
229
263
  # Plot the averaged values in the averaging range:
230
- ax.plot([av_start, av_end], [av_mat_tc, av_mat_tc], '-', markersize=2, linewidth=2, color='deeppink', label='$\overline{\kappa}_{mat}$')
231
- ax.plot([av_start, av_end], [av_eff_tc, av_eff_tc], '-', markersize=2, linewidth=2, color='royalblue', label='$\overline{\kappa}_{eff}$')
264
+ ax.plot([av_start, av_end], [av_mat_tc, av_mat_tc], '-', markersize=2, linewidth=2, color='deeppink', label=r'$\overline{\kappa}_{mat}$')
265
+ ax.plot([av_start, av_end], [av_eff_tc, av_eff_tc], '-', markersize=2, linewidth=2, color='royalblue', label=r'$\overline{\kappa}_{eff}$')
232
266
 
233
267
  ax.set_ylabel('Thermal conductivity (W/m·K)')
234
268
  ax.set_xlabel('Time (ns)')
235
269
 
236
270
  ax.set_xlim(left=0.0)
237
271
  ax.legend()
238
- kappa_mat_str = "$\overline{\kappa}_{mat}$"
239
- kappa_eff_str = "$\overline{\kappa}_{eff}$"
272
+ kappa_mat_str = r"$\overline{\kappa}_{mat}$"
273
+ kappa_eff_str = r"$\overline{\kappa}_{eff}$"
240
274
  ax.set_title(f'{kappa_mat_str} = {av_mat_tc} ± {std_mat_tc} W/m·K, {kappa_eff_str} = {av_eff_tc} ± {std_eff_tc} W/m·K', color='grey')
241
275
  fig.savefig("Thermal conductivity.pdf", format='pdf', bbox_inches="tight")
242
276
  plt.close(fig)
@@ -312,7 +346,7 @@ def plot_heat_flux_map(file, label, units="a.u."):
312
346
  fig = plt.figure()
313
347
  heat_flux_map = np.genfromtxt(file, unpack=False, delimiter=',', skip_header=0, encoding='utf-8')
314
348
  heat_flux_map = np.flipud(heat_flux_map)
315
- minimum_of_colorbar = 1e6
349
+ minimum_of_colorbar = 1e5
316
350
  boundaries = [(-cf.width / 2) * 1e6, (cf.width / 2) * 1e6, 0, cf.length * 1e6]
317
351
  plt.imshow(heat_flux_map, cmap='jet', interpolation='none', extent=boundaries,
318
352
  norm=LogNorm(vmin=minimum_of_colorbar, vmax=np.amax(heat_flux_map)))
@@ -456,7 +490,7 @@ def plot_material_properties():
456
490
  elif cf.media == "Graphite":
457
491
  material = Graphite(cf.temp)
458
492
  else:
459
- print(f"Material {cf.media} is not supported")
493
+ logging.error(f"Material {cf.media} is not supported")
460
494
  sys.exit()
461
495
 
462
496
  # Plot phonon dispersion:
@@ -469,35 +503,45 @@ def plot_material_properties():
469
503
  ax.set_xlim(left=0)
470
504
 
471
505
  # Add material properties:
472
- ax.set_title(f'{material.name}, T = {cf.temp} K, C$_p$ = {material.heat_capacity:.3f} J/kg·K, ρ = {material.density} kg/m³')
506
+ ax.set_title(f'{material.name}, T = {cf.temp} K, C$_p$ = {material.heat_capacity:.3f} J/kg·K, ρ = {material.density} kg/m³', color="grey")
473
507
 
474
508
  fig.savefig("Material properties.pdf", format='pdf', bbox_inches="tight")
475
509
  plt.close(fig)
476
510
 
477
511
 
478
512
  def plot_data(mfp_sampling=False):
479
- """Create plots of various distributions"""
480
- plot_structure()
481
- plot_trajectories()
482
- plot_angle_distribution()
483
- plot_free_path_distribution()
484
- plot_frequency_distribution()
485
- plot_wavelength_distribution()
486
- plot_travel_time_distribution()
487
- plot_mean_free_path_distribution()
488
- plot_velocity_distribution()
489
- plot_time_in_segments()
490
- plot_thermal_conductivity()
491
- plot_temperature_profile()
492
- plot_heat_flux_profile()
493
- plot_thermal_map()
494
- plot_pixel_volumes()
495
- plot_scattering_statistics()
513
+ """Create plots of various distributions, maps, profiles, and other quantities"""
514
+ function_list = [
515
+ plot_structure,
516
+ plot_trajectories,
517
+ plot_angle_distribution,
518
+ plot_scattering_angle_distribution,
519
+ plot_free_path_distribution,
520
+ plot_frequency_distribution,
521
+ plot_wavelength_distribution,
522
+ plot_travel_time_distribution,
523
+ plot_mean_free_path_distribution,
524
+ plot_velocity_distribution,
525
+ plot_time_in_segments,
526
+ plot_thermal_conductivity,
527
+ plot_temperature_profile,
528
+ plot_heat_flux_profile,
529
+ plot_thermal_map,
530
+ plot_pixel_volumes,
531
+ plot_scattering_statistics,
532
+ plot_scattering_map,
533
+ plot_material_properties,
534
+ ]
535
+
536
+ # Run main functions and handle exceptions:
537
+ for func in function_list:
538
+ try:
539
+ func()
540
+ except Exception as e:
541
+ logging.warning(f"Function {func.__name__} failed: {e}")
542
+
543
+ # Run additional functions:
496
544
  plot_cumulative_thermal_conductivity(mfp_sampling)
497
545
  plot_heat_flux_map(file="Data/Heat flux map xy.csv", label="Heat flux map", units="W/m²")
498
546
  plot_heat_flux_map(file="Data/Heat flux map x.csv", label="Heat flux map x", units="W/m²")
499
547
  plot_heat_flux_map(file="Data/Heat flux map y.csv", label="Heat flux map y", units="W/m²")
500
- # plot_heat_flux_map(file="Data/Heat flux map x weighted.csv", label="Heat flux map x weighted", units="W/m²")
501
- # plot_heat_flux_map(file="Data/Heat flux map y weighted.csv", label="Heat flux map y weighted", units="W/m²")
502
- plot_scattering_map()
503
- plot_material_properties()
@@ -5,14 +5,15 @@ After the run, we record various parameters of this run into flight object.
5
5
 
6
6
  from freepaths.config import cf
7
7
  from freepaths.scattering import internal_scattering, surface_scattering, reinitialization
8
- from freepaths.scattering_types import ScatteringTypes
8
+ from freepaths.scattering_types import ScatteringTypes, ScatteringPlaces
9
9
 
10
10
 
11
- def run_phonon(phonon, flight, scatter_stats, segment_stats, thermal_maps, scatter_maps, material):
11
+ def run_phonon(phonon, flight, scatter_stats, places_stats, segment_stats, thermal_maps, scatter_maps, material):
12
12
  """Run one phonon through the system and record parameters of this run"""
13
13
 
14
14
  # Initialize object that will store scattering types:
15
15
  scattering_types = ScatteringTypes()
16
+ triangle_scattering_places = ScatteringPlaces()
16
17
 
17
18
  # Run the phonon step-by-step:
18
19
  for step_number in range(cf.number_of_timesteps):
@@ -21,7 +22,7 @@ def run_phonon(phonon, flight, scatter_stats, segment_stats, thermal_maps, scatt
21
22
  # Check if different scattering events happened during current time step:
22
23
  if cf.include_internal_scattering:
23
24
  internal_scattering(phonon, flight, scattering_types)
24
- surface_scattering(phonon, scattering_types)
25
+ surface_scattering(phonon, scattering_types, triangle_scattering_places)
25
26
  reinitialization(phonon, scattering_types)
26
27
 
27
28
  # If any scattering has occurred, record it:
@@ -43,6 +44,15 @@ def run_phonon(phonon, flight, scatter_stats, segment_stats, thermal_maps, scatt
43
44
  phonon.assign_internal_scattering_time(material)
44
45
  if cf.is_two_dimensional_material:
45
46
  phonon.phi = 0.0
47
+
48
+ # If hole scattering has occured, record it:
49
+ if triangle_scattering_places.is_scattered:
50
+ places_stats.save_scattering_events(phonon.y, triangle_scattering_places)
51
+ if scattering_types.is_diffuse_on_hole:
52
+ flight.save_hole_diff_scattering_angle(phonon.theta)
53
+ if scattering_types.is_specular_on_hole:
54
+ flight.save_hole_spec_scattering_angle(phonon.theta)
55
+
46
56
  else:
47
57
  flight.add_step(cf.timestep)
48
58
 
@@ -50,6 +60,7 @@ def run_phonon(phonon, flight, scatter_stats, segment_stats, thermal_maps, scatt
50
60
  thermal_maps.add_energy_to_maps(phonon, step_number, material)
51
61
  segment_stats.record_time_in_segment(phonon.y)
52
62
  scattering_types.reset()
63
+ triangle_scattering_places.reset()
53
64
  phonon.move()
54
65
 
55
66
  # If the phonon reached cold side, record it and break the loop:
@@ -107,7 +107,7 @@ def ceiling_scattering(ph, scattering_types, x, y, z):
107
107
  scattering_types.top_bottom = in_plane_surface_scattering(ph, cf.top_roughness)
108
108
 
109
109
 
110
- def surface_scattering(ph, scattering_types):
110
+ def surface_scattering(ph, scattering_types, triangle_scattering_places):
111
111
  """Check for a surface scattering on this step"""
112
112
 
113
113
  # Preliminary move to see if phonon would cross something:
@@ -38,21 +38,20 @@ def vertical_surface_left_scattering(ph, roughness, cf, is_diffuse=False):
38
38
  p = specularity(a, roughness, ph.wavelength)
39
39
 
40
40
  # Specular scattering:
41
- if random() < p and not is_diffuse:
41
+ if random() < p and (not is_diffuse):
42
42
  ph.theta = - ph.theta
43
43
  return Scattering.SPECULAR
44
44
 
45
45
  # Diffuse scattering:
46
- else:
47
- for attempt in range(10):
46
+ for attempt in range(10):
48
47
 
49
- # Lambert cosine distribution:
50
- ph.theta = -pi/2 + asin(2*random() - 1)
51
- ph.phi = asin((asin(2*random() - 1))/(pi/2))
48
+ # Lambert cosine distribution:
49
+ ph.theta = -pi/2 + asin(2*random() - 1)
50
+ ph.phi = asin((asin(2*random() - 1))/(pi/2))
52
51
 
53
- # Accept the angles if they do not cause new scattering:
54
- if no_new_scattering(ph, cf):
55
- return Scattering.DIFFUSE
52
+ # Accept the angles if they do not cause new scattering:
53
+ if no_new_scattering(ph, cf):
54
+ return Scattering.DIFFUSE
56
55
 
57
56
 
58
57
  def vertical_surface_right_scattering(ph, roughness, cf, is_diffuse=False):
@@ -63,21 +62,20 @@ def vertical_surface_right_scattering(ph, roughness, cf, is_diffuse=False):
63
62
  p = specularity(a, roughness, ph.wavelength)
64
63
 
65
64
  # Specular scattering:
66
- if random() < p and not is_diffuse:
65
+ if random() < p and (not is_diffuse):
67
66
  ph.theta = - ph.theta
68
67
  return Scattering.SPECULAR
69
68
 
70
69
  # Diffuse scattering:
71
- else:
72
- for attempt in range(10):
70
+ for attempt in range(10):
73
71
 
74
- # Lambert cosine distribution:
75
- ph.theta = +pi/2 + asin(2*random() - 1)
76
- ph.phi = asin((asin(2*random() - 1))/(pi/2))
72
+ # Lambert cosine distribution:
73
+ ph.theta = +pi/2 + asin(2*random() - 1)
74
+ ph.phi = asin((asin(2*random() - 1))/(pi/2))
77
75
 
78
- # Accept the angles if they do not cause new scattering:
79
- if no_new_scattering(ph, cf):
80
- return Scattering.DIFFUSE
76
+ # Accept the angles if they do not cause new scattering:
77
+ if no_new_scattering(ph, cf):
78
+ return Scattering.DIFFUSE
81
79
 
82
80
 
83
81
  def horizontal_surface_down_scattering(ph, roughness, is_diffuse=False):
@@ -88,17 +86,16 @@ def horizontal_surface_down_scattering(ph, roughness, is_diffuse=False):
88
86
  p = specularity(a, roughness, ph.wavelength)
89
87
 
90
88
  # Specular scattering:
91
- if random() < p and not is_diffuse:
89
+ if random() < p and (not is_diffuse):
92
90
  ph.theta = sign(ph.theta)*pi - ph.theta
93
91
  return Scattering.SPECULAR
94
92
 
95
93
  # Diffuse scattering:
96
- else:
97
- # Lambert cosine distribution:
98
- rand_sign = sign((2*random() - 1))
99
- ph.theta = rand_sign*pi/2 + rand_sign*acos(random())
100
- ph.phi = asin((asin(2*random() - 1))/(pi/2))
101
- return Scattering.DIFFUSE
94
+ # Lambert cosine distribution:
95
+ rand_sign = sign((2*random() - 1))
96
+ ph.theta = rand_sign*pi/2 + rand_sign*acos(random())
97
+ ph.phi = asin((asin(2*random() - 1))/(pi/2))
98
+ return Scattering.DIFFUSE
102
99
 
103
100
 
104
101
  def horizontal_surface_up_scattering(ph, roughness, is_diffuse=False):
@@ -114,18 +111,17 @@ def horizontal_surface_up_scattering(ph, roughness, is_diffuse=False):
114
111
  return Scattering.SPECULAR
115
112
 
116
113
  # Diffuse scattering:
117
- else:
118
- # Lambert cosine distribution:
119
- ph.theta = asin(2*random() - 1)
120
- ph.phi = asin((asin(2*random() - 1))/(pi/2))
121
- return Scattering.DIFFUSE
114
+ # Lambert cosine distribution:
115
+ ph.theta = asin(2*random() - 1)
116
+ ph.phi = asin((asin(2*random() - 1))/(pi/2))
117
+ return Scattering.DIFFUSE
122
118
 
123
119
 
124
120
  def inclined_surfaces_down_scattering(ph, beta, x, x0, roughness):
125
121
  """Scattering from a inclined surfaces pointing down like V"""
126
122
 
127
123
  # Calculate angle to the surface and specular scattering probability:
128
- a = acos(cos(ph.phi)*cos(ph.theta - sign(x - x0)*(pi/2 - beta)))
124
+ a = acos(cos(ph.phi)*cos(pi/2 - abs(ph.theta) - beta))
129
125
  p = specularity(a, roughness, ph.wavelength)
130
126
 
131
127
  # Specular scattering:
@@ -134,18 +130,18 @@ def inclined_surfaces_down_scattering(ph, beta, x, x0, roughness):
134
130
  return Scattering.SPECULAR
135
131
 
136
132
  # Diffuse scattering:
137
- else:
138
- rand_sign = sign((2*random() - 1))
139
- ph.theta = rand_sign*pi - rand_sign*asin(random()) - sign(x - x0)*(pi/2 - beta)
140
- ph.phi = asin((asin(2*random() - 1))/(pi/2))
141
- return Scattering.DIFFUSE
133
+ rand_sign = sign((2*random() - 1))
134
+ ph.theta = rand_sign*pi - rand_sign*asin(random()) - sign(x - x0)*(pi/2 - beta)
135
+ ph.phi = asin((asin(2*random() - 1))/(pi/2))
136
+ return Scattering.DIFFUSE
142
137
 
143
138
 
144
139
  def inclined_surfaces_up_scattering(ph, beta, x, x0, roughness):
145
140
  """Scattering from a inclined surfaces pointing up like ^"""
146
141
 
147
142
  # Calculate angle to the surface and specular scattering probability:
148
- a = acos(cos(ph.phi)*cos(ph.theta + sign(x - x0)*(pi/2 - beta)))
143
+ a = acos(cos(ph.phi)*cos(pi/2 - abs(ph.theta) + beta))
144
+ # a = acos(cos(ph.phi)*cos(abs(ph.theta) - pi/2 + beta))
149
145
  p = specularity(a, roughness, ph.wavelength)
150
146
 
151
147
  # Specular scattering:
@@ -154,11 +150,9 @@ def inclined_surfaces_up_scattering(ph, beta, x, x0, roughness):
154
150
  return Scattering.SPECULAR
155
151
 
156
152
  # Diffuse scattering:
157
- else:
158
- # Lambert cosine distribution:
159
- ph.theta = asin(2*random() - 1) + sign(x - x0)*(pi/2 - beta)
160
- ph.phi = asin((asin(2*random() - 1))/(pi/2))
161
- return Scattering.DIFFUSE
153
+ ph.theta = asin(2*random() - 1) + sign(x - x0)*(pi/2 - beta)
154
+ ph.phi = asin((asin(2*random() - 1))/(pi/2))
155
+ return Scattering.DIFFUSE
162
156
 
163
157
 
164
158
  def in_plane_surface_scattering(ph, roughness):
@@ -174,22 +168,21 @@ def in_plane_surface_scattering(ph, roughness):
174
168
  return Scattering.SPECULAR
175
169
 
176
170
  # Diffuse scattering:
177
- else:
178
- # Random distribution:
179
- # theta = -pi + random()*2*pi
180
- # phi = -asin(random())
171
+ # Random distribution:
172
+ # theta = -pi + random()*2*pi
173
+ # phi = -asin(random())
181
174
 
182
- # Lambert cosine distribution:
183
- ph.theta = - pi + random()*2*pi
184
- ph.phi = - sign(ph.phi) * random()*pi/2
185
- return Scattering.DIFFUSE
175
+ # Lambert cosine distribution:
176
+ ph.theta = - pi + random()*2*pi
177
+ ph.phi = - sign(ph.phi) * random()*pi/2
178
+ return Scattering.DIFFUSE
186
179
 
187
180
 
188
181
  def circle_outer_scattering(ph, tangent_theta, y, y0, roughness, cf):
189
182
  """Scattering from the outer surface of the circle"""
190
183
 
191
184
  # Calculate angle to the surface and specular scattering probability:
192
- a = acos(cos(ph.phi)*cos(ph.theta + sign(y - y0)*tangent_theta))
185
+ a = acos(cos(ph.phi)*cos(ph.theta - tangent_theta))
193
186
  p = specularity(a, roughness, ph.wavelength)
194
187
 
195
188
  # Specular scattering:
@@ -198,20 +191,19 @@ def circle_outer_scattering(ph, tangent_theta, y, y0, roughness, cf):
198
191
  return Scattering.SPECULAR
199
192
 
200
193
  # Diffuse scattering:
201
- else:
202
- for attempt in range(10):
194
+ for attempt in range(10):
203
195
 
204
- # Random distribution:
205
- # theta = tangent_theta - (-pi/2 + pi*random()) - pi*(y < y0)
206
- # phi = asin(2*random() - 1)
196
+ # Random distribution:
197
+ # theta = tangent_theta - (-pi/2 + pi*random()) - pi*(y < y0)
198
+ # phi = asin(2*random() - 1)
207
199
 
208
- # Lambert cosine distribution:
209
- ph.theta = tangent_theta - (asin(2*random() - 1)) - pi*(y < y0)
210
- ph.phi = asin((asin(2*random() - 1))/(pi/2))
200
+ # Lambert cosine distribution:
201
+ ph.theta = tangent_theta - (asin(2*random() - 1)) - pi*(y < y0)
202
+ ph.phi = asin((asin(2*random() - 1))/(pi/2))
211
203
 
212
- # Accept the angles only if they do not immediately cause new scattering:
213
- if no_new_scattering(ph, cf):
214
- return Scattering.DIFFUSE
204
+ # Accept the angles only if they do not immediately cause new scattering:
205
+ if no_new_scattering(ph, cf):
206
+ return Scattering.DIFFUSE
215
207
 
216
208
 
217
209
  def circle_inner_scattering(ph, tangent_theta, y, y0, roughness):
@@ -226,10 +218,9 @@ def circle_inner_scattering(ph, tangent_theta, y, y0, roughness):
226
218
  return Scattering.SPECULAR
227
219
 
228
220
  # Diffuse scattering:
229
- else:
230
- ph.theta = tangent_theta - asin(2*random()-1) + pi*(y >= y0)
231
- ph.phi = asin((asin(2*random() - 1))/(pi/2))
232
- return Scattering.DIFFUSE
221
+ ph.theta = tangent_theta - asin(2*random()-1) + pi*(y >= y0)
222
+ ph.phi = asin((asin(2*random() - 1))/(pi/2))
223
+ return Scattering.DIFFUSE
233
224
 
234
225
 
235
226
  def circle_inclined_inner_scattering(ph, tangent_theta, y, y0, roughness):
@@ -263,7 +254,6 @@ def circle_inclined_inner_scattering(ph, tangent_theta, y, y0, roughness):
263
254
  return Scattering.SPECULAR
264
255
 
265
256
  # Diffuse scattering:
266
- else:
267
- ph.theta = tangent_theta - asin(2*random()-1) + pi*(y >= y0)
268
- ph.phi = asin((asin(2*random() - 1))/(pi/2)) # - (pi / 2 - pillar.wall_angle)
269
- return Scattering.DIFFUSE
257
+ ph.theta = tangent_theta - asin(2*random()-1) + pi*(y >= y0)
258
+ ph.phi = asin((asin(2*random() - 1))/(pi/2)) # - (pi / 2 - pillar.wall_angle)
259
+ return Scattering.DIFFUSE
@@ -36,9 +36,19 @@ class ScatteringTypes:
36
36
 
37
37
  @property
38
38
  def is_internal(self):
39
- """Is any of the scattering types diffuse?"""
39
+ """Is the scattering type internal?"""
40
40
  return self.internal is not None
41
41
 
42
+ @property
43
+ def is_diffuse_on_hole(self):
44
+ """Was there a diffuse scattering on holes?"""
45
+ return self.holes == Scattering.DIFFUSE
46
+
47
+ @property
48
+ def is_specular_on_hole(self):
49
+ """Was there a specular scattering on holes?"""
50
+ return self.holes == Scattering.SPECULAR
51
+
42
52
  @property
43
53
  def is_scattered(self):
44
54
  """Has any of the scattering events occurred?"""
@@ -57,3 +67,26 @@ class ScatteringTypes:
57
67
  self.walls = None
58
68
  self.internal = None
59
69
  self.hot_side = None
70
+
71
+
72
+ class ScatteringPlaces:
73
+ """Phonon scattering places on a triangle"""
74
+
75
+ def __init__(self):
76
+ """Initialize possible scattering places"""
77
+ self.right_wall = None
78
+ self.left_wall = None
79
+ self.floor = None
80
+
81
+ @property
82
+ def is_scattered(self):
83
+ """Has any of the scattering events occurred?"""
84
+ return any([self.right_wall,
85
+ self.left_wall,
86
+ self.floor])
87
+
88
+ def reset(self):
89
+ """Reset all scattering places to None"""
90
+ self.right_wall = None
91
+ self.left_wall = None
92
+ self.floor = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: freepaths
3
- Version: 1.9.2
3
+ Version: 2.0
4
4
  Summary: Phonon Monte Carlo simulator
5
5
  Home-page: https://github.com/anufrievroman/freepaths
6
6
  Author: Roman Anufriev
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes