redback 1.1__py3-none-any.whl → 1.12.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 (40) hide show
  1. redback/__init__.py +1 -1
  2. redback/filters.py +57 -45
  3. redback/likelihoods.py +274 -6
  4. redback/model_library.py +2 -2
  5. redback/plotting.py +5 -3
  6. redback/priors/blackbody_spectrum_at_z.prior +3 -0
  7. redback/priors/bpl_cooling_envelope.prior +9 -0
  8. redback/priors/gaussianrise_cooling_envelope.prior +1 -5
  9. redback/priors/gaussianrise_cooling_envelope_bolometric.prior +1 -5
  10. redback/priors/powerlaw_plus_blackbody.prior +12 -0
  11. redback/priors/powerlaw_plus_blackbody_spectrum_at_z.prior +13 -0
  12. redback/priors/salt2.prior +6 -0
  13. redback/priors/shock_cooling_and_arnett_bolometric.prior +11 -0
  14. redback/priors/smooth_exponential_powerlaw_cooling_envelope_bolometric.prior +9 -0
  15. redback/priors/sn_nickel_fallback.prior +9 -0
  16. redback/priors/wr_bh_merger.prior +10 -0
  17. redback/priors/wr_bh_merger_bolometric.prior +8 -0
  18. redback/priors.py +14 -3
  19. redback/sed.py +185 -41
  20. redback/simulate_transients.py +13 -3
  21. redback/tables/filters.csv +260 -258
  22. redback/tables/qdot_rosswogkorobkin24.npz +0 -0
  23. redback/transient_models/afterglow_models.py +32 -16
  24. redback/transient_models/combined_models.py +16 -11
  25. redback/transient_models/extinction_models.py +310 -84
  26. redback/transient_models/gaussianprocess_models.py +1 -12
  27. redback/transient_models/kilonova_models.py +3 -3
  28. redback/transient_models/phase_models.py +97 -43
  29. redback/transient_models/phenomenological_models.py +172 -0
  30. redback/transient_models/spectral_models.py +101 -0
  31. redback/transient_models/stellar_interaction_models.py +254 -0
  32. redback/transient_models/supernova_models.py +349 -62
  33. redback/transient_models/tde_models.py +193 -54
  34. redback/utils.py +34 -7
  35. {redback-1.1.dist-info → redback-1.12.1.dist-info}/METADATA +7 -4
  36. {redback-1.1.dist-info → redback-1.12.1.dist-info}/RECORD +39 -28
  37. {redback-1.1.dist-info → redback-1.12.1.dist-info}/WHEEL +1 -1
  38. redback/tables/qdot_rosswogkorobkin24.pck +0 -0
  39. {redback-1.1.dist-info → redback-1.12.1.dist-info}/licenses/LICENCE.md +0 -0
  40. {redback-1.1.dist-info → redback-1.12.1.dist-info}/top_level.txt +0 -0
@@ -28,39 +28,77 @@ def _analytic_fallback(time, l0, t_0):
28
28
  def _semianalytical_fallback():
29
29
  pass
30
30
 
31
+
31
32
  def _cooling_envelope(mbh_6, stellar_mass, eta, alpha, beta, **kwargs):
32
33
  """
34
+ Sarin and Metzger 24 cooling envelope model.
35
+ Also includes partial disruptions by assuming only fraction of stellar mass is disrupted.
36
+
33
37
  :param mbh_6: mass of supermassive black hole in units of 10^6 solar mass
34
38
  :param stellar_mass: stellar mass in units of solar masses
35
39
  :param eta: SMBH feedback efficiency (typical range: etamin - 0.1)
36
40
  :param alpha: disk viscosity
37
- :param beta: TDE penetration factor (typical range: 1 - beta_max)
38
- :param kwargs:
41
+ :param beta: TDE penetration factor (typical range: 0.1 - beta_max).
42
+ :param kwargs: Binding energy constant, zeta, hoverR, t_0_init, f_debris (optional, defaults to 1 unless
43
+ calculate_f_debris=True), calculate_f_debris (optional, defaults to False).
39
44
  :return: named tuple with bolometric luminosity, photosphere radius, temperature, and other parameters
40
45
  """
41
46
  t_0_init = kwargs.get('t_0_init', 1.0)
42
47
  binding_energy_const = kwargs.get('binding_energy_const', 0.8)
43
- zeta = kwargs.get('zeta',2.0)
48
+ zeta = kwargs.get('zeta', 2.0)
44
49
  hoverR = kwargs.get('hoverR', 0.3)
50
+ calculate_f_debris = kwargs.get('calculate_f_debris', False)
51
+
52
+ # Determine debris fraction
53
+ if 'f_debris' in kwargs:
54
+ # User explicitly provided f_debris - use that value
55
+ f_debris = kwargs['f_debris']
56
+ f_mbh = None
57
+ g_mstar = None
58
+ scaling_factor = None
59
+ elif calculate_f_debris:
60
+ # Calculate debris fraction from beta using Ryu et al. scaling
61
+ # R_t = r_t * f(m_bh) * g(m_star)
62
+ # f(m_bh) = 0.80 + 0.26 * (mbh/10^6)^0.5
63
+ f_mbh = 0.80 + 0.26 * (mbh_6) ** 0.5
64
+
65
+ # g(m_star) = (1.47 + exp[(M_star - 0.669)/0.137]) / (1 + 2.34 * exp[(M_star - 0.669)/0.137])
66
+ exp_term = np.exp((stellar_mass - 0.669) / 0.137)
67
+ g_mstar = (1.47 + exp_term) / (1 + 2.34 * exp_term)
68
+
69
+ # Combined scaling factor
70
+ scaling_factor = f_mbh * g_mstar
71
+
72
+ # f_debris = (beta * scaling_factor)^3
73
+ f_debris = (beta * scaling_factor) ** 3
74
+ f_debris = np.clip(f_debris, 0.0, 1.0) # Ensure physical bounds
75
+ else:
76
+ # Default behavior: assume complete disruption
77
+ f_debris = 1.0
78
+ f_mbh = None
79
+ g_mstar = None
80
+ scaling_factor = None
45
81
 
