redback 1.0.31__py3-none-any.whl → 1.1__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 (48) hide show
  1. redback/__init__.py +3 -2
  2. redback/analysis.py +321 -4
  3. redback/filters.py +57 -23
  4. redback/get_data/directory.py +18 -0
  5. redback/likelihoods.py +260 -0
  6. redback/model_library.py +12 -2
  7. redback/plotting.py +335 -4
  8. redback/priors/blackbody_spectrum_with_absorption_and_emission_lines.prior +9 -0
  9. redback/priors/csm_shock_and_arnett_two_rphots.prior +11 -0
  10. redback/priors/exp_rise_powerlaw_decline.prior +6 -0
  11. redback/priors/powerlaw_spectrum_with_absorption_and_emission_lines.prior +8 -0
  12. redback/priors/shockcooling_morag.prior +6 -0
  13. redback/priors/shockcooling_morag_and_arnett.prior +10 -0
  14. redback/priors/shockcooling_morag_and_arnett_bolometric.prior +9 -0
  15. redback/priors/shockcooling_morag_bolometric.prior +5 -0
  16. redback/priors/shockcooling_sapirandwaxman.prior +6 -0
  17. redback/priors/shockcooling_sapirandwaxman_bolometric.prior +5 -0
  18. redback/priors/shockcooling_sapirwaxman_and_arnett.prior +10 -0
  19. redback/priors/shockcooling_sapirwaxman_and_arnett_bolometric.prior +9 -0
  20. redback/priors/shocked_cocoon_and_arnett.prior +13 -0
  21. redback/priors/synchrotron_ism.prior +6 -0
  22. redback/priors/synchrotron_massloss.prior +6 -0
  23. redback/priors/synchrotron_pldensity.prior +7 -0
  24. redback/priors/thermal_synchrotron_v2_fluxdensity.prior +8 -0
  25. redback/priors/thermal_synchrotron_v2_lnu.prior +7 -0
  26. redback/priors.py +10 -3
  27. redback/result.py +9 -1
  28. redback/sampler.py +46 -4
  29. redback/sed.py +48 -1
  30. redback/simulate_transients.py +5 -1
  31. redback/tables/filters.csv +265 -254
  32. redback/transient/__init__.py +2 -3
  33. redback/transient/transient.py +648 -10
  34. redback/transient_models/__init__.py +3 -2
  35. redback/transient_models/extinction_models.py +3 -2
  36. redback/transient_models/gaussianprocess_models.py +45 -0
  37. redback/transient_models/general_synchrotron_models.py +296 -6
  38. redback/transient_models/phenomenological_models.py +154 -7
  39. redback/transient_models/shock_powered_models.py +503 -40
  40. redback/transient_models/spectral_models.py +82 -0
  41. redback/transient_models/supernova_models.py +333 -7
  42. redback/transient_models/tde_models.py +57 -41
  43. redback/utils.py +302 -51
  44. {redback-1.0.31.dist-info → redback-1.1.dist-info}/METADATA +8 -6
  45. {redback-1.0.31.dist-info → redback-1.1.dist-info}/RECORD +48 -29
  46. {redback-1.0.31.dist-info → redback-1.1.dist-info}/WHEEL +1 -1
  47. {redback-1.0.31.dist-info → redback-1.1.dist-info/licenses}/LICENCE.md +0 -0
  48. {redback-1.0.31.dist-info → redback-1.1.dist-info}/top_level.txt +0 -0
@@ -2,11 +2,471 @@ import numpy as np
2
2
  from collections import namedtuple
3
3
  from scipy import special
4
4
  from scipy.interpolate import interp1d
5
- from redback.constants import *
5
+ import redback.constants as cc
6
+ from astropy import units as uu
6
7
  import redback.sed as sed
7
8
  from astropy.cosmology import Planck18 as cosmo # noqa
8
9
  from redback.utils import calc_kcorrected_properties, citation_wrapper, lambda_to_nu
9
10
 
