redback 1.0.2__py3-none-any.whl → 1.0.31__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. redback/__init__.py +1 -1
  2. redback/constraints.py +15 -0
  3. redback/eos.py +1 -0
  4. redback/get_data/fink.py +1 -1
  5. redback/model_library.py +2 -2
  6. redback/priors/bazin_sne.prior +5 -0
  7. redback/priors/csm_shock_and_arnett.prior +11 -0
  8. redback/priors/csm_shock_and_arnett_bolometric.prior +10 -0
  9. redback/priors/csm_shock_breakout.prior +7 -0
  10. redback/priors/nicholl_bns.prior +2 -1
  11. redback/priors/pwn.prior +7 -0
  12. redback/priors/shocked_cocoon.prior +6 -6
  13. redback/priors/sn_fallback.prior +8 -0
  14. redback/priors/stream_stream_tde.prior +10 -0
  15. redback/priors/stream_stream_tde_bolometric.prior +9 -0
  16. redback/priors/tde_fallback.prior +9 -0
  17. redback/priors/tde_fallback_bolometric.prior +6 -0
  18. redback/priors/tde_synchrotron.prior +6 -0
  19. redback/priors/two_comp_kne_rosswog_heatingrate.prior +2 -2
  20. redback/priors/villar_sne.prior +7 -0
  21. redback/priors.py +1 -1
  22. redback/simulate_transients.py +11 -4
  23. redback/tables/GRBs_w_redshift.txt +430 -413
  24. redback/tables/LGRB_table.txt +70 -6
  25. redback/tables/SGRB_table.txt +139 -135
  26. redback/tables/qdot_rosswogkorobkin24.pck +0 -0
  27. redback/transient/afterglow.py +14 -5
  28. redback/transient/kilonova.py +5 -2
  29. redback/transient/prompt.py +14 -4
  30. redback/transient/supernova.py +6 -2
  31. redback/transient/tde.py +5 -2
  32. redback/transient/transient.py +27 -10
  33. redback/transient_models/afterglow_models.py +110 -146
  34. redback/transient_models/combined_models.py +39 -33
  35. redback/transient_models/extinction_models.py +1 -2
  36. redback/transient_models/general_synchrotron_models.py +518 -0
  37. redback/transient_models/integrated_flux_afterglow_models.py +2 -2
  38. redback/transient_models/kilonova_models.py +88 -72
  39. redback/transient_models/magnetar_models.py +1 -1
  40. redback/transient_models/phenomenological_models.py +57 -2
  41. redback/transient_models/shock_powered_models.py +159 -110
  42. redback/transient_models/supernova_models.py +161 -7
  43. redback/transient_models/tde_models.py +849 -4
  44. redback/utils.py +28 -12
  45. {redback-1.0.2.dist-info → redback-1.0.31.dist-info}/METADATA +42 -5
  46. {redback-1.0.2.dist-info → redback-1.0.31.dist-info}/RECORD +49 -35
  47. {redback-1.0.2.dist-info → redback-1.0.31.dist-info}/WHEEL +1 -1
  48. {redback-1.0.2.dist-info → redback-1.0.31.dist-info}/LICENCE.md +0 -0
  49. {redback-1.0.2.dist-info → redback-1.0.31.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  import os
4
4
  from os.path import join
5
5
  from typing import Union
6
+ import re
6
7
 
7
8
  import numpy as np
8
9
  import pandas as pd
@@ -26,7 +27,8 @@ class Afterglow(Transient):
26
27
  flux_density_err: np.ndarray = None, magnitude: np.ndarray = None, magnitude_err: np.ndarray = None,
27
28
  redshift: float = np.nan, photon_index: float = np.nan, frequency: np.ndarray = None,
28
29
  bands: np.ndarray = None, system: np.ndarray = None, active_bands: Union[np.ndarray, str] = 'all',
29
- use_phase_model: bool = False, optical_data: bool = False, **kwargs: None) -> None:
30
+ plotting_order: Union[np.ndarray, str] = None, use_phase_model: bool = False,
31
+ optical_data: bool = False, **kwargs: None) -> None:
30
32
 
31
33
  """
32
34
  This is a general constructor for the Afterglow class. Note that you only need to give data corresponding to
@@ -81,6 +83,8 @@ class Afterglow(Transient):
81
83
  :type bands: np.ndarray, optional
82
84
  :param active_bands: List or array of active bands to be used in the analysis. Use all available bands if 'all' is given.
83
85
  :type active_bands: Union[list, np.ndarray]
86
+ :param plotting_order: Order in which to plot the bands/and how unique bands are stored.
87
+ :type plotting_order: Union[np.ndarray, str], optional
84
88
  :param kwargs:
85
89
  Additional classes that can be customised to fulfil the truncation on flux to luminosity conversion:
86
90
  FluxToLuminosityConverter: Conversion class to convert fluxes to luminosities.
@@ -99,7 +103,8 @@ class Afterglow(Transient):
99
103
  Lum50=Lum50, Lum50_err=Lum50_err, flux=flux, flux_err=flux_err, flux_density=flux_density,
100
104
  flux_density_err=flux_density_err, use_phase_model=use_phase_model, optical_data=optical_data,
101
105
  magnitude=magnitude, magnitude_err=magnitude_err, frequency=frequency, redshift=redshift,
102
- photon_index=photon_index, system=system, bands=bands, active_bands=active_bands, **kwargs)
106
+ photon_index=photon_index, system=system, bands=bands, active_bands=active_bands,
107
+ plotting_order=plotting_order, **kwargs)
103
108
  self._set_data()
104
109
  self._set_photon_index()
105
110
  self._set_t90()
@@ -306,9 +311,13 @@ class Afterglow(Transient):
306
311
  :return: The cleaned string converted into a float.
307
312
  :rtype: float
308
313
  """