46
82
  # gravitational radius
47
83
  Rg = cc.graviational_constant * mbh_6 * 1.0e6 * (cc.solar_mass / cc.speed_of_light ** (2.0))
48
84
  # stellar mass in cgs
49
85
  Mstar = stellar_mass * cc.solar_mass
86
+ # effective disrupted mass
87
+ Mdisrupt = f_debris * Mstar
50
88
  # stellar radius in cgs
51
89
  Rstar = stellar_mass ** (0.8) * cc.solar_radius
52
90
  # tidal radius
53
- Rt = Rstar * (mbh_6*1.0e6 /stellar_mass) ** (1./3.)
91
+ Rt = Rstar * (mbh_6 * 1.0e6 / stellar_mass) ** (1. / 3.)
54
92
  # circularization radius
55
- Rcirc = 2.0*Rt/beta
56
- # fall-back time of most tightly bound debris
57
- tfb = calc_tfb(binding_energy_const, mbh_6, stellar_mass)
93
+ Rcirc = 2.0 * Rt / beta
94
+ # fall-back time of most tightly bound debris (uses effective disrupted mass)
95
+ tfb = calc_tfb(binding_energy_const, mbh_6, stellar_mass * f_debris)
58
96
  # Eddington luminosity of SMBH in units of 1e40 erg/s
59
97
  Ledd40 = 1.4e4 * mbh_6
60
- time_temp = np.logspace(np.log10(1.0*tfb), np.log10(5000*tfb), 5000)
61
- tdays = time_temp/cc.day_to_s
98
+ time_temp = np.logspace(np.log10(1.0 * tfb), np.log10(5000 * tfb), 5000)
99
+ tdays = time_temp / cc.day_to_s
62
100
 
63
- #set up grids
101
+ # set up grids
64
102
  # mass of envelope in Msun
65
103
  Me = np.empty_like(tdays)
66
104
  # thermal energy of envelope in units of 1e40 ergs
@@ -90,28 +128,30 @@ def _cooling_envelope(mbh_6, stellar_mass, eta, alpha, beta, **kwargs):
90
128
  # proxy x-ray luminosity (not used directly in optical light curve calculation)
91
129
  LX40 = np.empty_like(tdays)
92
130
 
93
- Mdotfb = (0.8 * Mstar / (3.0 * tfb)) * (time_temp / tfb) ** (-5. / 3.)
131
+ # Modified fallback rate using disrupted mass
132
+ Mdotfb = (0.8 * Mdisrupt / (3.0 * tfb)) * (time_temp / tfb) ** (-5. / 3.)
94
133
 
95
134
  # ** initialize grid quantities at t = t_0_init [grid point 0] **
96
- # initial envelope mass at t_0_init
97
- Me[0] = 0.1 * Mstar + (0.4 * Mstar) * (1.0 - t_0_init**(-2. / 3.))
135
+ # initial envelope mass at t_0_init (scaled by disruption fraction)
136
+ Me[0] = f_debris * (0.1 * Mstar + (0.4 * Mstar) * (1.0 - t_0_init ** (-2. / 3.)))
98
137
  # initial envelope radius determined by energy of TDE process
99
- Rv[0] = (2. * Rt**(2.0)/(5.0 * binding_energy_const * Rstar)) * (Me[0]/Mstar)
138
+ Rv[0] = (2. * Rt ** (2.0) / (5.0 * binding_energy_const * Rstar)) * (Me[0] / (f_debris * Mstar))
100
139
  # initial thermal energy of envelope
101
140
  Ee40[0] = ((2.0 * cc.graviational_constant * mbh_6 * 1.0e6 * Me[0]) / (5.0 * Rv[0])) * 2.0e-7
102
141
  # initial characteristic optical depth
103
- Lamb[0] = 0.38 * Me[0] / (10.0 *np.pi * Rv[0] ** (2.0))
142
+ Lamb[0] = 0.38 * Me[0] / (10.0 * np.pi * Rv[0] ** (2.0))
104
143
  # initial photosphere radius
105
144
  Rph[0] = Rv[0] * (1.0 + np.log(Lamb[0]))
106
145
  # initial fallback stream accretion radius
107
146
  Racc[0] = zeta * Rv[0]
108
147
  # initial fallback accretion heating rate in 1e40 erg/s
109
- Edotfb40[0] = (cc.graviational_constant * mbh_6 * 1.0e6 * Mdotfb[0]/Racc[0]) * (2.0e-7)
148
+ Edotfb40[0] = (cc.graviational_constant * mbh_6 * 1.0e6 * Mdotfb[0] / Racc[0]) * (2.0e-7)
110
149
  # initial luminosity of envelope
