winnet_movie.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # Authors: M. Jacobi, J. Kuske, M. Reichert
3 # Movie script inspired by Skynet (J. Lippuner)
4 import sys
5 import os
6 # Get the path of the script and add it to the path (necessary for the imports)
7 script_path = os.path.dirname(os.path.realpath(__file__))
8 sys.path.append(os.path.join(script_path,'src_files/'))
9 from src_files.FlowAnimation import FlowAnimation
10 from src_files.wreader import wreader
11 from tqdm import tqdm
12 import matplotlib.pyplot as plt
13 import optparse
14 
15 
16 
17 #--- define options ----------------------------------------------------------
18 p = optparse.OptionParser()
19 p.add_option("-i","--input", action="store", dest="rundir", default='.', \
20  help="Simulation directory to visualize (default: current directory)")
21 p.add_option("--disable_flow", action="store_true", dest="plot_flow", default=False, \
22  help="Whether or not to plot the flow arrows.")
23 p.add_option("--flow_min", action="store", dest="flow_min", default="", \
24  help="Lower limit of the flow.")
25 p.add_option("--flow_max", action="store", dest="flow_max", default="", \
26  help="Upper limit of the flow.")
27 p.add_option("--fix_flows", action="store_true", dest="fix_flows", default=False, \
28  help="Whether or not the flows are adapted to the data or lie between flow_min and flow_max.")
29 p.add_option("--flow_range", action="store", dest="flow_range", default="", \
30  help="Log range of the flows in case that they are not fixed.")
31 p.add_option("--fix_flow_arrow_width", action="store_true", dest="fix_flow_arrow_width", default=False, \
32  help="Fix the width of the flow arrows to constant width.")
33 p.add_option("--flow_cmap", action="store", dest="flow_cmap", default="", \
34  help="Colormap of the flows.")
35 p.add_option("--separate_fission", action="store_true", dest="separate_fission", default=False, \
36  help="Whether or not to show arrows also for fission. If not present, hatched areas will be plotted.")
37 p.add_option("--fission_minflow", action="store", dest="fission_minflow", default="", \
38  help="Minimum flow to get indicated as fission region in case the separate fission flag is not given.")
39 p.add_option("--x_min", action="store", dest="x_min", default="", \
40  help="Lower limit of the mass fraction.")
41 p.add_option("--x_max", action="store", dest="x_max", default="", \
42  help="Upper limit of the mass fraction.")
43 p.add_option("--x_cmap", action="store", dest="x_cmap", default="", \
44  help="Colormap of the mass fractions.")
45 p.add_option("--disable_abar", action="store_true", dest="disable_abar", default=False, \
46  help="Whether or not disabling the indication of Abar.")
47 p.add_option("--mass_bins_cmap", action="store", dest="mass_bins_cmap", default="", \
48  help="Colormap of the background colors.")
49 p.add_option("--disable_magic", action="store_true", dest="disable_magic", default=False, \
50  help="Whether or not disabling the indication for the magic number.")
51 p.add_option("--additional_plot", action="store", dest="additional_plot", default="", \
52  help="Whether or not to show an additional plot in the top left corner. "+
53  "Possible options are 'timescales', 'tracked', or 'energy'"+
54  " for plotting average timescales, mass fractions of tracked nuclei, or nuclear energy generation.")
55 p.add_option("--tau_min", action="store", dest="tau_min", default="", \
56  help="Lower limit of the average timescales.")
57 p.add_option("--tau_max", action="store", dest="tau_max", default="", \
58  help="Upper limit of the average timescales.")
59 p.add_option("--engen_min", action="store", dest="engen_min", default="", \
60  help="Lower limit of the Energy.")
61 p.add_option("--engen_max", action="store", dest="engen_max", default="", \
62  help="Upper limit of the Energy.")
63 p.add_option("--tracked_min", action="store", dest="tracked_min", default="", \
64  help="Lower limit of the tracked nuclei mass fractions.")
65 p.add_option("--tracked_max", action="store", dest="tracked_max", default="", \
66  help="Upper limit of the tracked nuclei mass fractions.")
67 p.add_option("--time_min", action="store", dest="t_min", default="", \
68  help="Lower limit of the time.")
69 p.add_option("--time_max", action="store", dest="t_max", default="", \
70  help="Upper limit of the time.")
71 p.add_option("--disable_mainout", action="store_true", dest="disable_mainout", default=False, \
72  help="Whether or not disabling the mainout plot.")
73 p.add_option("--density_min", action="store", dest="density_min", default="", \
74  help="Lower limit of the density.")
75 p.add_option("--density_max", action="store", dest="density_max", default="", \
76  help="Upper limit of the density.")
77 p.add_option("--temperature_min", action="store", dest="temperature_min", default="", \
78  help="Lower limit of the temperatures.")
79 p.add_option("--temperature_max", action="store", dest="temperature_max", default="", \
80  help="Upper limit of the temperature.")
81 p.add_option("--ye_min", action="store", dest="ye_min", default="", \
82  help="Lower limit of the electron fraction.")
83 p.add_option("--ye_max", action="store", dest="ye_max", default="", \
84  help="Upper limit of the electron fraction.")
85 p.add_option("--frame_min", action="store", dest="frame_min", default="", \
86  help="Value of the first frame (default = 1).")
87 p.add_option("--frame_max", action="store", dest="frame_max", default="", \
88  help="Value of the last frame (default = end of the simulation).")
89 p.add_option("--save", action="store_true", dest="save", default=False, \
90  help="Whether or not saving the movie.")
91 p.add_option("--save_frames", action="store_true", dest="save_frames", default=False, \
92  help="Whether or not saving the frames into a folder.")
93 p.add_option("--output", action="store", dest="output_name", default='flow_movie.mp4', \
94  help="Output name of the movie.")
95 p.add_option('--parallel_save', action='store_true', dest='parallel_save', default=False, \
96  help='Whether or not to save the movie in parallel.')
97 p.add_option('--parallel_cpus', action='store', dest='parallel_cpus', default='5', \
98  help='Number of CPUs to use for parallel saving.')
99 p.add_option("--interval", action="store", dest="interval", default='10', \
100  help="Interval of the movie (larger value equals slower).")
101 p.add_option("--mpirun_path", action="store", dest="mpirun_path", default='', \
102  help="Path of the mpirun command to use for parallel saving.")
103 p.set_usage("""
104  Visualize a WinNet simulation. Ensure that at least
105  snapshot_every or h_snapshot_every parameter was enabled in the
106  parameter file. To plot timescales, energy, tracked nuclei, mainout,
107  or reaction flows, the necessary parameters have to be enabled in the
108  parameter file.
109 
110  Usage: ./winnet_movie.py -i <rundir>
111  Example: ./winnet_movie.py -i runs/test""")
112 
113 
114 #--- parse options -----------------------------------------------------------
115 (options,args) = p.parse_args()
116 run_path = options.rundir
117 
118 kwargs = {}
119 kwargs['timescalerange'] = (1e-12, 1e10)
120 kwargs['trackedrange'] = (1e-8, 1e0)
121 kwargs['energyrange'] = (1e10, 1e20)
122 kwargs['timerange'] = (1e-5 , 1e5)
123 kwargs['densityrange'] = (1e-5, 1e12)
124 kwargs['temperaturerange'] = (0, 10)
125 kwargs['yerange'] = (0.0, 0.55)
126 
127 if options.flow_min: kwargs['flow_min'] = float(options.flow_min)
128 if options.flow_max: kwargs['flow_max'] = float(options.flow_max)
129 if options.plot_flow: kwargs['plot_flow'] = False if options.plot_flow else True
130 if options.separate_fission: kwargs['separate_fission'] = True
131 if options.fission_minflow: kwargs['fission_minflow'] = float(options.fission_minflow)
132 if options.fix_flows: kwargs['flow_adapt_prange'] = False
133 if options.flow_range: kwargs['flow_prange'] = float(options.flow_range)
134 if options.fix_flow_arrow_width: kwargs['flow_adapt_width'] = True
135 if options.flow_cmap: kwargs['cmapNameFlow'] = options.flow_cmap
136 if options.x_min: kwargs['X_min'] = float(options.x_min)
137 if options.x_max: kwargs['X_max'] = float(options.x_max)
138 if options.x_cmap: kwargs['cmapNameX'] = options.x_cmap
139 if options.disable_abar: kwargs['plot_abar'] = (not options.disable_abar)
140 if options.mass_bins_cmap: kwargs['cmapNameMassBins'] = options.mass_bins_cmap
141 if options.disable_magic: kwargs['plot_magic'] = (not options.disable_magic)
142 if options.additional_plot: kwargs['additional_plot'] = options.additional_plot.lower().strip()
143 if options.tau_min: kwargs['timescalerange'] = (float(options.tau_min),kwargs['timescalerange'][1])
144 if options.tau_max: kwargs['timescalerange'] = (kwargs['timescalerange'][0], float(options.tau_max))
145 if options.engen_min: kwargs['energyrange'] = (float(options.engen_min), kwargs['energyrange'][1])
146 if options.engen_max: kwargs['energyrange'] = (kwargs['energyrange'][0], float(options.engen_max))
147 if options.tracked_min: kwargs['trackedrange'] = (float(options.tracked_min), kwargs['trackedrange'][1])
148 if options.tracked_max: kwargs['trackedrange'] = (kwargs['trackedrange'][0], float(options.tracked_max))
149 if options.t_min: kwargs['timerange'] = (float(options.t_min), kwargs['timerange'][1])
150 if options.t_max: kwargs['timerange'] = (kwargs['timerange'][0], float(options.t_max))
151 if options.disable_mainout: kwargs['plot_mainout'] = (not options.disable_mainout)
152 if options.density_min: kwargs['densityrange'] = (float(options.density_min), kwargs['densityrange'][1])
153 if options.density_max: kwargs['densityrange'] = (kwargs['densityrange'][0], float(options.density_max))
154 if options.temperature_min: kwargs['temperaturerange'] = (float(options.temperature_min), kwargs['temperaturerange'][1])
155 if options.temperature_max: kwargs['temperaturerange'] = (kwargs['temperaturerange'][0], float(options.temperature_max))
156 if options.ye_min: kwargs['yerange'] = (float(options.ye_min), kwargs['yerange'][1])
157 if options.ye_max: kwargs['yerange'] = (kwargs['yerange'][0], float(options.ye_max))
158 
159 
160 
161 # Sanity checks
162 w = wreader(run_path)
163 
164 # Check if the run has snapshots
165 value = w.check_existence('snapshot')
166 if value == 0:
167  raise ValueError('No snapshots found. Please enable snapshots in the parameter file.')
168 
169 # Sanity for timescales and so on, disable if not found
170 if options.additional_plot:
171  if options.additional_plot == 'timescales':
172  value = w.check_existence('timescales')
173  if value == 0:
174  print('No timescales found. Disabling timescales. Remove --additional_plot to disable this message.')
175  kwargs['additional_plot'] = 'none'
176  elif options.additional_plot == 'energy':
177  value = w.check_existence('energy')
178  if value == 0:
179  print('No energy found. Disabling energy. Remove --additional_plot to disable this message.')
180  kwargs['additional_plot'] = 'none'
181  elif options.additional_plot == 'tracked':
182  value = w.check_existence('tracked_nuclei')
183  if value == 0:
184  print('No tracked nuclei found. Disabling tracked nuclei. Remove --additional_plot to disable this message.')
185  kwargs['additional_plot'] = 'none'
186 if not options.disable_mainout:
187  value = w.check_existence('mainout')
188  if value == 0:
189  print('No mainout found. Disabling mainout. Set --disable_mainout to disable this message.')
190  kwargs['plot_mainout'] = False
191 if not options.plot_flow:
192  value = w.check_existence('flows')
193  if value == 0:
194  print('No flow found. Disabling flow. Set --disable_flow to disable this message.')
195  kwargs['plot_flow'] = False
196 
197 
198 if options.frame_min: frame_min = int(options.frame_min)
199 else: frame_min = 1
200 if options.frame_max: frame_max = int(options.frame_max)
201 else: frame_max = w.nr_of_snaps
202 
203 # Ensure that not both is chosen
204 if options.save_frames and options.save:
205  raise ValueError('Cannot save frames and movie at the same time. Please choose one of them.')
206 
207 # Check if frames should be saved into a folder
208 if options.save_frames:
209  # Create the output folder if it doesnt exist yet
210  if options.output_name:
211  os.mkdir(options.output_name)
212 
213  if not options.parallel_save:
214  # Create figure
215  fig = plt.figure(figsize=(15, 8))
216  if options.output_name:
217  anim = FlowAnimation(run_path, fig, frame_dir=options.output_name, **kwargs)
218  else:
219  anim = FlowAnimation(run_path, fig, **kwargs)
220 
221  # Save the frames
222  for i in tqdm(range(frame_min, frame_max)):
223  anim.save_frame(i)
224  else: # parallel saving
225  # Sanity check, does mpi4py exist?
226  try:
227  from mpi4py import MPI
228  except ImportError:
229  raise ImportError('mpi4py not found. Please install it to use parallel saving.')
230 
231  # Next check, is ffmpeg installed?
232  if os.system('ffmpeg -version > /dev/null') != 0:
233  raise ImportError('ffmpeg not found. Please install it to use parallel saving.')
234 
235  # Get folder location of this script
236  script_path = os.path.dirname(os.path.realpath(__file__))
237  # The options have to be passed to the parallel_save.py script
238  # Therefore save them
239  # try to import pickle
240  try:
241  import pickle
242  except ImportError:
243  raise ImportError('pickle not found. Please install it to use parallel saving.')
244 
245  option_dict_path = os.path.join(script_path, 'src_files/data/options.pkl')
246  with open(option_dict_path, 'wb') as f:
247  pickle.dump(kwargs, f)
248 
249  # Get the path to the parallel_save.py script
250  parallel_save_path = os.path.join(script_path, 'src_files', 'parallel_save.py')
251 
252  # Check if the mpirun path is given
253  if not options.mpirun_path:
254  # Get the correct mpirun
255  mpirun = os.popen('whereis mpirun').read().strip().split()
256  # Get the mpirun that has oneapi in the path
257  mpirun = [m for m in mpirun if 'oneapi' in m]
258  if not mpirun:
259  raise ImportError('No mpirun with oneapi found. Please install it to use parallel saving.')
260  mpirun = mpirun[0]
261  else:
262  # Take the given mpirun path
263  mpirun = options.mpirun_path
264 
265  # Test if the mpirun path is correct
266  if os.system(f'{mpirun} -version > /dev/null') != 0:
267  raise ImportError('mpirun not found or wrong path. Please install it to use parallel saving.')
268 
269  # Run the parallel saving
270  os.system(f'{mpirun} -n {options.parallel_cpus} python {parallel_save_path} {run_path} {frame_min} {frame_max} {options.interval} TRUE')
271 
272  # Remove the options file
273  os.remove(option_dict_path)
274 
275  # Move to the output destination
276  if options.output_name:
277  os.system(f'mv {run_path}/frames/* {options.output_name}')
278 
279  print('Finished saving frames!')
280 
281 # Check if things should be saved or shown
282 elif options.save:
283  if not options.parallel_save:
284  # Funcanimation
285  fig = plt.figure(figsize=(15, 8))
286 
287  # Animate the flows
288  anim = FlowAnimation(run_path, fig, **kwargs)
289 
290  ani = anim.get_funcanimation(frames=range(frame_min, frame_max))
291  ani.save(options.output_name, fps=int(options.interval))
292  else: # Parallel saving
293  # Sanity check, does mpi4py exist?
294  try:
295  from mpi4py import MPI
296  except ImportError:
297  raise ImportError('mpi4py not found. Please install it to use parallel saving.')
298 
299  # Next check, is ffmpeg installed?
300  if os.system('ffmpeg -version > /dev/null') != 0:
301  raise ImportError('ffmpeg not found. Please install it to use parallel saving.')
302 
303  # Get folder location of this script
304  script_path = os.path.dirname(os.path.realpath(__file__))
305  # The options have to be passed to the parallel_save.py script
306  # Therefore save them
307  # try to import pickle
308  try:
309  import pickle
310  except ImportError:
311  raise ImportError('pickle not found. Please install it to use parallel saving.')
312 
313  option_dict_path = os.path.join(script_path, 'src_files/data/options.pkl')
314  with open(option_dict_path, 'wb') as f:
315  pickle.dump(kwargs, f)
316 
317  # Get the path to the parallel_save.py script
318  parallel_save_path = os.path.join(script_path, 'src_files', 'parallel_save.py')
319 
320  # Check if the mpirun path is given
321  if not options.mpirun_path:
322  # Get the correct mpirun
323  mpirun = os.popen('whereis mpirun').read().strip().split()
324  # Get the mpirun that has oneapi in the path
325  mpirun = [m for m in mpirun if 'oneapi' in m]
326  if not mpirun:
327  raise ImportError('No mpirun with oneapi found. Please install it to use parallel saving.')
328  mpirun = mpirun[0]
329  else:
330  # Take the given mpirun path
331  mpirun = options.mpirun_path
332 
333  # Test if the mpirun path is correct
334  if os.system(f'{mpirun} -version > /dev/null') != 0:
335  raise ImportError('mpirun not found or wrong path. Please install it to use parallel saving.')
336 
337  # Run the parallel saving
338  os.system(f'{mpirun} -n {options.parallel_cpus} python {parallel_save_path} {run_path} {frame_min} {frame_max} {options.interval}')
339 
340  # Remove the options file
341  os.remove(option_dict_path)
342 
343  print('Finished saving movie!')
344 else:
345  # Funcanimation
346  fig = plt.figure(figsize=(15, 8))
347 
348  # Animate the flows
349  anim = FlowAnimation(run_path, fig, **kwargs)
350  ani = anim.get_funcanimation(interval=int(options.interval), frames=range(frame_min, frame_max))
351  plt.show()
src_files.wreader
Definition: wreader.py:1
src_files.FlowAnimation
Definition: FlowAnimation.py:1
src_files.wreader.wreader
Definition: wreader.py:11
src_files.FlowAnimation.FlowAnimation
Definition: FlowAnimation.py:22