309
- for r in ["PL", "CPL", ",", "C", "~", " ", 'Gemini:emission', '()']:
310
- string = string.replace(r, "")
311
- return float(string)
314
+ try:
315
+ for r in ["PL", "CPL", ",", "C", "~", " ", 'Gemini:emission', '()']:
316
+ string = string.replace(r, "")
317
+ new_float = float(string)
318
+ except ValueError:
319
+ new_float = float(re.findall("\d+\.\d+", string)[0])
320
+ return new_float
312
321
 
313
322
  def analytical_flux_to_luminosity(self) -> None:
314
323
  """Converts flux to luminosity using the analytical method."""
@@ -20,7 +20,8 @@ class Kilonova(OpticalTransient):
20
20
  flux_density: np.ndarray = None, flux_density_err: np.ndarray = None, magnitude: np.ndarray = None,
21
21
  magnitude_err: np.ndarray = None, redshift: float = np.nan, photon_index: float = np.nan,
22
22
  bands: np.ndarray = None, system: np.ndarray = None, active_bands: Union[np.ndarray, str] = 'all',
23
- use_phase_model: bool = False, optical_data: bool = True, **kwargs: None) -> None:
23
+ plotting_order: Union[np.ndarray, str] = None, use_phase_model: bool = False,
24
+ optical_data: bool = True, **kwargs: None) -> None:
24
25
  """This is a general constructor for the Kilonova class. Note that you only need to give data corresponding to
25
26
  the data mode you are using. For luminosity data provide times in the rest frame, if using a phase model
26
27
  provide time in MJD, else use the default time (observer frame).
@@ -74,6 +75,8 @@ class Kilonova(OpticalTransient):
74
75
  :type bands: np.ndarray, optional
75
76
  :param active_bands: List or array of active bands to be used in the analysis. Use all available bands if 'all' is given.
76
77
  :type active_bands: Union[list, np.ndarray]
78
+ :param plotting_order: Order in which to plot the bands/and how unique bands are stored.
79
+ :type plotting_order: Union[np.ndarray, str], optional
77
80
  :param kwargs: Additional callables:
78
81
  bands_to_frequency: Conversion function to convert a list of bands to frequencies. Use
79
82
  redback.utils.bands_to_frequency if not given.
@@ -85,7 +88,7 @@ class Kilonova(OpticalTransient):
85
88
  Lum50_err=Lum50_err, flux_density=flux_density, flux_density_err=flux_density_err,
86
89
  magnitude=magnitude, magnitude_err=magnitude_err, data_mode=data_mode, name=name, bands=bands,
87
90
  system=system, active_bands=active_bands, use_phase_model=use_phase_model, redshift=redshift,
88
- photon_index=photon_index, optical_data=optical_data, **kwargs)
91
+ photon_index=photon_index, optical_data=optical_data, plotting_order=plotting_order, **kwargs)
89
92
  self.directory_structure = redback.get_data.directory.open_access_directory_structure(
90
93
  transient=name, transient_type="kilonova")
91
94
  self._set_data()
@@ -8,7 +8,7 @@ import pandas as pd
8
8
  from typing import Union
9
9
 
10
10
  from redback.get_data.utils import get_batse_trigger_from_grb
11
- from redback.get_data.directory import swift_prompt_directory_structure
11
+ from redback.get_data.directory import swift_prompt_directory_structure, batse_prompt_directory_structure
12
12
  from redback.transient.transient import Transient
13
13
 
14
14
  dirname = os.path.dirname(__file__)
@@ -61,7 +61,12 @@ class PromptTimeSeries(Transient):
61
61
  self.channels = channels
62
62
  self.instrument = instrument
63
63
  self._set_data()
64
- self.directory_structure = swift_prompt_directory_structure(grb=self.name, bin_size=self.bin_size)
64
+ if self.instrument == "batse":
65
+ self.directory_structure = batse_prompt_directory_structure(grb=self.name)
66
+ elif self.instrument == "swift":
67
+ self.directory_structure = swift_prompt_directory_structure(grb=self.name, bin_size=self.bin_size)
68
+ else:
69
+ raise ValueError("Instrument must be either 'batse' or 'swift'.")
65
70
 
66
71
  @classmethod
67
72
  def from_batse_grb_name(
@@ -95,8 +100,9 @@ class PromptTimeSeries(Transient):
95
100
  :rtype tuple:
96
101
  """
97
102
  name = f"GRB{name.lstrip('GRB')}"
98
- directory_structure = swift_prompt_directory_structure(grb=name)
99
- _time_series_data = np.genfromtxt(directory_structure.processed_file_path, delimiter=",")[1:]
103
+ directory_structure = batse_prompt_directory_structure(grb=name)
104
+ path = directory_structure.directory_path + name.lstrip('GRB') + '_BATSE_lc.csv'
105
+ _time_series_data = np.genfromtxt(path, delimiter=",")[1:]
100
106
 
101
107
  bin_left = _time_series_data[:, 0]
102
108
  bin_right = _time_series_data[:, 1]
@@ -150,6 +156,8 @@ class PromptTimeSeries(Transient):
150
156
  :type kwargs: None