111
150
  Lrad[0] = Ledd40 + Edotfb40[0]
112
151
  # initial SMBH accretion timescale in s
113
- tacc[0] = 2.2e-17 * (10. / (3. * alpha)) * (Rv[0] ** (2.0)) / (cc.graviational_constant * mbh_6 * 1.0e6 * Rcirc) ** (0.5) * (hoverR) ** (
114
- -2.0)
152
+ tacc[0] = 2.2e-17 * (10. / (3. * alpha)) * (Rv[0] ** (2.0)) / (
153
+ cc.graviational_constant * mbh_6 * 1.0e6 * Rcirc) ** (0.5) * (hoverR) ** (
154
+ -2.0)
115
155
  # initial SMBH accretion rate in g/s
116
156
  MdotBH[0] = (Me[0] / tacc[0])
117
157
  # initial SMBH feedback heating rate in 1e40 erg/s
@@ -127,7 +167,7 @@ def _cooling_envelope(mbh_6, stellar_mass, eta, alpha, beta, **kwargs):
127
167
  # update envelope radius based on its new energy
128
168
  Rv[ii] = ((2.0 * cc.graviational_constant * mbh_6 * 1.0e6 * Me[ii]) / (5.0 * Ee40[ii])) * (2.0e-7)
129
169
  # update envelope optical depth
130
- Lamb[ii] = 0.38 * Me[ii] / (10.0 *np.pi * Rv[ii] ** (2.0))
170
+ Lamb[ii] = 0.38 * Me[ii] / (10.0 * np.pi * Rv[ii] ** (2.0))
131
171
  # update envelope photosphere radius
132
172
  Rph[ii] = Rv[ii] * (1.0 + np.log(Lamb[ii]))
133
173
  # update accretion radius
@@ -137,10 +177,11 @@ def _cooling_envelope(mbh_6, stellar_mass, eta, alpha, beta, **kwargs):
137
177
  # update total radiated luminosity
138
178
  Lrad[ii] = Ledd40 + Edotfb40[ii]
139
179
  # update photosphere temperature in K
140
- Teff[ii] = 1.0e10 * ((Ledd40 + Edotfb40[ii]) / (4.0 *np.pi * cc.sigma_sb * Rph[ii] ** (2.0))) ** (0.25)
180
+ Teff[ii] = 1.0e10 * ((Ledd40 + Edotfb40[ii]) / (4.0 * np.pi * cc.sigma_sb * Rph[ii] ** (2.0))) ** (0.25)
141
181
  # update SMBH accretion timescale in seconds
142
- tacc[ii] = 2.2e-17 * (10. / (3.0 * alpha)) * (Rv[ii] ** (2.0)) / (cc.graviational_constant * mbh_6 * 1.0e6 * Rcirc) ** (0.5) * (
143
- hoverR) ** (-2.0)
182
+ tacc[ii] = 2.2e-17 * (10. / (3.0 * alpha)) * (Rv[ii] ** (2.0)) / (
183
+ cc.graviational_constant * mbh_6 * 1.0e6 * Rcirc) ** (0.5) * (
184
+ hoverR) ** (-2.0)
144
185
  # update SMBH accretion rate in g/s
145
186
  MdotBH[ii] = (Me[ii] / tacc[ii])
146
187
  # update proxy X-ray luminosity
@@ -151,19 +192,24 @@ def _cooling_envelope(mbh_6, stellar_mass, eta, alpha, beta, **kwargs):
151
192
  output = namedtuple('output', ['bolometric_luminosity', 'photosphere_temperature',
152
193
  'photosphere_radius', 'lum_xray', 'accretion_radius',
153
194
  'SMBH_accretion_rate', 'time_temp', 'nulnu',
154
- 'time_since_fb','tfb', 'lnu', 'envelope_radius', 'envelope_mass',
155
- 'rtidal', 'rcirc', 'termination_time', 'termination_time_id'])
195
+ 'time_since_fb', 'tfb', 'lnu', 'envelope_radius', 'envelope_mass',
196
+ 'rtidal', 'rcirc', 'termination_time', 'termination_time_id', 'f_debris',
197
+ 'f_mbh', 'g_mstar', 'scaling_factor'])
156
198
  try:
157
- constraint_1 = np.min(np.where(Rv < Rcirc/2.))
199
+ constraint_1 = np.min(np.where(Rv < Rcirc / 2.))
200
+ if constraint_1 == 0.:
201
+ # ignore constraining on Rv < Rcirc/2. if it is at the first time step
202
+ constraint_1 = 5000
158
203
  constraint_2 = np.min(np.where(Me < 0.0))
159
204
  except ValueError:
160
205
  constraint_1 = len(time_temp)
161
206
  constraint_2 = len(time_temp)
162
207
  constraint = np.min([constraint_1, constraint_2])
163
208
  termination_time_id = np.min([constraint_1, constraint_2])
209
+
164
210
  nu = 6.0e14
165
211
  expon = 1. / (np.exp(cc.planck * nu / (cc.boltzmann_constant * Teff)) - 1.0)
166
- nuLnu40 = (8.0*np.pi ** (2.0) * Rph ** (2.0) / cc.speed_of_light ** (2.0))
212
+ nuLnu40 = (8.0 * np.pi ** (2.0) * Rph ** (2.0) / cc.speed_of_light ** (2.0))
167
213
  nuLnu40 = nuLnu40 * ((cc.planck * nu) * (nu ** (2.0))) / 1.0e30