11
+
12
+ def _shockcooling_morag(time, v_shock, m_env, f_rho_m, radius, kappa):
13
+ """
14
+ Compute shock‑cooling parameters from the model of Morag, Sapir, & Waxman.
15
+
16
+ This function calculates the bolometric luminosity, effective temperature, and
17
+ effective photospheric radius based on a shock‑cooling model. The model uses
18
+ several scaling relations. For example, the breakout time is given by:
19
+
20
+ .. math::
21
+
22
+ t_{\mathrm{br}} = t_{\mathrm{br,0}}\, R^{1.26}\, v_s^{-1.13}\, (f_\rho M)^{-0.13}\,,
23
+
24
+ where the coefficient :math:`t_{\mathrm{br,0}} = 0.036` days, and similar
25
+ relations exist for the breakout luminosity :math:`L_{\mathrm{br}}` and the breakout
26
+ color temperature :math:`T_{\mathrm{col,br}}`. A transparency time is also defined:
27
+
28
+ .. math::
29
+
30
+ t_{\mathrm{tr}} = t_{\mathrm{tr,0}}\, \sqrt{\frac{\kappa\, M_{\mathrm{env}}}{v_s}}\,,
31
+
32
+ with :math:`t_{\mathrm{tr,0}} = 19.5` days.
33
+
34
+ A dimensionless time is defined as
35
+
36
+ .. math::
37
+
38
+ \tilde{t} = \frac{t - t_{\mathrm{exp}}}{t_{\mathrm{br}}}\,.
39
+
40
+ The bolometric luminosity is then computed using
41
+
42
+ .. math::
43
+
44
+ L(t) = L_{\mathrm{br}}\left\{\tilde{t}^{-4/3} + A\,\exp\left[-\left(\frac{a\,t}{t_{\mathrm{tr}}}\right)^\alpha\right]\tilde{t}^{-0.17}\right\}\,,
45
+
46
+ and the color temperature by
47
+
48
+ .. math::
49
+
50
+ T_{\mathrm{col}}(t) = T_{\mathrm{col,br}}\, \min\left(0.97\,\tilde{t}^{-1/3},\; \tilde{t}^{-0.45}\right)\,.
51
+
52
+ The effective temperature in Kelvin is obtained by converting the color temperature
53
+ (in eV) using the Boltzmann constant and the photospheric radius is estimated via the
54
+ Stefan–Boltzmann law
55
+
56
+ .. math::
57
+
58
+ R_{\mathrm{bb}} = \frac{1}{T^2}\,\sqrt{\frac{L}{4\pi\,\sigma_{\mathrm{SB}}}}\,.
59
+
60
+ :param time: Time at which to evaluate the model (in days).
61
+ :type time: float or array_like
62
+ :param v_shock: Shock speed in units of 10^(8.5) cm/s.
63
+ :type v_shock: float
64
+ :param m_env: Envelope mass in solar masses.
65
+ :type m_env: float
66
+ :param f_rho_m: Product of the dimensionless factor f_ρ and the ejecta mass in solar masses.
67
+ :type f_rho_m: float
68
+ :param radius: Progenitor radius in units of 10^(13) cm.
69
+ :type radius: float
70
+ :param t_exp: Explosion epoch in days. Default is 0.
71
+ :type t_exp: float
72
+ :param kappa: Opacity relative to the electron scattering opacity. Default is 1.
73
+ :type kappa: float
74
+
75
+ :return: A namedtuple ``ShockCoolingResult`` with the following fields:
76
+ - luminosity: Bolometric luminosity in erg/s.
77
+ - t_photosphere: Effective temperature in Kelvin.
78
+ - r_photosphere: Effective photospheric radius in cm.
79
+ - min_time: Minimum time for which the model is valid in days.
80
+ - max_time: Maximum time for which the model is valid in days.
81
+ :rtype: ShockCoolingResult
82
+ """
83
+ # Normalization constants
84
+ v_norm = 10 ** 8.5 # (cm/s) for shock speed normalization, roughly 3.16e8 cm/s.
85
+ kappa_norm = 0.34 # (cm²/g) fiducial opacity.
86
+ R_norm = 1e13 # (cm) normalization for progenitor radius.
87
+
88
+ # Convert absolute inputs to dimensionless units required by the model
89
+ v_shock = v_shock / v_norm # Dimensionless shock speed.
90
+ kappa = kappa / kappa_norm # Dimensionless opacity.
91
+ radius = radius / R_norm # Dimensionless progenitor radius.
92
+
93
+ # --- Model coefficients ---
94
+ t_br_0 = 0.036 # days (0.86 h)
95
+ L_br_0 = 3.69e42 # erg/s
96
+ T_col_br_0 = 8.19 # eV
97
+ t_tr_0 = 19.5 # days
98
+ A = 0.9
99
+ a_value = 2.0
100
+ alpha = 0.5
101
+ t07ev0 = 6.86
102
+
103
+ # --- Physical constants ---
104
+ k_B_ev = 8.617333262e-5 # Boltzmann constant in eV/K
105
+ sigma_sb = cc.sigma_sb # Stefan-Boltzmann constant in erg/(s cm^2 K^4)
106
+ c3 = 1.0 / np.sqrt(4.0 * np.pi * sigma_sb)
107
+
108
+ # --- Compute intermediate scales ---
109
+ t_br = t_br_0 * np.power(radius, 1.26) * np.power(v_shock, -1.13) * np.power(f_rho_m, -0.13)
110
+ L_br = L_br_0 * np.power(radius, 0.78) * np.power(v_shock, 2.11) * np.power(f_rho_m, 0.11) * np.power(kappa, -0.89)
111
+ T_col_br = T_col_br_0 * np.power(radius, -0.32) * np.power(v_shock, 0.58) * np.power(f_rho_m, 0.03) * np.power(kappa, -0.22)
112
+ t_tr = t_tr_0 * np.sqrt(kappa * m_env / v_shock)
113
+
114
+ # --- Adjust time for the explosion epoch and compute dimensionless time ---
115
+ ttilde = time / t_br
116
+
117
+ # --- Compute bolometric luminosity ---
118
+ luminosity = L_br * (np.power(ttilde, -4.0 / 3.0) +
119
+ A * np.exp(-np.power(a_value * time / t_tr, alpha)) * np.power(ttilde, -0.17))
120
+
121
+ # --- Compute color temperature ---
122
+ T_col = T_col_br * np.minimum(0.97 * np.power(ttilde, -1.0 / 3.0),
123
+ np.power(ttilde, -0.45))
124
+
125
+ # Convert color temperature from eV to Kelvin.
126
+ t_photosphere = T_col / k_B_ev
127
+
128
+ # --- Compute effective photospheric radius using the Stefan-Boltzmann law ---
129
+ r_photosphere = c3 * np.sqrt(luminosity) / np.power(t_photosphere, 2)
130
+
131
+ min_time = 0.012 * radius
132
+
133
+ t07ev = t07ev0 * radius ** 0.56 * v_shock ** 0.16 * kappa ** -0.61 * f_rho_m ** -0.06
134
+ max_time = np.minimum(t07ev, t_tr / a_value)
135
+ ShockCoolingResult = namedtuple('ShockCoolingResult', ['t_photosphere', 'r_photosphere',
136
+ 'luminosity', 'min_time', 'max_time'])
137
+ return ShockCoolingResult(t_photosphere=t_photosphere, r_photosphere=r_photosphere, luminosity=luminosity,
138
+ min_time=min_time, max_time=max_time)
139
+
140
+ @citation_wrapper('https://academic.oup.com/mnras/article/522/2/2764/7086123#443111844')
141
+ def shockcooling_morag_bolometric(time, v_shock, m_env, f_rho_m, radius, kappa, **kwargs):
142
+ """
143
+ Bolometric lightcurve following the Morag, Sapir, & Waxman model.
144
+
145
+ :param time: time in source frame in days
146
+ :param v_shock: shock speed in km/s
147
+ :param m_env: envelope mass in solar masses
148
+ :param f_rho_m: f_rho * M (with M in solar masses). f_rho is typically, of order unity
149
+ :param radius: star/envelope radius in units of 10^13 cm
150
+ :param kappa: opacity in cm^2/g
151
+ :param kwargs: Additional parameters required by model
152
+ :return: bolometric luminosity in erg/s
153
+ """
154
+ v_shock = v_shock * 1e5
155
+ radius = radius * 1e13
156
+ output = _shockcooling_morag(time, v_shock, m_env, f_rho_m, radius, kappa)
157
+ lum = output.luminosity
158
+ return lum
159
+
160
+ @citation_wrapper('https://academic.oup.com/mnras/article/522/2/2764/7086123#443111844')
161
+ def shockcooling_morag(time, redshift, v_shock, m_env, f_rho_m, radius, kappa, **kwargs):
162
+ """
163
+ Lightcurve following the Morag, Sapir, & Waxman model
164
+
165
+ :param time: time in observer frame in days
166
+ :param redshift: redshift
167
+ :param v_shock: shock speed in km/s
168
+ :param m_env: envelope mass in solar masses
169
+ :param f_rho_m: f_rho * M (with M in solar masses). f_rho is typically, of order unity
170
+ :param radius: star/envelope radius in units of 10^13 cm
171
+ :param kappa: opacity in cm^2/g
172
+ :param kwargs: Additional parameters required by model
173
+ :param time_temp: Optional argument to set your desired time array (in source frame days) to evaluate the model on.
174
+ :param frequency: Required if output_format is 'flux_density'.
175
+ frequency to calculate - Must be same length as time array or a single number).
176
+ :param bands: Required if output_format is 'magnitude' or 'flux'.
177
+ :param output_format: 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
178
+ :param lambda_array: Optional argument to set your desired wavelength array (in Angstroms) to evaluate the SED on.
179
+ :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
180
+ :return: set by output format - 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
181
+ """
182
+ v_shock = v_shock * 1e5
183
+ radius = radius * 1e13
184
+ cosmology = kwargs.get('cosmology', cosmo)
185
+ dl = cosmology.luminosity_distance(redshift).cgs.value
186
+ time_temp = kwargs.get('time_temp', np.linspace(0.01, 60, 100))
187
+ time_obs = time
188
+ output = _shockcooling_morag(time_temp, v_shock, m_env, f_rho_m, radius, kappa)
189
+ if kwargs['output_format'] == 'namedtuple':
190
+ return output
191
+ elif kwargs['output_format'] == 'flux_density':
192
+ time = time_obs
193
+ frequency = kwargs['frequency']
194
+ # interpolate properties onto observation times
195
+ temp_func = interp1d(time_temp, y=output.t_photosphere)
196
+ rad_func = interp1d(time_temp, y=output.r_photosphere)
197
+ # convert to source frame time and frequency
198
+ frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
199
+
200
+ temp = temp_func(time)
201
+ photosphere = rad_func(time)
202
+
203
+ flux_density = sed.blackbody_to_flux_density(temperature=temp, r_photosphere=photosphere,
204
+ dl=dl, frequency=frequency)
205
+
206
+ return flux_density.to(uu.mJy).value
207
+ else:
208
+ lambda_observer_frame = kwargs.get('lambda_array', np.geomspace(100, 60000, 200))
209
+ time_observer_frame = time_temp * (1. + redshift)
210
+ frequency, time = calc_kcorrected_properties(frequency=lambda_to_nu(lambda_observer_frame),
211
+ redshift=redshift, time=time_observer_frame)
212
+ fmjy = sed.blackbody_to_flux_density(temperature=output.t_photosphere,
213
+ r_photosphere=output.r_photosphere, frequency=frequency[:, None], dl=dl)
214
+ fmjy = fmjy.T
215
+ spectra = fmjy.to(uu.mJy).to(uu.erg / uu.cm ** 2 / uu.s / uu.Angstrom,
216
+ equivalencies=uu.spectral_density(wav=lambda_observer_frame * uu.Angstrom))
217
+ if kwargs['output_format'] == 'spectra':
218
+ return namedtuple('output', ['time', 'lambdas', 'spectra'])(time=time_observer_frame,
219
+ lambdas=lambda_observer_frame,
220
+ spectra=spectra)
221
+ else:
222
+ return sed.get_correct_output_format_from_spectra(time=time_obs, time_eval=time_observer_frame,
223
+ spectra=spectra, lambda_array=lambda_observer_frame,
224
+ **kwargs)
225
+ def _shockcooling_sapirandwaxman(time, v_shock, m_env, f_rho_m, radius, kappa, nn=1.5, RW=False):
226
+ """
227
+ Calculate shock-cooling properties following the Sapir & Waxman (and Rabinak & Waxman) model
228
+
229
+ The model equations (with time t in days) are given as follows:
230
+
231
+ Pre-exponential luminosity:
232
+
233
+ .. math::
234
+ L_{RW} = L_0 \left[ \frac{t^2 \, v_{\mathrm{dim}}}{f_{\rho} \, \kappa_{\mathrm{dim}}}\right]^{-\epsilon_2}
235
+ v_{\mathrm{dim}}^2 \frac{R_{\mathrm{dim}}}{\kappa_{\mathrm{dim}}},
236
+
237
+ where
238
+
239
+ .. math::
240
+ v_{\mathrm{dim}} = \frac{v_s}{10^{8.5}\,\mathrm{cm/s}}, \quad
241
+ \kappa_{\mathrm{dim}} = \frac{\kappa}{0.34\,\mathrm{cm^2/g}}, \quad
242
+ R_{\mathrm{dim}} = \frac{R}{10^{13}\,\mathrm{cm}}.
243
+
244
+ The transparency timescale is defined as:
245
+
246
+ .. math::
247
+ t_{\mathrm{tr}} = 19.5 \, \left[\frac{\kappa_{\mathrm{dim}} \, M_{\mathrm{env}}}{v_{\mathrm{dim}}}\right]^{1/2}.
248
+
249
+ The full luminosity is then:
250
+
251
+ .. math::
252
+ L = L_{RW} \, A \, \exp\left[-\left(\frac{a\, t}{t_{\mathrm{tr}}}\right)^{\alpha}\right].
253
+
254
+ The photospheric temperature in eV is given by:
255
+
256
+ .. math::
257
+ T_{\mathrm{ph}} = T_0 \left[\frac{t^2 \, v_{\mathrm{dim}}^2}{f_{\rho} \, \kappa_{\mathrm{dim}}}\right]^{\epsilon_1}
258
+ \kappa_{\mathrm{dim}}^{-0.25} \, t^{-0.5} \, R_{\mathrm{dim}}^{0.25},
259
+
260
+ and a color correction:
261
+
262
+ .. math::
263
+ T_{\mathrm{col}} = T_{\mathrm{ph}} \; \times \; \text{(color correction factor)}.
264
+
265
+ Finally, converting from eV to Kelvin:
266
+
267
+ .. math::
268
+ T_{\mathrm{K}} = \frac{T_{\mathrm{col}}}{k_B}, \quad \text{with } k_B = 8.61733 \times 10^{-5}\,\mathrm{eV/K},
269
+
270
+ and the photospheric radius is derived using the Stefan–Boltzmann relation:
271
+
272
+ .. math::
273
+ R_{\mathrm{bb}} = \frac{\sqrt{L/(4\pi\sigma)}}{T_{\mathrm{K}}^2} \quad
274
+ \text{with } \sigma = 5.670374419 \times 10^{-5}\,\mathrm{erg\,s^{-1}\,cm^{-2}\,K^{-4}}.
275
+
276
+ :param time: Time (in days) at which to evaluate the model.
277
+ :type time: float or array-like
278
+ :param v_shock: Shock speed in cm/s.
279
+ :type v_shock: float
280
+ :param m_env: Envelope mass in solar masses.
281
+ :type m_env: float
282
+ :param f_rho_m: The product :math:`f_{\\rho} \, M` (with M in solar masses). Typically of order unity.
283
+ :type f_rho_m: float
284
+ :param radius: Progenitor radius in cm.
285
+ :type radius: float
286
+ :param kappa: Ejecta opacity in cm²/g (e.g., approximately 0.34 for pure electron scattering).
287
+ :type kappa: float
288
+ :param nn: The polytropic index of the progenitor. Must be either 1.5 (default) or 3.0.
289
+ :type nn: float, optional
290
+ :param RW: If True, use the simplified Rabinak & Waxman formulation (sets a = 0 and adjusts the temperature correction factor).
291
+ :type RW: bool, optional
292
+ :return: A named tuple with the following fields:
293
+ - **t_photosphere**: Color temperature in Kelvin,
294
+ - **r_photosphere**: Derived photospheric radius in cm,
295
+ - **luminosity**: Bolometric luminosity in erg/s.
296
+ - **min_time**: Minimum time for which the model is valid in days.
297
+ - **max_time**: Maximum time for which the model is valid in days.
298
+ :rtype: namedtuple
299
+ """
300
+ # Normalization constants
301
+ v_norm = 10 ** 8.5 # (cm/s) for shock speed normalization, roughly 3.16e8 cm/s.
302
+ kappa_norm = 0.34 # (cm²/g) fiducial opacity.
303
+ R_norm = 1e13 # (cm) normalization for progenitor radius.
304
+
305
+ # Set parameters based on the chosen polytropic index n.
306
+ if nn == 1.5:
307
+ AA = 0.94
308
+ a_val = 1.67
309
+ alpha = 0.8
310
+ epsilon_1 = 0.027
311
+ epsilon_2 = 0.086
312
+ L_0 = 2.0e42 # erg/s
313
+ T_0 = 1.61 # eV
314
+ Tph_to_Tcol = 1.1
315
+ elif nn == 3.0:
316
+ AA = 0.79
317
+ a_val = 4.57
318
+ alpha = 0.73
319
+ epsilon_1 = 0.016
320
+ epsilon_2 = 0.175
321
+ L_0 = 2.1e42 # erg/s
322
+ T_0 = 1.69 # eV
323
+ Tph_to_Tcol = 1.0
324
+ else:
325
+ raise ValueError("n can only be 1.5 or 3.0.")
326
+
327
+ if RW:
328
+ a_val = 0.0
329
+ Tph_to_Tcol = 1.2
330
+
331
+
332
+ # Convert absolute inputs to dimensionless units required by the model
333
+ v_dim = v_shock / v_norm # Dimensionless shock speed.
334
+ kappa_dim = kappa / kappa_norm # Dimensionless opacity.
335
+ R_dim = radius / R_norm # Dimensionless progenitor radius.
336
+
337
+ # Pre-exponential luminosity
338
+ L_RW = L_0 * np.power(time ** 2 * v_dim / (f_rho_m * kappa_dim), -epsilon_2) \
339
+ * np.power(v_dim, 2) * R_dim / kappa_dim
340
+
341
+ # Transparency timescale in days
342
+ t_tr = 19.5 * np.power((kappa_dim * m_env / v_dim), 0.5)
343
+
344
+ # Full luminosity with exponential cutoff
345
+ lum = L_RW * AA * np.exp(-np.power(a_val * time / t_tr, alpha))
346
+
347
+ # Photospheric temperature in eV
348
+ T_ph = T_0 * np.power(time ** 2 * np.power(v_dim, 2) / (f_rho_m * kappa_dim), epsilon_1) \
349
+ * np.power(kappa_dim, -0.25) * np.power(time, -0.5) * np.power(R_dim, 0.25)
350
+ # Apply the color correction factor
351
+ T_col = T_ph * Tph_to_Tcol
352
+
353
+ # Convert temperature from eV to Kelvin
354
+ k_B = 8.61733e-5 # Boltzmann constant in eV/K
355
+ temperature_K = T_col / k_B
356
+
357
+ min_time = 0.2 * R_dim / v_dim * np.maximum(0.5, R_dim ** 0.4 * (f_rho_m * kappa) ** -0.2 * v_dim ** -0.7)
358
+ max_time = 7.4 * (R_dim / kappa_dim) ** 0.55
359
+ #
360
+ # # turn luminosity at times < min_time to 0 and at times > max_time to a small number
361
+ # lum = np.where(time < min_time, 1e4, lum)
362
+ # lum = np.where(time > max_time, 1e4, lum)
363
+
364
+ # Calculate the photospheric radius using the Stefan–Boltzmann law
365
+ sigma = cc.sigma_sb # Stefan–Boltzmann constant [erg s^-1 cm^-2 K^-4]
366
+ radius_cm = np.sqrt(lum / (4 * np.pi * sigma)) / (temperature_K ** 2)
367
+
368
+ ShockCoolingResult = namedtuple('ShockCoolingResult', ['t_photosphere', 'r_photosphere',
369
+ 'luminosity', 'min_time', 'max_time'])
370
+ return ShockCoolingResult(t_photosphere=temperature_K, r_photosphere=radius_cm, luminosity=lum,
371
+ min_time=min_time, max_time=max_time)
372
+
373
+
374
+ @citation_wrapper('https://iopscience.iop.org/article/10.3847/1538-4357/aa64df')
375
+ def shockcooling_sapirandwaxman_bolometric(time, v_shock, m_env, f_rho_m, radius, kappa, **kwargs):
376
+ """
377
+ Bolometric lightcurve following the Sapir & Waxman (and Rabinak & Waxman) model.
378
+
379
+ :param time: time in source frame in days
380
+ :param v_shock: shock speed in km/s
381
+ :param m_env: envelope mass in solar masses
382
+ :param f_rho_m: f_rho * M (with M in solar masses). f_rho is typically, of order unity
383
+ :param radius: star/envelope radius in units of 10^13 cm
384
+ :param kappa: opacity in cm^2/g
385
+ :param kwargs: Additional parameters required by model
386
+ :param n: index of progenitor density profile, 1.5 (default) or 3.0
387
+ :param RW: If True, use the simplified Rabinak & Waxman formulation (off by default)
388
+ :return: bolometric luminosity in erg/s
389
+ """
390
+ n = kwargs.get('n', 1.5)
391
+ v_shock = v_shock * 1e5
392
+ RW = kwargs.get('RW', False)
393
+ radius = radius * 1e13
394
+ output = _shockcooling_sapirandwaxman(time, v_shock, m_env, f_rho_m, radius, kappa, nn=n, RW=RW)
395
+ lum = output.luminosity
396
+ return lum
397
+
398
+ @citation_wrapper('https://iopscience.iop.org/article/10.3847/1538-4357/aa64df')
399
+ def shockcooling_sapirandwaxman(time, redshift, v_shock, m_env, f_rho_m, radius, kappa, **kwargs):
400
+ """
401
+ Lightcurve following the Sapir & Waxman (and Rabinak & Waxman) model
402
+
403
+ :param time: time in observer frame in days
404
+ :param redshift: redshift
405
+ :param v_shock: shock speed in km/s
406
+ :param m_env: envelope mass in solar masses
407
+ :param f_rho_m: f_rho * M (with M in solar masses). f_rho is typically, of order unity
408
+ :param radius: star/envelope radius in units of 10^13 cm
409
+ :param kappa: opacity in cm^2/g
410
+ :param kwargs: Additional parameters required by model
411
+ :param time_temp: Optional argument to set your desired time array (in source frame days) to evaluate the model on.
412
+ :param n: index of progenitor density profile, 1.5 (default) or 3.0
413
+ :param RW: If True, use the simplified Rabinak & Waxman formulation (off by default)
414
+ :param frequency: Required if output_format is 'flux_density'.
415
+ frequency to calculate - Must be same length as time array or a single number).
416
+ :param bands: Required if output_format is 'magnitude' or 'flux'.
417
+ :param output_format: 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
418
+ :param lambda_array: Optional argument to set your desired wavelength array (in Angstroms) to evaluate the SED on.
419
+ :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
420
+ :return: set by output format - 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
421
+ """
422
+
423
+ n = kwargs.get('n', 1.5)
424
+ v_shock = v_shock * 1e5
425
+ RW = kwargs.get('RW', False)
426
+ radius = radius * 1e13
427
+ cosmology = kwargs.get('cosmology', cosmo)
428
+ dl = cosmology.luminosity_distance(redshift).cgs.value
429
+ time_temp = kwargs.get('time_temp', np.linspace(0.01, 60, 100))
430
+ time_obs = time
431
+ output = _shockcooling_sapirandwaxman(time_temp, v_shock, m_env, f_rho_m, radius, kappa, nn=n, RW=RW)
432
+ if kwargs['output_format'] == 'namedtuple':
433
+ return output
434
+ elif kwargs['output_format'] == 'flux_density':
435
+ time = time_obs
436
+ frequency = kwargs['frequency']
437
+ # interpolate properties onto observation times
438
+ temp_func = interp1d(time_temp, y=output.t_photosphere)
439
+ rad_func = interp1d(time_temp, y=output.r_photosphere)
440
+ # convert to source frame time and frequency
441
+ frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
442
+
443
+ temp = temp_func(time)
444
+ photosphere = rad_func(time)
445
+
446
+ flux_density = sed.blackbody_to_flux_density(temperature=temp, r_photosphere=photosphere,
447
+ dl=dl, frequency=frequency)
448
+
449
+ return flux_density.to(uu.mJy).value
450
+ else:
451
+ lambda_observer_frame = kwargs.get('lambda_array', np.geomspace(100, 60000, 200))
452
+ time_observer_frame = time_temp * (1. + redshift)
453
+ frequency, time = calc_kcorrected_properties(frequency=lambda_to_nu(lambda_observer_frame),
454
+ redshift=redshift, time=time_observer_frame)
455
+ fmjy = sed.blackbody_to_flux_density(temperature=output.t_photosphere,
456
+ r_photosphere=output.r_photosphere, frequency=frequency[:, None], dl=dl)
457
+ fmjy = fmjy.T
458
+ spectra = fmjy.to(uu.mJy).to(uu.erg / uu.cm ** 2 / uu.s / uu.Angstrom,
459
+ equivalencies=uu.spectral_density(wav=lambda_observer_frame * uu.Angstrom))
460
+ if kwargs['output_format'] == 'spectra':
461
+ return namedtuple('output', ['time', 'lambdas', 'spectra'])(time=time_observer_frame,
462
+ lambdas=lambda_observer_frame,
463
+ spectra=spectra)
464
+ else:
465
+ return sed.get_correct_output_format_from_spectra(time=time_obs, time_eval=time_observer_frame,
466
+ spectra=spectra, lambda_array=lambda_observer_frame,
467
+ **kwargs)
468
+
469
+
10
470
  @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2022ApJ...933..238M/abstract')