151
157
  """
152
158
  plt.step(self.time, self.counts / self.bin_size)
159
+ plt.ylabel('Counts')
160
+ plt.xlabel('Time')
153
161
  plt.show()
154
162
  plt.clf()
155
163
 
@@ -177,6 +185,8 @@ class PromptTimeSeries(Transient):
177
185
  plt.clf()
178
186
  plt.step(self.time, self.counts / self.bin_size)
179
187
  plt.plot(self.time, model(self.time, **dict(posterior.iloc[-1])))
188
+ plt.ylabel('Counts')
189
+ plt.xlabel('Time')
180
190
  plt.show()
181
191
  plt.clf()
182
192
 
@@ -15,7 +15,8 @@ class Supernova(OpticalTransient):
15
15
  flux_density: np.ndarray = None, flux_density_err: np.ndarray = None, magnitude: np.ndarray = None,
16
16
  magnitude_err: np.ndarray = None, redshift: float = np.nan, photon_index: float = np.nan,
17
17
  bands: np.ndarray = None, system: np.ndarray = None, active_bands: Union[np.ndarray, str] = 'all',
18
- use_phase_model: bool = False, optical_data:bool = True, **kwargs: None) -> None:
18
+ plotting_order: Union[np.ndarray, str] = None, use_phase_model: bool = False,
19
+ optical_data:bool = True, **kwargs: None) -> None:
19
20
  """
20
21
  This is a general constructor for the Supernova class. Note that you only need to give data corresponding to
21
22
  the data mode you are using. For luminosity data provide times in the rest frame, if using a phase model
@@ -69,6 +70,8 @@ class Supernova(OpticalTransient):
69
70
  :type bands: np.ndarray, optional
70
71
  :param active_bands: List or array of active bands to be used in the analysis. Use all available bands if 'all' is given.
71
72
  :type active_bands: Union[list, np.ndarray]
73
+ :param plotting_order: Order in which to plot the bands/and how unique bands are stored.
74
+ :type plotting_order: Union[np.ndarray, str], optional
72
75
  :param kwargs: Additional callables:
73
76
  bands_to_frequency: Conversion function to convert a list of bands to frequencies. Use
74
77
  redback.utils.bands_to_frequency if not given.
@@ -80,7 +83,8 @@ class Supernova(OpticalTransient):
80
83
  Lum50_err=Lum50_err, flux_density=flux_density, flux_density_err=flux_density_err,
81
84
  magnitude=magnitude, magnitude_err=magnitude_err, data_mode=data_mode, name=name,
82
85
  use_phase_model=use_phase_model, bands=bands, system=system, active_bands=active_bands,
83
- redshift=redshift, photon_index=photon_index, **kwargs)
86
+ redshift=redshift, photon_index=photon_index, optical_data=optical_data,
87
+ plotting_order=plotting_order, **kwargs)
84
88
  self.directory_structure = redback.get_data.directory.open_access_directory_structure(
85
89
  transient=name, transient_type="supernova")
86
90
  self._set_data()
redback/transient/tde.py CHANGED
@@ -15,7 +15,8 @@ class TDE(OpticalTransient):
15
15
  flux_density: np.ndarray = None, flux_density_err: np.ndarray = None, magnitude: np.ndarray = None,
16
16
  magnitude_err: np.ndarray = None, redshift: float = np.nan, photon_index: float = np.nan,
17
17
  bands: np.ndarray = None, system: np.ndarray = None, active_bands: Union[np.ndarray, str] = 'all',
18
- use_phase_model: bool = False, optical_data:bool = True, **kwargs: None) -> None:
18
+ plotting_order: Union[np.ndarray, str] = None, use_phase_model: bool = False,
19
+ optical_data:bool = True, **kwargs: None) -> None:
19
20
  """
20
21
 
21
22
  :param name: Name of the transient.
@@ -66,6 +67,8 @@ class TDE(OpticalTransient):
66
67
  :type bands: np.ndarray, optional
67
68
  :param active_bands: List or array of active bands to be used in the analysis. Use all available bands if 'all' is given.
68
69
  :type active_bands: Union[list, np.ndarray]
70
+ :param plotting_order: Order in which to plot the bands/and how unique bands are stored.
71
+ :type plotting_order: Union[np.ndarray, str], optional
69
72
  :param kwargs: Additional callables:
70
73
  bands_to_frequency: Conversion function to convert a list of bands to frequencies. Use
71
74
  redback.utils.bands_to_frequency if not given.
@@ -77,7 +80,7 @@ class TDE(OpticalTransient):
77
80
  magnitude=magnitude, magnitude_err=magnitude_err, data_mode=data_mode, name=name,
78
81
  use_phase_model=use_phase_model, optical_data=optical_data, bands=bands,
79
82
  system=system, active_bands=active_bands,redshift=redshift,
80
- photon_index=photon_index, **kwargs)
83
+ photon_index=photon_index, plotting_order=plotting_order, **kwargs)
81
84
  self.directory_structure = redback.get_data.directory.open_access_directory_structure(
82
85
  transient=self.name, transient_type="tidal_disruption_event")
83
86
  self._set_data()
@@ -38,7 +38,7 @@ class Transient(object):
38
38
  ttes: np.ndarray = None, bin_size: float = None, redshift: float = np.nan, data_mode: str = None,
39
39
  name: str = '', photon_index: float = np.nan, use_phase_model: bool = False,
40
40
  optical_data: bool = False, frequency: np.ndarray = None, system: np.ndarray = None, bands: np.ndarray = None,
41
- active_bands: Union[np.ndarray, str] = None, **kwargs: None) -> None:
41
+ active_bands: Union[np.ndarray, str] = None, plotting_order: Union[np.ndarray, str] = None, **kwargs: None) -> None:
42
42
  """This is a general constructor for the Transient class. Note that you only need to give data corresponding to
43
43
  the data mode you are using. For luminosity data provide times in the rest frame, if using a phase model
44
44
  provide time in MJD, else use the default time (observer frame).
@@ -98,6 +98,8 @@ class Transient(object):
98
98
  :param active_bands: List or array of active bands to be used in the analysis.