168
214
  nuLnu40 = nuLnu40 * expon
169
215
  nuLnu40 = nuLnu40 * (nu / 1.0e10)
@@ -187,6 +233,10 @@ def _cooling_envelope(mbh_6, stellar_mass, eta, alpha, beta, **kwargs):
187
233
  output.termination_time_id = termination_time_id
188
234
  output.tfb = tfb
189
235
  output.nulnu = nuLnu40[:constraint] * 1e40
236
+ output.f_debris = f_debris
237
+ output.f_mbh = f_mbh
238
+ output.g_mstar = g_mstar
239
+ output.scaling_factor = scaling_factor
190
240
  return output
191
241
 
192
242
  @citation_wrapper('https://arxiv.org/abs/2307.15121,https://ui.adsabs.harvard.edu/abs/2022arXiv220707136M/abstract')
@@ -201,7 +251,7 @@ def cooling_envelope(time, redshift, mbh_6, stellar_mass, eta, alpha, beta, **kw
201
251
  :param eta: SMBH feedback efficiency (typical range: etamin - 0.1)
202
252
  :param alpha: disk viscosity
203
253
  :param beta: TDE penetration factor (typical range: 1 - beta_max)
204
- :param kwargs: Additional parameters
254
+ :param kwargs: Additional parameters, check _cooling_envelope for more information
205
255
  :param frequency: Required if output_format is 'flux_density'.
206
256
  frequency to calculate - Must be same length as time array or a single number).
207
257
  :param bands: Required if output_format is 'magnitude' or 'flux'.
@@ -256,9 +306,10 @@ def cooling_envelope(time, redshift, mbh_6, stellar_mass, eta, alpha, beta, **kw
256
306
  **kwargs)
257
307
 
258
308
  @citation_wrapper('https://arxiv.org/abs/2307.15121,https://ui.adsabs.harvard.edu/abs/2022arXiv220707136M/abstract')
259
- def gaussianrise_cooling_envelope_bolometric(time, peak_time, sigma_t, mbh_6, stellar_mass, eta, alpha, beta, **kwargs):
309
+ def gaussianrise_cooling_envelope_bolometric(time, peak_time, sigma_t, mbh_6, stellar_mass, eta, alpha, beta,
310
+ **kwargs):
260
311
  """
261
- Full lightcurve, with gaussian rise till fallback time and then the metzger tde model,
312
+ Full lightcurve, with gaussian rise till xi * fallback time and then the metzger tde model,
262
313
  bolometric version for fitting the bolometric lightcurve
263
314
 
264
315
  :param time: time in source frame in days
@@ -269,28 +320,116 @@ def gaussianrise_cooling_envelope_bolometric(time, peak_time, sigma_t, mbh_6, st
269
320
  :param eta: SMBH feedback efficiency (typical range: etamin - 0.1)
270
321
  :param alpha: disk viscosity
271
322
  :param beta: TDE penetration factor (typical range: 1 - beta_max)
272
- :param kwargs: Additional parameters
323
+ :param kwargs: Additional parameters, check _cooling_envelope for more information
324
+ :param xi: Optional, default is 1. transition factor - Gaussian transitions to cooling envelope at xi * tfb
273
325
  :return luminosity in ergs/s
274
326
  """
275
327
  output = _cooling_envelope(mbh_6, stellar_mass, eta, alpha, beta, **kwargs)
276
328
  kwargs['binding_energy_const'] = kwargs.get('binding_energy_const', 0.8)
277
329
  tfb_sf = calc_tfb(kwargs['binding_energy_const'], mbh_6, stellar_mass) # source frame
278
- f1 = pm.gaussian_rise(time=tfb_sf, a_1=1, peak_time=peak_time * cc.day_to_s, sigma_t=sigma_t * cc.day_to_s)
330
+
331
+ # Transition time
332
+ xi = kwargs.get('xi', 1.)
333
+ transition_time = xi * tfb_sf
334
+
335
+ # Find the luminosity value at the transition time by interpolating the cooling envelope model
336
+ # Create interpolation function for the cooling envelope model
337
+ cooling_envelope_func = interp1d(output.time_temp, output.bolometric_luminosity,
338
+ bounds_error=False, fill_value='extrapolate')
339
+
340
+ # Get luminosity at transition time
341
+ f1 = pm.gaussian_rise(time=transition_time, a_1=1,
342
+ peak_time=peak_time * cc.day_to_s,
343
+ sigma_t=sigma_t * cc.day_to_s)
279
344
 
280
345
  # get normalisation
281
- f2 = output.bolometric_luminosity[0]
282
- norm = f2/f1
346
+ f2 = cooling_envelope_func(transition_time)
347
+ norm = f2 / f1
283
348
 