11
471
  def _csm_shock_breakout(time, csm_mass, v_min, beta, kappa, shell_radius, shell_width_ratio, **kwargs):
12
472
  """
@@ -23,15 +483,14 @@ def _csm_shock_breakout(time, csm_mass, v_min, beta, kappa, shell_radius, shell_
23
483
  """
24
484
  v0 = v_min * 1e5
25
485
  e0 = 0.5 * csm_mass * v0**2
486
+ velocity = v0/beta
26
487
  shell_radius *= 1e14
27
488
  shell_width = shell_width_ratio * shell_radius
28
- tdyn = shell_radius / v0
29
- tshell = shell_width / v0
30
- time = time * day_to_s
489
+ tdyn = shell_radius / velocity
490
+ tshell = shell_width / velocity
491
+ time = time * cc.day_to_s
31
492
 
32
- velocity = v0/beta
33
-
34
- tda = (3 * kappa * csm_mass / (4 * np.pi * speed_of_light * velocity)) ** 0.5
493
+ tda = (3 * kappa * csm_mass / (4 * np.pi * cc.speed_of_light * velocity)) ** 0.5
35
494
 
36
495
  term1 = ((tdyn + tshell + time) ** 3 - (tdyn + beta * time) ** 3) ** (2 / 3)
37
496
  term2 = ((tdyn + tshell) ** 3 - tdyn ** 3) ** (1 / 3)