99
99
  Use all available bands if 'all' is given.
100
100
  :type active_bands: Union[list, np.ndarray], optional
101
+ :param plotting_order: Order in which to plot the bands/and how unique bands are stored.
102
+ :type plotting_order: Union[np.ndarray, str], optional
101
103
  :param kwargs: Additional callables:
102
104
  bands_to_frequency: Conversion function to convert a list of bands to frequencies.
103
105
  Use redback.utils.bands_to_frequency if not given.
@@ -142,6 +144,7 @@ class Transient(object):
142
144
  self.name = name
143
145
  self.use_phase_model = use_phase_model
144
146
  self.optical_data = optical_data
147
+ self.plotting_order = plotting_order
145
148
 
146
149
  self.meta_data = None
147
150
  self.photon_index = photon_index
@@ -179,7 +182,7 @@ class Transient(object):
179
182
  @classmethod
180
183
  def from_lasair_data(
181
184
  cls, name: str, data_mode: str = "magnitude", active_bands: Union[np.ndarray, str] = 'all',
182
- use_phase_model: bool = False) -> Transient:
185
+ use_phase_model: bool = False, plotting_order: Union[np.ndarray, str] = None) -> Transient:
183
186
  """Constructor method to built object from LASAIR data.
184
187
 
185
188
  :param name: Name of the transient.
@@ -189,6 +192,8 @@ class Transient(object):
189
192
  :param active_bands: Sets active bands based on array given.
190
193
  If argument is 'all', all unique bands in `self.bands` will be used.
191
194
  :type active_bands: Union[np.ndarray, str]
195
+ :param plotting_order: Order in which to plot the bands/and how unique bands are stored.
196
+ :type plotting_order: Union[np.ndarray, str], optional
192
197
  :param use_phase_model: Whether to use a phase model.
193
198
  :type use_phase_model: bool, optional
194
199
 
@@ -214,12 +219,12 @@ class Transient(object):
214
219
  return cls(name=name, data_mode=data_mode, time=time_days, time_err=None, time_mjd=time_mjd,
215
220
  flux_density=flux_density, flux_density_err=flux_density_err, magnitude=magnitude,
216
221
  magnitude_err=magnitude_err, flux=flux, flux_err=flux_err, bands=bands, active_bands=active_bands,
217
- use_phase_model=use_phase_model, optical_data=True)
222
+ use_phase_model=use_phase_model, optical_data=True, plotting_order=plotting_order)
218
223
 
219
224
  @classmethod
220
225
  def from_simulated_optical_data(
221
226
  cls, name: str, data_mode: str = "magnitude", active_bands: Union[np.ndarray, str] = 'all',
222
- use_phase_model: bool = False) -> Transient:
227
+ plotting_order: Union[np.ndarray, str] = None, use_phase_model: bool = False) -> Transient:
223
228
  """Constructor method to built object from SimulatedOpticalTransient.
224
229
 
225
230
  :param name: Name of the transient.
@@ -229,6 +234,8 @@ class Transient(object):
229
234
  :param active_bands: Sets active bands based on array given.
230
235
  If argument is 'all', all unique bands in `self.bands` will be used.
231
236
  :type active_bands: Union[np.ndarray, str]
237
+ :param plotting_order: Order in which to plot the bands/and how unique bands are stored.
238
+ :type plotting_order: Union[np.ndarray, str], optional
232
239
  :param use_phase_model: Whether to use a phase model.
233
240
  :type use_phase_model: bool, optional
234
241
 
@@ -250,7 +257,7 @@ class Transient(object):
250
257
  return cls(name=name, data_mode=data_mode, time=time_days, time_err=None, time_mjd=time_mjd,
251
258
  flux_density=flux_density, flux_density_err=flux_density_err, magnitude=magnitude,
252
259
  magnitude_err=magnitude_err, flux=flux, flux_err=flux_err, bands=bands, active_bands=active_bands,
253
- use_phase_model=use_phase_model, optical_data=True)
260
+ use_phase_model=use_phase_model, optical_data=True, plotting_order=plotting_order)
254
261
 
255
262
  @property
256
263
  def _time_attribute_name(self) -> str:
@@ -501,7 +508,10 @@ class Transient(object):
501
508
  :return: All bands that we get from the data, eliminating all duplicates.
502
509
  :rtype: np.ndarray
503
510
  """
504
- return np.unique(self.bands)
511
+ if self.plotting_order is not None:
512
+ return self.plotting_order
513
+ else:
514
+ return np.unique(self.bands)
505
515
 
506
516
  @property
507
517
  def unique_frequencies(self) -> np.ndarray:
@@ -789,7 +799,8 @@ class OpticalTransient(Transient):
789
799
  flux_density_err: np.ndarray = None, magnitude: np.ndarray = None, magnitude_err: np.ndarray = None,
790
800
  redshift: float = np.nan, photon_index: float = np.nan, frequency: np.ndarray = None,
791
801
  bands: np.ndarray = None, system: np.ndarray = None, active_bands: Union[np.ndarray, str] = 'all',
792
- use_phase_model: bool = False, optical_data:bool = True, **kwargs: None) -> None:
802
+ plotting_order: Union[np.ndarray, str] = None, use_phase_model: bool = False,
803
+ optical_data:bool = True, **kwargs: None) -> None:
793
804
  """This is a general constructor for the Transient class. Note that you only need to give data corresponding to
794
805
  the data mode you are using. For luminosity data provide times in the rest frame, if using a phase model
795
806
  provide time in MJD, else use the default time (observer frame).
@@ -839,6 +850,8 @@ class OpticalTransient(Transient):
839
850
  :param active_bands: List or array of active bands to be used in the analysis.