284
- #evaluate giant array of bolometric luminosities
285
- tt_pre_fb = np.linspace(0, tfb_sf, 100)
286
- tt_post_fb = output.time_temp
287
- full_time = np.concatenate([tt_pre_fb, tt_post_fb])
288
- f1 = pm.gaussian_rise(time=tt_pre_fb, a_1=norm,
289
- peak_time=peak_time * cc.day_to_s, sigma_t=sigma_t * cc.day_to_s)
290
- f2 = output.bolometric_luminosity
291
- full_lbol = np.concatenate([f1, f2])
349
+ # evaluate giant array of bolometric luminosities
350
+ tt_pre_transition = np.linspace(0, transition_time, 100)
351
+ # Only use cooling envelope times after the transition
352
+ tt_post_transition = output.time_temp[output.time_temp >= transition_time]
353
+
354
+ full_time = np.concatenate([tt_pre_transition, tt_post_transition])
355
+
356
+ # Gaussian part before transition
357
+ f1_array = pm.gaussian_rise(time=tt_pre_transition, a_1=norm,
358
+ peak_time=peak_time * cc.day_to_s,
359
+ sigma_t=sigma_t * cc.day_to_s)
360
+
361
+ # Cooling envelope part after transition
362
+ f2_array = output.bolometric_luminosity[output.time_temp >= transition_time]
363
+
364
+ full_lbol = np.concatenate([f1_array, f2_array])
292
365
  lbol_func = interp1d(full_time, y=full_lbol, fill_value='extrapolate')
293
- return lbol_func(time*cc.day_to_s)
366
+
367
+ return lbol_func(time * cc.day_to_s)
368
+
369
+
370
+ @citation_wrapper('https://arxiv.org/abs/2307.15121,https://ui.adsabs.harvard.edu/abs/2022arXiv220707136M/abstract')
371
+ def smooth_exponential_powerlaw_cooling_envelope_bolometric(time, peak_time, alpha_1, alpha_2, smoothing_factor,
372
+ mbh_6, stellar_mass, eta, alpha, beta, **kwargs):
373
+ """
374
+ Full lightcurve, with smoothed exponential power law rise till xi * fallback time and then the metzger tde model,
375
+ bolometric version for fitting the bolometric lightcurve
376
+
377
+ :param time: time in source frame in days
378
+ :param peak_time: peak time in days
379
+ :param alpha_1: power law index before peak
380
+ :param alpha_2: power law index after peak
381
+ :param smoothing_factor: controls transition smoothness at peak (higher = smoother)
382
+ :param mbh_6: mass of supermassive black hole in units of 10^6 solar mass
383
+ :param stellar_mass: stellar mass in units of solar masses
384
+ :param eta: SMBH feedback efficiency (typical range: etamin - 0.1)
385
+ :param alpha: disk viscosity
386
+ :param beta: TDE penetration factor (typical range: 1 - beta_max)
387
+ :param xi: Optional transition factor - smooth exponential power law transitions to cooling envelope at xi * tfb
388
+ :param kwargs: Additional parameters, check _cooling_envelope for more information
389
+ :return luminosity in ergs/s
390
+ """
391
+ # Get cooling envelope output
392
+ output = _cooling_envelope(mbh_6, stellar_mass, eta, alpha, beta, **kwargs)
393
+ kwargs['binding_energy_const'] = kwargs.get('binding_energy_const', 0.8)
394
+ tfb_sf = calc_tfb(kwargs['binding_energy_const'], mbh_6, stellar_mass) # source frame
395
+
396
+ # Transition time
397
+ xi = kwargs.get('xi', 1.)
398
+ transition_time = xi * tfb_sf
399
+
400
+ # Find the luminosity value at the transition time by interpolating the cooling envelope model
401
+ # Create interpolation function for the cooling envelope model
402
+ cooling_envelope_func = interp1d(output.time_temp, output.bolometric_luminosity,
403
+ bounds_error=False, fill_value='extrapolate')
404
+
405
+ # Get luminosity at transition time using smooth exponential power law
406
+ f1 = pm.smooth_exponential_powerlaw(np.array([transition_time]), 1.0,
407
+ peak_time * cc.day_to_s,
408
+ alpha_1, alpha_2, smoothing_factor)[0]
409
+
410
+ # get normalisation
411
+ f2 = cooling_envelope_func(transition_time)
412
+ norm = f2 / f1
413
+
414
+ # evaluate giant array of bolometric luminosities
415
+ tt_pre_transition = np.linspace(0, transition_time, 100)
416
+ # Only use cooling envelope times after the transition
417
+ tt_post_transition = output.time_temp[output.time_temp >= transition_time]
418
+
419
+ full_time = np.concatenate([tt_pre_transition, tt_post_transition])
420
+
421
+ # Smooth exponential power law part before transition
422
+ f1_array = pm.smooth_exponential_powerlaw(tt_pre_transition, norm,
423
+ peak_time * cc.day_to_s,
424
+ alpha_1, alpha_2, smoothing_factor)
425
+
426
+ # Cooling envelope part after transition
427
+ f2_array = output.bolometric_luminosity[output.time_temp >= transition_time]
428
+
429
+ full_lbol = np.concatenate([f1_array, f2_array])
430
+ lbol_func = interp1d(full_time, y=full_lbol, fill_value='extrapolate')
431
+
432
+ return lbol_func(time * cc.day_to_s)
294
433
 
295
434
 
296
435
  @citation_wrapper('https://arxiv.org/abs/2307.15121,https://ui.adsabs.harvard.edu/abs/2022arXiv220707136M/abstract')
