FlowAnimation.py
Go to the documentation of this file.
1 # Authors: M. Jacobi, J. Kuske, M. Reichert
2 ################################################################################
3 import os
4 import numpy as np
5 import matplotlib.pyplot as plt
6 import matplotlib as mpl
7 import matplotlib.patches as patches
8 import matplotlib.patheffects as PathEffects
9 from matplotlib.collections import PatchCollection
10 from tqdm import tqdm
11 from matplotlib import cm
12 from matplotlib.patches import Arrow, FancyBboxPatch
13 from matplotlib.colors import LogNorm, SymLogNorm
14 from matplotlib.colors import ListedColormap, LinearSegmentedColormap
15 from matplotlib.animation import FuncAnimation
16 from matplotlib.widgets import Slider, Button
17 from wreader import wreader
18 from h5py import File
19 from nucleus_multiple_class import nucleus_multiple
20 from ngamma_eq import ngamma_eq
21 from winvn_class import winvn
22 
23 ################################################################################
24 
25 class FlowAnimation(object):
26  """
27  Class to create an animation of the abundances and their flow for the nuclear reaction network WinNet.
28  """
29 
30  def __init__(
31  self,
32  path,
33  fig,
34  # Folder to save the frames in
35  frame_dir = None,
36  # Flows
37  plot_flow = True,
38  # flow_group = 'flows',
39  flow_min = 1e-8,
40  flow_max = 1e1,
41  separate_fission = True,
42  fission_minflow = 1e-10,
43  flow_cbar = True,
44  flow_adapt_prange = True,
45  flow_prange = 5,
46  flow_adapt_width = True,
47  flow_maxArrowWidth= 2.0,
48  flow_minArrowWidth= 0.3,
49  cmapNameFlow = 'viridis',
50  # Mass fractions
51  abun_cbar = True,
52  X_min = 1e-8,
53  X_max = 1,
54  cmapNameX = 'inferno',
55  # Mass bins
56  plot_abar = True,
57  plotMassBins = True,
58  addMassBinLabels = True,
59  alphaMassBins = 0.5,
60  cmapNameMassBins = 'jet',
61  massBins = [[1,1],[2,71],[72,93],[94,110],[111,144],[145,169],[170,187],[188,205],[206,252],[253,337]],
62  massBinLabels = ['','','1st peak','','2nd peak','rare earths', '', '3rd peak', '', 'fissioning'],
63  # Magic numbers
64  plot_magic = True,
65  # Additional plots
66  additional_plot = 'none',
67  # Tracked nuclei
68  trackedrange = (1e-8, 1),
69  # Additional mainout
70  amainoutrange = (5e-10, 1),
71  # Energy
72  energyrange = (1e10, 1e20),
73  # Timescales
74  timescalerange = (1e-12, 1e10),
75  timerange = (1e-5 , 1e5),
76  # Mainout
77  plot_mainout = True,
78  densityrange = (1e-5, 1e12),
79  temperaturerange = (0, 10),
80  yerange = (0.0, 0.55),
81  plot_logo = True,
82  indicate_r_path = False,
83  winvn_path = None,
84  interactive = False
85  ):
86  """
87  Parameters
88  ----------
89  path : str
90  Path to the WinNet data.
91  fig : matplotlib.figure.Figure
92  Figure to plot the animation on.
93  frame_dir : str
94  Folder to save the frames in, default is path/frames.
95  plot_flow : bool
96  Plot the flow of the abundances.
97  flow_min : float
98  Minimum value for the flow.
99  flow_max : float
100  Maximum value for the flow.
101  separate_fission : bool
102  Separate the fissioning region from the fission products in the flow plot.
103  fission_minflow : float
104  Minimum value to indicate a fission region.
105  flow_cbar : bool
106  Plot the colorbar for the flow.
107  flow_adapt_prange : bool
108  Adapt the color range of the flow to the data.
109  flow_prange : float
110  Range (in log10) of the flow.
111  flow_adapt_width : bool
112  Adapt the width of the flow arrows to the flow.
113  flow_maxArrowWidth : float
114  Maximum width of the flow arrows.
115  flow_minArrowWidth : float
116  Minimum width of the flow arrows.
117  cmapNameFlow : str
118  Name of the colormap for the flow.
119  abun_cbar : bool
120  Plot the colorbar for the mass fractions.
121  X_min : float
122  Minimum value for the mass fractions.
123  X_max : float
124  Maximum value for the mass fractions.
125  cmapNameX : str
126  Name of the colormap for the mass fractions.
127  plot_abar : bool
128  Plot the average mass number.
129  plotMassBins : bool
130  Plot the mass bins.
131  addMassBinLabels : bool
132  Add labels to the mass bins.
133  alphaMassBins : float
134  Transparency of the mass bins.
135  cmapNameMassBins : str
136  Name of the colormap for the mass bin color.
137  massBins : list
138  List of mass bins.
139  massBinLabels : list
140  List of labels for the mass bins.
141  plot_magic : bool
142  Plot the magic numbers in the abundance plot.
143  additional_plot : str
144  Additional plot to be made, possible values: 'None', 'timescales', 'energy', 'tracked'.
145  trackedrange : tuple
146  Range of the tracked nuclei plot.
147  amainoutrange : tuple
148  Range of the additional mainout plot.
149  energyrange : tuple
150  Range of the energy axis.
151  timescalerange : tuple
152  Range of the timescales.
153  timerange : tuple
154  Range of the time axis.
155  plot_mainout : bool
156  Plot the mainout data.
157  densityrange : tuple
158  Range of the density axis in the mainout plot.
159  temperaturerange : tuple
160  Range of the temperature axis in the mainout plot.
161  yerange : tuple
162  Range of the electron fraction axis in the mainout plot.
163  plot_logo : bool
164  Plot the WinNet logo.
165  indicate_r_path : bool
166  Indicate the r-process path.
167  winvn_path : str
168  Path to the winvn file in case r-process path should be indicated.
169  interactive : bool
170  Enable interactive mode.
171  """
172 
173 
174  # Make some sanity check and ensure that the user has the correct version of Matplotlib
175  if (mpl.__version__ < '3.8.0'):
176  print('Using old version of Matplotlib ('+str(mpl.__version__)+'), some features may not work.')
177  print('Need 3.8 or higher.')
178 
179 
180  # Set the paths
181  # Data directory:
182  # Remember where this file is located
183  self.__script_path = os.path.dirname(os.path.abspath(__file__))
184  self.__data_path = os.path.join(self.__script_path,"data")
185  # Frame directory:
186  if frame_dir is None:
187  self.frame_dir = f'{path}/frames'
188  else:
189  self.frame_dir = frame_dir
190 
191  # WinNet run path
192  self.path = path
193 
194  # Save the parameters in class variables
195  self.X_min = X_min # Minimum value for the mass fractions
196  self.X_max = X_max # Maximum value for the mass fractions
197  self.plotMassBins = plotMassBins # Plot the mass bins
198  self.plot_abar = plot_abar # Plot the average mass number
199  self.addMassBinLabels = addMassBinLabels # Add labels to the mass bins
200  self.alphaMassBins = alphaMassBins # Transparency of the mass bins
201  self.cmapNameMassBins = cmapNameMassBins # Name of the colormap for the mass bin color
202  self.massBins = massBins # List of mass bins
203  self.massBinLabels = massBinLabels # List of labels for the mass bins
204  self.additional_plot = additional_plot.lower() # Additional plot to be made, possible values: 'None', 'timescales', 'energy', 'tracked'
205  self.energyrange = energyrange # Range of the energy axis
206  self.trackedrange = trackedrange # Range of the tracked nuclei plot
207  self.timescalerange = timescalerange # Range of the timescales
208  self.timerange = timerange # Range of the time axis
209  self.plot_mainout = plot_mainout # Plot the mainout data
210  self.plot_logo = plot_logo # Plot the WinNet logo
211  self.interactive = interactive # Have it interactive
212  self.flow_group = 'flows' # Name of the group in the HDF5 file that contains the flow data
213  self.plot_flow = plot_flow # Plot the flow of the abundances
214  self.fig = fig # Figure to plot the animation on
215  self.separate_fission = separate_fission # Separate the fissioning region from the fission products in the flow plot
216  self.plot_magic = plot_magic # Plot the magic numbers in the abundance plot
217  self.densityrange = densityrange # Range of the density axis in the mainout plot
218  self.temperaturerange = temperaturerange # Range of the temperature axis in the mainout plot
219  self.yerange = yerange # Range of the electron fraction axis in the mainout plot
220  self.cmapNameX = cmapNameX # Name of the colormap for the mass fractions
221  self.cmapNameFlow = cmapNameFlow # Name of the colormap for the flow
222  self.flow_adapt_width = flow_adapt_width # Adapt the width of the flow arrows to the flow
223  self.flow_maxArrowWidth = flow_maxArrowWidth # Maximum width of the flow arrows
224  self.flow_minArrowWidth = flow_minArrowWidth # Minimum width of the flow arrows
225  self.flow_min = flow_min # Minimum value for the flow
226  self.flow_max = flow_max # Maximum value for the flow
227  self.flow_adapt_prange = flow_adapt_prange # Adapt the color range of the flow to the data
228  self.fission_minflow = fission_minflow # Minimum value for the fission flow
229  self.amainoutrange = amainoutrange # Range of the additional mainout plot
230  self.indicate_r_path = indicate_r_path # Indicate the r-process path
231  self.winvn_path = winvn_path # Path to the winvn file in case r-process path should be indicated
232 
233  if (self.flow_adapt_prange):
234  self.flow_prange = flow_prange # Range (in log10) of the flow
235  else:
236  self.flow_prange = np.log10(self.flow_max) - np.log10(self.flow_min)
237 
238  # Check which additional plot should be made
239  if self.additional_plot == 'timescales':
240  self.plot_timescales = True
241  self.plot_energy = False
242  self.plot_tracked = False
243  self.plot_addmainout = False
244  elif self.additional_plot == 'energy':
245  self.plot_timescales = False
246  self.plot_energy = True
247  self.plot_tracked = False
248  self.plot_addmainout = False
249  elif self.additional_plot == 'tracked':
250  self.plot_timescales = False
251  self.plot_energy = False
252  self.plot_tracked = True
253  self.plot_addmainout = False
254  elif self.additional_plot == 'mainout':
255  self.plot_timescales = False
256  self.plot_energy = False
257  self.plot_tracked = False
258  self.plot_addmainout = True
259  elif self.additional_plot == 'none':
260  self.plot_timescales = False
261  self.plot_energy = False
262  self.plot_tracked = False
263  self.plot_addmainout = False
264  else:
265  raise ValueError(f"Additional plot {self.additional_plot} not recognized. Possible values: 'None', 'timescales', 'energy', 'tracked'")
266 
267  # Initialize a class to read WinNet data
268  self.wreader = wreader(path)
269 
270  # Read the stable isotopes
271  self.N_stab, self.Z_stab = np.loadtxt(os.path.join(self.__data_path,'../../../class_files/data/stableiso.dat'),
272  unpack=True, usecols=(1, 2), dtype=int)
273 
274  # Read the nuclear chart nuclei
275  sunet_path = os.path.join(self.__data_path, "sunet_really_complete")
276  nuclei_names = np.loadtxt(sunet_path,dtype=str)
277  nm = nucleus_multiple(names=nuclei_names)
278  self.__A_plot = nm.A
279  self.__Z_plot = nm.Z
280  self.__N_plot = nm.N
281  self.__min_N, self.__max_N = np.min(self.__N_plot), np.max(self.__N_plot)
282  self.__min_Z, self.__max_Z = np.min(self.__Z_plot), np.max(self.__Z_plot)
283 
284 
285  # Other data that does not change like magic numbers
286  self.nMagic = [8, 20, 28, 50, 82, 126, 184] # Magic numbers in neutrons
287  self.zMagic = [8, 20, 28, 50, 82, 114] # Magic numbers in protons
288  self.magic_excess = 4 # How long should the line stick out over the nuc. chart?
289 
290  # Timescale plotting parameters
291  self.timescale_colors = ["C1","C2","C3","C4","C5","C6","C7","C8","C9","C0"]
292  self.timescale_entries = [['ag','ga'],['ng','gn'],['an','na'],['np','pn'],['pg','gp'],['ap','pa'],["beta"],["bfiss"],["nfiss"],["sfiss"]]
293  self.timescale_labels = [r"$\tau_{\alpha,\gamma}$",r"$\tau_{n,\gamma}$",r"$\tau_{\alpha,n}$",r"$\tau_{n,p}$",r"$\tau_{p,\gamma}$",
294  r"$\tau_{\alpha,p}$",r"$\tau_{\beta}$",r"$\tau_{\rm{bfiss}}$",r"$\tau_{\rm{nfiss}}$",r"$\tau_{\rm{sfiss}}$"]
295 
296  # Energy plotting parameters
297  self.energy_colors = ["k","C2","C3","C4","C5","C6","C7","C8","C9","C0"]
298  self.energy_entries = ['tot', 'ag_ga', 'ng_gn', 'an_na', 'np_pn', 'pg_gp', 'ap_pa', 'beta', 'fiss']
299  self.energy_labels = ['Total', r"$( \alpha,\gamma )$", r"$( n,\gamma )$", r"$( \alpha,n )$", r"$( n,p )$",
300  r"$( p,\gamma )$", r"$( \alpha,p )$", r"$\beta$", r"$\rm{fission}$"]
301  self.energy_lw = np.ones(len(self.energy_entries))
302  self.energy_lw[0] = 2
303 
304  # Set up the norm of the flow
305  self.flow_norm = LogNorm(flow_min, flow_max, clip=True)
306  # In case of adaptive flow ranges, keep track of the maximums to adapt the ranges with a rolling average
307  self.flow_max_history = np.ones(5)*np.nan
308 
309  # If the flow is not plotted, then the fissioning region should not be separated
310  # and the flow colorbar should not be plotted
311  if (not self.plot_flow):
312  self.separate_fission = False
313  flow_cbar = False
314 
315  # Initialize the axes and figure
316  self.init_axes()
317  # Initialize the data
318  self.init_data()
319  # Initialize the plot
320  self.init_plot()
321  # Initialize the colorbars
322  self.init_cbars(abun_cbar, flow_cbar)
323 
324  # Set up the limits of the plot
325  self.limits_plot = self.ax.get_xlim(), self.ax.get_ylim()
326 
327  # For interactive flow range
328  self.flow_max_offset = 0.0
329  self.flow_min_offset = 0.0
330  # For interactive mafra range
331  self.mafra_max_offset = 0.0
332  self.mafra_min_offset = 0.0
333 
334  if self.indicate_r_path or self.interactive:
335  self.__init_ngamma_eq()
336 
337  if self.interactive:
339  self.__interactive_box = None
340  self.__interactive_textbox = None
341  self.winvn = winvn(self.winvn_path)
342  self.winvn.read_winvn()
343  self.winvn.calculate_Sn()
344  df = self.winvn.get_dataframe()
345  Z = df['Z'].values
346  N = df['N'].values
347  # Set a tuple of N and Z as index
348  df.set_index(['N','Z'], inplace=True)
349  self.winvn.set_dataframe(df)
350  # Prepare the other backgrounds
351  self.__background_Y_2 = np.zeros_like(self.__background_Y_1)*np.nan
352  self.__background_Y_2[N,Z] = df['binding energy'].values/(Z+N)
353  self.__background_Y_3 = np.zeros_like(self.__background_Y_1)*np.nan
354  self.__background_Y_3[N,Z] = df['Sn'].values
355  self.forward_mode = 0
356 
357 
358  def __init_ngamma_eq(self):
359  """
360  Initialize the ngamma_eq class.
361  """
363  self.ngamma_eq_plot = self.ax.plot([],[],color='purple',lw=1.5,zorder=99)
364  self.ngamma_eq_plot_o = self.ax.plot([],[],color='w',lw=2.5,zorder=98)
365 
366 
367 
369  sunet_path = self.wreader.template['net_source']
370  nuclei_names = np.loadtxt(sunet_path,dtype=str)
371  nm = nucleus_multiple(names=nuclei_names)
372 
373  self.__sunet_lines = []
374  # Loop through Zs
375  for Z in np.unique(nm.Z):
376  # Find the Ns that are have larger than distance one to the next N
377  mask = (nm.Z == Z)
378  Ns = nm.N[mask]
379  # Find the Ns that are have larger than distance one to the next N
380  diff = np.diff(Ns)
381  mask = np.where(diff > 1)[0]
382  # Loop through the Ns
383  # Plot left and right
384  line = self.ax.plot([np.min(Ns)-0.5, np.min(Ns)-0.5], [Z-0.5, Z+0.5], color='red', zorder=1000, lw=1)
385  self.__sunet_lines.append(line)
386  line = self.ax.plot([np.max(Ns)+0.5, np.max(Ns)+0.5], [Z-0.5, Z+0.5], color='red', zorder=1000, lw=1)
387  self.__sunet_lines.append(line)
388  for i in mask:
389  # Add a line to the plot
390  line = self.ax.plot([Ns[i]+0.5, Ns[i]+0.5], [Z-0.5, Z+0.5], color='red', zorder=1000, lw=1)
391  self.__sunet_lines.append(line)
392  line = self.ax.plot([Ns[i+1]-0.5, Ns[i+1]-0.5], [Z-0.5, Z+0.5], color='red', zorder=1000, lw=1)
393  self.__sunet_lines.append(line)
394 
395  # Same but for Z
396  for N in np.unique(nm.N):
397  # Find the Ns that are have larger than distance one to the next N
398  mask = (nm.N == N)
399  Zs = nm.Z[mask]
400  # Find the Ns that are have larger than distance one to the next N
401  diff = np.diff(Zs)
402  mask = np.where(diff > 1)[0]
403  # Loop through the Ns
404  # Plot left and right
405  line = self.ax.plot([N-0.5, N+0.5], [np.min(Zs)-0.5, np.min(Zs)-0.5], color='red', zorder=1000, lw=1)
406  self.__sunet_lines.append(line)
407  line = self.ax.plot([N-0.5, N+0.5], [np.max(Zs)+0.5, np.max(Zs)+0.5], color='red', zorder=1000, lw=1)
408  self.__sunet_lines.append(line)
409  for i in mask:
410  # Add a line to the plot
411  line = self.ax.plot([N-0.5, N+0.5], [Zs[i]+0.5, Zs[i]+0.5], color='red', zorder=1000, lw=1)
412  self.__sunet_lines.append(line)
413  line = self.ax.plot([N-0.5, N+0.5], [Zs[i+1]-0.5, Zs[i+1]-0.5], color='red', zorder=1000, lw=1)
414  self.__sunet_lines.append(line)
415 
416  # Hide the lines
417  for line in self.__sunet_lines:
418  for l in line:
419  l.set_visible(False)
420  self.sunet_indication = False
421 
422 
423 
424 
425  def init_axes(self):
426  """
427  Initialize the axes and everything figure related of the plot.
428  """
429  # Make the hatch linewidth smaller
430  mpl.rcParams['hatch.linewidth'] = 0.8
431 
432  # Set up the figure
433  self.ax = self.fig.gca()
434  self.ax.set_aspect('equal')
435 
436  # Set up the axes for the nuclear chart
437  self.__init_nucchart_ax()
438 
439  # Set up the axes for the mainout plot
440  if self.plot_mainout:
441  self.__init_axMainout()
442 
443  # Set up the axes for the mass fraction plot
444  self.__init_axAbund()
445 
446  # Timescale stuff
447  if self.plot_timescales:
448  self.__init_axTimescales()
449 
450  # Energy stuff
451  if self.plot_energy:
452  self.__init_axEnergy()
453 
454  # Tracked nuclei
455  if self.plot_tracked:
456  self.__init_axTracked()
457 
458  # Additional mainout
459  if self.plot_addmainout:
460  self.__init_axAddMainout()
461 
462  # WinNet logo
463  if self.plot_logo:
464  self.__init_logo()
465 
466  # interactive stuff
467  if self.interactive:
468  self.__init_interactive()
469 
470  # Start with a running movie
471  self.movie_paused = False
472 
473  # Make white behind the colorbars and plots
474  self.ax.add_patch(patches.Rectangle((0.3, 0.84), 0.8, 0.15, fill=True, color='w', zorder=100, transform=self.fig.transFigure))
475  self.ax.add_patch(patches.Rectangle((0.15, 0.745), 0.395, 0.2, fill=True, color='w', zorder=100, transform=self.fig.transFigure))
476 
477 
478 
480  """
481  Initialize the axes and everything figure related of the nuclear chart.
482  """
483  # Set up the main figure of the nuclear chart, i.e., remove borders, ticks, etc.
484  self.ax.xaxis.set_visible(False)
485  self.ax.yaxis.set_visible(False)
486  self.ax.spines[['right', 'top', "bottom", "left"]].set_visible(False)
487 
488 
489  def __init_axAbund(self):
490  """
491  Initialize the axes and everything figure related of the mass fraction plot.
492  """
493  # Add summed mass fraction plot
494  self.axAbund = plt.axes([0.15,0.78,0.35,0.15])
495  self.axAbund.set_xlabel(r'Mass number $A$')
496  self.axAbund.set_ylabel(r'X(A)')
497  self.axAbund.set_xlim(0,300)
498  self.axAbund.set_yscale('log')
499  self.axAbund.set_ylim(self.X_min, self.X_max)
500  if self.plot_abar:
501  self.axAbund.axvline(np.nan, color='tab:red',label=r"$\bar{A}$")
502  self.axAbund.legend(loc='upper right')
503  # Add mass fraction bins if needed
504  if self.plotMassBins:
505  self.axMassFrac = self.axAbund.twinx()
506  self.axMassFrac.set_ylabel(r'$X(A)$')
507  self.axMassFrac.set_ylim(0,1)
508  self.axMassFrac.set_yscale('linear')
509 
510 
512  """
513  Initialize the axes and everything figure related of the timescales plot.
514  """
515  self.axTimescales = plt.axes([0.15,0.55,0.20,0.17])
516  self.axTimescales.set_xlabel('Time [s]')
517  self.axTimescales.set_ylabel('Timescales [s]')
518  self.axTimescales.set_yscale('log')
519  self.axTimescales.set_ylim(self.timescalerange[0],self.timescalerange[1])
520  self.axTimescales.set_xscale('log')
521  self.axTimescales.set_xlim(self.timerange[0],self.timerange[1])
522 
523  def __init_axTracked(self):
524  """
525  Initialize the axes and everything figure related of the tracked nuclei plot.
526  """
527  self.axTracked = plt.axes([0.15,0.55,0.20,0.17])
528  self.axTracked.set_xlabel('Time [s]')
529  self.axTracked.set_ylabel('Mass fractions')
530  self.axTracked.set_yscale('log')
531  self.axTracked.set_ylim(self.trackedrange[0],self.trackedrange[1])
532  self.axTracked.set_xscale('log')
533  self.axTracked.set_xlim(self.timerange[0],self.timerange[1])
534 
535  def __init_axEnergy(self):
536  """
537  Initialize the axes and everything figure related of the energy plot.
538  """
539  self.axEnergy = plt.axes([0.15,0.55,0.20,0.17])
540  self.axEnergy.set_xlabel('Time [s]')
541  self.axEnergy.set_ylabel('Energy [erg/g/s]')
542  self.axEnergy.set_yscale('log')
543  self.axEnergy.set_ylim(self.energyrange[0],self.energyrange[1])
544  self.axEnergy.set_xscale('log')
545  self.axEnergy.set_xlim(self.timerange[0],self.timerange[1])
546 
548  """
549  Initialize the axes and everything figure related of the energy plot.
550  """
551  self.axAddMainout = plt.axes([0.15,0.55,0.20,0.17])
552  self.axAddMainout.set_xlabel('Time [s]')
553  self.axAddMainout.set_ylabel('Abundance')
554  self.axAddMainout.set_yscale('log')
555  self.axAddMainout.set_ylim(self.amainoutrange[0],self.amainoutrange[1])
556  self.axAddMainout.set_xscale('log')
557  self.axAddMainout.set_xlim(self.timerange[0],self.timerange[1])
558 
559  def __init_axMainout(self):
560  """
561  Initialize the axes and everything figure related of the mainout plot.
562  """
563  def make_patch_spines_invisible(ax):
564  ax.set_frame_on(True)
565  ax.patch.set_visible(False)
566  for sp in ax.spines.values():
567  sp.set_visible(False)
568  # Density
569  self.axMainout = plt.axes([0.65,0.2,0.25,0.25])
570  self.axMainout.set_xlabel('Time [s]')
571  self.axMainout.set_ylabel(r'Density [g/cm$^3$]')
572  self.axMainout.set_yscale('log')
573  self.axMainout.set_ylim(self.densityrange[0],self.densityrange[1])
574  self.axMainout.set_xscale('log')
575  self.axMainout.set_xlim(self.timerange[0],self.timerange[1])
576  # Temperature
577  self.axMainout_temp = self.axMainout.twinx()
578  self.axMainout_temp.set_ylabel(r'Temperature [GK]')
579  self.axMainout_temp.set_ylim(self.temperaturerange[0],self.temperaturerange[1])
580  self.axMainout_temp.spines["left"].set_position(("axes", -0.2))
581  make_patch_spines_invisible(self.axMainout_temp)
582  self.axMainout_temp.spines["left"].set_visible(True)
583  self.axMainout_temp.yaxis.set_label_position('left')
584  self.axMainout_temp.yaxis.set_ticks_position('left')
585  self.axMainout_temp.yaxis.label.set_color("tab:red")
586  self.axMainout_temp.yaxis.set_tick_params(colors="tab:red")
587  # Ye
588  self.axMainout_ye = self.axMainout.twinx()
589  self.axMainout_ye.set_ylabel(r'Electron fraction')
590  self.axMainout_ye.set_ylim(self.yerange[0],self.yerange[1])
591  make_patch_spines_invisible(self.axMainout_ye)
592  self.axMainout_ye.spines["right"].set_visible(True)
593  self.axMainout_ye.yaxis.set_label_position('right')
594  self.axMainout_ye.yaxis.set_ticks_position('right')
595  self.axMainout_ye.yaxis.label.set_color("tab:blue")
596  self.axMainout_ye.yaxis.set_tick_params(colors="tab:blue")
597 
598 
599  def __init_logo(self):
600  """
601  Initialize the axes and everything figure related of the WinNet logo.
602  """
603  self.axLogo = plt.axes([0.75,0.45,0.15,0.15])
604  self.axLogo.axis('off')
605  self.logo = self.axLogo.imshow(plt.imread(os.path.join(self.__data_path,'WinNet_logo.png')))
606 
608 
609  self.ax_slider = plt.axes([0.18, 0.08, 0.72, 0.02], facecolor='lightgoldenrodyellow')
610  self.ax_button = plt.axes([0.18-0.018, 0.08, 0.012, 0.022]) # Adjust `bottom` for centering
611 
612  self.play_button = Button(self.ax_button, "❚❚")
613  self.play_button.label.set_color("red")
614  self.play_button.label.set_fontsize(8)
615  self.play_button.on_clicked(self.pause_movie)
616  self.fig.canvas.mpl_connect('key_press_event', self.arrow_update)
617  self.__interactive_ax = None
618 
619  # Add a bookmark at a certain time in the slider
620  # Calculate neutron freeze-out time
621  min_val = 1-self.wreader.mainout['yn']/self.wreader.mainout['yheavy']
622  nfreezeout = np.argmin(abs(min_val))
623  # Check if its really the freeze-out time by checking if it switches from larger one to smaller 1
624  if (min_val[nfreezeout-1] < 0) and (min_val[nfreezeout+1] > 0):
625  # self.ax_slider.plot([nfreezeout,nfreezeout],[0,0.25], color='tab:red', linestyle='-', linewidth=1) # Bookmark indicators
626  self.ax_slider.axvline(nfreezeout, color='tab:red', linestyle='-', linewidth=1) # Bookmark indicators
627 
628  # Check which data could be shown
629  self.available_data = []
630  self.toggle_buttons = []
631  if self.wreader.check_existence('tracked_nuclei') !=0:
632  self.available_data.append('tracked_nuclei')
633  self.toggle_buttons.append(Button(plt.axes([0.18-0.018, 0.05, 0.012, 0.022]), "⚛"))
634  # Fontsize
635  self.toggle_buttons[-1].label.set_fontsize(12)
636  self.toggle_buttons[-1].label.set_color('k')
637  self.toggle_buttons[-1].on_clicked(self.toggle_button_event)
638 
639  if self.wreader.check_existence('timescales') !=0:
640  self.available_data.append('timescales')
641  amount_buttons = len(self.toggle_buttons)
642  self.toggle_buttons.append(Button(plt.axes([0.18-0.018+0.015*amount_buttons, 0.05, 0.012, 0.022]), r"$\tau$"))
643  self.toggle_buttons[-1].label.set_fontsize(12)
644  self.toggle_buttons[-1].label.set_color('tab:green')
645  self.toggle_buttons[-1].on_clicked(self.toggle_button_event)
646 
647  if self.wreader.check_existence('energy') !=0:
648  self.available_data.append('energy')
649  amount_buttons = len(self.toggle_buttons)
650  self.toggle_buttons.append(Button(plt.axes([0.18-0.018+0.015*amount_buttons, 0.05, 0.012, 0.022]), "⚡"))
651  self.toggle_buttons[-1].label.set_fontsize(12)
652  self.toggle_buttons[-1].label.set_color('tab:orange')
653  self.toggle_buttons[-1].on_clicked(self.toggle_button_event)
654 
655  if self.wreader.check_existence('mainout') !=0:
656  self.available_data.append('mainout')
657  amount_buttons = len(self.toggle_buttons)
658  self.toggle_buttons.append(Button(plt.axes([0.18-0.018+0.015*amount_buttons, 0.05, 0.012, 0.022]), "m"))
659  self.toggle_buttons[-1].label.set_fontsize(12)
660  self.toggle_buttons[-1].label.set_color('tab:blue')
661  self.toggle_buttons[-1].on_clicked(self.toggle_button_event)
662  self.active_button = None
663 
664  # Add zoom button
665  self.zoom_button = Button(plt.axes([0.18-0.018+0.015*(len(self.toggle_buttons)+0.2), 0.05, 0.012, 0.022]), "+")
666  self.zoom_button.label.set_fontsize(12)
667  self.zoom_button.label.set_color('k')
668  self.zoom_button.on_clicked(self.zoom_button_event)
669  self.zoomed = False
670 
671  # Check if the sunet path exists
672  supath = self.wreader.template['net_source']
673  addbutton = 0
674  if os.path.exists(supath):
675  self.sunet_button = Button(plt.axes([0.18-0.018+0.015*(len(self.toggle_buttons)+1+0.2), 0.05, 0.012, 0.022]), "S")
676  self.sunet_button.label.set_fontsize(12)
677  self.sunet_button.label.set_color('k')
678  self.sunet_button.on_clicked(self.sunet_button_event)
679  addbutton += 1
680  if self.wreader.check_existence('mainout') !=0:
681  if not self.indicate_r_path:
682  self.__init_ngamma_eq()
683  self.ngamma_eq_plot[0].set_visible(self.indicate_r_path)
684  self.ngamma_eq_plot_o[0].set_visible(self.indicate_r_path)
685  self.r_path_button = Button(plt.axes([0.18-0.018+0.015*(len(self.toggle_buttons)+1+addbutton+0.2), 0.05, 0.012, 0.022]), "r")
686  self.r_path_button.label.set_fontsize(12)
687  self.r_path_button.label.set_color('k')
688  self.r_path_button.on_clicked(self.r_path_button_event)
689  addbutton += 1
690 
691  # Create button for background color
692  self.ax_button_bg = plt.axes([0.18-0.018+0.015*(len(self.toggle_buttons)+1+addbutton+0.4), 0.05, 0.012, 0.022])
693  self.bg_button = Button(self.ax_button_bg, "B")
694  self.bg_button.label.set_fontsize(12)
695  self.bg_button.label.set_color('k')
696  self.bg_button.on_clicked(self.change_bg)
697  self.background = 1
698  addbutton += 1
699 
700 
701  # Check if flow is plotted and add a button to change the flow range
702  if self.plot_flow:
703  self.flow_buttons = [Button(plt.axes([0.88, 0.905, 0.01, 0.02]), "+")]
704  self.flow_buttons.append(Button(plt.axes([0.869, 0.905, 0.01, 0.02]), "-"))
705  self.flow_buttons.append(Button(plt.axes([0.7605, 0.905, 0.01, 0.02]),"+"))
706  self.flow_buttons.append(Button(plt.axes([0.75, 0.905, 0.01, 0.02]), "-"))
707  # Add a button to change reset
708  self.flow_buttons.append(Button(plt.axes([0.771, 0.905, 0.01, 0.02]), "⟲"))
709  # Add button next to - to switch off
710  self.flow_buttons.append(Button(plt.axes([0.858, 0.905, 0.01, 0.02]),"○"))
711 
712  for f in self.flow_buttons:
713  f.label.set_fontsize(12)
714  f.label.set_color('k')
715  f.on_clicked(self.flow_button_event)
716 
717  # Mass fraction buttons
718  self.mafra_buttons = [Button(plt.axes([0.71, 0.905, 0.01, 0.02]), "+")]
719  self.mafra_buttons.append(Button(plt.axes([0.699, 0.905, 0.01, 0.02]), "-"))
720  self.mafra_buttons.append(Button(plt.axes([0.5905, 0.905, 0.01, 0.02]),"+"))
721  self.mafra_buttons.append(Button(plt.axes([0.58, 0.905, 0.01, 0.02]), "-"))
722  # Add a button to change reset
723  self.mafra_buttons.append(Button(plt.axes([0.601, 0.905, 0.01, 0.02]), "⟲"))
724  # Add button next to - to switch off
725  self.mafra_buttons.append(Button(plt.axes([0.688, 0.905, 0.01, 0.02]),"○"))
726 
727  else:
728  self.mafra_buttons = [Button(plt.axes([0.88, 0.905, 0.01, 0.02]), "+")]
729  self.mafra_buttons.append(Button(plt.axes([0.869, 0.905, 0.01, 0.02]), "-"))
730  self.mafra_buttons.append(Button(plt.axes([0.7605, 0.905, 0.01, 0.02]),"+"))
731  self.mafra_buttons.append(Button(plt.axes([0.75, 0.905, 0.01, 0.02]), "-"))
732  # Add a button to change reset
733  self.mafra_buttons.append(Button(plt.axes([0.771, 0.905, 0.01, 0.02]), "⟲"))
734  # Add button next to - to switch off
735  self.mafra_buttons.append(Button(plt.axes([0.858, 0.905, 0.01, 0.02]),"○"))
736 
737  for f in self.mafra_buttons:
738  f.label.set_fontsize(12)
739  f.label.set_color('k')
740  f.on_clicked(self.mafra_button_event)
741 
742 
743  def change_bg(self, event):
744  self.background = self.background + 1
745  if self.background >3:
746  self.background = 1
747 
748  if self.background == 1:
750  self.background_im.set_cmap(self.__background_cmap)
751  self.background_im.set_array(self.background_Y.T)
752  # also set the limits again
753  self.background_im.set_clim(vmin=(min(self.values)),vmax=(max(self.values)))
754  self.cb_bg.ax.set_visible(False)
755  self.logo.set_visible(True)
756  elif self.background == 2:
757  self.background_Y = self.__background_Y_2
758  self.background_im.set_cmap('nipy_spectral')
759  self.cb_bg.set_label('BE/A [MeV]')
760  # Set the norm (linear)
761  self.background_im.set_norm( plt.Normalize(vmin=5,vmax=np.nanmax(self.background_Y)))
762  self.background_im.set_array((self.background_Y.T))
763  self.cb_bg.ax.set_visible(True)
764  # Hide the WinNet logo
765  self.logo.set_visible(False)
766  elif self.background == 3:
767  self.background_Y = self.__background_Y_3
768 
769  # Create a colormap with alpha
770  original_cmap = cm.nipy_spectral # Choose your colormap
771  alpha = 0.5 # Set alpha value (0.0 to 1.0)
772 
773  # Create a colormap with modified alpha
774  colors = original_cmap(np.linspace(0, 1, original_cmap.N))
775  colors[:, -1] = alpha # Set alpha channel
776  transparent_cmap = ListedColormap(colors)
777 
778  self.background_im.set_cmap(transparent_cmap)
779  self.cb_bg.set_label('Sn [MeV]')
780  # Set the norm (linear)
781  self.background_im.set_norm( plt.Normalize(vmin=0,vmax=10))
782  self.background_im.set_array((self.background_Y.T))
783  self.cb_bg.ax.set_visible(True)
784  # Hide the WinNet logo
785  self.logo.set_visible(False)
786 
787 
788  # also set the limits again and make it log scale
789  # self.background_im.set_clim(vmin=np.nanmin(self.background_Y),vmax=np.nanmax(self.background_Y))
790 
791 
792  self.fig.canvas.draw_idle()
793 
794 
795  def flow_button_event(self, event):
796  if event.inaxes == self.flow_buttons[0].ax:
797  self.flow_max_offset += 0.5
798  elif event.inaxes == self.flow_buttons[1].ax:
799  self.flow_max_offset -= 0.5
800  elif event.inaxes == self.flow_buttons[2].ax:
801  self.flow_min_offset -= 0.5
802  elif event.inaxes == self.flow_buttons[3].ax:
803  self.flow_min_offset += 0.5
804  elif event.inaxes == self.flow_buttons[4].ax:
805  self.flow_max_offset = 0.0
806  self.flow_min_offset = 0.0
807  elif event.inaxes == self.flow_buttons[5].ax:
808  if self.flow_adapt_width:
809  self.flow_patch.set_visible(not self.flow_patch.get_visible())
810  self.flow_buttons[5].label.set_text("○" if self.flow_patch.get_visible() else "●")
811  else:
812  self.quiver.set_visible(not self.quiver.get_visible())
813  self.flow_buttons[5].label.set_text("○" if self.quiver.get_visible() else "●")
814 
815 
816  # Refresh the animation at current position
817  if self.movie_paused:
818  self.update_frame(self.slider_bar.val)
819 
820  self.fig.canvas.draw_idle()
821 
822  def mafra_button_event(self, event):
823  if event.inaxes == self.mafra_buttons[0].ax:
824  self.mafra_max_offset += 0.5
825  elif event.inaxes == self.mafra_buttons[1].ax:
826  self.mafra_max_offset -= 0.5
827  elif event.inaxes == self.mafra_buttons[2].ax:
828  self.mafra_min_offset += 0.5
829  elif event.inaxes == self.mafra_buttons[3].ax:
830  self.mafra_min_offset -= 0.5
831  elif event.inaxes == self.mafra_buttons[4].ax:
832  self.mafra_max_offset = 0.0
833  self.mafra_min_offset = 0.0
834  elif event.inaxes == self.mafra_buttons[5].ax:
835  self.abun_im.set_visible(not self.abun_im.get_visible())
836  self.mafra_buttons[5].label.set_text("○" if self.abun_im.get_visible() else "●")
837 
838 
839  norm = plt.Normalize(vmin=np.log10(self.X_min*10**self.mafra_min_offset), vmax=np.log10(self.X_max*10**self.mafra_max_offset))
840  # self.abun_cbar.set_norm(norm)
841  self.abun_im.set_norm(norm)
842  # Also change the colorbar
843  norm = LogNorm(vmin=self.X_min*10**self.mafra_min_offset, vmax=self.X_max*10**self.mafra_max_offset, clip=True)
844  self.mafra_sm.set_norm(norm)
845 
846  self.fig.canvas.draw_idle()
847 
848 
849  def r_path_button_event(self, event):
850  self.indicate_r_path = not self.indicate_r_path
851  if self.indicate_r_path:
852  # Update the data and the animation
853  ii = self.slider_bar.val
854  self.update_data(ii)
855  self.update_frame(ii)
856  self.ngamma_eq_plot[0].set_visible(self.indicate_r_path)
857  self.ngamma_eq_plot_o[0].set_visible(self.indicate_r_path)
858  self.fig.canvas.draw_idle()
859 
860  def sunet_button_event(self, event):
861  self.sunet_indication = not self.sunet_indication
862  for line in self.__sunet_lines:
863  for l in line:
864  l.set_visible(self.sunet_indication)
865  self.fig.canvas.draw_idle()
866 
867 
868  def zoom_button_event(self, event):
869  self.__toggle_zoom()
870  if self.zoomed:
871  self.zoom_button.label.set_text("-")
872  else:
873  self.zoom_button.label.set_text("+")
874 
875  def toggle_button_event(self, event):
876  # Find the button that was clicked
877  for i, button in enumerate(self.toggle_buttons):
878  if event.inaxes == button.ax:
879  # Toggle the state: activate this button and deactivate others
880  if self.active_button != button:
881  # Unpress the previously active button if there is one
882  if self.active_button:
883  for t in ['top','right','bottom','left']:
884  self.active_button.ax.spines[t].set_color('k')
885  self.active_button.ax.spines[t].set_linewidth(0.5)
886  # Set the new active button
887  # Ändere die Umrandung des Buttons
888  for t in ['top','right','bottom','left']:
889  button.ax.spines[t].set_color('red')
890  button.ax.spines[t].set_linewidth(2)
891 
892  self.active_button = button
893  if not (self.__interactive_ax is None):
894  self.__interactive_ax.remove()
895  if self.available_data[i] == 'timescales':
896  self.__toggle_timescales()
897  elif self.available_data[i] == 'energy':
898  self.__toggle_energy()
899  elif self.available_data[i] == 'tracked_nuclei':
900  self.__toggle_tracked()
901  elif self.available_data[i] == 'mainout':
902  self.__toggle_addmainout()
903  else:
904  # Unpress the button
905  for t in ['top','right','bottom','left']:
906  button.ax.spines[t].set_color('k')
907  button.ax.spines[t].set_linewidth(0.5)
908  self.active_button = None
909  if not (self.__interactive_ax is None):
910  self.__interactive_ax.remove()
911  self.__interactive_ax = None
912  self.plot_timescales = False
913  self.plot_energy = False
914  self.plot_tracked = False
915  self.plot_addmainout = False
916  self.fig.canvas.draw_idle()
917  return
918 
919 
920  def init_data(self):
921  """
922  Initialize the data for the plot.
923  """
924  # Read all things related to the snapshots
925  self.Z = self.wreader.Z
926  self.N = self.wreader.N
927  self.A = self.wreader.A
928  self.X = self.wreader.X[0,:]
929  # Get the number of timesteps, i.e., the number of snapshots
930  self.n_timesteps = self.wreader.nr_of_snaps
931 
932  # Set up timescale data
933  if self.plot_timescales:
934  self.__init_data_timescales(-1)
935 
936  # Set up energy data
937  if self.plot_energy:
938  self.__init_data_energy(-1)
939 
940  # Set up tracked nuclei data
941  if self.plot_tracked:
942  self.__init_data_tracked(-1)
943 
944  # Set up additional mainout data
945  if self.plot_addmainout:
946  self.__init_data_addmainout(-1)
947 
948  # Set up mainout data
949  if self.plot_mainout:
950  self.mainout_time = self.wreader.mainout['time']
951  self.mainout_density = self.wreader.mainout['dens']
952  self.mainout_temperature = self.wreader.mainout['temp']
953  self.mainout_ye = self.wreader.mainout['ye']
954 
955  if self.indicate_r_path:
956  self.__init_ngamma_eq()
957 
958  self.time = 0
959 
960  # Set up the Abar
961  self.Abar = 1.0/np.sum(self.X/self.A)
962  # Set up the sum of the mass fractions
963  self.Asum, self.Xsum = self.sum_over_A(self.A, self.X)
964  # Set up the mass fraction bins
965  self.Xbins = np.zeros(len(self.massBins),dtype=float)
966 
967  # Create custom colormap, with colormap for abundances and also the background colors
968  abucmap = mpl.colormaps[self.cmapNameX]
969  self.__abundance_colors = abucmap
970 
971  # Colors for background
972  massbin_colormap = mpl.colormaps[self.cmapNameMassBins]
973  amount_mass_bins = len(self.massBins)
974  massbin_colors = massbin_colormap(np.linspace(0, 1, amount_mass_bins))
975  massbin_colors[:,3] = self.alphaMassBins
976  self.massbin_colors = massbin_colors
977  self.__background_cmap = ListedColormap(self.massbin_colors)
978 
979  # self.values = np.linspace(np.log10(self.X_min)-amount_mass_bins*dist, np.log10(self.X_max),num=256+amount_mass_bins+1,endpoint=True)
980  self.values = np.linspace(0, 1,num=amount_mass_bins,endpoint=True)
981 
982  # Create the background array that will contain numbers according to the background colors
983  background_Y = np.empty((self.__max_N+1, self.__max_Z+1))
984  background_Y[:,:] = np.nan
985  for index, mbin in enumerate(self.massBins):
986  mask = (self.__A_plot >= self.massBins[index][0]) & (self.__A_plot <= self.massBins[index][1])
987  background_Y[self.__N_plot[mask],self.__Z_plot[mask]] = self.values[index]
988  self.__background_Y = background_Y
989  self.__background_Y_1 = np.copy(background_Y)
990 
991  # Set up the axes for the nuclear chart
992  self.n = np.arange(0, self.__max_N+1)
993  self.z = np.arange(0, self.__max_Z+1)
994 
995  # Set up the abundance array
996  self.abun = np.zeros_like(self.__background_Y) * np.nan
997 
998  # Set up the array for the fission region
999  self.fis_region = np.zeros_like(self.abun)
1000 
1001  # Set up the flow arrays if necessary
1002  if (self.plot_flow):
1003  self.flow_N, self.flow_Z = np.array([0]), np.array([0])
1004  self.flow_dn, self.flow_dz = np.array([0]), np.array([0])
1005  self.flow = np.array([0])
1006 
1007 
1008  def init_plot(self):
1009  """
1010  Initialize the plots.
1011  """
1012  self.background_im = self.ax.pcolormesh(self.n,self.z,self.__background_Y.T,
1013  cmap = self.__background_cmap,vmin=(min(self.values)),
1014  vmax=(max(self.values)),linewidth=0.0,edgecolor="face")
1015 
1016  # Plot the nuclear chart
1017  self.abun_im = self.ax.pcolormesh(self.n,self.z,self.abun.T,
1018  cmap = self.__abundance_colors,vmin=(np.log10(self.X_min)),
1019  vmax=(np.log10(self.X_max)),linewidth=0.0,edgecolor="face")
1020 
1021 
1022  if (self.plot_flow):
1023  # Plot the flows as quiver
1024  self.quiver = self.ax.quiver(
1025  self.flow_N, self.flow_Z,
1026  self.flow_dn, self.flow_dz,
1027  self.flow,
1028  norm=self.flow_norm,
1029  cmap=self.cmapNameFlow, angles='xy', scale_units='xy', scale=1,
1030  units='xy', width=0.1, headwidth=3, headlength=4
1031  )
1032 
1033  if self.flow_adapt_width:
1034  # Create patchcollection of arrows
1035  width = (self.flow_maxArrowWidth-self.flow_minArrowWidth)/self.flow_prange
1036  with np.errstate(divide='ignore'):
1037  arrowwidth = (np.log10(self.flow)-np.log10(self.flow_min))*width
1038  arrowwidth = np.maximum(arrowwidth, self.flow_minArrowWidth)
1039 
1040 
1041  flow_arrows = [Arrow(self.flow_N[i],self.flow_Z[i],self.flow_dn[i],self.flow_dz[i],width=arrowwidth[i],color='k') for i in range(len(self.flow))]
1042  a = PatchCollection(flow_arrows, cmap=self.cmapNameFlow, norm=self.flow_norm)
1043  a.set_array(self.flow)
1044  self.flow_patch = self.ax.add_collection(a)
1045 
1046  # Plot the fission region of positive fission products
1047  fisspos = self.fis_region.T
1048  fisspos[:] = np.nan
1049  self.fis_im_pos = self.ax.pcolor(self.n,self.z,
1050  fisspos,hatch='//////', edgecolor='tab:red',facecolor='none',
1051  linewidth=0.0,zorder=1000
1052  )
1053 
1054  # Plot the fission region of negative fission products
1055  fissneg = self.fis_region.T
1056  fissneg[:] = np.nan
1057  self.fis_im_neg = self.ax.pcolor(self.n,self.z,
1058  fissneg,hatch='//////', edgecolor='tab:blue',facecolor='none',
1059  linewidth=0.0,zorder=1000
1060  )
1061 
1062 
1063  # Plot stable isotopes as black rectangles
1064  edgecolors = np.full((max(self.n+1),max(self.z+1)),"none")
1065  edgecolors[self.N_stab, self.Z_stab] = "k"
1066  edgecolors = edgecolors.T.ravel()
1067  self.stable_im = self.ax.pcolormesh(self.n,self.z,self.abun.T,
1068  facecolor="none",linewidth=0.5,edgecolor=edgecolors)
1069  # Alternatively make a scatter
1070  # self.stable_im = self.ax.scatter(
1071  # N_stab, Z_stab, c='k', marker='o', s=1)
1072 
1073  # Plot the sum of the mass fractions
1074  self.mafra_plot = self.axAbund.plot(self.Asum, self.Xsum, color='k', lw=1.2)
1075 
1076  if self.plotMassBins:
1077  # Plot the mass bins
1078  self.mafrabin_plot = [self.axMassFrac.bar(self.massBins[i][0], self.Xbins[i],
1079  width=self.massBins[i][1]+1-self.massBins[i][0], align='edge',
1080  color=self.massbin_colors[i], edgecolor='grey') for i in range(len(self.massBins))]
1081 
1082  for i,b in enumerate(self.massBins):
1083  px = (b[0])+1
1084  py = 1
1085  axis_to_data = self.axAbund.transAxes + self.axAbund.transData.inverted()
1086  data_to_axis = axis_to_data.inverted()
1087  trans = data_to_axis.transform((px,py))
1088  txt = self.axAbund.text(trans[0],1.1,self.massBinLabels[i],transform = self.axAbund.transAxes,
1089  ha='left',va='center',clip_on=False, fontsize=8,color=self.massbin_colors[i])
1090  txt.set_path_effects([PathEffects.withStroke(linewidth=0.5, foreground='k')])
1091 
1092  # Plot the average mass number as red vertical line
1093  if self.plot_abar:
1094  self.Abar_plot = self.axAbund.axvline(self.Abar, color='tab:red', lw=1)
1095 
1096  # Plot the mainout data
1097  if self.plot_mainout:
1098  self.mainout_dens_plot = self.axMainout.plot (np.nan, np.nan, color='k' , lw=2, label=r"$\rho$")
1099  self.mainout_temp_plot = self.axMainout_temp.plot(np.nan, np.nan, color='tab:red' , lw=2, label=r"T$_9$")
1100  self.mainout_ye_plot = self.axMainout_ye.plot (np.nan, np.nan, color='tab:blue', lw=2, label=r"Y$_e$")
1101  # Create the legend
1102  lines = [self.mainout_dens_plot[0], self.mainout_temp_plot[0], self.mainout_ye_plot[0]]
1103  self.axMainout.legend(lines, [l.get_label() for l in lines],loc='upper right')
1104 
1105  # Set the Textbox for the mainout data
1106  left_side = "$t$"+"\n"+rf"$\rho$"+"\n"+rf"$T_9$"+"\n"+rf"$Y_e$"
1107  right_side = f"= {self.format_time(self.mainout_time[-1])[0]}\n"+\
1108  f"= {self.to_latex_exponent(self.mainout_density[-1])}\n"+\
1109  f"= {self.to_latex_exponent(self.mainout_temperature[-1])}\n"+\
1110  f"= {self.mainout_ye[-1]:.3f}"
1111  units = f"{self.format_time(self.mainout_time[-1])[1]}\n"+\
1112  f"g/cm$^3$\n"+\
1113  "GK\n"+\
1114  ""
1115 
1116  # Make a background box
1117  y_pos = 0.07
1118  rect = patches.FancyBboxPatch((0.35, y_pos-0.01), 0.17, 0.135, transform=self.ax.transAxes, boxstyle="round,pad=0.01", ec="k", fc="lightgrey", zorder=1,alpha=0.5)
1119  self.ax.add_patch(rect)
1120 
1121  # Plot the text
1122  self.ax.text(0.35, y_pos, left_side, transform=self.ax.transAxes, fontsize=12,)
1123  self.Mainout_text = self.ax.text(0.37, y_pos, right_side, transform=self.ax.transAxes, fontsize=12,)
1124  self.Mainout_units = self.ax.text(0.48, y_pos, units, transform=self.ax.transAxes, fontsize=12,)
1125 
1126 
1127  # Set the arrow at the bottom left
1128  arrowLength = 20
1129  self.ax.arrow(-8, -8, arrowLength, 0, head_width=2, head_length=2, fc='k', ec='k')
1130  self.ax.arrow(-8, -8, 0, arrowLength, head_width=2, head_length=2, fc='k', ec='k')
1131  self.ax.text(arrowLength-8+3,0-8,'N',horizontalalignment='left',verticalalignment='center',fontsize=14,clip_on=True)
1132  self.ax.text(0-8,arrowLength-8+3,'Z',horizontalalignment='center',verticalalignment='bottom',fontsize=14,clip_on=True)
1133 
1134  # Plot the timescales
1135  if self.plot_timescales:
1136  self.__init_plot_timescales()
1137  # Plot the energy
1138  if self.plot_energy:
1139  self.__init_plot_energy()
1140  # Plot the additional mainout
1141  if self.plot_addmainout:
1142  self.__init_plot_addmainout()
1143  # Plot the tracked nuclei
1144  if self.plot_tracked:
1145  self.__init_plot_tracked()
1146 
1147  # Plot magic numbers
1148  if self.plot_magic:
1149  # First neutron numbers
1150  for n in self.nMagic:
1151  if (any(self.__N_plot == n)):
1152  # Find minimum and maximum Z for this N
1153  zmin = np.min(self.__Z_plot[self.__N_plot == n])
1154  zmax = np.max(self.__Z_plot[self.__N_plot == n])
1155  # Plot horizontal line from zmin - self.magic_excess to zmax + self.magic_excess
1156  self.ax.plot([n-0.5, n-0.5],[zmin-self.magic_excess, zmax+self.magic_excess], color='k', ls="--", lw=0.5)
1157  self.ax.plot([n+0.5, n+0.5],[zmin-self.magic_excess, zmax+self.magic_excess], color='k', ls="--", lw=0.5)
1158  # write the number on the bottom, truncate text when out of range
1159  self.ax.text(n,zmin-self.magic_excess-1,int(n),ha='center',va='top',clip_on=True)
1160  # Second proton numbers
1161  for z in self.zMagic:
1162  # Find minimum and maximum N for this Z
1163  if (any(self.__Z_plot == z)):
1164  nmin = np.min(self.__N_plot[self.__Z_plot == z])
1165  nmax = np.max(self.__N_plot[self.__Z_plot == z])
1166  self.ax.plot([nmin-self.magic_excess, nmax+self.magic_excess],[z-0.5, z-0.5], color='k', ls="--", lw=0.5)
1167  self.ax.plot([nmin-self.magic_excess, nmax+self.magic_excess],[z+0.5, z+0.5], color='k', ls="--", lw=0.5)
1168  # write the number on the bottom
1169  self.ax.text(nmin-self.magic_excess-1,z,int(z),ha='right',va='center',clip_on=True)
1170 
1171  if self.separate_fission:
1172  # Make a legend
1173  # Get the ratio of x and y of the figure
1174  ratio = self.fig.get_figwidth()/self.fig.get_figheight()
1175  self.ax.add_patch(mpl.patches.Rectangle((0.88, 0.70), 0.01, 0.01*ratio, fill=False, transform=self.ax.transAxes, hatch="////", edgecolor='tab:blue', lw=1))
1176  self.ax.text(0.9, 0.70, 'Fissioning region', transform=self.ax.transAxes, fontsize=8, verticalalignment='bottom', horizontalalignment='left')
1177  self.ax.add_patch(mpl.patches.Rectangle((0.88, 0.67), 0.01, 0.01*ratio, fill=False, transform=self.ax.transAxes, hatch="////", edgecolor='tab:red', lw=1))
1178  self.ax.text(0.9, 0.67, 'Fission products', transform=self.ax.transAxes, fontsize=8, verticalalignment='bottom', horizontalalignment='left')
1179 
1180 
1181 
1183  ls = ["-","--"]
1184  self.ts_plot = [ [ self.axTimescales.plot(self.ts_time,self.ts_data[i][j], color=self.timescale_colors[i], ls=ls[j],
1185  label=(self.timescale_labels[i] if (j == 0) else "")) for j in range(len(self.ts_data[i]))] for i in range(len(self.ts_data))]
1186  # Also make the background of the box non-transparent
1187  self.axTimescales.legend(loc='upper right', ncol=2, bbox_to_anchor=(1.3, 1.0), frameon=True, facecolor='white', edgecolor='black', framealpha=1.0, fontsize=8)
1188 
1191  label=self.addmainout_label[i], lw=2) for i,k in enumerate(self.addmainout_data.keys())]
1192  # Also make the background of the box non-transparent
1193  self.axAddMainout.legend(loc='upper right', ncol=1, bbox_to_anchor=(1.15, 1.0), frameon=True, facecolor='white', edgecolor='black', framealpha=1.0, fontsize=8)
1194 
1195 
1197  self.energy_plot = [self.axEnergy.plot(self.energy_time,self.energy_data[i], color=self.energy_colors[i],
1198  label=self.energy_labels[i], lw=self.energy_lw[i]) for i in range(len(self.energy_data))]
1199  # Also make the background of the box non-transparent
1200  self.axEnergy.legend(loc='upper right', ncol=2, bbox_to_anchor=(1.3, 1.0), frameon=True, facecolor='white', edgecolor='black', framealpha=1.0, fontsize=8)
1201 
1203  self.tracked_plot = [self.axTracked.plot(self.tracked_time,self.track_nuclei_data[i],
1204  label=self.track_nuclei_labels[i]) for i in range(len(self.track_nuclei_labels))]
1205  # Also make the background of the box non-transparent
1206  self.axTracked.legend(loc='upper right', ncol=2, bbox_to_anchor=(1.3, 1.0), frameon=True, facecolor='white', edgecolor='black', framealpha=1.0, fontsize=8)
1207 
1208 
1209 
1210  def init_cbars(self, abun_cbar, flow_cbar):
1211  """
1212  Initialize the colorbars.
1213  """
1214  # Set up the number of colorbars
1215  n_cbars = abun_cbar + flow_cbar
1216  if n_cbars == 0:
1217  self.cax = []
1218  return
1219  if n_cbars == 1:
1220  self.cax = [self.fig.add_axes([0.75, 0.88, 0.14, 0.02])]
1221  elif n_cbars == 2:
1222  self.cax = [self.fig.add_axes([0.58, 0.88, 0.14, 0.02]),
1223  self.fig.add_axes([0.75, 0.88, 0.14, 0.02])]
1224 
1225  # Counter for the colorbars
1226  ii = 0
1227  # Plot the abundance colorbar
1228  if abun_cbar:
1229  # Make a custom colormap since the abundance one has the background colors in as well
1230  self.mafra_sm = mpl.cm.ScalarMappable(norm=LogNorm(vmin=self.X_min,vmax=self.X_max), cmap="inferno")
1231  self.abun_cbar = self.fig.colorbar(self.mafra_sm,
1232  cax=self.cax[ii], orientation='horizontal', label='')
1233  self.abun_cbar.ax.set_title('Mass fraction')
1234  ii += 1
1235 
1236  # Plot the flow colorbar
1237  if flow_cbar:
1239  self.quiver,
1240  cax=self.cax[ii],
1241  orientation='horizontal',
1242  label='',
1243  )
1244  self.flow_cbar.ax.set_title('Flow')
1245  ii += 1
1246 
1247  if self.interactive:
1248  self.ax_bg_cb = plt.axes([0.75,0.54,0.15,0.02])
1249  # Horizontal colorbar
1250  self.cb_bg = plt.colorbar(self.background_im, cax=self.ax_bg_cb, orientation='horizontal')
1251  self.cb_bg.set_label('BE/A [MeV]')
1252  # Hide the colorbar
1253  self.cb_bg.ax.set_visible(False)
1254 
1255 
1256 
1257  def update_data(self, ii):
1258  """
1259  Update the data for the plot.
1260  """
1261 
1262  self.time = self.wreader.snapshot_time[ii]
1263  yy = self.wreader.Y[ii]
1264  xx = yy * self.A
1265  # self.abun = self.__background_Y.copy()
1266  self.abun[:,:] = np.nan
1267  mask = xx > self.X_min*10**self.mafra_min_offset
1268  self.abun[self.N[mask], self.Z[mask]] = np.log10(xx[mask])
1269 
1270  self.Asum, self.Xsum = self.sum_over_A(self.A, xx)
1271  self.Abar = 1.0/np.sum(yy)
1272 
1273  for i in range(len(self.massBins)):
1274  mask = (self.A >= self.massBins[i][0]) & (self.A <= self.massBins[i][1])
1275  self.Xbins[i] = np.sum(xx[mask])
1276 
1277 
1278  if self.plot_timescales:
1279  self.__init_data_timescales(ii)
1280 
1281  if self.plot_energy:
1282  self.__init_data_energy(ii)
1283 
1284  if self.plot_addmainout:
1285  self.__init_data_addmainout(ii)
1286 
1287  if self.plot_tracked:
1288  self.__init_data_tracked(ii)
1289 
1290  if self.plot_mainout:
1291  self.mainout_time = self.wreader.mainout['time'][:ii]
1292  self.mainout_time = self.mainout_time-self.mainout_time[0]
1293  self.mainout_density = self.wreader.mainout['dens'][:ii]
1294  self.mainout_temperature = self.wreader.mainout['temp'][:ii]
1295  self.mainout_ye = self.wreader.mainout['ye'][:ii]
1296 
1297  if self.indicate_r_path:
1298  self.ngamma_eq.calc_r_process_path(self.wreader.mainout['dens'][ii],self.wreader.mainout['temp'][ii],self.wreader.mainout['yn'][ii])
1299 
1300 
1301  if ii == 0: return # no flows in first timestep
1302 
1303  if self.plot_flow:
1304  fpath=f'{self.path}/WinNet_data.h5'
1305  flow_dict = self.wreader.flow_entry(ii, self.flow_group)
1306  nin = flow_dict['n_in']
1307  zin = flow_dict['p_in']
1308  nout = flow_dict['n_out']
1309  zout = flow_dict['p_out']
1310  flow = flow_dict['flow']
1311  dz = zout - zin
1312  dn = nout - nin
1313  mask = flow > min(self.flow_norm.vmin,self.fission_minflow)
1314  self.flow_N = nin[mask]
1315  self.flow_Z = zin[mask]
1316  self.flow_dn = dn[mask]
1317  self.flow_dz = dz[mask]
1318  self.flow = flow[mask]
1319  # Keep track of the maximum flows for the colorbar
1320  self.flow_max_history = np.roll(self.flow_max_history,1)
1321  try:
1322  ## might raise error if flow is not above threshold
1323  self.flow_max_history[0] = np.max(self.flow)
1324  except:
1325  pass
1326  if self.separate_fission:
1327  self.handle_fission()
1328 
1329  def __init_data_timescales(self, ii):
1330  self.ts_time = self.wreader.tau['time'][:ii]
1331  self.ts_time = self.ts_time-self.ts_time[0]
1332  self.ts_data = [ [ self.wreader.tau['tau_'+str(self.timescale_entries[i][j])][:ii]
1333  for j in range(len(self.timescale_entries[i]))] for i in range(len(self.timescale_entries)) ]
1334 
1335  def __init_data_addmainout(self, ii):
1336  self.addmainout_time = self.wreader.mainout['time'][:ii]
1337  self.addmainout_time = self.addmainout_time-self.addmainout_time[0]
1338  self.addmainout_label = [r"Y$_n$", r"Y$_p$", r"Y$_\alpha$", r"Y$_{\text{heavy}}$", r"Y$_{\text{light}}$"]
1340  self.addmainout_data["yn"] = self.wreader.mainout['yn'][:ii]
1341  self.addmainout_data["yp"] = self.wreader.mainout['yp'][:ii]
1342  self.addmainout_data["ya"] = self.wreader.mainout['ya'][:ii]
1343  self.addmainout_data["yheavy"] = self.wreader.mainout['yheavy'][:ii]
1344  self.addmainout_data["ylight"] = self.wreader.mainout['ylight'][:ii]
1345 
1346  def __init_data_energy(self, ii):
1347  self.energy_time = self.wreader.energy['time'][:ii]
1348  self.energy_time = self.energy_time-self.energy_time[0]
1349  self.energy_data = [ self.wreader.energy['engen_'+self.energy_entries[i]][:ii] for i in range(len(self.energy_entries)) ]
1350 
1351  def __init_data_tracked(self, ii, force_label_init=False):
1352  self.tracked_time = self.wreader.tracked_nuclei['time'][:ii]
1353  self.tracked_time = self.tracked_time-self.tracked_time[0]
1354  self.track_nuclei_data = [ self.wreader.tracked_nuclei[n][:ii] for n in self.wreader.tracked_nuclei['names'] ]
1355  if ii == -1 or force_label_init:
1356  self.track_nuclei_labels= self.wreader.tracked_nuclei['latex_names']
1357 
1358  def handle_fission(self,):
1359  """
1360  Separate the fissioning region from the fission products in the flow plot.
1361  """
1362 
1363  fis_mask = np.abs(self.flow_dn + self.flow_dz) > 32
1364  fis_N = self.flow_N[fis_mask]
1365  fis_Z = self.flow_Z[fis_mask]
1366  fis_dn = self.flow_dn[fis_mask]
1367  fis_dz = self.flow_dz[fis_mask]
1368  fis_flow = self.flow[fis_mask]
1369 
1370  mask = self.flow>self.flow_norm.vmin
1371 
1372  self.flow_N = self.flow_N[((~fis_mask) & mask)]
1373  self.flow_Z = self.flow_Z[((~fis_mask) & mask)]
1374  self.flow_dn = self.flow_dn[((~fis_mask) & mask)]
1375  self.flow_dz = self.flow_dz[((~fis_mask) & mask)]
1376  self.flow = self.flow[((~fis_mask) & mask)]
1377 
1378  self.fis_region.fill(0)
1379  for nn, zz, dn, dz, ff in zip(fis_N, fis_Z, fis_dn, fis_dz, fis_flow):
1380  self.fis_region[nn, zz] -= ff
1381  self.fis_region[nn+dn, zz+dz] += ff
1382  self.fis_region[(self.fis_region == 0)] = np.nan
1383 
1384 
1385  def update_abun_plot(self,):
1386  self.abun_im.set_array(self.abun.T)
1387  self.mafra_plot[0].set_ydata(self.Xsum)
1388  if self.plot_abar:
1389  self.Abar_plot.set_xdata([self.Abar])
1390  if self.plotMassBins:
1391  [self.mafrabin_plot[i][0].set_height(self.Xbins[i]) for i in range(len(self.massBins))]
1392  if self.plot_timescales:
1393  [ [ self.ts_plot[i][j][0].set_xdata(self.ts_time) for j in range(len(self.ts_plot[i]))] for i in range(len(self.ts_plot)) ]
1394  [ [ self.ts_plot[i][j][0].set_ydata(self.ts_data[i][j]) for j in range(len(self.ts_plot[i]))] for i in range(len(self.ts_plot)) ]
1395  if self.plot_energy:
1396  [ self.energy_plot[i][0].set_xdata(self.energy_time) for i in range(len(self.energy_plot))]
1397  [ self.energy_plot[i][0].set_ydata(self.energy_data[i]) for i in range(len(self.energy_plot))]
1398  if self.plot_addmainout:
1399  [ self.addmainout_plot[i][0].set_xdata(self.addmainout_time) for i in range(len(self.addmainout_plot))]
1400  [ self.addmainout_plot[i][0].set_ydata(self.addmainout_data[k]) for i,k in enumerate(self.addmainout_data.keys())]
1401  if self.plot_tracked:
1402  [ self.tracked_plot[i][0].set_xdata(self.tracked_time) for i in range(len(self.tracked_plot))]
1403  [ self.tracked_plot[i][0].set_ydata(self.track_nuclei_data[i]) for i in range(len(self.tracked_plot))]
1404 
1405  if self.plot_mainout:
1406  self.mainout_dens_plot[0].set_xdata(self.mainout_time)
1407  self.mainout_dens_plot[0].set_ydata(self.mainout_density)
1408  self.mainout_temp_plot[0].set_xdata(self.mainout_time)
1409  self.mainout_temp_plot[0].set_ydata(self.mainout_temperature)
1410  self.mainout_ye_plot[0].set_xdata(self.mainout_time)
1411  self.mainout_ye_plot[0].set_ydata(self.mainout_ye)
1412  right_side = f"= {self.to_latex_exponent(self.format_time(self.mainout_time[-1])[0])}\n"+\
1413  f"= {self.to_latex_exponent(self.mainout_density[-1])}\n"+\
1414  f"= {self.to_latex_exponent(self.mainout_temperature[-1])}\n"+\
1415  f"= {self.mainout_ye[-1]:.3f}"
1416  self.Mainout_text.set_text(right_side)
1417  units = f"{self.format_time(self.mainout_time[-1])[1]}\n"+\
1418  f"g/cm$^3$\n"+\
1419  "GK\n"+\
1420  ""
1421  self.Mainout_units.set_text(units)
1422 
1423 
1425  if self.plot_flow:
1426  fisspos = self.fis_region.T.copy()
1427  fisspos[self.fis_region.T<0] = np.nan
1428  self.fis_im_pos.set_array(fisspos)
1429  fissneg = self.fis_region.T.copy()
1430  fissneg[self.fis_region.T>0] = np.nan
1431  self.fis_im_neg.set_array(fissneg)
1432 
1433  def update_flow_plot(self,):
1434  if self.plot_flow:
1435  # Adapt flowmin and flowmax
1436  if self.flow_adapt_prange:
1437  lmaxflow = (np.nanmean(np.log10(self.flow_max_history)))+0.5+self.flow_max_offset
1438  lminflow = lmaxflow-self.flow_prange-self.flow_min_offset
1439  self.flow_cbar.mappable.set_clim(vmin=10**lminflow, vmax=10**lmaxflow)
1440  self.flow_max = 10**lmaxflow
1441  self.flow_min = 10**lminflow
1442 
1443  # Plot with a quiver as the width does not have to be adapted
1444  if not self.flow_adapt_width:
1445  self.quiver.N=len(self.flow_N)
1446  self.quiver.set_offsets(np.array([self.flow_N, self.flow_Z]).T)
1447  self.quiver.set_UVC(self.flow_dn, self.flow_dz, self.flow)
1448  else:
1449  # Quiver does not allow for changing the width of the arrows
1450  # Therefore, we have to us a patchcollection and draw it everytime new.
1451  if self.flow_patch.get_visible():
1452  self.flow_patch.remove()
1453  width = (self.flow_maxArrowWidth-self.flow_minArrowWidth)/self.flow_prange
1454  with np.errstate(divide='ignore'):
1455  arrowwidth = (np.log10(self.flow)-np.log10(self.flow_min))*width + self.flow_minArrowWidth
1456  flow_arrows = [Arrow(self.flow_N[i],self.flow_Z[i],self.flow_dn[i],self.flow_dz[i],width=arrowwidth[i],color='k') for i in range(len(self.flow))]
1457  a = PatchCollection(flow_arrows, cmap=self.cmapNameFlow, norm=self.flow_norm)
1458  a.set_array(self.flow)
1459  self.flow_patch = self.ax.add_collection(a)
1460 
1461 
1463  if self.indicate_r_path:
1464  self.ngamma_eq_plot[0].set_xdata(self.ngamma_eq.path_N)
1465  self.ngamma_eq_plot[0].set_ydata(self.ngamma_eq.path_Z)
1466  self.ngamma_eq_plot_o[0].set_xdata(self.ngamma_eq.path_N)
1467  self.ngamma_eq_plot_o[0].set_ydata(self.ngamma_eq.path_Z)
1468 
1469 
1470  def update_frame(self, ii):
1471  self.update_data(ii)
1472 
1473  self.update_abun_plot()
1474  self.update_fission_plot()
1475  self.update_flow_plot()
1476  self.update_ngamma_plot()
1477  self.update_slider(ii)
1478  self.update_interactive_text(ii)
1479  return ii
1480 
1481 
1483  if self.interactive:
1484  if self.__interactive_textbox is not None:
1485  # Get the text and only change the last line
1486  text = self.__interactive_textbox.get_text()
1487  text = text.split("\n")
1488  N = int(text[1].split(" = ")[1])
1489  Z = int(text[2].split(" = ")[1])
1490  X = 10**self.abun[N,Z]
1491  if (X < self.X_min*10**self.mafra_min_offset) or np.isnan(X):
1492  X = 0
1493  text[-1] = f"X = {X:.2e}"
1494  self.__interactive_textbox.set_text("\n".join(text))
1495 
1496  def save_frame(self, ii):
1497  self.update_frame(ii)
1498  # self.fig.canvas.draw()
1499  # self.fig.canvas.flush_events()
1500  plt.savefig(f'{self.frame_dir}/frame_{ii}.png',
1501  dpi=300, bbox_inches='tight')
1502  return ii
1503 
1504  def get_funcanimation(self, frames=None, **kwargs):
1505  if frames is None:
1506  frames = range(self.n_timesteps)
1507  if self.interactive and self.forward_mode == 1:
1508  frames = frames[::100]
1509  self.frames=frames
1510  self.animation = FuncAnimation(self.fig, self.update_frame,
1511  frames=frames, **kwargs)
1512  if self.interactive:
1513  self.time_slider()
1514  return self.animation
1515 
1516  def time_slider(self):
1517  self.slider_bar = Slider(self.ax_slider, '', 1, self.n_timesteps-1, valinit=1)
1518  self.slider_bar.valtext.set_text('')
1519  self.slider_bar.on_changed(self.on_slider_update)
1520  self.fig.canvas.mpl_connect('button_press_event', self.on_slider_click)
1521  self.fig.canvas.mpl_connect('button_release_event', self.on_slider_release)
1522 
1523  def on_slider_update(self, val):
1524  ii = int(self.slider_bar.val)
1525  self.update_frame(ii)
1526 
1527  def update_slider(self, ii):
1528  try:
1529  # avoid infinite recursion if misusing slider as timebar for animation
1530  self.slider_bar.eventson =False
1531  self.slider_bar.set_val(ii)
1532  self.slider_bar.eventson = True
1533 
1534  self.slider_bar.valtext.set_text('')
1535  except:
1536  pass
1537 
1538  def pause_movie(self, click_event):
1539  if self.movie_paused:
1540  # Only resume if the slider is not being dragged
1541  ii = int(self.slider_bar.val)
1542  new_seq = list(range(ii, self.frames[-1])) + list(range(self.frames[0], ii))
1543  self.animation._iter_gen = lambda: iter(new_seq)
1544  self.animation.frame_seq = self.animation.new_frame_seq()
1545  self.animation.resume()
1546  self.movie_paused = False
1547  self.play_button.label.set_text("❚❚")
1548  self.play_button.label.set_color("red")
1549  # Update the appearance of the button
1550  else:
1551  self.animation.pause()
1552  self.movie_paused = True
1553  self.play_button.label.set_text(" ▶")
1554  self.play_button.label.set_color("green")
1555 
1556  # Update the appearance of the button
1557 
1558  def on_slider_click(self, event):
1559  if event.inaxes == self.ax_slider:
1560  self.animation.pause() # Pause the animation when clicking the slider
1561  self.movie_paused = True
1562  self.play_button.label.set_text(" ▶")
1563  self.play_button.label.set_color("green")
1564  elif event.inaxes == self.ax:
1565  toolbar = plt.get_current_fig_manager().toolbar
1566  active_tool = toolbar.mode # Get the current active tool
1567  if active_tool == '':
1568  if event.dblclick:
1569  self.__toggle_zoom()
1570  else:
1571  # Get the coordinates of the click
1572  x, y = event.xdata, event.ydata
1573  nucl_n = int(np.round(x))
1574  nucl_z = int(np.round(y))
1575  # Check if abundances are nan there
1576  if np.isnan(self.__background_Y[nucl_n, nucl_z]):
1577  if not (self.__interactive_box is None):
1578  # Remove the rectangle if it exists
1579  self.__interactive_box.remove()
1580  self.__interactive_box = None
1581  if not (self.__interactive_textbox is None):
1582  # Remove the textbox if it exists
1583  self.__interactive_textbox.remove()
1584  self.__interactive_textbox = None
1585  else:
1586  if not (self.__interactive_box is None):
1587  # Remove the rectangle if it exists
1588  self.__interactive_box.remove()
1589  self.__interactive_box = None
1590  if not (self.__interactive_textbox is None):
1591  # Remove the textbox if it exists
1592  self.__interactive_textbox.remove()
1593  self.__interactive_textbox = None
1594 
1595  # Create a rectangle there
1596  self.__interactive_box = self.ax.add_patch(
1597  patches.Rectangle((nucl_n-0.5, nucl_z-0.5), 1, 1, linewidth=1, edgecolor='r', facecolor='none'))
1598 
1599  # Create textbox with information
1600  df = self.winvn.get_dataframe()
1601  # Get the name of the nucleus
1602  nucl_name = df.loc[(nucl_n, nucl_z), 'name']
1603  text = nucl_name.capitalize() + "\n"
1604  text+= f"N = {nucl_n}\nZ = {nucl_z}\nA = {nucl_n+nucl_z}"
1605  # Add mass fraction
1606  X = 10**self.abun[nucl_n, nucl_z]
1607  # Set 0 if below limit
1608  if (X < (self.X_min*10**self.mafra_min_offset)) or np.isnan(X):
1609  X = 0
1610  text+= f"\nX = {X:.2e}"
1611 
1612 
1613  # Also make a border around it
1614  self.__interactive_textbox = self.ax.text(0.44, 0.23, text, transform=self.ax.transAxes, fontsize=10,
1615  horizontalalignment='left',
1616  verticalalignment='bottom', bbox=dict(facecolor='white',
1617  edgecolor='black', boxstyle='round,pad=0.5'))
1618  self.fig.canvas.draw_idle()
1619 
1620 
1621  def on_slider_release(self, event):
1622  # Reset slider_dragging to False when the mouse is released
1623  if event.inaxes == self.ax_slider:
1624  self.on_slider_update(self.slider_bar.val) # Final update after release
1625 
1626  def arrow_update(self, event):
1627  ii = int(self.slider_bar.val)
1628  if event.key in ['left', 'down']:
1629  self.movie_paused = False
1630  self.pause_movie(event)
1631  if ii !=self.slider_bar.valmin:
1632  self.slider_bar.set_val(ii-1)
1633  elif event.key in ['right', 'up']:
1634  self.movie_paused = False
1635  self.pause_movie(event)
1636  if ii !=self.slider_bar.valmax:
1637  self.slider_bar.set_val(ii+1)
1638  elif event.key == " ":
1639  self.pause_movie(event)
1640  elif ((event.key == "t") or (event.key == "e")
1641  or (event.key == 'n') or (event.key == 'd')
1642  or (event.key == 'm')):
1643 
1644  if not (self.__interactive_ax is None):
1645  self.__interactive_ax.remove()
1646 
1647  if event.key == "t":
1648  # Toggle timescales
1649  self.__toggle_timescales()
1650  elif event.key == 'e':
1651  # Toggle energy
1652  self.__toggle_energy()
1653  elif event.key == 'n':
1654  # Toggle tracked nuclei
1655  self.__toggle_tracked()
1656  elif event.key == 'm':
1657  # Toggle tracked nuclei
1658  self.__toggle_addmainout()
1659  elif event.key == "d":
1660  # Shut of additional plots
1661  self.plot_timescales = False
1662  self.plot_energy = False
1663  self.plot_tracked = False
1664  self.plot_addmainout = False
1665  self.__interactive_ax = None
1666 
1667  self.fig.canvas.draw_idle()
1668 
1670  if 'timescales' in self.available_data:
1671  # Toggle timescales
1672  if self.plot_timescales == True:
1673  self.plot_timescales = False
1674  self.plot_energy = False
1675  self.plot_tracked = False
1676  self.plot_addmainout = False
1677  self.__interactive_ax = None
1678  else:
1679  ii = int(self.slider_bar.val)
1680  self.__init_data_timescales(ii)
1681  self.__init_axTimescales()
1682  self.plot_timescales = True
1683  self.plot_energy = False
1684  self.plot_tracked = False
1685  self.plot_addmainout = False
1686  self.__init_plot_timescales()
1687  self.__interactive_ax = self.axTimescales
1688 
1689  def __toggle_energy(self):
1690  if 'energy' in self.available_data:
1691  # Toggle energy
1692  if self.plot_energy == True:
1693  self.plot_timescales = False
1694  self.plot_energy = False
1695  self.plot_tracked = False
1696  self.plot_addmainout = False
1697  self.__interactive_ax = None
1698  else:
1699  ii = int(self.slider_bar.val)
1700  self.__init_data_energy(ii)
1701  self.__init_axEnergy()
1702  self.plot_timescales = False
1703  self.plot_energy = True
1704  self.plot_tracked = False
1705  self.plot_addmainout = False
1706  self.__init_plot_energy()
1707  self.__interactive_ax = self.axEnergy
1708 
1710  if 'mainout' in self.available_data:
1711  # Toggle additional mainout information
1712  if self.plot_addmainout == True:
1713  self.plot_timescales = False
1714  self.plot_energy = False
1715  self.plot_tracked = False
1716  self.plot_addmainout = False
1717  self.__interactive_ax = None
1718  else:
1719  ii = int(self.slider_bar.val)
1720  self.__init_data_addmainout(ii)
1721  self.__init_axAddMainout()
1722  self.plot_timescales = False
1723  self.plot_energy = False
1724  self.plot_tracked = False
1725  self.plot_addmainout = True
1726  self.__init_plot_addmainout()
1727  self.__interactive_ax = self.axAddMainout
1728 
1729  def __toggle_tracked(self):
1730  if 'tracked_nuclei' in self.available_data:
1731  # Toggle energy
1732  if self.plot_tracked == True:
1733  self.plot_timescales = False
1734  self.plot_energy = False
1735  self.plot_tracked = False
1736  self.plot_addmainout = False
1737  self.__interactive_ax = None
1738  else:
1739  ii = int(self.slider_bar.val)
1740  self.__init_data_tracked(ii, force_label_init=True)
1741  self.__init_axTracked()
1742  self.plot_timescales = False
1743  self.plot_energy = False
1744  self.plot_tracked = True
1745  self.plot_addmainout = False
1746  self.__init_plot_tracked()
1747  self.__interactive_ax = self.axTracked
1748 
1749  def __toggle_zoom(self):
1750  if self.zoomed:
1751  self.ax.set_xlim(self.limits_plot[0])
1752  self.ax.set_ylim(self.limits_plot[1])
1753  self.zoomed = False
1754  else:
1755  self.ax.set_xlim(-5.5, 100)
1756  self.ax.set_ylim(-6.5, 50)
1757  self.zoomed = True
1758  self.fig.canvas.draw_idle()
1759 
1760 
1761 
1762  @staticmethod
1764  """
1765  Convert a number to a latex string with exponent.
1766  """
1767  if x == 0:
1768  return '0'
1769  exponent = np.floor(np.log10(x))
1770  mantissa = x / 10**exponent
1771  return f'{mantissa:.2f}'+r'$\times 10^{'+f'{int(exponent)}'+r'}$'
1772 
1773 
1774  @staticmethod
1775  def format_time(time):
1776  """
1777  Format a time in seconds to a more human readable format.
1778  """
1779  if time < 1:
1780  return time*1000, 'ms'
1781  if time < 60:
1782  return time, 's'
1783  if time < 3600:
1784  return time/60, 'min'
1785  if time < 3600*24:
1786  return time/3600, 'h'
1787  if time < 3600*24*365:
1788  return time/86400, 'd'
1789  if time < 3600*24*365*1000:
1790  return time/31536000, 'y'
1791  if time < 3600*24*365*1000*1000:
1792  return time/31536000/1000, 'ky'
1793  else:
1794  return time/31536000_000_000, 'My'
1795 
1796  def sum_over_A(self,A,X):
1797  A_unique = np.arange(max(A)+1)
1798  X_sum = np.zeros_like(A_unique,dtype=float)
1799  for a, x in zip(A,X):
1800  X_sum[int(a)] += x
1801  return A_unique, X_sum
1802 
1803 ################################################################################
1804 
1805 # Funcanimation
1806 
1807 if __name__ == "__main__":
1808  run_path = "../Example_NSM_dyn_ejecta_rosswog_hdf5"
1809  fig = plt.figure(figsize=(15, 8))
1810 
1811  # z_drip , n_drip = np.loadtxt('/home/mjacobi/frdm/dripline.dat', unpack=True)
1812  # plt.plot(n_drip, z_drip, 'k--', lw=1)
1813 
1814  anim = FlowAnimation(run_path, fig, flow_group='flows')
1815  ani = anim.get_funcanimation(interval=10, frames=range(1, anim.n_timesteps))
1816  plt.show()
src_files.FlowAnimation.FlowAnimation.__toggle_energy
def __toggle_energy(self)
Definition: FlowAnimation.py:1689
src_files.FlowAnimation.FlowAnimation.format_time
def format_time(time)
Definition: FlowAnimation.py:1775
src_files.FlowAnimation.FlowAnimation.mainout_density
mainout_density
Definition: FlowAnimation.py:951
src_files.FlowAnimation.FlowAnimation.update_abun_plot
def update_abun_plot(self)
Definition: FlowAnimation.py:1385
src_files.FlowAnimation.FlowAnimation.axMainout
axMainout
Definition: FlowAnimation.py:569
src_files.FlowAnimation.FlowAnimation.zoomed
zoomed
Definition: FlowAnimation.py:669
src_files.FlowAnimation.FlowAnimation.__toggle_addmainout
def __toggle_addmainout(self)
Definition: FlowAnimation.py:1709
src_files.FlowAnimation.FlowAnimation.__A_plot
__A_plot
Definition: FlowAnimation.py:223
src_files.FlowAnimation.FlowAnimation.timescale_entries
timescale_entries
Definition: FlowAnimation.py:237
src_files.FlowAnimation.FlowAnimation.ngamma_eq
ngamma_eq
Definition: FlowAnimation.py:362
src_files.FlowAnimation.FlowAnimation.flow_adapt_prange
flow_adapt_prange
Definition: FlowAnimation.py:172
src_files.FlowAnimation.FlowAnimation.cmapNameX
cmapNameX
Definition: FlowAnimation.py:165
src_files.FlowAnimation.FlowAnimation.available_data
available_data
Definition: FlowAnimation.py:629
src_files.FlowAnimation.FlowAnimation.change_bg
def change_bg(self, event)
Definition: FlowAnimation.py:743
src_files.FlowAnimation.FlowAnimation.background_Y
background_Y
Definition: FlowAnimation.py:749
src_files.FlowAnimation.FlowAnimation.interactive
interactive
Definition: FlowAnimation.py:156
src_files.FlowAnimation.FlowAnimation.flow_button_event
def flow_button_event(self, event)
Definition: FlowAnimation.py:795
src_files.FlowAnimation.FlowAnimation.stable_im
stable_im
Definition: FlowAnimation.py:1067
src_files.FlowAnimation.FlowAnimation.ts_plot
ts_plot
Definition: FlowAnimation.py:1184
src_files.FlowAnimation.FlowAnimation.magic_excess
magic_excess
Definition: FlowAnimation.py:233
src_files.FlowAnimation.FlowAnimation.plot_timescales
plot_timescales
Definition: FlowAnimation.py:185
src_files.FlowAnimation.FlowAnimation.__toggle_timescales
def __toggle_timescales(self)
Definition: FlowAnimation.py:1669
src_files.FlowAnimation.FlowAnimation.__init_axEnergy
def __init_axEnergy(self)
Definition: FlowAnimation.py:535
src_files.FlowAnimation.FlowAnimation.Xsum
Xsum
Definition: FlowAnimation.py:963
src_files.FlowAnimation.FlowAnimation.axLogo
axLogo
Definition: FlowAnimation.py:603
src_files.FlowAnimation.FlowAnimation.axMainout_ye
axMainout_ye
Definition: FlowAnimation.py:588
src_files.FlowAnimation.FlowAnimation.n
n
Definition: FlowAnimation.py:992
src_files.FlowAnimation.FlowAnimation.cax
cax
Definition: FlowAnimation.py:1217
src_files.FlowAnimation.FlowAnimation.densityrange
densityrange
Definition: FlowAnimation.py:162
src_files.FlowAnimation.FlowAnimation.ax_button_bg
ax_button_bg
Definition: FlowAnimation.py:692
src_files.FlowAnimation.FlowAnimation.quiver
quiver
Definition: FlowAnimation.py:1024
src_files.FlowAnimation.FlowAnimation.Abar
Abar
Definition: FlowAnimation.py:961
src_files.FlowAnimation.FlowAnimation.indicate_r_path
indicate_r_path
Definition: FlowAnimation.py:175
src_files.FlowAnimation.FlowAnimation.__sunet_lines
__sunet_lines
Definition: FlowAnimation.py:373
src_files.FlowAnimation.FlowAnimation.ax_bg_cb
ax_bg_cb
Definition: FlowAnimation.py:1248
src_files.FlowAnimation.FlowAnimation.forward_mode
forward_mode
Definition: FlowAnimation.py:300
src_files.FlowAnimation.FlowAnimation.Z_stab
Z_stab
Definition: FlowAnimation.py:216
src_files.FlowAnimation.FlowAnimation.flow_maxArrowWidth
flow_maxArrowWidth
Definition: FlowAnimation.py:168
src_files.FlowAnimation.FlowAnimation.mafrabin_plot
mafrabin_plot
Definition: FlowAnimation.py:1078
src_files.FlowAnimation.FlowAnimation.r_path_button_event
def r_path_button_event(self, event)
Definition: FlowAnimation.py:849
src_files.FlowAnimation.FlowAnimation.__init_interactive
def __init_interactive(self)
Definition: FlowAnimation.py:607
src_files.FlowAnimation.FlowAnimation.toggle_buttons
toggle_buttons
Definition: FlowAnimation.py:630
src_files.FlowAnimation.FlowAnimation.z
z
Definition: FlowAnimation.py:993
src_files.FlowAnimation.FlowAnimation.__init_data_addmainout
def __init_data_addmainout(self, ii)
Definition: FlowAnimation.py:1335
src_files.FlowAnimation.FlowAnimation.plot_mainout
plot_mainout
Definition: FlowAnimation.py:154
src_files.FlowAnimation.FlowAnimation.__init_ngamma_eq
def __init_ngamma_eq(self)
Definition: FlowAnimation.py:358
src_files.FlowAnimation.FlowAnimation.sum_over_A
def sum_over_A(self, A, X)
Definition: FlowAnimation.py:1796
src_files.FlowAnimation.FlowAnimation.frame_dir
frame_dir
Definition: FlowAnimation.py:132
src_files.FlowAnimation.FlowAnimation.flow_min
flow_min
Definition: FlowAnimation.py:170
src_files.FlowAnimation.FlowAnimation.alphaMassBins
alphaMassBins
Definition: FlowAnimation.py:145
src_files.FlowAnimation.FlowAnimation.to_latex_exponent
def to_latex_exponent(x)
Definition: FlowAnimation.py:1763
src_files.FlowAnimation.FlowAnimation.__init_data_tracked
def __init_data_tracked(self, ii, force_label_init=False)
Definition: FlowAnimation.py:1351
src_files.FlowAnimation.FlowAnimation.ts_time
ts_time
Definition: FlowAnimation.py:1330
src_files.FlowAnimation.FlowAnimation.fis_region
fis_region
Definition: FlowAnimation.py:999
src_files.FlowAnimation.FlowAnimation.massBins
massBins
Definition: FlowAnimation.py:147
src_files.FlowAnimation.FlowAnimation.update_interactive_text
def update_interactive_text(self, ii)
Definition: FlowAnimation.py:1482
src_files.FlowAnimation.FlowAnimation.axTimescales
axTimescales
Definition: FlowAnimation.py:515
src_files.FlowAnimation.FlowAnimation.init_axes
def init_axes(self)
Definition: FlowAnimation.py:425
src_files.FlowAnimation.FlowAnimation.sunet_indication
sunet_indication
Definition: FlowAnimation.py:420
src_files.FlowAnimation.FlowAnimation.plot_tracked
plot_tracked
Definition: FlowAnimation.py:187
src_files.FlowAnimation.FlowAnimation.separate_fission
separate_fission
Definition: FlowAnimation.py:160
src_files.FlowAnimation.FlowAnimation.n_timesteps
n_timesteps
Definition: FlowAnimation.py:930
src_files.FlowAnimation.FlowAnimation.__init_plot_energy
def __init_plot_energy(self)
Definition: FlowAnimation.py:1196
src_files.FlowAnimation.FlowAnimation.time_slider
def time_slider(self)
Definition: FlowAnimation.py:1516
src_files.FlowAnimation.FlowAnimation.flow_max
flow_max
Definition: FlowAnimation.py:171
src_files.FlowAnimation.FlowAnimation.__init_axTimescales
def __init_axTimescales(self)
Definition: FlowAnimation.py:511
src_files.FlowAnimation.FlowAnimation.flow_patch
flow_patch
Definition: FlowAnimation.py:1044
src_files.FlowAnimation.FlowAnimation.Z
Z
Definition: FlowAnimation.py:925
src_files.FlowAnimation.FlowAnimation.__init_data_energy
def __init_data_energy(self, ii)
Definition: FlowAnimation.py:1346
src_files.FlowAnimation.FlowAnimation.mafra_button_event
def mafra_button_event(self, event)
Definition: FlowAnimation.py:822
src_files.FlowAnimation.FlowAnimation.__interactive_ax
__interactive_ax
Definition: FlowAnimation.py:617
src_files.FlowAnimation.FlowAnimation.ngamma_eq_plot
ngamma_eq_plot
Definition: FlowAnimation.py:363
src_files.FlowAnimation.FlowAnimation.flow_Z
flow_Z
Definition: FlowAnimation.py:1003
src_files.FlowAnimation.FlowAnimation.ngamma_eq_plot_o
ngamma_eq_plot_o
Definition: FlowAnimation.py:364
benam_class::read_winvn
subroutine, private read_winvn(winvn)
Reads nuclear properties (name,a,n,z,spin,mass excess,partition functions) from file 'winvn' and writ...
Definition: benam_class.f90:675
src_files.FlowAnimation.FlowAnimation.ax
ax
Definition: FlowAnimation.py:433
src_files.FlowAnimation.FlowAnimation.__background_Y_1
__background_Y_1
Definition: FlowAnimation.py:989
src_files.FlowAnimation.FlowAnimation.axAddMainout
axAddMainout
Definition: FlowAnimation.py:551
src_files.FlowAnimation.FlowAnimation.track_nuclei_labels
track_nuclei_labels
Definition: FlowAnimation.py:1356
src_files.FlowAnimation.FlowAnimation.pause_movie
def pause_movie(self, click_event)
Definition: FlowAnimation.py:1538
src_files.FlowAnimation.FlowAnimation.animation
animation
Definition: FlowAnimation.py:1510
src_files.FlowAnimation.FlowAnimation.mafra_max_offset
mafra_max_offset
Definition: FlowAnimation.py:276
src_files.FlowAnimation.FlowAnimation.arrow_update
def arrow_update(self, event)
Definition: FlowAnimation.py:1626
src_files.FlowAnimation.FlowAnimation.energyrange
energyrange
Definition: FlowAnimation.py:150
src_files.FlowAnimation.FlowAnimation.__toggle_zoom
def __toggle_zoom(self)
Definition: FlowAnimation.py:1749
src_files.FlowAnimation.FlowAnimation.axTracked
axTracked
Definition: FlowAnimation.py:527
src_files.FlowAnimation.FlowAnimation.__Z_plot
__Z_plot
Definition: FlowAnimation.py:224
src_files.FlowAnimation.FlowAnimation.values
values
Definition: FlowAnimation.py:980
src_files.FlowAnimation.FlowAnimation.energy_plot
energy_plot
Definition: FlowAnimation.py:1197
src_files.FlowAnimation.FlowAnimation.__N_plot
__N_plot
Definition: FlowAnimation.py:225
src_files.FlowAnimation.FlowAnimation.Xbins
Xbins
Definition: FlowAnimation.py:965
src_files.FlowAnimation.FlowAnimation.__toggle_tracked
def __toggle_tracked(self)
Definition: FlowAnimation.py:1729
src_files.FlowAnimation.FlowAnimation.Abar_plot
Abar_plot
Definition: FlowAnimation.py:1094
src_files.FlowAnimation.FlowAnimation.tracked_time
tracked_time
Definition: FlowAnimation.py:1352
src_files.FlowAnimation.FlowAnimation.zMagic
zMagic
Definition: FlowAnimation.py:232
src_files.FlowAnimation.FlowAnimation.abun
abun
Definition: FlowAnimation.py:996
src_files.FlowAnimation.FlowAnimation.flow_minArrowWidth
flow_minArrowWidth
Definition: FlowAnimation.py:169
src_files.FlowAnimation.FlowAnimation.X
X
Definition: FlowAnimation.py:928
src_files.FlowAnimation.FlowAnimation.__background_Y_3
__background_Y_3
Definition: FlowAnimation.py:298
src_files.FlowAnimation.FlowAnimation.temperaturerange
temperaturerange
Definition: FlowAnimation.py:163
src_files.FlowAnimation.FlowAnimation.update_frame
def update_frame(self, ii)
Definition: FlowAnimation.py:1470
src_files.FlowAnimation.FlowAnimation.Mainout_text
Mainout_text
Definition: FlowAnimation.py:1123
src_files.FlowAnimation.FlowAnimation.massBinLabels
massBinLabels
Definition: FlowAnimation.py:148
src_files.FlowAnimation.FlowAnimation.Mainout_units
Mainout_units
Definition: FlowAnimation.py:1124
src_files.FlowAnimation.FlowAnimation.trackedrange
trackedrange
Definition: FlowAnimation.py:151
src_files.FlowAnimation.FlowAnimation.flow_norm
flow_norm
Definition: FlowAnimation.py:250
src_files.FlowAnimation.FlowAnimation.__background_Y_2
__background_Y_2
Definition: FlowAnimation.py:296
src_files.FlowAnimation.FlowAnimation.flow_buttons
flow_buttons
Definition: FlowAnimation.py:703
src_files.FlowAnimation.FlowAnimation.flow_max_offset
flow_max_offset
Definition: FlowAnimation.py:273
src_files.FlowAnimation.FlowAnimation.mainout_temp_plot
mainout_temp_plot
Definition: FlowAnimation.py:1099
src_files.FlowAnimation.FlowAnimation.init_data
def init_data(self)
Definition: FlowAnimation.py:920
src_files.FlowAnimation.FlowAnimation.__init_logo
def __init_logo(self)
Definition: FlowAnimation.py:599
src_files.FlowAnimation.FlowAnimation.__init__
def __init__(self, path, fig, frame_dir=None, plot_flow=True, flow_min=1e-8, flow_max=1e1, separate_fission=True, fission_minflow=1e-10, flow_cbar=True, flow_adapt_prange=True, flow_prange=5, flow_adapt_width=True, flow_maxArrowWidth=2.0, flow_minArrowWidth=0.3, cmapNameFlow='viridis', abun_cbar=True, X_min=1e-8, X_max=1, cmapNameX='inferno', plot_abar=True, plotMassBins=True, addMassBinLabels=True, alphaMassBins=0.5, cmapNameMassBins='jet', massBins=[[1, 1],[2, 71],[72, 93],[94, 110],[111, 144],[145, 169],[170, 187],[188, 205],[206, 252],[253, 337]], massBinLabels=['','', '1st peak','', '2nd peak', 'rare earths', '', '3rd peak', '', 'fissioning'], plot_magic=True, additional_plot='none', trackedrange=(1e-8, 1), amainoutrange=(5e-10, 1), energyrange=(1e10, 1e20), timescalerange=(1e-12, 1e10), timerange=(1e-5, 1e5), plot_mainout=True, densityrange=(1e-5, 1e12), temperaturerange=(0, 10), yerange=(0.0, 0.55), plot_logo=True, indicate_r_path=False, winvn_path=None, interactive=False)
Definition: FlowAnimation.py:30
src_files.FlowAnimation.FlowAnimation.movie_paused
movie_paused
Definition: FlowAnimation.py:471
src_files.FlowAnimation.FlowAnimation.mafra_min_offset
mafra_min_offset
Definition: FlowAnimation.py:277
src_files.FlowAnimation.FlowAnimation.flow_dn
flow_dn
Definition: FlowAnimation.py:1316
src_files.FlowAnimation.FlowAnimation.timescalerange
timescalerange
Definition: FlowAnimation.py:152
src_files.FlowAnimation.FlowAnimation.track_nuclei_data
track_nuclei_data
Definition: FlowAnimation.py:1354
src_files.FlowAnimation.FlowAnimation.on_slider_update
def on_slider_update(self, val)
Definition: FlowAnimation.py:1523
src_files.FlowAnimation.FlowAnimation.time
time
Definition: FlowAnimation.py:958
src_files.FlowAnimation.FlowAnimation.play_button
play_button
Definition: FlowAnimation.py:612
src_files.FlowAnimation.FlowAnimation.path
path
Definition: FlowAnimation.py:137
src_files.FlowAnimation.FlowAnimation.init_cbars
def init_cbars(self, abun_cbar, flow_cbar)
Definition: FlowAnimation.py:1210
src_files.FlowAnimation.FlowAnimation.wreader
wreader
Definition: FlowAnimation.py:213
src_files.FlowAnimation.FlowAnimation.flow_N
flow_N
Definition: FlowAnimation.py:1314
src_files.FlowAnimation.FlowAnimation.A
A
Definition: FlowAnimation.py:927
src_files.FlowAnimation.FlowAnimation.ax_slider
ax_slider
Definition: FlowAnimation.py:609
src_files.FlowAnimation.FlowAnimation.__data_path
__data_path
Definition: FlowAnimation.py:129
src_files.FlowAnimation.FlowAnimation.axMainout_temp
axMainout_temp
Definition: FlowAnimation.py:577
src_files.FlowAnimation.FlowAnimation.energy_labels
energy_labels
Definition: FlowAnimation.py:244
src_files.FlowAnimation.FlowAnimation.addmainout_label
addmainout_label
Definition: FlowAnimation.py:1338
src_files.FlowAnimation.FlowAnimation.additional_plot
additional_plot
Definition: FlowAnimation.py:149
src_files.FlowAnimation.FlowAnimation.__interactive_textbox
__interactive_textbox
Definition: FlowAnimation.py:285
src_files.FlowAnimation.FlowAnimation.on_slider_release
def on_slider_release(self, event)
Definition: FlowAnimation.py:1621
src_files.FlowAnimation.FlowAnimation.flow_max_history
flow_max_history
Definition: FlowAnimation.py:252
src_files.FlowAnimation.FlowAnimation.update_slider
def update_slider(self, ii)
Definition: FlowAnimation.py:1527
src_files.FlowAnimation.FlowAnimation.mainout_ye
mainout_ye
Definition: FlowAnimation.py:953
summarize.axis
axis
Definition: summarize.py:441
src_files.FlowAnimation.FlowAnimation.sunet_button_event
def sunet_button_event(self, event)
Definition: FlowAnimation.py:860
src_files.FlowAnimation.FlowAnimation.__init_axAddMainout
def __init_axAddMainout(self)
Definition: FlowAnimation.py:547
src_files.FlowAnimation.FlowAnimation.toggle_button_event
def toggle_button_event(self, event)
Definition: FlowAnimation.py:875
src_files.FlowAnimation.FlowAnimation.r_path_button
r_path_button
Definition: FlowAnimation.py:685
src_files.FlowAnimation.FlowAnimation.update_fission_plot
def update_fission_plot(self)
Definition: FlowAnimation.py:1424
src_files.FlowAnimation.FlowAnimation.N
N
Definition: FlowAnimation.py:926
src_files.FlowAnimation.FlowAnimation.__max_N
__max_N
Definition: FlowAnimation.py:226
src_files.FlowAnimation.FlowAnimation.flow
flow
Definition: FlowAnimation.py:1005
src_files.FlowAnimation.FlowAnimation.addmainout_data
addmainout_data
Definition: FlowAnimation.py:1339
src_files.FlowAnimation.FlowAnimation.massbin_colors
massbin_colors
Definition: FlowAnimation.py:976
src_files.FlowAnimation.FlowAnimation.fig
fig
Definition: FlowAnimation.py:159
Plot_me.colorbar
colorbar
Definition: Plot_me.py:33
src_files.FlowAnimation.FlowAnimation.__init_axMainout
def __init_axMainout(self)
Definition: FlowAnimation.py:559
src_files.FlowAnimation.FlowAnimation.mainout_dens_plot
mainout_dens_plot
Definition: FlowAnimation.py:1098
src_files.FlowAnimation.FlowAnimation.__background_Y
__background_Y
Definition: FlowAnimation.py:988
src_files.FlowAnimation.FlowAnimation.abun_im
abun_im
Definition: FlowAnimation.py:1017
src_files.FlowAnimation.FlowAnimation.energy_time
energy_time
Definition: FlowAnimation.py:1347
src_files.FlowAnimation.FlowAnimation.flow_group
flow_group
Definition: FlowAnimation.py:157
src_files.FlowAnimation.FlowAnimation.nMagic
nMagic
Definition: FlowAnimation.py:231
src_files.FlowAnimation.FlowAnimation.__init_plot_addmainout
def __init_plot_addmainout(self)
Definition: FlowAnimation.py:1189
src_files.FlowAnimation.FlowAnimation.slider_bar
slider_bar
Definition: FlowAnimation.py:1517
src_files.FlowAnimation.FlowAnimation.__init_sunet_indicator
def __init_sunet_indicator(self)
Definition: FlowAnimation.py:368
src_files.FlowAnimation.FlowAnimation.mafra_plot
mafra_plot
Definition: FlowAnimation.py:1074
src_files.FlowAnimation.FlowAnimation.flow_dz
flow_dz
Definition: FlowAnimation.py:1004
src_files.FlowAnimation.FlowAnimation.__background_cmap
__background_cmap
Definition: FlowAnimation.py:977
src_files.FlowAnimation.FlowAnimation.winvn_path
winvn_path
Definition: FlowAnimation.py:176
src_files.FlowAnimation.FlowAnimation.cmapNameMassBins
cmapNameMassBins
Definition: FlowAnimation.py:146
src_files.FlowAnimation.FlowAnimation.frames
frames
Definition: FlowAnimation.py:1509
src_files.FlowAnimation.FlowAnimation.__init_data_timescales
def __init_data_timescales(self, ii)
Definition: FlowAnimation.py:1329
src_files.FlowAnimation.FlowAnimation.update_ngamma_plot
def update_ngamma_plot(self)
Definition: FlowAnimation.py:1462
src_files.FlowAnimation.FlowAnimation.energy_data
energy_data
Definition: FlowAnimation.py:1349
src_files.FlowAnimation.FlowAnimation.sunet_button
sunet_button
Definition: FlowAnimation.py:675
src_files.FlowAnimation.FlowAnimation.__script_path
__script_path
Definition: FlowAnimation.py:128
src_files.FlowAnimation.FlowAnimation.addMassBinLabels
addMassBinLabels
Definition: FlowAnimation.py:144
src_files.FlowAnimation.FlowAnimation.update_flow_plot
def update_flow_plot(self)
Definition: FlowAnimation.py:1433
src_files.FlowAnimation.FlowAnimation.X_max
X_max
Definition: FlowAnimation.py:141
src_files.FlowAnimation.FlowAnimation.plotMassBins
plotMassBins
Definition: FlowAnimation.py:142
src_files.FlowAnimation.FlowAnimation.energy_lw
energy_lw
Definition: FlowAnimation.py:246
src_files.FlowAnimation.FlowAnimation.handle_fission
def handle_fission(self)
Definition: FlowAnimation.py:1358
src_files.FlowAnimation.FlowAnimation.save_frame
def save_frame(self, ii)
Definition: FlowAnimation.py:1496
src_files.FlowAnimation.FlowAnimation.cmapNameFlow
cmapNameFlow
Definition: FlowAnimation.py:166
src_files.FlowAnimation.FlowAnimation.winvn
winvn
Definition: FlowAnimation.py:286
src_files.FlowAnimation.FlowAnimation.mainout_time
mainout_time
Definition: FlowAnimation.py:950
src_files.FlowAnimation.FlowAnimation.plot_addmainout
plot_addmainout
Definition: FlowAnimation.py:188
src_files.FlowAnimation.FlowAnimation.__init_plot_tracked
def __init_plot_tracked(self)
Definition: FlowAnimation.py:1202
src_files.FlowAnimation.FlowAnimation.__init_plot_timescales
def __init_plot_timescales(self)
Definition: FlowAnimation.py:1182
src_files.FlowAnimation.FlowAnimation.axMassFrac
axMassFrac
Definition: FlowAnimation.py:505
src_files.FlowAnimation.FlowAnimation.get_funcanimation
def get_funcanimation(self, frames=None, **kwargs)
Definition: FlowAnimation.py:1504
src_files.FlowAnimation.FlowAnimation.logo
logo
Definition: FlowAnimation.py:605
src_files.FlowAnimation.FlowAnimation.timescale_labels
timescale_labels
Definition: FlowAnimation.py:238
src_files.FlowAnimation.FlowAnimation.plot_energy
plot_energy
Definition: FlowAnimation.py:186
src_files.FlowAnimation.FlowAnimation.energy_entries
energy_entries
Definition: FlowAnimation.py:243
src_files.FlowAnimation.FlowAnimation.cb_bg
cb_bg
Definition: FlowAnimation.py:1250
src_files.nucleus_multiple_class.nucleus_multiple
Definition: nucleus_multiple_class.py:10
src_files.FlowAnimation.FlowAnimation.fis_im_pos
fis_im_pos
Definition: FlowAnimation.py:1049
src_files.FlowAnimation.FlowAnimation.plot_magic
plot_magic
Definition: FlowAnimation.py:161
src_files.FlowAnimation.FlowAnimation.mafra_buttons
mafra_buttons
Definition: FlowAnimation.py:718
src_files.FlowAnimation.FlowAnimation.timerange
timerange
Definition: FlowAnimation.py:153
src_files.FlowAnimation.FlowAnimation.plot_flow
plot_flow
Definition: FlowAnimation.py:158
src_files.FlowAnimation.FlowAnimation.zoom_button
zoom_button
Definition: FlowAnimation.py:665
src_files.FlowAnimation.FlowAnimation.background_im
background_im
Definition: FlowAnimation.py:1012
src_files.FlowAnimation.FlowAnimation.axAbund
axAbund
Definition: FlowAnimation.py:494
src_files.FlowAnimation.FlowAnimation.mainout_temperature
mainout_temperature
Definition: FlowAnimation.py:952
src_files.FlowAnimation.FlowAnimation.__max_Z
__max_Z
Definition: FlowAnimation.py:227
src_files.FlowAnimation.FlowAnimation.plot_logo
plot_logo
Definition: FlowAnimation.py:155
src_files.FlowAnimation.FlowAnimation.energy_colors
energy_colors
Definition: FlowAnimation.py:242
src_files.FlowAnimation.FlowAnimation.zoom_button_event
def zoom_button_event(self, event)
Definition: FlowAnimation.py:868
src_files.FlowAnimation.FlowAnimation.X_min
X_min
Definition: FlowAnimation.py:140
src_files.FlowAnimation.FlowAnimation.yerange
yerange
Definition: FlowAnimation.py:164
src_files.FlowAnimation.FlowAnimation.flow_prange
flow_prange
Definition: FlowAnimation.py:179
src_files.FlowAnimation.FlowAnimation.update_data
def update_data(self, ii)
Definition: FlowAnimation.py:1257
src_files.FlowAnimation.FlowAnimation.addmainout_time
addmainout_time
Definition: FlowAnimation.py:1336
src_files.FlowAnimation.FlowAnimation.__init_axAbund
def __init_axAbund(self)
Definition: FlowAnimation.py:489
src_files.ngamma_eq.ngamma_eq
Definition: ngamma_eq.py:7
src_files.winvn_class.winvn
Definition: winvn_class.py:7
src_files.FlowAnimation.FlowAnimation.__interactive_box
__interactive_box
Definition: FlowAnimation.py:284
src_files.FlowAnimation.FlowAnimation.tracked_plot
tracked_plot
Definition: FlowAnimation.py:1203
src_files.FlowAnimation.FlowAnimation.fis_im_neg
fis_im_neg
Definition: FlowAnimation.py:1057
src_files.wreader.wreader
Definition: wreader.py:12
src_files.FlowAnimation.FlowAnimation.__abundance_colors
__abundance_colors
Definition: FlowAnimation.py:969
src_files.FlowAnimation.FlowAnimation.timescale_colors
timescale_colors
Definition: FlowAnimation.py:236
src_files.FlowAnimation.FlowAnimation.flow_min_offset
flow_min_offset
Definition: FlowAnimation.py:274
src_files.FlowAnimation.FlowAnimation.abun_cbar
abun_cbar
Definition: FlowAnimation.py:1231
src_files.FlowAnimation.FlowAnimation.ts_data
ts_data
Definition: FlowAnimation.py:1332
src_files.FlowAnimation.FlowAnimation.axEnergy
axEnergy
Definition: FlowAnimation.py:539
src_files.FlowAnimation.FlowAnimation.addmainout_plot
addmainout_plot
Definition: FlowAnimation.py:1190
src_files.FlowAnimation.FlowAnimation
Definition: FlowAnimation.py:25
src_files.FlowAnimation.FlowAnimation.limits_plot
limits_plot
Definition: FlowAnimation.py:270
src_files.FlowAnimation.FlowAnimation.fission_minflow
fission_minflow
Definition: FlowAnimation.py:173
src_files.FlowAnimation.FlowAnimation.ax_button
ax_button
Definition: FlowAnimation.py:610
src_files.FlowAnimation.FlowAnimation.background
background
Definition: FlowAnimation.py:697
src_files.FlowAnimation.FlowAnimation.mafra_sm
mafra_sm
Definition: FlowAnimation.py:1230
src_files.FlowAnimation.FlowAnimation.__init_nucchart_ax
def __init_nucchart_ax(self)
Definition: FlowAnimation.py:479
src_files.FlowAnimation.FlowAnimation.__init_axTracked
def __init_axTracked(self)
Definition: FlowAnimation.py:523
src_files.FlowAnimation.FlowAnimation.init_plot
def init_plot(self)
Definition: FlowAnimation.py:1008
src_files.FlowAnimation.FlowAnimation.mainout_ye_plot
mainout_ye_plot
Definition: FlowAnimation.py:1100
src_files.FlowAnimation.FlowAnimation.active_button
active_button
Definition: FlowAnimation.py:662
src_files.FlowAnimation.FlowAnimation.on_slider_click
def on_slider_click(self, event)
Definition: FlowAnimation.py:1558
src_files.FlowAnimation.FlowAnimation.flow_adapt_width
flow_adapt_width
Definition: FlowAnimation.py:167
src_files.FlowAnimation.FlowAnimation.bg_button
bg_button
Definition: FlowAnimation.py:693
src_files.FlowAnimation.FlowAnimation.amainoutrange
amainoutrange
Definition: FlowAnimation.py:174
src_files.FlowAnimation.FlowAnimation.plot_abar
plot_abar
Definition: FlowAnimation.py:143
src_files.FlowAnimation.FlowAnimation.flow_cbar
flow_cbar
Definition: FlowAnimation.py:1238