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.
- {freepaths-1.9.2 → freepaths-2.0}/PKG-INFO +1 -1
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/__main__.py +1 -1
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/config.py +5 -1
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/data.py +55 -0
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/flight.py +10 -0
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/holes.py +7 -2
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/main_tracing.py +7 -2
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/maps.py +1 -1
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/materials.py +1 -1
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/output_info.py +28 -28
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/output_plots.py +74 -30
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/run_phonon.py +14 -3
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/scattering.py +1 -1
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/scattering_primitives.py +60 -70
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/scattering_types.py +34 -1
- {freepaths-1.9.2 → freepaths-2.0}/freepaths.egg-info/PKG-INFO +1 -1
- {freepaths-1.9.2 → freepaths-2.0}/README.md +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/animation.py +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/default_config.py +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/main_mfp_sampling.py +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/move.py +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/output_structure.py +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/phonon.py +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/progress.py +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/scattering_semicircle.py +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/freepaths/sources.py +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/freepaths.egg-info/SOURCES.txt +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/freepaths.egg-info/dependency_links.txt +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/freepaths.egg-info/entry_points.txt +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/freepaths.egg-info/requires.txt +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/freepaths.egg-info/top_level.txt +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/pyproject.toml +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/setup.cfg +0 -0
- {freepaths-1.9.2 → freepaths-2.0}/setup.py +0 -0
|
@@ -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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
49
|
+
sc_on_walls = 100*(np.sum(scatter_stats.wall_diffuse) +
|
|
50
50
|
np.sum(scatter_stats.wall_specular)) / total
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
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
|
-
|
|
59
|
-
|
|
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
|
-
|
|
62
|
-
|
|
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{
|
|
69
|
-
f'({
|
|
70
|
-
f'{
|
|
71
|
-
f'\n{
|
|
72
|
-
f'({
|
|
73
|
-
f'{
|
|
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
|
-
|
|
79
|
+
sc_on_holes = 100*(np.sum(scatter_stats.hole_diffuse) +
|
|
80
80
|
np.sum(scatter_stats.hole_specular)) / total
|
|
81
|
-
|
|
82
|
-
|
|
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{
|
|
85
|
-
f'({
|
|
86
|
-
f'{
|
|
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
|
-
|
|
90
|
+
sc_on_pill = 100*(np.sum(scatter_stats.pillar_diffuse) +
|
|
91
91
|
np.sum(scatter_stats.pillar_specular)) / total
|
|
92
|
-
|
|
93
|
-
|
|
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{
|
|
96
|
-
f'({
|
|
97
|
-
f'{
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
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
|
-
|
|
47
|
-
for attempt in range(10):
|
|
46
|
+
for attempt in range(10):
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
72
|
-
for attempt in range(10):
|
|
70
|
+
for attempt in range(10):
|
|
73
71
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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(
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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 +
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
# phi = -asin(random())
|
|
171
|
+
# Random distribution:
|
|
172
|
+
# theta = -pi + random()*2*pi
|
|
173
|
+
# phi = -asin(random())
|
|
181
174
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
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
|
|
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
|
-
|
|
202
|
-
for attempt in range(10):
|
|
194
|
+
for attempt in range(10):
|
|
203
195
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
196
|
+
# Random distribution:
|
|
197
|
+
# theta = tangent_theta - (-pi/2 + pi*random()) - pi*(y < y0)
|
|
198
|
+
# phi = asin(2*random() - 1)
|
|
207
199
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|