@@ -308,7 +447,7 @@ def gaussianrise_cooling_envelope(time, redshift, peak_time, sigma_t, mbh_6, ste
308
447
  :param eta: SMBH feedback efficiency (typical range: etamin - 0.1)
309
448
  :param alpha: disk viscosity
310
449
  :param beta: TDE penetration factor (typical range: 1 - beta_max)
311
- :param kwargs: Additional parameters
450
+ :param kwargs: Additional parameters, check _cooling_envelope for more information
312
451
  :param xi: Optional argument (default set to one) to change the point where lightcurve switches from Gaussian rise to cooling envelope.
313
452
  stitching_point = xi * tfb (where tfb is fallback time). So a xi=1 means the stitching point is at fallback time.
314
453
  :param frequency: Required if output_format is 'flux_density'.
@@ -428,7 +567,7 @@ def bpl_cooling_envelope(time, redshift, peak_time, alpha_1, alpha_2, mbh_6, ste
428
567
  :param eta: SMBH feedback efficiency (typical range: etamin - 0.1)
429
568
  :param alpha: disk viscosity
430
569
  :param beta: TDE penetration factor (typical range: 1 - beta_max)
431
- :param kwargs: Additional parameters
570
+ :param kwargs: Additional parameters, check _cooling_envelope for more information
432
571
  :param xi: Optional argument (default set to one) to change the point where lightcurve switches from Gaussian rise to cooling envelope.
433
572
  stitching_point = xi * tfb (where tfb is fallback time). So a xi=1 means the stitching point is at fallback time.
434
573
  :param frequency: Required if output_format is 'flux_density'.
@@ -1134,7 +1273,7 @@ def fitted(time, redshift, log_mh, a_bh, m_disc, r0, tvi, t_form, incl, **kwargs
1134
1273
  **kwargs)
1135
1274
 
1136
1275
  @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2024arXiv240815048M/abstract')
1137
- def fitted_pl_decay(time, redshift, log_mh, a_bh, m_disc, r0, tvi, t_form, incl, log_L, t_decay, p, log_T, sigma, t_peak, **kwargs):
1276
+ def fitted_pl_decay(time, redshift, log_mh, a_bh, m_disc, r0, tvi, t_form, incl, log_L, t_decay, p, log_T, sigma_t, t_peak, **kwargs):
1138
1277
  """
1139
1278
  An import of FitTeD to model the plateau phase, with a gaussian rise and power-law decay
1140
1279
 
@@ -1151,7 +1290,7 @@ def fitted_pl_decay(time, redshift, log_mh, a_bh, m_disc, r0, tvi, t_form, incl,
1151
1290
  :param t_decay: fallback timescale (days)
1152
1291
  :param p: power-law decay index
1153
1292
  :param log_T: single temperature blackbody temperature for decay model (log_10 Kelvin)
1154
- :param sigma: gaussian rise timescale (days)
1293
+ :param sigma_t: gaussian rise timescale (days)
1155
1294
  :param t_peak: time of light curve peak (days)
1156
1295
  :param kwargs: Must be all the kwargs required by the specific output_format
1157
1296
  :param output_format: 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
@@ -1180,13 +1319,13 @@ def fitted_pl_decay(time, redshift, log_mh, a_bh, m_disc, r0, tvi, t_form, incl,
1180
1319
  if len(freqs_un) == 1:
1181
1320
  nulnus_plateau = m.model_UV(time, log_mh, a_bh, m_disc, r0, tvi, t_form, ang, v=freqs_un[0])
1182
1321
  nulnus_decay = m.decay_model(time, log_L, t_decay, p, t_peak, log_T, v=freqs_un[0])
1183
- nulnus_rise = m.rise_model(time, log_L, sigma, t_peak, log_T, v=freqs_un[0])
1322
+ nulnus_rise = m.rise_model(time, log_L, sigma_t, t_peak, log_T, v=freqs_un[0])
1184
1323
  else:
1185
1324
  for i in range(0,len(freqs_un)):
1186
1325
  inds = np.where(frequency == freqs_un[i])[0]
1187
1326
  nulnus[inds] = m.model_UV([time[j] for j in inds], log_mh, a_bh, m_disc, r0, tvi, t_form, ang, freqs_un[i])
1188
1327
  nulnus_decay[inds] = m.decay_model([time[j] for j in inds], log_L, t_decay, p, t_peak, log_T, v=freqs_un[i])
1189
- nulnus_rise[inds] = m.rise_model([time[j] for j in inds], log_L, sigma, t_peak, log_T, v=freqs_un[i])
1328
+ nulnus_rise[inds] = m.rise_model([time[j] for j in inds], log_L, sigma_t, t_peak, log_T, v=freqs_un[i])
1190
1329
  nulnus = nulnus_plateau + nulnus_rise + nulnus_decay
1191
1330
  flux_density = nulnus/(4.0 * np.pi * dl**2 * frequency)
1192
1331
  return flux_density/1.0e-26
@@ -1201,7 +1340,7 @@ def fitted_pl_decay(time, redshift, log_mh, a_bh, m_disc, r0, tvi, t_form, incl,
1201
1340
  nulnus_plateau = m.model_SEDs(time, log_mh, a_bh, m_disc, r0, tvi, t_form, ang, frequency)
1202
1341
 
1203
1342
  freq_0 = 6e14
1204
- l_e_amp = (model.decay_model(time, log_L, t_decay, t_peak, log_T, freq_0) + model.rise_model(time, log_L, sigma, t_peak, log_T, freq_0))
1343
+ l_e_amp = (model.decay_model(time, log_L, t_decay, t_peak, log_T, freq_0) + model.rise_model(time, log_L, sigma_t, t_peak, log_T, freq_0))
1205
1344
  nulnus_risedecay = ((l_e_amp[:, None] * (frequency/freq_0)**4 *
1206
1345
  (np.exp(cc.planck * freq_0/(cc.boltzmann_constant * 10**log_T)) - 1)/(np.exp(cc.planck * frequency/(cc.boltzmann_constant * 10**log_T)) - 1)).T)
1207
1346
  flux_density = ((nulnus_risedecay + nulnus_plateau)/(4.0 * np.pi * dl**2 * frequency[:,np.newaxis] * 1.0e-26))
@@ -1218,7 +1357,7 @@ def fitted_pl_decay(time, redshift, log_mh, a_bh, m_disc, r0, tvi, t_form, incl,
1218
1357
  **kwargs)
1219
1358
 
1220
1359
  @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2024arXiv240815048M/abstract')
1221
- def fitted_exp_decay(time, redshift, log_mh, a_bh, m_disc, r0, tvi, t_form, incl, log_L, t_decay, log_T, sigma, t_peak, **kwargs):
1360
+ def fitted_exp_decay(time, redshift, log_mh, a_bh, m_disc, r0, tvi, t_form, incl, log_L, t_decay, log_T, sigma_t, t_peak, **kwargs):
1222
1361
  """
1223
1362
  An import of FitTeD to model the plateau phase, with a gaussian rise and exponential decay
1224
1363
 
@@ -1234,7 +1373,7 @@ def fitted_exp_decay(time, redshift, log_mh, a_bh, m_disc, r0, tvi, t_form, incl
1234
1373
  :param log_L: single temperature blackbody amplitude for decay model (log_10 erg/s)
1235
1374
  :param t_decay: fallback timescale (days)
1236
1375
  :param log_T: single temperature blackbody temperature for decay model (log_10 Kelvin)
1237
- :param sigma: gaussian rise timescale (days)
1376
+ :param sigma_t: gaussian rise timescale (days)
1238
1377
  :param t_peak: time of light curve peak (days)
1239
1378
  :param kwargs: Must be all the kwargs required by the specific output_format
1240
1379
  :param output_format: 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
@@ -1263,13 +1402,13 @@ def fitted_exp_decay(time, redshift, log_mh, a_bh, m_disc, r0, tvi, t_form, incl
1263
1402
  if len(freqs_un) == 1:
1264
1403
  nulnus_plateau = m.model_UV(time, log_mh, a_bh, m_disc, r0, tvi, t_form, ang, v=freqs_un[0])
1265
1404
  nulnus_decay = m.decay_model(time, log_L, t_decay, t_peak, log_T, v=freqs_un[0])
1266
- nulnus_rise = m.rise_model(time, log_L, sigma, t_peak, log_T, v=freqs_un[0])
1405
+ nulnus_rise = m.rise_model(time, log_L, sigma_t, t_peak, log_T, v=freqs_un[0])
1267
1406
  else:
1268
1407
  for i in range(0,len(freqs_un)):
1269
1408
  inds = np.where(frequency == freqs_un[i])[0]
1270
1409
  nulnus[inds] = m.model_UV([time[j] for j in inds], log_mh, a_bh, m_disc, r0, tvi, t_form, ang, freqs_un[i])
1271
1410
  nulnus_decay[inds] = m.decay_model([time[j] for j in inds], log_L, t_decay, t_peak, log_T, v=freqs_un[i])
1272
- nulnus_rise[inds] = m.rise_model([time[j] for j in inds], log_L, sigma, t_peak, log_T, v=freqs_un[i])
1411
+ nulnus_rise[inds] = m.rise_model([time[j] for j in inds], log_L, sigma_t, t_peak, log_T, v=freqs_un[i])
1273
1412
  nulnus = nulnus_plateau + nulnus_rise + nulnus_decay
1274
1413
  flux_density = nulnus/(4.0 * np.pi * dl**2 * frequency)
1275
1414
  return flux_density/1.0e-26
@@ -1284,7 +1423,7 @@ def fitted_exp_decay(time, redshift, log_mh, a_bh, m_disc, r0, tvi, t_form, incl
1284
1423
  nulnus_plateau = m.model_SEDs(time, log_mh, a_bh, m_disc, r0, tvi, t_form, ang, frequency)
1285
1424
 
1286
1425
  freq_0 = 6e14
1287
- l_e_amp = (m.decay_model(time, log_L, t_decay, t_peak, log_T, freq_0) + m.rise_model(time, log_L, sigma, t_peak, log_T, freq_0))
1426
+ l_e_amp = (m.decay_model(time, log_L, t_decay, t_peak, log_T, freq_0) + m.rise_model(time, log_L, sigma_t, t_peak, log_T, freq_0))
1288
1427
  nulnus_risedecay = ((l_e_amp[:, None] * (frequency/freq_0)**4 *
1289
1428
  (np.exp(cc.planck * freq_0/(cc.boltzmann_constant * 10**log_T)) - 1)/(np.exp(cc.planck * frequency/(cc.boltzmann_constant * 10**log_T)) - 1)).T)
1290
1429
  flux_density = ((nulnus_risedecay + nulnus_plateau)/(4.0 * np.pi * dl**2 * frequency[:,np.newaxis] * 1.0e-26))
redback/utils.py CHANGED
@@ -125,12 +125,24 @@ def citation_wrapper(r):
125
125
 
126
126
  return wrapper
127
127
 
128
+ def calc_effective_width_hz_from_angstrom(effective_width, effective_wavelength):
129
+ """
130
+ Calculate the effective width in Hz from the effective wavelength in Angstrom
131
+
132
+ :param effective_width: effective_width in Angstrom
133
+ :param effective_wavelength: effective wavelength in Angstrom
134
+ :return: effective width in Hz
135
+ """
136
+ wavelength_m = effective_wavelength * 1.0e-10
137
+ effective_width_m = effective_width * 1.0e-10
138
+ effective_width = (3.0e8 / (wavelength_m**2)) * effective_width_m
139
+ return effective_width
128
140
 
129
141
  def calc_tfb(binding_energy_const, mbh_6, stellar_mass):
130
142
  """
131
143
  Calculate the fall back timescale for a SMBH disrupting a stellar mass object
132
144
  :param binding_energy_const:
133
- :param mbh_6: SMBH mass in solar masses
145
+ :param mbh_6: SMBH mass in 10^6 solar masses
134
146
  :param stellar_mass: stellar mass in solar masses
135
147
  :return: fall back time in seconds
136
148
  """
@@ -1260,20 +1272,35 @@ def get_heating_terms(ye, vel, **kwargs):
1260
1272
  return heating_terms
1261
1273
 
1262
1274
 
1275
+ # Global cache to avoid recreating interpolator every time
1276
+ _qdot_interpolator_cache = None
1277
+
1263
1278
  def _calculate_rosswogkorobkin24_qdot(time_array, ejecta_velocity, electron_fraction):
1264
- import pickle
1279
+ import numpy as np
1280
+ from scipy.interpolate import RegularGridInterpolator
1265
1281
  import os
1266
- dirname = os.path.dirname(__file__)
1267
- with open(f"{dirname}/tables/qdot_rosswogkorobkin24.pck", 'rb') as file_handle:
1268
- qdot_object = pickle.load(file_handle)
1282
+
1283
+ global _qdot_interpolator_cache
1284
+
1285
+ if _qdot_interpolator_cache is None:
1286
+ dirname = os.path.dirname(__file__)
1287
+
1288
+ with np.load(f"{dirname}/tables/qdot_rosswogkorobkin24.npz") as data:
1289
+ qedt = data['qedt']
1290
+ v_grid = data['v_grid']
1291
+ ye_grid = data['ye_grid']
1292
+ time_grid = data['time_array']
1293
+
1294
+ _qdot_interpolator_cache = RegularGridInterpolator((v_grid, ye_grid, time_grid), qedt,
1295
+ bounds_error=False, fill_value=None)
1296
+
1269
1297
  steps = len(time_array)
1270
1298
  _ej_velocity = np.repeat(ejecta_velocity, steps)
1271
1299
  _ye = np.repeat(electron_fraction, steps)
1272
1300
  full_array = np.array([_ej_velocity, _ye, time_array]).T
1273
- lum_in = qdot_object(full_array)
1301
+ lum_in = _qdot_interpolator_cache(full_array)
1274
1302
  return lum_in
1275
1303
 
1276
-
1277
1304
  def electron_fraction_from_kappa(kappa):
1278
1305
  """
1279
1306
  Uses interpolation from Tanaka+19 to calculate
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: redback
3
- Version: 1.1
3
+ Version: 1.12.1
4
4
  Summary: A Bayesian inference and modelling pipeline for electromagnetic transients
5
5
  Home-page: https://github.com/nikhil-sarin/redback
6
6
  Author: Nikhil Sarin, Moritz Huebner
@@ -12,10 +12,10 @@ Classifier: Operating System :: OS Independent
12
12
  Requires-Python: >=3.10
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENCE.md
15
- Requires-Dist: numpy==1.26.0
15
+ Requires-Dist: numpy
16
16
  Requires-Dist: setuptools
17
17
  Requires-Dist: pandas
18
- Requires-Dist: scipy<1.14.0
18
+ Requires-Dist: scipy
19
19
  Requires-Dist: selenium
20
20
  Requires-Dist: matplotlib
21
21
  Requires-Dist: astropy
@@ -37,8 +37,11 @@ Requires-Dist: PyQt5; extra == "all"
37
37
  Requires-Dist: lalsuite; extra == "all"
38
38
  Requires-Dist: kilonova-heating-rate; extra == "all"
39
39
  Requires-Dist: redback-surrogates; extra == "all"
40
+ Requires-Dist: tensorflow; extra == "all"
41
+ Requires-Dist: keras; extra == "all"
40
42
  Requires-Dist: kilonovanet; extra == "all"
41
43
  Requires-Dist: astroquery; extra == "all"
44
+ Requires-Dist: pyphot==1.6.0; extra == "all"
42
45
  Dynamic: author
43
46
  Dynamic: author-email
44
47
  Dynamic: classifier
@@ -85,7 +88,7 @@ Simulate single transients or populations or simulate a full survey including no
85
88
  ### Contributing
86
89
  If you are interested in contributing please join the redback
87
90
  [slack](https://join.slack.com/t/redback-group/shared_invite/zt-2503mmkaq-EMEAgz7i3mY0pg1o~VUdqw)
88
- and email [Nikhil Sarin](mailto:nikhil.sarin@su.se?subject=Contributing%20to%20redback).
91
+ and email [Nikhil Sarin](mailto:nsarin.astro@gmail.com?subject=Contributing%20to%20redback).
89
92
 
90
93
  To make changes to redback, we require users to use a merge request system.
91
94