840
851
  Use all available bands if 'all' is given.
841
852
  :type active_bands: Union[list, np.ndarray], optional
853
+ :param plotting_order: Order in which to plot the bands/and how unique bands are stored.
854
+ :type plotting_order: Union[np.ndarray, str], optional
842
855
  :param use_phase_model: Whether we are using a phase model.
843
856
  :type use_phase_model: bool, optional
844
857
  :param optical_data: Whether we are fitting optical data, useful for plotting.
@@ -855,14 +868,15 @@ class OpticalTransient(Transient):
855
868
  flux=flux, flux_err=flux_err, redshift=redshift, photon_index=photon_index,
856
869
  flux_density=flux_density, flux_density_err=flux_density_err, magnitude=magnitude,
857
870
  magnitude_err=magnitude_err, data_mode=data_mode, name=name,
858
- use_phase_model=use_phase_model, optical_data=optical_data, system=system, bands=bands,
871
+ use_phase_model=use_phase_model, optical_data=optical_data,
872
+ system=system, bands=bands, plotting_order=plotting_order,
859
873
  active_bands=active_bands, **kwargs)
860
874
  self.directory_structure = None
861
875
 
862
876
  @classmethod
863
877
  def from_open_access_catalogue(
864
878
  cls, name: str, data_mode: str = "magnitude", active_bands: Union[np.ndarray, str] = 'all',
865
- use_phase_model: bool = False) -> OpticalTransient:
879
+ plotting_order: Union[np.ndarray, str] = None, use_phase_model: bool = False) -> OpticalTransient:
866
880
  """Constructor method to built object from Open Access Catalogue
867
881
 
868
882
  :param name: Name of the transient.
@@ -873,6 +887,8 @@ class OpticalTransient(Transient):
873
887
  Sets active bands based on array given.
874
888
  If argument is 'all', all unique bands in `self.bands` will be used.
875
889
  :type active_bands: Union[np.ndarray, str]
890
+ :param plotting_order: Order in which to plot the bands/and how unique bands are stored.
891
+ :type plotting_order: Union[np.ndarray, str], optional
876
892
  :param use_phase_model: Whether to use a phase model.
877
893
  :type use_phase_model: bool, optional
878
894
 
@@ -890,7 +906,8 @@ class OpticalTransient(Transient):
890
906
  return cls(name=name, data_mode=data_mode, time=time_days, time_err=None, time_mjd=time_mjd,
891
907
  flux_density=flux_density, flux_density_err=flux_density_err, magnitude=magnitude,
892
908
  magnitude_err=magnitude_err, bands=bands, system=system, active_bands=active_bands,
893
- use_phase_model=use_phase_model, optical_data=True, flux=flux, flux_err=flux_err)
909
+ use_phase_model=use_phase_model, optical_data=True, flux=flux, flux_err=flux_err,
910
+ plotting_order=plotting_order)
894
911
 
895
912
  @property
896
913
  def event_table(self) -> str:
@@ -1,6 +1,6 @@
1
1
  from astropy.cosmology import Planck18 as cosmo # noqa
2
2
  from inspect import isfunction
3
- from redback.utils import logger, citation_wrapper, calc_ABmag_from_flux_density, lambda_to_nu
3
+ from redback.utils import logger, citation_wrapper, calc_ABmag_from_flux_density, lambda_to_nu, bands_to_frequency
4
4
  from redback.constants import day_to_s, speed_of_light, solar_mass, proton_mass, electron_mass, sigma_T
5
5
  from redback.sed import get_correct_output_format_from_spectra
6
6
  import astropy.units as uu
@@ -285,16 +285,16 @@ class RedbackAfterglows():
285
285
  te = np.arcsin(cs / (self.cc * (G2 - 1.) ** 0.5)) # equivalent form for angle due to spreading
286
286
  # prepare ex and OmG in this function
287
287
  if self.is_expansion:
288
- ex = te # expansion
288
+ ex = te / (G2) # expansion
289
289
  fac = 0.5 * latstep
290
- OmG = rotstep * (np.cos(thi - fac) - np.cos(ex + thi + fac)) # equivalent form for linear spacing
290
+ OmG = rotstep * (np.cos(thi - fac) - np.cos(ex/self.res + thi + fac)) # equivalent form for linear spacing
291
291
  else:
292
- te = np.ones(te.size) # no expansion
292
+ ex = np.ones(te.size) # no expansion
293
293
  fac = 0.5 * latstep
294
294
  OmG = rotstep * (np.cos(thi - fac) - np.cos(thi + fac)) # equivalent form for linear spacing
295
295
  # prepare R
296
296
  size = G.size
297
- exponent = ((1 - np.cos(te[0])) / (1 - np.cos(te[:size]))) ** 0.5
297
+ exponent = ((1 - np.cos(latstep + ex[0])) / (1 - np.cos(latstep + ex[:size]))) ** (1/2)
298
298
  R = ((3. - k) * Ne[:size] / (self.fourpi * n)) ** (1. / (3. - k))
299
299
  R[1:] = np.diff(R) * exponent[1:size] ** (1. / (3. - k))
300
300
  R = np.cumsum(R)
@@ -688,150 +688,10 @@ def _get_kn_dynamics(n0, Eej, Mej):
688
688
  # convert from lab frame to observer time. Approximate expression acounting for radial+azimuthal time-of-flight effect
689
689
  # (eq. 26 from Nava et al. 2013; see also Waxman 1997)
690
690
  tobs = R / (Gamma ** 2 * (1.0 + beta) * speed_of_light) + np.insert(
691
- integrate.cumtrapz((1.0 - beta_sh) / beta_sh, x=R) / speed_of_light, 0, 0.0)
691
+ integrate.cumulative_trapezoid((1.0 - beta_sh) / beta_sh, x=R) / speed_of_light, 0, 0.0)
692
692
 
693
693
  return t, R, beta, Gamma, eden, tobs, beta_sh, Gamma_sh
694
694
 
695
- @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2022MNRAS.516.4949S/abstract')
696
- def kilonova_afterglow_redback(time, redshift, loge0, mej, logn0, logepse, logepsb, p,
697
- **kwargs):
698
- """
699
- Calculate the afterglow emission from a kilonova remnant, following the model of Sarin et al. 2022.
700
- This model was modified by Nikhil Sarin following code provided by Ben Margalit.
701
-
702
- :param time: time in observer frame (days) in observer frame
703
- :param redshift: source redshift
704
- :param loge0: log10 of the initial kinetic energy of the ejecta (erg)
705
- :param mej: ejecta mass (solar masses)
706
- :param logn0: log10 of the circumburst density (cm^-3)
707
- :param logepse: log10 of the fraction of shock energy given to electrons
708
- :param logepsb: log10 of the fraction of shock energy given to magnetic field
709
- :param p: power-law index of the electron energy distribution
710
- :param kwargs: Additional keyword arguments
711
- :param zeta_e: fraction of electrons participating in diffusive shock acceleration. Default is 1.
712
- :param output_format: Whether to output flux density or AB mag
713
- :param frequency: frequency in Hz for the flux density calculation
714
- :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
715
- :return: flux density or AB mag. Note this is going to give the monochromatic magnitude at the effective frequency for the band.
716
- For a proper calculation of the magntitude use the sed variant models.
717
- """
718
- Eej = 10 ** loge0
719
- Mej = mej * solar_mass
720
- cosmology = kwargs.get('cosmology', cosmo)
721
- epsilon_e = 10 ** logepse
722
- epsilon_B = 10 ** logepsb
723
- n0 = 10 ** logn0
724
- zeta_e = kwargs.get('zeta_e', 1.0)
725
- qe = 4.803e-10
726
-
727
- dl = cosmology.luminosity_distance(redshift).cgs.value
728
- # calculate blast-wave dynamics
729
- t, R, beta, Gamma, eden, tobs, beta_sh, Gamma_sh = _get_kn_dynamics(n0=n0, Eej=Eej, Mej=Mej)
730
-
731
- # shock-amplified magnetic field, minimum & cooling Lorentz factors
732
- B = (8.0 * np.pi * epsilon_B * eden) ** 0.5
733
- gamma_m = 1.0 + (epsilon_e / zeta_e) * ((p - 2.0) / (p - 1.0)) * (proton_mass / electron_mass) * (Gamma - 1.0)
734
- gamma_c = 6.0 * np.pi * electron_mass * speed_of_light / (sigma_T * Gamma * t * B ** 2)
735
-
736
- # number of emitting electrons, where zeta_DN is an approximate smooth interpolation between the "standard"
737
- # and deep-Newtonian regime discussed by Sironi & Giannios (2013)
738
- zeta_DN = (gamma_m - 1.0) / gamma_m
739
- Ne = zeta_DN * zeta_e * (4.0 * np.pi / 3.0) * R ** 3 * n0
740
-
741
- # LOS approximation
742
- mu = 1.0
743
- blueshift = Gamma * (1.0 - beta * mu)
744
-
745
- frequency = kwargs['frequency']
746
- if isinstance(frequency, float):
747
- frequency = np.ones(len(time)) * frequency
748
- fnu_func = {}
749
- for nu in frequency:
750
- Fnu_opt_thin = _pnu_synchrotron(nu * blueshift * (1.0 + redshift), B, gamma_m, gamma_c, Ne, p) * (1.0 + redshift) / (
751
- 4.0 * np.pi * dl ** 2 * blueshift)
752
-
753
- # correct for synchrotron self-absorption (approximate treatment, correct up to factors of order unity)
754
- Fnu_opt_thick = Gamma * (8 * np.pi ** 2 * (nu * blueshift * (1.0 + redshift)) ** 2 / speed_of_light ** 2) * R ** 2 * (
755
- 1.0 / 3.0) * electron_mass * speed_of_light ** 2 * np.maximum(gamma_m, (
756
- 2 * np.pi * electron_mass * speed_of_light * nu * blueshift * (1.0 + redshift) / (qe * B)) ** 0.5) * (1.0 + redshift) / (
757
- 4.0 * np.pi * dl ** 2 * blueshift)
758
- # new prescription:
759
- Fnu = Fnu_opt_thick * (1e0 - np.exp(-Fnu_opt_thin / Fnu_opt_thick))
760
- # add brute-force optically-thin case to avoid roundoff error in 1e0-np.exp(-x) term (above) when x->0
761
- Fnu[Fnu == 0.0] = Fnu_opt_thin[Fnu == 0.0]
762
-
763
- fnu_func[nu] = interp1d(tobs/day_to_s, Fnu, bounds_error=False, fill_value='extrapolate')
764
-
765
- # interpolate onto actual observed frequency and time values
766
- flux_density = []
767
- for freq, tt in zip(frequency, time):
768
- flux_density.append(fnu_func[freq](tt))
769
-
770
- fmjy = np.array(flux_density) / 1e-26
771
- if kwargs['output_format'] == 'flux_density':
772
- return fmjy
773
- elif kwargs['output_format'] == 'magnitude':
774
- return calc_ABmag_from_flux_density(fmjy).value
775
-
776
- @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2011Natur.478...82N/abstract')
777
- def kilonova_afterglow_nakarpiran(time, redshift, loge0, mej, logn0, logepse, logepsb, p, **kwargs):
778
- """
779
- A kilonova afterglow model based on Nakar & Piran 2011
780
-
781
- :param time: time in days in the observer frame
782
- :param redshift: source redshift
783
- :param loge0: initial kinetic energy in erg of ejecta
784
- :param mej: mass of ejecta in solar masses
785
- :param logn0: log10 of the number density of the circumburst medium in cm^-3
786
- :param logepse: log10 of the fraction of energy given to electrons
787
- :param logepsb: log10 of the fraction of energy given to the magnetic field
788
- :param p: electron power law index
789
- :param kwargs: Additional keyword arguments
790
- :param output_format: Whether to output flux density or AB mag
791
- :param frequency: frequency in Hz for the flux density calculation
792
- :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
793
- :return: flux density or AB mag. Note this is going to give the monochromatic magnitude at the effective frequency for the band.
794
- For a proper calculation of the magntitude use the sed variant models.
795
- :return:
796
- """
797
- Eej = 10 ** loge0
798
- Mej = mej * solar_mass
799
- Gamma0 = 1.0 + Eej / (Mej * speed_of_light ** 2)
800
- vej = speed_of_light * (1.0 - Gamma0 ** (-2)) ** 0.5
801
- cosmology = kwargs.get('cosmology', cosmo)
802
- epsilon_e = 10 ** logepse
803
- epsilon_B = 10 ** logepsb
804
- n0 = 10 ** logn0
805
- dl = cosmology.luminosity_distance(redshift).cgs.value
806
-
807
- # in days
808
- t_dec = 30 * (Eej / 1e49) ** (1.0 / 3.0) * (n0 / 1e0) ** (-1.0 / 3.0) * (vej / speed_of_light) ** (-5.0 / 3.0)
809
-
810
- fnu_dec_dict = {}
811
- fnu_func = {}
812
- temp_time = np.linspace(0.1, 100, 200) * t_dec
813
- frequency = kwargs['frequency']
814
- if isinstance(frequency, float):
815
- frequency = np.ones(len(time)) * frequency
816
- for freq in frequency:
817
- # Eq. 11 in Nakar & Piran 2011 (in Mjy)
818
- fnu_dec_dict[freq] = 0.3 * (Eej / 1e49) * n0 ** (0.25 * (p + 1)) * (epsilon_B / 1e-1) ** (0.25 * (p + 1)) * (
819
- epsilon_e / 1e-1) ** (p - 1) * (vej / speed_of_light) ** (0.5 * (5 * p - 7)) * (freq / 1.4e9) ** (
820
- -0.5 * (p - 1)) * (dl / 1e27) ** (-2)
821
- fnu = fnu_dec_dict[freq] * (temp_time / t_dec) ** 3
822
- fnu[temp_time > t_dec] = fnu_dec_dict[freq] * (temp_time[temp_time > t_dec] / t_dec) ** (-0.3 * (5 * p - 7))
823
- fnu_func[freq] = interp1d(temp_time, fnu, bounds_error=False, fill_value='extrapolate')
824
-
825
- # interpolate onto actual observed frequency and time values
826
- flux_density = []
827
- for freq, tt in zip(frequency, time):
828
- flux_density.append(fnu_func[freq](tt))
829
- fmjy = flux_density * uu.mJy
830
- if kwargs['output_format'] == 'flux_density':
831
- return fmjy.value
832
- elif kwargs['output_format'] == 'magnitude':
833
- return calc_ABmag_from_flux_density(fmjy.value).value
834
-
835
695
  @citation_wrapper('redback, https://ui.adsabs.harvard.edu/abs/2018MNRAS.481.2581L/abstract')
836
696
  def tophat_redback(time, redshift, thv, loge0, thc, logn0, p, logepse, logepsb, g0, xiN, **kwargs):
837
697
  """
@@ -2253,4 +2113,108 @@ def afterglow_models_sed(time, **kwargs):
2253
2113
  spectra=spectra, lambda_array=lambda_observer_frame,
2254
2114
  **kwargs)
2255
2115
 
2116
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2024ApJS..273...17W/abstract')
2117
+ def jetsimpy_tophat(time, redshift, thv, loge0, thc, nism, A, p, logepse, logepsb, g0, **kwargs):
2118
+ """
2119
+ A tophat jet model from jetsimpy
2120
+ :param time: time in days in observer frame
2121
+ :param redshift: source redshift
2122
+ :param thv: viewing angle in radians
2123
+ :param loge0: log10 on axis isotropic equivalent energy
2124
+ :param thc: half width of jet core/jet opening angle in radians
2125
+ :param nism: number density of ISM in cm^-3 (ntot = A * (r / 1e17)^-2 + nism (cm^-3))
2126
+ :param A: wind density scale (ntot = A * (r / 1e17)^-2 + nism (cm^-3))
2127
+ :param p: electron distribution power law index.
2128
+ :param logepse: log10 fraction of thermal energy in electrons
2129
+ :param logepsb: log10 fraction of thermal energy in magnetic field
2130
+ :param g0: initial lorentz factor
2131
+ :param kwargs: Additional keyword arguments
2132
+ :param output_format: Whether to output flux density or AB mag
2133
+ :param frequency: frequency in Hz for the flux density calculation
2134
+ :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
2135
+ :return: flux density or AB mag. Note this is going to give the monochromatic magnitude at the effective frequency for the band.
2136
+ """
2137
+ import jetsimpy #Can not use models unless jetsimpy is downloaded
2138
+ time = time * day_to_s
2139
+ cosmology = kwargs.get('cosmology', cosmo)
2140
+ dl = cosmology.luminosity_distance(redshift).cgs.value
2141
+ P = dict(Eiso = 10 ** loge0, lf = g0, theta_c = thc, n0 = nism, A = A, eps_e = 10 ** logepse, eps_b = 10 ** logepsb, p = p, theta_v = thv, d = dl*3.24078e-25, z = redshift) #make a param dict
2142
+ if kwargs['output_format'] == 'flux_density':
2143
+ frequency = kwargs['frequency']
2144
+ flux_density = jetsimpy.FluxDensity_tophat(time, frequency, P)
2145
+ return flux_density
2146
+ else:
2147
+ frequency = bands_to_frequency(kwargs['bands'])
2148
+ flux_density = jetsimpy.FluxDensity_tophat(time, frequency, P)
2149
+ return calc_ABmag_from_flux_density(flux_density).value
2150
+
2151
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2024ApJS..273...17W/abstract')
2152
+ def jetsimpy_gaussian(time, redshift, thv, loge0, thc, nism, A, p, logepse, logepsb, g0, **kwargs):
2153
+ """
2154
+ A gaussian jet model from jetsimpy
2155
+ :param time: time in days in observer frame
2156
+ :param redshift: source redshift
2157
+ :param thv: viewing angle in radians
2158
+ :param loge0: log10 on axis isotropic equivalent energy
2159
+ :param thc: half width of jet core/jet opening angle in radians
2160
+ :param nism: number density of ISM in cm^-3 (ntot = A * (r / 1e17)^-2 + nism (cm^-3))
2161
+ :param A: wind density scale (ntot = A * (r / 1e17)^-2 + nism (cm^-3))
2162
+ :param p: electron distribution power law index.
2163
+ :param logepse: log10 fraction of thermal energy in electrons
2164
+ :param logepsb: log10 fraction of thermal energy in magnetic field
2165
+ :param g0: initial lorentz factor
2166
+ :param kwargs: Additional keyword arguments
2167
+ :param output_format: Whether to output flux density or AB mag
2168
+ :param frequency: frequency in Hz for the flux density calculation
2169
+ :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
2170
+ :return: flux density or AB mag. Note this is going to give the monochromatic magnitude at the effective frequency for the band.
2171
+ """
2172
+ import jetsimpy #Can not use models unless jetsimpy is downloaded
2173
+ time = time * day_to_s
2174
+ cosmology = kwargs.get('cosmology', cosmo)
2175
+ dl = cosmology.luminosity_distance(redshift).cgs.value
2176
+ P = dict(Eiso = 10 ** loge0, lf = g0, theta_c = thc, n0 = nism, A = A, eps_e = 10 ** logepse, eps_b = 10 ** logepsb, p = p, theta_v = thv, d = dl*3.24078e-25, z = redshift) #make a param dict
2177
+ if kwargs['output_format'] == 'flux_density':
2178
+ frequency = kwargs['frequency']
2179
+ flux_density = jetsimpy.FluxDensity_gaussian(time, frequency, P)
2180
+ return flux_density
2181
+ else:
2182
+ frequency = bands_to_frequency(kwargs['bands'])
2183
+ flux_density = jetsimpy.FluxDensity_gaussian(time, frequency, P)
2184
+ return calc_ABmag_from_flux_density(flux_density).value
2256
2185
 
2186
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2024ApJS..273...17W/abstract')
2187
+ def jetsimpy_powerlaw(time, redshift, thv, loge0, thc, nism, A, p, logepse, logepsb, g0, s, **kwargs):
2188
+ """
2189
+ A power-law jet model from jetsimpy
2190
+ :param time: time in days in observer frame
2191
+ :param redshift: source redshift
2192
+ :param thv: viewing angle in radians
2193
+ :param loge0: log10 on axis isotropic equivalent energy
2194
+ :param thc: half width of jet core/jet opening angle in radians
2195
+ :param nism: number density of ISM in cm^-3 (ntot = A * (r / 1e17)^-2 + nism (cm^-3))
2196
+ :param A: wind density scale (ntot = A * (r / 1e17)^-2 + nism (cm^-3))
2197
+ :param p: electron distribution power law index.
2198
+ :param logepse: log10 fraction of thermal energy in electrons
2199
+ :param logepsb: log10 fraction of thermal energy in magnetic field
2200
+ :param g0: initial lorentz factor
2201
+ :param s: power-law jet slope
2202
+ :param kwargs: Additional keyword arguments
2203
+ :param output_format: Whether to output flux density or AB mag
2204
+ :param frequency: frequency in Hz for the flux density calculation
2205
+ :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
2206
+ :return: flux density or AB mag. Note this is going to give the monochromatic magnitude at the effective frequency for the band.
2207
+ """
2208
+ import jetsimpy #Can not use models unless jetsimpy is downloaded
2209
+ time = time * day_to_s
2210
+ cosmology = kwargs.get('cosmology', cosmo)
2211
+ dl = cosmology.luminosity_distance(redshift).cgs.value
2212
+ P = dict(Eiso = 10 ** loge0, lf = g0, theta_c = thc, n0 = nism, A = A, eps_e = 10 ** logepse, eps_b = 10 ** logepsb, p = p, theta_v = thv, d = dl*3.24078e-25, z = redshift, s = s) #make a param dict
2213
+ if kwargs['output_format'] == 'flux_density':
2214
+ frequency = kwargs['frequency']
2215
+ flux_density = jetsimpy.FluxDensity_powerlaw(time, frequency, P)
2216
+ return flux_density
2217
+ else:
2218
+ frequency = bands_to_frequency(kwargs['bands'])
2219
+ flux_density = jetsimpy.FluxDensity_powerlaw(time, frequency, P)
2220
+ return calc_ABmag_from_flux_density(flux_density).value