@@ -45,7 +504,7 @@ def _csm_shock_breakout(time, csm_mass, v_min, beta, kappa, shell_radius, shell_
45
504
  volume = 4./3. * np.pi * velocity**3 * ((tdyn + tshell + time)**3 - (tdyn + beta*time)**3)
46
505
  radius = velocity * (tdyn + tshell + time)
47
506
  rphotosphere = radius - 2*volume/(3 * kappa * csm_mass)
48
- teff = (lbol / (4 * np.pi * rphotosphere ** 2 * sigma_sb)) ** 0.25
507
+ teff = (lbol / (4 * np.pi * rphotosphere ** 2 * cc.sigma_sb)) ** 0.25
49
508
  output = namedtuple('output', ['lbol', 'r_photosphere', 'temperature', 'time_temp',
50
509
  'tdyn', 'tshell', 'e0', 'tda', 'velocity'])
51
510
  output.lbol = lbol
@@ -72,11 +531,10 @@ def csm_shock_breakout_bolometric(time, csm_mass, v_min, beta, kappa, shell_radi
72
531
  :param shell_radius: radius of shell in 10^14 cm
73
532
  :param shell_width_ratio: shell width ratio (deltaR/R0)
74
533
  :param kwargs: Additional parameters required by model
75
- :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
76
534
  :return: bolometric luminosity
77
535
  """
78
- csm_mass = csm_mass * solar_mass
79
- time_temp = np.geomspace(1e-2, 200, 300) # days
536
+ csm_mass = csm_mass * cc.solar_mass
537
+ time_temp = np.linspace(1e-2, 200, 300) # days
80
538
  outputs = _csm_shock_breakout(time_temp, v_min=v_min, beta=beta,
81
539
  kappa=kappa, csm_mass=csm_mass, shell_radius=shell_radius,
82
540
  shell_width_ratio=shell_width_ratio, **kwargs)
@@ -104,12 +562,11 @@ def csm_shock_breakout(time, redshift, csm_mass, v_min, beta, kappa, shell_radiu
104
562
  :param lambda_array: Optional argument to set your desired wavelength array (in Angstroms) to evaluate the SED on.
105
563
  :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
106
564
  :return: set by output format - 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
107
- :return:
108
565
  """
109
- csm_mass = csm_mass * solar_mass
566
+ csm_mass = csm_mass * cc.solar_mass
110
567
  cosmology = kwargs.get('cosmology', cosmo)
111
568
  dl = cosmology.luminosity_distance(redshift).cgs.value
112
- time_temp = np.geomspace(1e-2, 40, 300) #days
569
+ time_temp = np.linspace(1e-2, 60, 300) #days
113
570
  time_obs = time
114
571
  outputs = _csm_shock_breakout(time_temp, v_min=v_min, beta=beta,
115
572
  kappa=kappa, csm_mass=csm_mass, shell_radius=shell_radius,
@@ -168,11 +625,11 @@ def _shock_cooling(time, mass, radius, energy, **kwargs):
168
625
  delta = kwargs.get('delta',1.1)
169
626
  kk_pow = (nn - 3) * (3 - delta) / (4 * np.pi * (nn - delta))
170
627
  kappa = 0.2
171
- mass = mass * solar_mass
628
+ mass = mass * cc.solar_mass
172
629
  vt = (((nn - 5) * (5 - delta) / ((nn - 3) * (3 - delta))) * (2 * energy / mass))**0.5
173
- td = ((3 * kappa * kk_pow * mass) / ((nn - 1) * vt * speed_of_light))**0.5
630
+ td = ((3 * kappa * kk_pow * mass) / ((nn - 1) * vt * cc.speed_of_light))**0.5
174
631
 
175
- prefactor = np.pi * (nn - 1) / (3 * (nn - 5)) * speed_of_light * radius * vt**2 / kappa
632
+ prefactor = np.pi * (nn - 1) / (3 * (nn - 5)) * cc.speed_of_light * radius * vt**2 / kappa
176
633
  lbol_pre_td = prefactor * np.power(td / time, 4 / (nn - 2))
177
634
  lbol_post_td = prefactor * np.exp(-0.5 * (time * time / td / td - 1))
178
635
  lbol = np.zeros(len(time))
@@ -185,7 +642,7 @@ def _shock_cooling(time, mass, radius, energy, **kwargs):
185
642
  r_photosphere = r_photosphere_pre_td + r_photosphere_post_td
186
643
 
187
644
  sigmaT4 = lbol / (4 * np.pi * r_photosphere**2)
188
- temperature = np.power(sigmaT4 / sigma_sb, 0.25)
645
+ temperature = np.power(sigmaT4 / cc.sigma_sb, 0.25)
189
646
 
190
647
  output = namedtuple('output', ['lbol', 'r_photosphere', 'temperature', 'td'])
191
648
  output.lbol = lbol
@@ -211,17 +668,17 @@ def _shocked_cocoon_nicholl(time, kappa, mejecta, vejecta, cos_theta_cocoon, sho
211
668
  """
212
669
  ckm = 3e10 / 1e5
213
670
  vejecta = vejecta * ckm
214
- diffusion_constant = solar_mass / (4 * np.pi * speed_of_light * km_cgs)
215
- num = speed_of_light / km_cgs
216
- rshock = speed_of_light * tshock
671
+ diffusion_constant = cc.solar_mass / (4 * np.pi * cc.speed_of_light * cc.km_cgs)
672
+ num = cc.speed_of_light / cc.km_cgs
673
+ rshock = cc.speed_of_light * tshock
217
674
  mshocked = shocked_fraction * mejecta
218
675
  theta = np.arccos(cos_theta_cocoon)
219
- taudiff = np.sqrt(diffusion_constant * kappa * mshocked / vejecta) / day_to_s
676
+ taudiff = np.sqrt(diffusion_constant * kappa * mshocked / vejecta) / cc.day_to_s
220
677
 
221
678
  tthin = (num / vejecta) ** 0.5 * taudiff
222
679
 
223
- l0 = (theta **2 / 2)**(1. / 3.) * (mshocked * solar_mass *
224
- vejecta * km_cgs * rshock / (taudiff * day_to_s)**2)
680
+ l0 = (theta **2 / 2)**(1. / 3.) * (mshocked * cc.solar_mass *
681
+ vejecta * cc.km_cgs * rshock / (taudiff * cc.day_to_s)**2)
225
682
 
226
683
  lbol = l0 * (time / taudiff)**-(4/(nn+2)) * (1 + np.tanh(tthin-time))/2.
227
684
  output = namedtuple('output', ['lbol', 'tthin', 'taudiff','mshocked'])
@@ -279,18 +736,18 @@ def shock_cooling(time, redshift, log10_mass, log10_radius, log10_energy, **kwar
279
736
  if kwargs['output_format'] == 'flux_density':
280
737
  frequency = kwargs['frequency']
281
738
  frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
282
- output = _shock_cooling(time*day_to_s, mass=mass, radius=radius, energy=energy, **kwargs)
739
+ output = _shock_cooling(time*cc.day_to_s, mass=mass, radius=radius, energy=energy, **kwargs)
283
740
  flux_density = sed.blackbody_to_flux_density(temperature=output.temperature, r_photosphere=output.r_photosphere,
284
741
  dl=dl, frequency=frequency)
285
742
  return flux_density.to(uu.mJy).value
286
743
  else:
287
- time_temp = np.linspace(1e-2, 10, 100)
744
+ time_temp = np.linspace(1e-2, 60, 100)
288
745
  lambda_observer_frame = kwargs.get('lambda_array', np.geomspace(100, 60000, 100))
289
746
 
290
747
  time_observer_frame = time_temp
291
748
  frequency, time = calc_kcorrected_properties(frequency=lambda_to_nu(lambda_observer_frame),
292
749
  redshift=redshift, time=time_observer_frame)
293
- output = _shock_cooling(time=time * day_to_s, mass=mass, radius=radius, energy=energy, **kwargs)
750
+ output = _shock_cooling(time=time * cc.day_to_s, mass=mass, radius=radius, energy=energy, **kwargs)
294
751
  fmjy = sed.blackbody_to_flux_density(temperature=output.temperature,
295
752
  r_photosphere=output.r_photosphere, frequency=frequency[:, None], dl=dl)
296
753
  fmjy = fmjy.T
@@ -387,7 +844,7 @@ def _emissivity_pl(x, nism, bfield, theta, xi, p, z_cool):
387
844
  :param z_cool: normalised cooling lorentz factor
388
845
  :return: synchrotron emissivity of power-law electrons
389
846
  """
390
- val = _c_j(p)*(qe**3/(electron_mass*speed_of_light**2))*xi*nism*bfield*_g_theta(theta=theta,p=p)*x**(-(p-1.0)/2.0)
847
+ val = _c_j(p)*(cc.qe**3/(cc.electron_mass*cc.speed_of_light**2))*xi*nism*bfield*_g_theta(theta=theta,p=p)*x**(-(p-1.0)/2.0)
391
848
  # correct emission at low-frequencies x < x_m:
392
849
  val *= _low_freq_jpl_correction(x=x,theta=theta,p=p)
393
850
  # fast-cooling correction:
@@ -407,7 +864,7 @@ def _emissivity_thermal(x, nism, bfield, theta, z_cool):
407
864
  """
408
865
  ff = 2.0*theta**2/special.kn(2,1.0/theta)
409
866
  ix = 4.0505*x**(-1.0/6.0)*( 1.0 + 0.40*x**(-0.25) + 0.5316*x**(-0.5) )*np.exp(-1.8899*x**(1.0/3.0))
410
- val = (3.0**0.5/(8.0*np.pi))*(qe**3/(electron_mass*speed_of_light**2))*ff*nism*bfield*x*ix
867
+ val = (3.0**0.5/(8.0*np.pi))*(cc.qe**3/(cc.electron_mass*cc.speed_of_light**2))*ff*nism*bfield*x*ix
411
868
  # fast-cooling correction:
412
869
  z0 = (2.0*x)**(1.0/3.0)
413
870
  val *= np.minimum(1e0, (z0/z_cool)**(-1))
@@ -424,7 +881,7 @@ def _alphanu_th(x, nism, bfield, theta, z_cool):
424
881
  """
425
882
  ff = 2.0 * theta ** 2 / special.kn(2, 1.0 / theta)
426
883
  ix = 4.0505*x**(-1.0/6.0)*( 1.0 + 0.40*x**(-0.25) + 0.5316*x**(-0.5) )*np.exp(-1.8899*x**(1.0/3.0))
427
- val = (np.pi*3.0**(-3.0/2.0))*qe*(nism/(theta**5*bfield))*ff*x**(-1.0)*ix
884
+ val = (np.pi*3.0**(-3.0/2.0))*cc.qe*(nism/(theta**5*bfield))*ff*x**(-1.0)*ix
428
885
  # fast-cooling correction:
429
886
  z0 = (2.0*x)**(1.0/3.0)
430
887
  val *= np.minimum( 1e0, (z0/z_cool)**(-1) )
@@ -441,7 +898,7 @@ def _alphanu_pl(x, nism, bfield, theta, xi, p, z_cool):
441
898
  :param z_cool: normalised cooling lorentz factor
442
899
  :return: Synchrotron absorption coeff of power-law electrons
443
900
  """
444
- val = _c_alpha(p)*qe*(xi*nism/(theta**5*bfield))*_g_theta(theta,p=p)*x**(-(p+4.0)/2.0)
901
+ val = _c_alpha(p)*cc.qe*(xi*nism/(theta**5*bfield))*_g_theta(theta,p=p)*x**(-(p+4.0)/2.0)
445
902
  # correct emission at low-frequencies x < x_m:
446
903
  val *= _low_freq_apl_correction(x,theta,p)
447
904
  # fast-cooling correction:
@@ -479,24 +936,24 @@ def _shocked_cocoon(time, mej, vej, eta, tshock, shocked_fraction, cos_theta_coc
479
936
  :param kappa: opacity
480
937
  :return: namedtuple with lbol, r_photosphere, and temperature
481
938
  """
482
- c_kms = speed_of_light / km_cgs
939
+ c_kms = cc.speed_of_light / cc.km_cgs
483
940
  vej = vej * c_kms
484
- diff_const = solar_mass / (4*np.pi * speed_of_light * km_cgs)
485
- rshock = tshock * speed_of_light
941
+ diff_const = cc.solar_mass / (4*np.pi * cc.speed_of_light * cc.km_cgs)
942
+ rshock = tshock * cc.speed_of_light
486
943
  shocked_mass = mej * shocked_fraction
487
944
  theta = np.arccos(cos_theta_cocoon)
488
- tau_diff = np.sqrt(diff_const * kappa * shocked_mass / vej) / day_to_s
945
+ tau_diff = np.sqrt(diff_const * kappa * shocked_mass / vej) / cc.day_to_s
489
946
 
490
947
  t_thin = (c_kms / vej) ** 0.5 * tau_diff
491
948
 
492
- l0 = (theta ** 2 / 2) ** (1 / 3) * (shocked_mass * solar_mass *
493
- vej * km_cgs * rshock / (tau_diff * day_to_s) ** 2)
949
+ l0 = (theta ** 2 / 2) ** (1 / 3) * (shocked_mass * cc.solar_mass *
950
+ vej * cc.km_cgs * rshock / (tau_diff * cc.day_to_s) ** 2)
494
951
 
495
952
  lbol = l0 * (time/tau_diff)**(-4/(eta+2)) * (1 + np.tanh(t_thin - time))/2
496
953
 
497
954
  v_photosphere = vej * (time / t_thin) ** (-2. / (eta + 3))
498
- r_photosphere = km_cgs * day_to_s * v_photosphere * time
499
- temperature = (lbol / (4.0 * np.pi * sigma_sb * r_photosphere**2))**0.25
955
+ r_photosphere = cc.km_cgs * cc.day_to_s * v_photosphere * time
956
+ temperature = (lbol / (4.0 * np.pi * cc.sigma_sb * r_photosphere**2))**0.25
500
957
 
501
958
  output = namedtuple('output', ['lbol', 'r_photosphere', 'temperature'])
502
959
  output.lbol = lbol
@@ -558,7 +1015,7 @@ def shocked_cocoon(time, redshift, mej, vej, eta, tshock, shocked_fraction, cos_
558
1015
  return flux_density.to(uu.mJy).value
559
1016
  else:
560
1017
  lambda_observer_frame = kwargs.get('frequency_array', np.geomspace(100, 60000, 100))
561
- time_temp = np.linspace(1e-2, 10, 100)
1018
+ time_temp = np.linspace(1e-2, 100, 100)
562
1019
  time_observer_frame = time_temp
563
1020
  frequency, time = calc_kcorrected_properties(frequency=lambda_to_nu(lambda_observer_frame),
564
1021
  redshift=redshift, time=time_observer_frame)
@@ -581,4 +1038,10 @@ def shocked_cocoon(time, redshift, mej, vej, eta, tshock, shocked_fraction, cos_
581
1038
 
582
1039
  @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2022ApJ...928..122M/abstract')
583
1040
  def csm_truncation_shock():
1041
+ """
1042
+ Multi-zone version of Margalit 2022 model for CSM shock breakout and cooling one zone model is implemented as
1043
+ csm_shock_breakout
1044
+
1045
+ :return:
1046
+ """
584
1047
  raise NotImplementedError("This model is not yet implemented.")