freepaths 2.2.4__tar.gz → 2.3.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 (41) hide show
  1. {freepaths-2.2.4 → freepaths-2.3.0}/PKG-INFO +7 -3
  2. {freepaths-2.2.4 → freepaths-2.3.0}/README.md +6 -2
  3. freepaths-2.3.0/freepaths/__main__.py +64 -0
  4. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/config.py +1 -2
  5. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/data.py +6 -4
  6. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/default_config.py +7 -7
  7. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/main_tracing.py +20 -9
  8. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/maps.py +4 -3
  9. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/output_info.py +11 -17
  10. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/output_plots.py +35 -25
  11. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths.egg-info/PKG-INFO +7 -3
  12. freepaths-2.2.4/freepaths/__main__.py +0 -42
  13. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/animation.py +0 -0
  14. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/electron.py +0 -0
  15. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/flight.py +0 -0
  16. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/interface_smmm.py +0 -0
  17. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/main_mfp_sampling.py +0 -0
  18. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/materials.py +0 -0
  19. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/move.py +0 -0
  20. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/output_structure.py +0 -0
  21. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/particle.py +0 -0
  22. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/particle_types.py +0 -0
  23. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/phonon.py +0 -0
  24. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/post_computations.py +0 -0
  25. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/progress.py +0 -0
  26. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/run_particle.py +0 -0
  27. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/scatterers.py +0 -0
  28. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/scattering.py +0 -0
  29. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/scattering_interfaces.py +0 -0
  30. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/scattering_primitives.py +0 -0
  31. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/scattering_semicircle.py +0 -0
  32. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/scattering_types.py +0 -0
  33. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths/sources.py +0 -0
  34. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths.egg-info/SOURCES.txt +0 -0
  35. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths.egg-info/dependency_links.txt +0 -0
  36. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths.egg-info/entry_points.txt +0 -0
  37. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths.egg-info/requires.txt +0 -0
  38. {freepaths-2.2.4 → freepaths-2.3.0}/freepaths.egg-info/top_level.txt +0 -0
  39. {freepaths-2.2.4 → freepaths-2.3.0}/pyproject.toml +0 -0
  40. {freepaths-2.2.4 → freepaths-2.3.0}/setup.cfg +0 -0
  41. {freepaths-2.2.4 → freepaths-2.3.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: freepaths
3
- Version: 2.2.4
3
+ Version: 2.3.0
4
4
  Summary: Phonon Monte Carlo simulator
5
5
  Home-page: https://github.com/anufrievroman/freepaths
6
6
  Author: Roman Anufriev
@@ -54,9 +54,13 @@ FreePATHS is a command line application, so it runs inside Linux, MacOS, or Wind
54
54
 
55
55
  There are two modes of using the program. Main mode traces a large number of phonons through a structure and collects statistics about their paths. The MFP sampling mode measures phonon mean free paths using a small number of phonons and calculates the thermal conductivity by integrating phonon dispersion.
56
56
 
57
- ### Demo
57
+ ### Getting started
58
58
 
59
- If you simply run `freepaths` without specifying an input file, the program will run a demo simulation.
59
+ If you run `freepaths` without any arguments, the program will print a usage summary. To run a demo simulation with default parameters, use the `--demo` flag:
60
+
61
+ `freepaths --demo`
62
+
63
+ Example input files are available in the [examples](https://github.com/anufrievroman/freepaths/tree/master/examples) folder.
60
64
 
61
65
  ### Main mode
62
66
 
@@ -18,9 +18,13 @@ FreePATHS is a command line application, so it runs inside Linux, MacOS, or Wind
18
18
 
19
19
  There are two modes of using the program. Main mode traces a large number of phonons through a structure and collects statistics about their paths. The MFP sampling mode measures phonon mean free paths using a small number of phonons and calculates the thermal conductivity by integrating phonon dispersion.
20
20
 
21
- ### Demo
21
+ ### Getting started
22
22
 
23
- If you simply run `freepaths` without specifying an input file, the program will run a demo simulation.
23
+ If you run `freepaths` without any arguments, the program will print a usage summary. To run a demo simulation with default parameters, use the `--demo` flag:
24
+
25
+ `freepaths --demo`
26
+
27
+ Example input files are available in the [examples](https://github.com/anufrievroman/freepaths/tree/master/examples) folder.
24
28
 
25
29
  ### Main mode
26
30
 
@@ -0,0 +1,64 @@
1
+ """FreePATHS - Free Phonon and THermal Simulator"""
2
+
3
+ import sys
4
+ import argparse
5
+ import colorama
6
+ from colorama import Fore, Style
7
+
8
+ from freepaths.particle_types import ParticleType
9
+
10
+ __version__ = "2.3.0"
11
+
12
+ colorama.init()
13
+
14
+ # Parse user arguments:
15
+ parser = argparse.ArgumentParser(
16
+ prog = 'FreePATHS',
17
+ description = 'Phonon Monte Carlo simulator',
18
+ epilog = 'For more information, examples, and tutorials, visit: https://anufrievroman.gitbook.io/freepaths'
19
+ )
20
+ parser.add_argument('input_file', nargs='?', default=None, help='The input file')
21
+ parser.add_argument("-v", "--version", action="version", version=f"FreePATHS {__version__}")
22
+ parser.add_argument("-s", "--sampling", help="Run in phonon MFP sampling mode", action="store_true")
23
+ parser.add_argument("-e", "--electron", help="Run simulation for electrons", action="store_true")
24
+ parser.add_argument("--demo", help="Run a demo simulation with default parameters", action="store_true")
25
+ args = parser.parse_args()
26
+
27
+
28
+ def run():
29
+ """Run the program depending on the mode"""
30
+ print(f"\n{Fore.BLUE}FreePATHS v{__version__}{Style.RESET_ALL}")
31
+
32
+ if not args.input_file and not args.demo:
33
+ print("\nUsage:")
34
+ print(f" freepaths <input_file> run phonon simulation")
35
+ print(f" freepaths <input_file> -e run electron simulation")
36
+ print(f" freepaths <input_file> -s run in MFP sampling mode")
37
+ print(f" freepaths --demo run a demo with default parameters")
38
+ print(f" freepaths --version show version")
39
+ print(f"\nExample input files:")
40
+ print(f" https://github.com/anufrievroman/freepaths/tree/master/examples")
41
+ print(f"\nDocumentation:")
42
+ print(f" https://anufrievroman.gitbook.io/freepaths")
43
+ sys.exit(0)
44
+
45
+ try:
46
+ if args.sampling:
47
+ import freepaths.main_mfp_sampling
48
+ freepaths.main_mfp_sampling.main(args.input_file, ParticleType.PHONON)
49
+
50
+ elif args.electron:
51
+ import freepaths.main_tracing
52
+ freepaths.main_tracing.main(args.input_file, ParticleType.ELECTRON)
53
+
54
+ else:
55
+ import freepaths.main_tracing
56
+ freepaths.main_tracing.main(args.input_file, ParticleType.PHONON)
57
+
58
+ except KeyboardInterrupt:
59
+ print(f"\n{Fore.RED}Simulation interrupted by user.{Style.RESET_ALL}")
60
+ sys.exit(0)
61
+
62
+
63
+ if __name__ == "__main__":
64
+ run()
@@ -26,6 +26,7 @@ parser = argparse.ArgumentParser(prog='FreePATHS', description='Monte Carlo simu
26
26
  parser.add_argument('input_file', nargs='?', default=None, help='The input file')
27
27
  parser.add_argument("-s", "--sampling", help="Run in MFP sampling mode", action="store_true")
28
28
  parser.add_argument("-e", "--electron", help="Run with electrons", action="store_true")
29
+ parser.add_argument("--demo", help="Run a demo simulation with default parameters", action="store_true")
29
30
  args = parser.parse_args()
30
31
 
31
32
 
@@ -36,8 +37,6 @@ if args.input_file:
36
37
  except FileNotFoundError:
37
38
  logging.error("Input file does not exist. Check if you are in the right folder and the file name is correct.")
38
39
  sys.exit()
39
- else:
40
- logging.warning("You provided no input file, so we will run a demo simulation:")
41
40
 
42
41
 
43
42
  class Config:
@@ -204,10 +204,12 @@ class ScatteringData(Data):
204
204
  def write_into_files(self):
205
205
  """Write data into a file"""
206
206
  filename = "Data/Scattering events statistics.csv"
207
- data = np.vstack((self.wall_diffuse, self.wall_specular, self.top_diffuse, self.top_specular, self.hole_diffuse,
208
- self.hole_specular, self.hot_side, self.internal, self.pillar_diffuse, self.pillar_specular,
209
- self.interfaces_diffuse, self.interfaces_specular,
210
- self.interfaces_transmission_diffuse, self.interfaces_transmission_specular)).T
207
+ n = cf.number_of_length_segments
208
+ data = np.vstack((self.wall_diffuse[:n], self.wall_specular[:n], self.top_diffuse[:n], self.top_specular[:n],
209
+ self.hole_diffuse[:n], self.hole_specular[:n], self.hot_side[:n], self.internal[:n],
210
+ self.pillar_diffuse[:n], self.pillar_specular[:n],
211
+ self.interfaces_diffuse[:n], self.interfaces_specular[:n],
212
+ self.interfaces_transmission_diffuse[:n], self.interfaces_transmission_specular[:n])).T
211
213
  header = ("Sidewalls diffuse, Sidewalls specular, Top & bottom diffuse, Top & bottom specular, "
212
214
  "Holes diffuse, Holes specular, Hot side, Internal, Pillars diffuse, Pillars specular, "
213
215
  "Interfaces diffuse, Interfaces specular, Interfaces transmission diffuse, Interfaces transmission specular")
@@ -7,18 +7,18 @@ from freepaths.sources import Source
7
7
 
8
8
  # General parameters:
9
9
  OUTPUT_FOLDER_NAME = "Si nanowire at 300 K"
10
- NUMBER_OF_PARTICLES = 5000
10
+ NUMBER_OF_PARTICLES = 10000
11
11
  NUMBER_OF_NODES = 400
12
12
  T = 300
13
13
  OUTPUT_SCATTERING_MAP = False
14
- OUTPUT_TRAJECTORIES_OF_FIRST = 50
14
+ OUTPUT_TRAJECTORIES_OF_FIRST = 20
15
15
  OUTPUT_STRUCTURE_COLOR = "#F0F0F0"
16
16
  NUMBER_OF_LENGTH_SEGMENTS = 10
17
17
  LOW_MEMORY_USAGE = False
18
18
 
19
19
  # Time parameters:
20
- TIMESTEP = 1e-12
21
- NUMBER_OF_TIMESTEPS = 300000
20
+ TIMESTEP = 2e-12
21
+ NUMBER_OF_TIMESTEPS = 200000
22
22
  NUMBER_OF_VIRTUAL_TIMESTEPS = NUMBER_OF_TIMESTEPS * 3
23
23
  NUMBER_OF_TIMEFRAMES = 8
24
24
  NUMBER_OF_STABILIZATION_TIMEFRAMES = 5
@@ -38,8 +38,8 @@ OUTPUT_PATH_ANIMATION = False
38
38
  OUTPUT_ANIMATION_FPS = 24
39
39
 
40
40
  # Map & profiles parameters:
41
- NUMBER_OF_PIXELS_X = 25
42
- NUMBER_OF_PIXELS_Y = 100
41
+ NUMBER_OF_PIXELS_X = 7
42
+ NUMBER_OF_PIXELS_Y = 67
43
43
  IGNORE_FAULTY_PARTICLES = False
44
44
 
45
45
  # Material parameters:
@@ -53,7 +53,7 @@ GRAY_APPROXIMATION_MFP = None
53
53
 
54
54
  # System dimensions [m]:
55
55
  THICKNESS = 150e-9
56
- WIDTH = 500e-9
56
+ WIDTH = 200e-9
57
57
  LENGTH = 2000e-9
58
58
  IS_TWO_DIMENSIONAL_MATERIAL = False
59
59
  INCLUDE_RIGHT_SIDEWALL = True
@@ -4,6 +4,7 @@ import os
4
4
  import sys
5
5
  import time
6
6
  import shutil
7
+ import signal
7
8
  import multiprocessing
8
9
  import traceback
9
10
  import logging
@@ -126,6 +127,7 @@ class ParticleSimulator:
126
127
 
127
128
 
128
129
  def worker_process(worker_id, particle_type: ParticleType,total_particles, shared_list, output_trajectories_of, finished_workers):
130
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
129
131
  try:
130
132
  # Create a particle simulator and run the simulation:
131
133
  simulator = ParticleSimulator(worker_id, particle_type, total_particles, shared_list, output_trajectories_of)
@@ -146,13 +148,17 @@ def worker_process(worker_id, particle_type: ParticleType,total_particles, share
146
148
 
147
149
  def display_workers_finished(finished_workers):
148
150
  """ Print out the number of active workers"""
149
- while True:
150
- text_to_display = f' Processes finished: {finished_workers.value}/{cf.num_workers}'
151
- sys.stdout.write(text_to_display)
152
- sys.stdout.write(f'\033[{len(text_to_display)}D') # move cursor back
153
- sys.stdout.flush()
154
- if finished_workers.value == cf.num_workers: break
155
- time.sleep(0.3)
151
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
152
+ try:
153
+ while True:
154
+ text_to_display = f' Processes finished: {finished_workers.value}/{cf.num_workers}'
155
+ sys.stdout.write(text_to_display)
156
+ sys.stdout.write(f'\033[{len(text_to_display)}D') # move cursor back
157
+ sys.stdout.flush()
158
+ if finished_workers.value == cf.num_workers: break
159
+ time.sleep(0.3)
160
+ except Exception:
161
+ pass
156
162
 
157
163
 
158
164
  def main(input_file, particle_type):
@@ -196,8 +202,13 @@ def main(input_file, particle_type):
196
202
 
197
203
  # Wait for all processes to finish:
198
204
  # Note that join is not called on worker_count_process because we do not want to wait for it to finish
199
- for process in processes:
200
- process.join()
205
+ try:
206
+ for process in processes:
207
+ process.join()
208
+ except KeyboardInterrupt:
209
+ for process in processes:
210
+ process.terminate()
211
+ raise
201
212
 
202
213
  # Wait for the worker count to finish but continue after 3 seconds:
203
214
  worker_count_process.join(timeout=3)
@@ -208,9 +208,10 @@ class ThermalMaps(Maps):
208
208
  slope, _ = np.polyfit(coordinates_y, self.temperature_profile_y[:, timeframe_number], 1)
209
209
  grad_T = -slope
210
210
 
211
- # Average heat flux:
212
- J_effective = np.mean(self.effective_heat_flux_profile_y[:, timeframe_number])
213
- J_material = np.mean(self.material_heat_flux_profile_y[:, timeframe_number])
211
+ # Average heat flux (skip first pixel — it has a spurious spike due to
212
+ # rethermalization being applied before map recording in the time-step loop):
213
+ J_effective = np.mean(self.effective_heat_flux_profile_y[1:, timeframe_number])
214
+ J_material = np.mean(self.material_heat_flux_profile_y[1:, timeframe_number])
214
215
 
215
216
  # By definition, J = -K * grad(T), so:
216
217
  if grad_T != 0:
@@ -100,26 +100,20 @@ def output_scattering_information(scatter_stats):
100
100
  )
101
101
 
102
102
  if cf.interfaces:
103
- sc_on_interf = 100*(np.sum(scatter_stats.interfaces_diffuse) +
104
- np.sum(scatter_stats.interfaces_specular)) / total
105
- sc_on_interf_diff = 100*np.sum(scatter_stats.interfaces_diffuse) / total_interf
106
- sc_on_interf_spec = 100*np.sum(scatter_stats.interfaces_specular) / total_interf
103
+ total_all_interf = total_interf + total_transmission
104
+ sc_on_interf = 100 * total_all_interf / total
105
+ sc_on_interf_diff = 100 * (np.sum(scatter_stats.interfaces_diffuse) +
106
+ np.sum(scatter_stats.interfaces_transmission_diffuse)) / total_all_interf
107
+ sc_on_interf_spec = 100 * (np.sum(scatter_stats.interfaces_specular) +
108
+ np.sum(scatter_stats.interfaces_transmission_specular)) / total_all_interf
109
+ refl_on_interf = 100 * total_interf / total_all_interf
110
+ trans_on_interf = 100 * total_transmission / total_all_interf
107
111
  info.extend([
108
112
  f'\n{sc_on_interf:.2f}% - scattering on interfaces ',
109
113
  f'({sc_on_interf_diff:.2f}% - diffuse, ',
110
- f'{sc_on_interf_spec:.2f}% - specular)']
111
- )
112
-
113
- trans_on_interf = 100 * (np.sum(scatter_stats.interfaces_transmission_diffuse) +
114
- np.sum(scatter_stats.interfaces_transmission_specular)) / total_interf
115
- trans_on_interf_diff = 100*np.sum(scatter_stats.interfaces_transmission_diffuse)/ total_transmission
116
- trans_on_interf_spec = 100*np.sum(scatter_stats.interfaces_transmission_specular)/ total_transmission
117
-
118
-
119
- info.extend([
120
- f'\n{trans_on_interf:.2f}% - transmission through interfaces ',
121
- f'({trans_on_interf_diff:.2f}% - diffuse, ',
122
- f'{trans_on_interf_spec:.2f}% - specular)'
114
+ f'{sc_on_interf_spec:.2f}% - specular), ',
115
+ f'of which {trans_on_interf:.2f}% - transmission, ',
116
+ f'{refl_on_interf:.2f}% - reflection',
123
117
  ])
124
118
 
125
119
  # Write the file:
@@ -271,19 +271,6 @@ def plot_interfaces_angles_distribution():
271
271
  np.savetxt('Data/Distribution of interfaces angles.csv', angle_distributions, fmt='%1.3e', delimiter=",")
272
272
 
273
273
 
274
- import subprocess
275
- import os
276
-
277
- def open_pdf_with_mupdf(pdf_path):
278
- try:
279
- # path of mu pdf
280
- mupdf_path = r"C:\Users\victo\Downloads\mupdf-1.26.2-windows\mupdf-1.26.2-windows\mupdf-gl.exe"
281
-
282
- # Lancer mupdf avec ton fichier
283
- subprocess.Popen([mupdf_path, os.path.abspath(pdf_path)])
284
- except Exception as e:
285
- print(f"[ERROR] Impossible d'ouvrir le PDF avec MuPDF : {e}")
286
-
287
274
  def plot_transmission_vs_angle():
288
275
  try:
289
276
  angles = np.loadtxt("Data/All interfaces angles.csv", dtype='float', encoding='utf-8')
@@ -808,8 +795,13 @@ def plot_temperature_profile():
808
795
  """Plot profile of temperature for each time segment"""
809
796
  fig, ax = plt.subplots()
810
797
  data = np.genfromtxt("Data/Temperature profiles y.csv", unpack=True, delimiter=',', skip_header=1, encoding='utf-8')
811
- for timeframe_num in range(len(data) - 1):
812
- ax.plot(data[0][1:], data[timeframe_num + 1][1:], linewidth=1, label=f'Time frame {timeframe_num+1}')
798
+ coords = data[0]
799
+ n_timeframes = len(data) - 1
800
+ for timeframe_num in range(n_timeframes):
801
+ ax.plot(coords[1:], data[timeframe_num + 1][1:], linewidth=1, label=f'Time frame {timeframe_num+1}')
802
+ # Linear fit of the last timeframe (same algorithm as thermal conductivity calculation)
803
+ slope, intercept = np.polyfit(coords, data[n_timeframes], 1)
804
+ ax.plot(coords[1:], slope * coords[1:] + intercept, '--', color='gray', linewidth=1, label='Linear fit (last frame)')
813
805
  ax.set_xlabel('Y (μm)')
814
806
  ax.set_ylabel('Temperature (K)')
815
807
  ax.legend()
@@ -819,11 +811,16 @@ def plot_temperature_profile():
819
811
  def plot_heat_flux_profile():
820
812
  """Plot profile of heat flux for each time segment"""
821
813
 
814
+ data = np.genfromtxt("Data/Heat flux profiles y.csv", unpack=True, delimiter=',', skip_header=1, encoding='utf-8')
815
+ n_timeframes = (len(data) - 1) // 2
816
+
822
817
  # Effective heat flux:
823
818
  fig, ax = plt.subplots()
824
- data = np.genfromtxt("Data/Heat flux profiles y.csv", unpack=True, delimiter=',', skip_header=1, encoding='utf-8')
825
- for timeframe_num in range((len(data) - 1) // 2):
826
- ax.plot(data[0], data[timeframe_num + 1], linewidth=1, label=f'Time frame {timeframe_num+1}')
819
+ for timeframe_num in range(n_timeframes):
820
+ ax.plot(data[0][1:], data[timeframe_num + 1][1:], linewidth=1, label=f'Time frame {timeframe_num+1}')
821
+ # Mean of the last timeframe, skipping first pixel (same as thermal conductivity calculation)
822
+ mean_flux = np.mean(data[n_timeframes][1:])
823
+ ax.axhline(mean_flux, color='gray', linestyle='--', linewidth=1, label='Mean (last frame)')
827
824
  ax.set_xlabel('Y (μm)')
828
825
  ax.set_ylabel('Heat flux (W/m²)')
829
826
  ax.legend()
@@ -832,8 +829,10 @@ def plot_heat_flux_profile():
832
829
 
833
830
  # Material heat flux:
834
831
  fig, ax = plt.subplots()
835
- for timeframe_num in range((len(data) - 1) // 2):
836
- ax.plot(data[0], data[2*timeframe_num + 1], linewidth=1, label=f'Time frame {timeframe_num+1}')
832
+ for timeframe_num in range(n_timeframes):
833
+ ax.plot(data[0][1:], data[2*timeframe_num + 1][1:], linewidth=1, label=f'Time frame {timeframe_num+1}')
834
+ mean_flux_mat = np.mean(data[2*n_timeframes - 1][1:])
835
+ ax.axhline(mean_flux_mat, color='gray', linestyle='--', linewidth=1, label='Mean (last frame)')
837
836
  ax.set_xlabel('Y (μm)')
838
837
  ax.set_ylabel('Heat flux (W/m²)')
839
838
  ax.legend()
@@ -872,7 +871,7 @@ def plot_heat_flux_map(file, label, units="a.u."):
872
871
  """Plot heat flux map as color map"""
873
872
  fig = plt.figure()
874
873
  heat_flux_map = np.genfromtxt(file, unpack=False, delimiter=',', skip_header=0, encoding='utf-8')
875
- heat_flux_map = np.flipud(heat_flux_map)
874
+ heat_flux_map = np.abs(np.flipud(heat_flux_map))
876
875
  minimum_of_colorbar = 1e5
877
876
  boundaries = [(-cf.width / 2) * 1e6, (cf.width / 2) * 1e6, 0, cf.length * 1e6]
878
877
  plt.imshow(heat_flux_map, cmap='jet', interpolation='none', extent=boundaries,
@@ -970,7 +969,8 @@ def plot_scattering_statistics():
970
969
  if scattering_type == 6: # Skip hot side scattering
971
970
  continue
972
971
  # Calculate and plot scattering events per second:
973
- scattering_rate = [events / time for events, time in zip(scattering_data[scattering_type, :], time_spent)]
972
+ scattering_rate = np.divide(scattering_data[scattering_type, :], time_spent,
973
+ out=np.zeros_like(time_spent), where=time_spent != 0)
974
974
  all_scattering_rates.append(scattering_rate)
975
975
  ax.plot(segments, scattering_rate, '-o', markersize=2)
976
976
 
@@ -995,6 +995,15 @@ def plot_scattering_statistics():
995
995
  data = np.vstack((segments, all_scattering_rates)).T
996
996
  np.savetxt(filename, data, fmt='%1.2e', delimiter=",", header=header)
997
997
 
998
+ # Save average scattering rates (one value per type, averaged over all segments):
999
+ avg_header = ("Sidewalls diffuse [1/ns], Sidewalls specular [1/ns], Top & bottom diffuse [1/ns], "
1000
+ "Top & bottom specular [1/ns], Holes diffuse [1/ns], Holes specular [1/ns], "
1001
+ "Internal [1/ns], Pillars diffuse [1/ns], Pillars specular [1/ns], "
1002
+ "Interfaces diffuse [1/ns], Interfaces specular [1/ns], "
1003
+ "Interfaces transmission diffuse [1/ns], Interfaces transmission specular [1/ns]")
1004
+ avg_data = np.array([np.mean(rate) for rate in all_scattering_rates])
1005
+ np.savetxt("Data/Scattering rates averaged.csv", avg_data.reshape(1, -1), fmt='%1.2e', delimiter=",", header=avg_header)
1006
+
998
1007
  def plot_scattering_rate_vs_energy():
999
1008
  fig, ax = plt.subplots()
1000
1009
  energies, scattering_rate = np.genfromtxt("Data/Scattering rate vs energy.csv", unpack=True, delimiter=',', usecols=(0,1), skip_header=1)
@@ -1099,11 +1108,8 @@ def plot_data(particle_type: ParticleType, cf, mfp_sampling=False):
1099
1108
  plot_trajectories,
1100
1109
  plot_angle_distribution,
1101
1110
  plot_free_path_distribution,
1102
- plot_frequency_distribution,
1103
- plot_wavelength_distribution,
1104
1111
  plot_travel_time_distribution,
1105
1112
  plot_mean_free_path_distribution,
1106
- plot_velocity_distribution,
1107
1113
  plot_energy_distribution,
1108
1114
  plot_travel_time_vs_energy,
1109
1115
  plot_transport_function,
@@ -1134,6 +1140,10 @@ def plot_data(particle_type: ParticleType, cf, mfp_sampling=False):
1134
1140
  else:
1135
1141
  function_list = electron_function_list
1136
1142
 
1143
+ # These plots require data files that are not saved in low memory mode:
1144
+ if cf.low_memory_usage:
1145
+ function_list = [f for f in function_list if f not in (plot_trajectories, plot_free_path_distribution)]
1146
+
1137
1147
  # Run main functions and handle exceptions:
1138
1148
  for func in function_list:
1139
1149
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: freepaths
3
- Version: 2.2.4
3
+ Version: 2.3.0
4
4
  Summary: Phonon Monte Carlo simulator
5
5
  Home-page: https://github.com/anufrievroman/freepaths
6
6
  Author: Roman Anufriev
@@ -54,9 +54,13 @@ FreePATHS is a command line application, so it runs inside Linux, MacOS, or Wind
54
54
 
55
55
  There are two modes of using the program. Main mode traces a large number of phonons through a structure and collects statistics about their paths. The MFP sampling mode measures phonon mean free paths using a small number of phonons and calculates the thermal conductivity by integrating phonon dispersion.
56
56
 
57
- ### Demo
57
+ ### Getting started
58
58
 
59
- If you simply run `freepaths` without specifying an input file, the program will run a demo simulation.
59
+ If you run `freepaths` without any arguments, the program will print a usage summary. To run a demo simulation with default parameters, use the `--demo` flag:
60
+
61
+ `freepaths --demo`
62
+
63
+ Example input files are available in the [examples](https://github.com/anufrievroman/freepaths/tree/master/examples) folder.
60
64
 
61
65
  ### Main mode
62
66
 
@@ -1,42 +0,0 @@
1
- """FreePATHS - Free Phonon and THermal Simulator"""
2
-
3
- import argparse
4
- import colorama
5
- from colorama import Fore, Style
6
-
7
- from freepaths.particle_types import ParticleType
8
-
9
- __version__ = "2.2.4"
10
-
11
- colorama.init()
12
-
13
- # Parse user arguments:
14
- parser = argparse.ArgumentParser(
15
- prog = 'FreePATHS',
16
- description = 'Phonon Monte Carlo simulator',
17
- epilog = 'For more information, examples, and tutorials, visit: https://anufrievroman.gitbook.io/freepaths'
18
- )
19
- parser.add_argument('input_file', nargs='?', default=None, help='The input file')
20
- parser.add_argument("-s", "--sampling", help="Run in phonon MFP sampling mode", action="store_true")
21
- parser.add_argument("-e", "--electron", help="Run simulation for electrons", action="store_true")
22
- args = parser.parse_args()
23
-
24
-
25
- def run():
26
- """Run the program depending on the mode"""
27
- print(f"\n{Fore.BLUE}FreePATHS v{__version__}{Style.RESET_ALL}")
28
- if args.sampling:
29
- import freepaths.main_mfp_sampling
30
- freepaths.main_mfp_sampling.main(args.input_file, ParticleType.PHONON)
31
-
32
- elif args.electron:
33
- import freepaths.main_tracing
34
- freepaths.main_tracing.main(args.input_file, ParticleType.ELECTRON)
35
-
36
- else:
37
- import freepaths.main_tracing
38
- freepaths.main_tracing.main(args.input_file, ParticleType.PHONON)
39
-
40
-
41
- if __name__ == "__main__":
42
- run()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes