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
@@ -3,7 +3,7 @@ import pandas as pd
3
3
  from redback.transient_models.phenomenological_models import exponential_powerlaw, fallback_lbol
4
4
  from redback.transient_models.magnetar_models import magnetar_only, basic_magnetar
5
5
  from redback.transient_models.magnetar_driven_ejecta_models import _ejecta_dynamics_and_interaction
6
- from redback.transient_models.shock_powered_models import _shock_cooling, _shocked_cocoon, _csm_shock_breakout
6
+ from redback.transient_models.shock_powered_models import _shocked_cocoon, _csm_shock_breakout
7
7
  import redback.interaction_processes as ip
8
8
  import redback.sed as sed
9
9
  import redback.photosphere as photosphere
@@ -13,7 +13,7 @@ from redback.constants import day_to_s, solar_mass, km_cgs, au_cgs, speed_of_lig
13
13
  from inspect import isfunction
14
14
  import astropy.units as uu
15
15
  from collections import namedtuple
16
- from scipy.interpolate import interp1d
16
+ from scipy.interpolate import interp1d, RegularGridInterpolator
17
17
 
18
18
  homologous_expansion_models = ['exponential_powerlaw_bolometric', 'arnett_bolometric',
19
19
  'basic_magnetar_powered_bolometric','slsn_bolometric',
@@ -115,6 +115,36 @@ def sncosmo_models(time, redshift, model_kwargs=None, **kwargs):
115
115
  elif kwargs['output_format'] == 'sncosmo_source':
116
116
  return model
117
117
 
118
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2007A%26A...466...11G/abstract, sncosmo')
119
+ def salt2(time, redshift, x0, x1, c, peak_time, **kwargs):
120
+ """
121
+ A wrapper to the salt2 model in sncosmo
122
+
123
+ :param time: time in days in observer frame (in mjd days)
124
+ :param redshift: redshift
125
+ :param x0: x0
126
+ :param x1: x1
127
+ :param c: c
128
+ :param peak_time: peak time in mjd
129
+ :param kwargs: Additional keyword arguments
130
+ :param cosmology: astropy cosmology object by default set to Planck18
131
+ :param mw_extinction: Boolean for whether there is MW extinction or not. Default True
132
+ :param host_extinction: Boolean for whether there is host extinction or not. Default True
133
+ if used adds an extra parameter ebv which must also be in kwargs; host galaxy E(B-V). Set to 0.1 by default
134
+ :param use_set_peak_magnitude: Boolean for whether to set the peak magnitude or not. Default False,
135
+ if True the following keyword arguments also apply. Else the brightness is set by the model_kwargs.
136
+ :param peak_abs_mag: SNe peak absolute magnitude default set to -19
137
+ :param peak_abs_mag_band: Band corresponding to the peak abs mag limit, default to standard::b. Must be in SNCosmo
138
+ :param magnitude_system: Mag system; default ab
139
+ :param output_format: 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
140
+ :return: set by output format - 'flux_density', 'magnitude', 'flux', 'sncosmo_source'
141
+ """
142
+ kwargs['sncosmo_model'] = 'salt2'
143
+ kwargs['peak_time'] = peak_time
144
+ model_kwargs = {'x0':x0, 'x1':x1, 'c':c}
145
+ out = sncosmo_models(time=time, redshift=redshift, model_kwargs=model_kwargs, **kwargs)
146
+ return out
147
+
118
148
  @citation_wrapper('redback')
119
149
  def exponential_powerlaw_bolometric(time, lbol_0, alpha_1, alpha_2, tpeak_d, **kwargs):
120
150
  """
@@ -198,6 +228,66 @@ def sn_fallback(time, redshift, logl1, tr, **kwargs):
198
228
  return sed.get_correct_output_format_from_spectra(time=time_obs, time_eval=time_observer_frame,
199
229
  spectra=spectra, lambda_array=lambda_observer_frame,
200
230
  **kwargs)
231
+
232
+ def sn_nickel_fallback(time, redshift, mej, f_nickel, logl1, tr, **kwargs):
233
+ """
234
+ :param time: observer frame time in days
235
+ :param redshift: source redshift
236
+ :param mej: total ejecta mass in solar masses
237
+ :param f_nickel: fraction of nickel mass
238
+ :param logl1: bolometric luminosity scale in log10 (cgs)
239
+ :param tr: transition time for luminosity
240
+ :param kwargs: Must be all the kwargs required by the specific interaction_process, photosphere, sed methods used
241
+ e.g., for Diffusion and TemperatureFloor: kappa, kappa_gamma, mej (solar masses), vej (km/s), floor temperature
242
+ :param interaction_process: Default is Diffusion.
243
+ Can also be None in which case the output is just the raw engine luminosity, or another interaction process.
244
+ :param photosphere: Default is TemperatureFloor.
245
+ kwargs must vej or relevant parameters if using different photosphere model
246
+ :param sed: Default is blackbody.
247
+ :param frequency: Required if output_format is ‘flux_density’.
248
+ frequency to calculate - Must be same length as time array or a single number).
249
+ :param bands: Required if output_format is ‘magnitude’ or ‘flux’.
250
+ :param output_format: ‘flux_density’, ‘magnitude’, ‘spectra’, ‘flux’, ‘sncosmo_source’
251
+ :param lambda_array: Optional argument to set your desired wavelength array (in Angstroms) to evaluate the SED on.
252
+ :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
253
+ :return: set by output format - ‘flux_density’, ‘magnitude’, ‘spectra’, ‘flux’, ‘sncosmo_source’
254
+ """
255
+ kwargs["interaction_process"] = kwargs.get("interaction_process", ip.Diffusion)
256
+ kwargs["photosphere"] = kwargs.get("photosphere", photosphere.TemperatureFloor)
257
+ kwargs["sed"] = kwargs.get("sed", sed.Blackbody)
258
+ cosmology = kwargs.get("cosmology", cosmo)
259
+ dl = cosmology.luminosity_distance(redshift).cgs.value
260
+ if kwargs['output_format'] == 'flux_density':
261
+ frequency = kwargs['frequency']
262
+ frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
263
+ lbol = fallback_lbol(time=time, logl1=logl1, tr=tr) + _nickelcobalt_engine(time=time, f_nickel=f_nickel, mej=mej)
264
+ photo = kwargs['photosphere'](time=time, luminosity=lbol, **kwargs)
265
+ sed_1 = kwargs['sed'](temperature=photo.photosphere_temperature, r_photosphere=photo.r_photosphere,
266
+ frequency=frequency, luminosity_distance=dl)
267
+ flux_density = sed_1.flux_density
268
+ return flux_density.to(uu.mJy).value
269
+ else:
270
+ time_obs = time
271
+ lambda_observer_frame = kwargs.get('lambda_array', np.geomspace(100, 60000, 100))
272
+ time_temp = np.geomspace(0.1, 3000, 300) # in days
273
+ time_observer_frame = time_temp * (1. + redshift)
274
+ frequency, time = calc_kcorrected_properties(frequency=lambda_to_nu(lambda_observer_frame),
275
+ redshift=redshift, time=time_observer_frame)
276
+ lbol = fallback_lbol(time=time, logl1=logl1, tr=tr) + _nickelcobalt_engine(time=time, f_nickel=f_nickel, mej=mej)
277
+ photo = kwargs['photosphere'](time=time, luminosity=lbol, **kwargs)
278
+ sed_1 = kwargs['sed'](temperature=photo.photosphere_temperature, r_photosphere=photo.r_photosphere,
279
+ frequency=frequency[:,None], luminosity_distance=dl)
280
+ fmjy = sed_1.flux_density.T
281
+ spectra = fmjy.to(uu.mJy).to(uu.erg / uu.cm ** 2 / uu.s / uu.Angstrom,
282
+ equivalencies=uu.spectral_density(wav=lambda_observer_frame * uu.Angstrom))
283
+ if kwargs['output_format'] == 'spectra':
284
+ return namedtuple('output', ['time', 'lambdas', 'spectra'])(time=time_observer_frame,
285
+ lambdas=lambda_observer_frame,
286
+ spectra=spectra)
287
+ else:
288
+ return sed.get_correct_output_format_from_spectra(time=time_obs, time_eval=time_observer_frame,
289
+ spectra=spectra, lambda_array=lambda_observer_frame,
290
+ **kwargs)
201
291
 
202
292
  @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2018ApJS..236....6G/abstract')
203
293
  def sn_exponential_powerlaw(time, redshift, lbol_0, alpha_1, alpha_2, tpeak_d, **kwargs):
@@ -363,10 +453,40 @@ def arnett(time, redshift, f_nickel, mej, **kwargs):
363
453
  spectra=spectra, lambda_array=lambda_observer_frame,
364
454
  **kwargs)
365
455
 
456
+ def shock_cooling_and_arnett_bolometric(time, log10_mass, log10_radius, log10_energy,
457
+ f_nickel, mej, vej, kappa, kappa_gamma, temperature_floor, **kwargs):
458
+ """
459
+ Bolometric luminosity of shock cooling and arnett model
460
+
461
+ :param time: time in days in source frame
462
+ :param log10_mass: log10 mass of extended material in solar masses
463
+ :param log10_radius: log10 radius of extended material in cm
464
+ :param log10_energy: log10 energy of extended material in ergs
465
+ :param f_nickel: fraction of nickel mass
466
+ :param mej: total ejecta mass in solar masses
467
+ :param vej: velocity of ejecta in km/s
468
+ :param kappa: opacity in cm^2/g
469
+ :param kappa_gamma: gamma-ray opacity in cm^2/g
470
+ :param temperature_floor: temperature floor in K
471
+ :param kwargs: Additional keyword arguments
472
+ :param nn: density power law slope
473
+ :param delta: inner density power law slope
474
+ :return: bolometric luminosity in erg/s
475
+ """
476
+ from redback.transient_models.shock_powered_models import shock_cooling_bolometric
477
+ lbol_1 = shock_cooling_bolometric(time=time * day_to_s, log10_mass=log10_mass, log10_radius=log10_radius,
478
+ log10_energy=log10_energy, **kwargs)
479
+ lbol_2 = arnett_bolometric(time=time, f_nickel=f_nickel, mej=mej, vej=vej, kappa=kappa,
480
+ kappa_gamma=kappa_gamma, temperature_floor=temperature_floor, **kwargs)
481
+ return lbol_1 + lbol_2
482
+
483
+
366
484
  @citation_wrapper('https://ui.adsabs.harvard.edu/abs/1982ApJ...253..785A/abstract, Piro+2021')
367
485
  def shock_cooling_and_arnett(time, redshift, log10_mass, log10_radius, log10_energy,
368
- f_nickel, mej, **kwargs):
486
+ f_nickel, mej, vej, kappa, kappa_gamma, temperature_floor, **kwargs):
369
487
  """
488
+ Photometric light curve of shock cooling and arnett model
489
+
370
490
  :param time: time in days
371
491
  :param redshift: source redshift
372
492
  :param log10_mass: log10 mass of extended material in solar masses
@@ -374,12 +494,13 @@ def shock_cooling_and_arnett(time, redshift, log10_mass, log10_radius, log10_ene
374
494
  :param log10_energy: log10 energy of extended material in ergs
375
495
  :param f_nickel: fraction of nickel mass
376
496
  :param mej: total ejecta mass in solar masses
377
- :param kwargs: Must be all the kwargs required by the specific interaction_process, photosphere, sed methods used
378
- e.g., for Diffusion and TemperatureFloor: kappa, kappa_gamma, vej (km/s), temperature_floor
497
+ :param vej: velocity of ejecta in km/s
498
+ :param kappa: opacity in cm^2/g
499
+ :param kappa_gamma: gamma-ray opacity in cm^2/g
500
+ :param temperature_floor: temperature floor in K
501
+ :param kwargs: Additional keyword arguments
379
502
  :param nn: density power law slope
380
503
  :param delta: inner density power law slope
381
- :param interaction_process: Default is Diffusion.
382
- Can also be None in which case the output is just the raw engine luminosity, or another interaction process.
383
504
  :param photosphere: Default is TemperatureFloor.
384
505
  kwargs must have vej or relevant parameters if using different photosphere model
385
506
  :param sed: Default is blackbody.
@@ -391,33 +512,19 @@ def shock_cooling_and_arnett(time, redshift, log10_mass, log10_radius, log10_ene
391
512
  :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
392
513
  :return: set by output format - 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
393
514
  """
394
- kwargs['interaction_process'] = kwargs.get("interaction_process", ip.Diffusion)
395
515
  kwargs['photosphere'] = kwargs.get("photosphere", photosphere.TemperatureFloor)
396
516
  kwargs['sed'] = kwargs.get("sed", sed.Blackbody)
397
517
  cosmology = kwargs.get('cosmology', cosmo)
398
518
  dl = cosmology.luminosity_distance(redshift).cgs.value
399
- mass = 10 ** log10_mass
400
- radius = 10 ** log10_radius
401
- energy = 10 ** log10_energy
402
519
 
403
520
  if kwargs['output_format'] == 'flux_density':
404
521
  frequency = kwargs['frequency']
405
522
  frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
406
- output = _shock_cooling(time * day_to_s, mass=mass, radius=radius, energy=energy, **kwargs)
407
- lbol_1 = output.lbol
408
- lbol_2 = _nickelcobalt_engine(time=time, f_nickel=f_nickel, mej=mej)
409
- lbol = lbol_1 + lbol_2
410
-
411
- if kwargs['interaction_process'] is not None:
412
- dense_resolution = kwargs.get("dense_resolution", 300)
413
- dense_times = np.linspace(0.01, time[-1]+100, dense_resolution)
414
- dense_lbols = _nickelcobalt_engine(time=dense_times, f_nickel=f_nickel, mej=mej)
415
- shock_cooling = _shock_cooling(dense_times * day_to_s, mass=mass, radius=radius, energy=energy, **kwargs).lbol
416
- dense_lbols += shock_cooling
417
- interaction_class = kwargs['interaction_process'](time=time, dense_times=dense_times, luminosity=dense_lbols,
418
- mej=mej, **kwargs)
419
- lbol = interaction_class.new_luminosity
420
- photo = kwargs['photosphere'](time=time, luminosity=lbol, **kwargs)
523
+ lbol = shock_cooling_and_arnett_bolometric(time, log10_mass=log10_mass, log10_radius=log10_radius,
524
+ log10_energy=log10_energy, f_nickel=f_nickel,
525
+ mej=mej, vej=vej, kappa=kappa, kappa_gamma=kappa_gamma,
526
+ temperature_floor=temperature_floor, **kwargs)
527
+ photo = kwargs['photosphere'](time=time, luminosity=lbol, vej=vej, temperature_floor=temperature_floor, **kwargs)
421
528
 
422
529
  sed_1 = kwargs['sed'](temperature=photo.photosphere_temperature, r_photosphere=photo.r_photosphere,
423
530
  frequency=frequency, luminosity_distance=dl)
@@ -430,10 +537,11 @@ def shock_cooling_and_arnett(time, redshift, log10_mass, log10_radius, log10_ene
430
537
  time_observer_frame = time_temp * (1. + redshift)
431
538
  frequency, time = calc_kcorrected_properties(frequency=lambda_to_nu(lambda_observer_frame),
432
539
  redshift=redshift, time=time_observer_frame)
433
- lbol_1 = _nickelcobalt_engine(time=time, f_nickel=f_nickel, mej=mej)
434
- lbol_2 = _shock_cooling(time * day_to_s, mass=mass, radius=radius, energy=energy, **kwargs).lbol
435
- lbol = lbol_1 + lbol_2
436
- photo = kwargs['photosphere'](time=time, luminosity=lbol, **kwargs)
540
+ lbol = shock_cooling_and_arnett_bolometric(time, log10_mass=log10_mass, log10_radius=log10_radius,
541
+ log10_energy=log10_energy, f_nickel=f_nickel,
542
+ mej=mej, vej=vej, kappa=kappa, kappa_gamma=kappa_gamma,
543
+ temperature_floor=temperature_floor, **kwargs)
544
+ photo = kwargs['photosphere'](time=time, luminosity=lbol, vej=vej, temperature_floor=temperature_floor, **kwargs)
437
545
  sed_1 = kwargs['sed'](temperature=photo.photosphere_temperature, r_photosphere=photo.r_photosphere,
438
546
  frequency=frequency[:,None], luminosity_distance=dl)
439
547
  fmjy = sed_1.flux_density.T
@@ -785,13 +893,12 @@ def slsn(time, redshift, p0, bp, mass_ns, theta_pb,**kwargs):
785
893
  lbol = slsn_bolometric(time=time, p0=p0, bp=bp, mass_ns=mass_ns, theta_pb=theta_pb, **kwargs)
786
894
  photo = kwargs['photosphere'](time=time, luminosity=lbol, **kwargs)
787
895
  full_sed = np.zeros((len(time), len(frequency)))
788
- for ii in range(len(frequency)):
789
- ss = kwargs['sed'](time=time, temperature=photo.photosphere_temperature,
790
- r_photosphere=photo.r_photosphere, frequency=frequency[ii],
791
- luminosity_distance=dl, cutoff_wavelength=cutoff_wavelength, luminosity=lbol)
792
- full_sed[:, ii] = ss.flux_density.to(uu.mJy).value
896
+ ss = kwargs['sed'](time=time, temperature=photo.photosphere_temperature,
897
+ r_photosphere=photo.r_photosphere, frequency=frequency[:, None],
898
+ luminosity_distance=dl, cutoff_wavelength=cutoff_wavelength, luminosity=lbol)
899
+ full_sed = ss.flux_density.to(uu.mJy).value.T
793
900
  spectra = (full_sed * uu.mJy).to(uu.erg / uu.cm ** 2 / uu.s / uu.Angstrom,
794
- equivalencies=uu.spectral_density(wav=lambda_observer_frame * uu.Angstrom))
901
+ equivalencies=uu.spectral_density(wav=lambda_observer_frame * uu.Angstrom))
795
902
  if kwargs['output_format'] == 'spectra':
796
903
  return namedtuple('output', ['time', 'lambdas', 'spectra'])(time=time_observer_frame,
797
904
  lambdas=lambda_observer_frame,
@@ -1375,17 +1482,17 @@ def type_1a(time, redshift, f_nickel, mej, **kwargs):
1375
1482
  :param line_duration: line duration, default is 25
1376
1483
  :param line_amplitude: line amplitude, default is 0.3
1377
1484
  :param frequency: Required if output_format is 'flux_density'.
1378
- frequency to calculate - Must be same length as time array or a single number).
1485
+ frequency to calculate - Must be same length as time array or a single number.
1379
1486
  :param bands: Required if output_format is 'magnitude' or 'flux'.
1380
1487
  :param output_format: 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
1381
1488
  :param lambda_array: Optional argument to set your desired wavelength array (in Angstroms) to evaluate the SED on.
1382
- :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
1489
+ :param cosmology: cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be an astropy.cosmology object.
1383
1490
  :return: set by output format - 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
1384
1491
  """
1385
1492
  cosmology = kwargs.get('cosmology', cosmo)
1386
1493
  dl = cosmology.luminosity_distance(redshift).cgs.value
1387
1494
  cutoff_wavelength = kwargs.get('cutoff_wavelength', 3000)
1388
- line_wavelength = kwargs.get('line_wavelength',7.5e3)
1495
+ line_wavelength = kwargs.get('line_wavelength', 7.5e3)
1389
1496
  line_width = kwargs.get('line_width', 500)
1390
1497
  line_time = kwargs.get('line_time', 50)
1391
1498
  line_duration = kwargs.get('line_duration', 25)
@@ -1399,13 +1506,13 @@ def type_1a(time, redshift, f_nickel, mej, **kwargs):
1399
1506
 
1400
1507
  photo = photosphere.TemperatureFloor(time=time, luminosity=lbol, **kwargs)
1401
1508
  sed_1 = sed.CutoffBlackbody(time=time, luminosity=lbol, temperature=photo.photosphere_temperature,
1402
- r_photosphere=photo.r_photosphere,frequency=frequency, luminosity_distance=dl,
1509
+ r_photosphere=photo.r_photosphere, frequency=frequency, luminosity_distance=dl,
1403
1510
  cutoff_wavelength=cutoff_wavelength)
1404
1511
  sed_2 = sed.Line(time=time, luminosity=lbol, frequency=frequency, luminosity_distance=dl,
1405
1512
  sed=sed_1, line_wavelength=line_wavelength,
1406
1513
  line_width=line_width, line_time=line_time,
1407
1514
  line_duration=line_duration, line_amplitude=line_amplitude)
1408
- flux_density = sed_2.flux_density
1515
+ flux_density = sed_2.flux_density.flatten()
1409
1516
  return flux_density.to(uu.mJy).value
1410
1517
  else:
1411
1518
  time_obs = time
@@ -1417,18 +1524,23 @@ def type_1a(time, redshift, f_nickel, mej, **kwargs):
1417
1524
  lbol = arnett_bolometric(time=time, f_nickel=f_nickel, mej=mej,
1418
1525
  interaction_process=ip.Diffusion, **kwargs)
1419
1526
  photo = photosphere.TemperatureFloor(time=time, luminosity=lbol, **kwargs)
1420
- full_sed = np.zeros((len(time), len(frequency)))
1421
- for ii in range(len(frequency)):
1422
- ss = sed.CutoffBlackbody(time=time, temperature=photo.photosphere_temperature,
1423
- r_photosphere=photo.r_photosphere, frequency=frequency[ii],
1424
- luminosity_distance=dl, cutoff_wavelength=cutoff_wavelength, luminosity=lbol)
1425
- sed_2 = sed.Line(time=time, luminosity=lbol, frequency=frequency[ii], luminosity_distance=dl,
1426
- sed=ss, line_wavelength=line_wavelength,
1427
- line_width=line_width, line_time=line_time,
1428
- line_duration=line_duration, line_amplitude=line_amplitude)
1429
- full_sed[:,ii] = sed_2.flux_density.to(uu.mJy).value
1527
+ # Here we construct the CutoffBlackbody SED with frequency reshaped to (n_freq, 1)
1528
+ ss = sed.CutoffBlackbody(time=time, temperature=photo.photosphere_temperature,
1529
+ r_photosphere=photo.r_photosphere, frequency=frequency[:, None],
1530
+ luminosity_distance=dl, cutoff_wavelength=cutoff_wavelength, luminosity=lbol)
1531
+ line_sed = sed.Line(time=time, luminosity=lbol, frequency=frequency[:, None],
1532
+ luminosity_distance=dl, sed=ss,
1533
+ line_wavelength=line_wavelength,
1534
+ line_width=line_width,
1535
+ line_time=line_time,
1536
+ line_duration=line_duration,
1537
+ line_amplitude=line_amplitude)
1538
+ full_sed = line_sed.flux_density.to(uu.mJy).value
1539
+ # The following line converts the full SED (in mJy) to erg/s/cm^2/Angstrom.
1430
1540
  spectra = (full_sed * uu.mJy).to(uu.erg / uu.cm ** 2 / uu.s / uu.Angstrom,
1431
- equivalencies=uu.spectral_density(wav=lambdas_observer_frame * uu.Angstrom))
1541
+ equivalencies=uu.spectral_density(
1542
+ wav=(lambdas_observer_frame.reshape(-1, 1) * uu.Angstrom))).T
1543
+ print(spectra.shape)
1432
1544
  if kwargs['output_format'] == 'spectra':
1433
1545
  return namedtuple('output', ['time', 'lambdas', 'spectra'])(time=time_observer_frame,
1434
1546
  lambdas=lambdas_observer_frame,
@@ -1439,6 +1551,7 @@ def type_1a(time, redshift, f_nickel, mej, **kwargs):
1439
1551
  **kwargs)
1440
1552
 
1441
1553
 
1554
+
1442
1555
  @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2018ApJS..236....6G/abstract')
1443
1556
  def type_1c(time, redshift, f_nickel, mej, pp, **kwargs):
1444
1557
  """
@@ -1588,7 +1701,7 @@ def general_magnetar_slsn(time, redshift, l0, tsd, nn, ** kwargs):
1588
1701
  spectra=spectra, lambda_array=lambda_observer_frame,
1589
1702
  **kwargs)
1590
1703
 
1591
- @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2024MNRAS.527.6455O/abstract')
1704
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2022MNRAS.516.4949S/abstract, https://ui.adsabs.harvard.edu/abs/2024MNRAS.527.6455O/abstract')
1592
1705
  def general_magnetar_driven_supernova_bolometric(time, mej, E_sn, kappa, l0, tau_sd, nn, kappa_gamma, **kwargs):
1593
1706
  """
1594
1707
  :param time: time in observer frame in days
@@ -1627,8 +1740,6 @@ def general_magnetar_driven_supernova_bolometric(time, mej, E_sn, kappa, l0, tau
1627
1740
  time = time * day_to_s
1628
1741
  lbol = lbol_func(time)
1629
1742
  v_ej = vej_func(time)
1630
- erot_total = np.trapz(magnetar_luminosity, x=time_temp)
1631
- erad_total = np.trapz(output.bolometric_luminosity, x=time_temp)
1632
1743
 
1633
1744
  dynamics_output = namedtuple('dynamics_output', ['v_ej', 'tau', 'time', 'bolometric_luminosity', 'kinetic_energy', 'erad_total',
1634
1745
  'thermalisation_efficiency', 'magnetar_luminosity', 'erot_total'])
@@ -1648,7 +1759,7 @@ def general_magnetar_driven_supernova_bolometric(time, mej, E_sn, kappa, l0, tau
1648
1759
  else:
1649
1760
  return lbol
1650
1761
 
1651
- @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2024MNRAS.527.6455O/abstract')
1762
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2022MNRAS.516.4949S/abstract, https://ui.adsabs.harvard.edu/abs/2024MNRAS.527.6455O/abstract')
1652
1763
  def general_magnetar_driven_supernova(time, redshift, mej, E_sn, kappa, l0, tau_sd, nn, kappa_gamma, **kwargs):
1653
1764
  """
1654
1765
  :param time: time in observer frame in days
@@ -1748,11 +1859,10 @@ def general_magnetar_driven_supernova(time, redshift, mej, E_sn, kappa, l0, tau_
1748
1859
  return dynamics_output
1749
1860
  else:
1750
1861
  full_sed = np.zeros((len(time), len(frequency)))
1751
- for ii in range(len(frequency)):
1752
- ss = kwargs['sed'](time=time_temp/day_to_s, temperature=photo.photosphere_temperature,
1753
- r_photosphere=photo.r_photosphere, frequency=frequency[ii],
1754
- luminosity_distance=dl, cutoff_wavelength=cutoff_wavelength, luminosity=output.bolometric_luminosity)
1755
- full_sed[:, ii] = ss.flux_density.to(uu.mJy).value
1862
+ ss = kwargs['sed'](time=time_temp/day_to_s, temperature=photo.photosphere_temperature,
1863
+ r_photosphere=photo.r_photosphere, frequency=frequency[:, None],
1864
+ luminosity_distance=dl, cutoff_wavelength=cutoff_wavelength, luminosity=output.bolometric_luminosity)
1865
+ full_sed = ss.flux_density.to(uu.mJy).value.T
1756
1866
  spectra = (full_sed * uu.mJy).to(uu.erg / uu.cm ** 2 / uu.s / uu.Angstrom,
1757
1867
  equivalencies=uu.spectral_density(wav=lambda_observer_frame * uu.Angstrom))
1758
1868
  if kwargs['output_format'] == 'spectra':
@@ -2009,4 +2119,181 @@ def shocked_cocoon_and_arnett(time, redshift, mej_c, vej_c, eta, tshock, shocked
2009
2119
  else:
2010
2120
  return sed.get_correct_output_format_from_spectra(time=time_obs, time_eval=time_observer_frame,
2011
2121
  spectra=spectra, lambda_array=lambda_observer_frame,
2012
- **kwargs)
2122
+ **kwargs)
2123
+
2124
+ @citation_wrapper("https://ui.adsabs.harvard.edu/abs/2025arXiv250602107S/abstract, https://ui.adsabs.harvard.edu/abs/2023PASJ...75..634M/abstract")
2125
+ def typeII_bolometric(time, progenitor, ni_mass, log10_mdot, beta, rcsm, esn, **kwargs):
2126
+ """
2127
+ Bolometric luminosity for a Type II supernova based on Sarin et al. 2025 surrogate model
2128
+ to stella grid in Moriya et al. 2023
2129
+
2130
+ :param time: Time in days in source frame
2131
+ :param progenitor: in solar masses
2132
+ :param ni_mass: in solar masses
2133
+ :param log10_mdot: in solar masses per year
2134
+ :param beta: dimensionless
2135
+ :param rcsm: in 10^14 cm
2136
+ :param esn: in 10^51
2137
+ :param kwargs: None
2138
+ :return: bolometric luminosity in erg/s
2139
+ """
2140
+ from redback_surrogates.supernovamodels import typeII_lbol
2141
+ tt, lbol = typeII_lbol(time=time, progenitor=progenitor, ni_mass=ni_mass,
2142
+ log10_mdot=log10_mdot, beta=beta, rcsm=rcsm, esn=esn, **kwargs)
2143
+ lbol_func = interp1d(tt, y=lbol, bounds_error=False, fill_value='extrapolate')
2144
+ return lbol_func(time)
2145
+
2146
+ @citation_wrapper("https://ui.adsabs.harvard.edu/abs/2025arXiv250602107S/abstract, https://ui.adsabs.harvard.edu/abs/2023PASJ...75..634M/abstract")
2147
+ def typeII_photosphere_properties(time, progenitor, ni_mass, log10_mdot, beta, rcsm, esn, **kwargs):
2148
+ """
2149
+ Photosphere properties for a Type II supernova based on Sarin et al. 2025 surrogate model
2150
+ to stella grid in Moriya et al. 2023
2151
+
2152
+ :param time: Time in days in source frame
2153
+ :param progenitor: in solar masses
2154
+ :param ni_mass: in solar masses
2155
+ :param log10_mdot: in solar masses per year
2156
+ :param beta: dimensionless
2157
+ :param rcsm: in 10^14 cm
2158
+ :param esn: in 10^51
2159
+ :param kwargs: None
2160
+ :return: photosphere properties (temperature in K, radius in cm)
2161
+ """
2162
+ from redback_surrogates.supernovamodels import typeII_photosphere
2163
+ tt, temp, rad = typeII_photosphere(time=time, progenitor=progenitor, ni_mass=ni_mass,
2164
+ log10_mdot=log10_mdot, beta=beta, rcsm=rcsm, esn=esn, **kwargs)
2165
+ temp_func = interp1d(tt, y=temp, bounds_error=False, fill_value='extrapolate')
2166
+ rad_func = interp1d(tt, y=rad, bounds_error=False, fill_value='extrapolate')
2167
+ return temp_func(time), rad_func(time)
2168
+
2169
+ @citation_wrapper("https://ui.adsabs.harvard.edu/abs/2025arXiv250602107S/abstract, https://ui.adsabs.harvard.edu/abs/2023PASJ...75..634M/abstract")
2170
+ def typeII_surrogate_sarin25(time, redshift, progenitor, ni_mass, log10_mdot, beta, rcsm, esn, **kwargs):
2171
+ """
2172
+ Type II supernova model based on Sarin et al. 2025 surrogate model
2173
+ to stella grid in Moriya et al. 2023
2174
+
2175
+ :param time: Time in days in observer frame
2176
+ :param redshift: redshift
2177
+ :param progenitor: in solar masses
2178
+ :param ni_mass: in solar masses
2179
+ :param log10_mdot: in solar masses per year
2180
+ :param beta: dimensionless
2181
+ :param rcsm: in 10^14 cm
2182
+ :param esn: in 10^51
2183
+ :param kwargs: Additional parameters for the model, such as:
2184
+ :param frequency: Required if output_format is 'flux_density'.
2185
+ frequency to calculate - Must be same length as time array or a single number).
2186
+ :param bands: Required if output_format is 'magnitude' or 'flux'.
2187
+ :param output_format: 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
2188
+ :param lambda_array: Optional argument to set your desired wavelength array (in Angstroms) to evaluate the SED on.
2189
+ :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
2190
+ :return: set by output format - 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
2191
+ """
2192
+ from redback_surrogates.supernovamodels import typeII_spectra
2193
+ cosmology = kwargs.get('cosmology', cosmo)
2194
+ dl = cosmology.luminosity_distance(redshift).cgs
2195
+
2196
+ # Get the rest-frame spectrum using typeII_spectra
2197
+ spectra_output = typeII_spectra(
2198
+ progenitor=progenitor,
2199
+ ni_mass=ni_mass,
2200
+ log10_mdot=log10_mdot,
2201
+ beta=beta,
2202
+ rcsm=rcsm,
2203
+ esn=esn,
2204
+ **kwargs
2205
+ )
2206
+
2207
+ # Extract components from the output
2208
+ rest_spectrum = spectra_output.spectrum # erg/s/Hz in rest frame
2209
+ standard_freqs = spectra_output.frequency.value # Angstrom in rest frame
2210
+ standard_times = spectra_output.time.value # days in rest frame
2211
+
2212
+ # Apply cosmological dimming
2213
+ observed_spectrum = rest_spectrum / (4 * np.pi * dl ** 2)
2214
+
2215
+ # Handle different output formats
2216
+ if kwargs.get('output_format') == 'flux_density':
2217
+ # Use redback's K-correction utilities
2218
+ frequency = kwargs['frequency']
2219
+ frequency, time = calc_kcorrected_properties(frequency=frequency, time=time, redshift=redshift)
2220
+
2221
+ # Convert wavelengths to frequencies for interpolation
2222
+ nu_array = lambda_to_nu(standard_freqs)
2223
+
2224
+ # Convert spectrum from erg/s/Hz to erg/s/cm²/Hz (already done above)
2225
+ # Convert to wavelength density for astropy conversion
2226
+ spectra_lambda = spectra_lambda.to(uu.erg / uu.cm ** 2 / uu.s / uu.Angstrom)
2227
+
2228
+ # Convert to mJy using astropy
2229
+ fmjy = spectra_lambda.to(uu.mJy,
2230
+ equivalencies=uu.spectral_density(wav=standard_freqs * uu.Angstrom)).value
2231
+
2232
+ # Create interpolator
2233
+ flux_interpolator = RegularGridInterpolator(
2234
+ (standard_times, nu_array),
2235
+ fmjy,
2236
+ bounds_error=False,
2237
+ fill_value=0.0
2238
+ )
2239
+
2240
+ # Prepare points for interpolation
2241
+ if isinstance(frequency, (int, float)):
2242
+ frequency = np.ones_like(time) * frequency
2243
+
2244
+ # Create points for evaluation
2245
+ points = np.column_stack((time, frequency))
2246
+
2247
+ # Return interpolated flux
2248
+ return flux_interpolator(points)
2249
+
2250
+ else:
2251
+ # Create denser grid for output (in rest frame)
2252
+ new_rest_times = np.geomspace(np.min(standard_times), np.max(standard_times), 200)
2253
+ new_rest_freqs = np.geomspace(np.min(standard_freqs), np.max(standard_freqs), 200)
2254
+
2255
+ # Create interpolator for the spectrum in rest frame
2256
+ spectra_func = RegularGridInterpolator(
2257
+ (standard_times, standard_freqs),
2258
+ observed_spectrum.value,
2259
+ bounds_error=False,
2260
+ fill_value=0.0
2261
+ )
2262
+
2263
+ # Create meshgrid for new grid points
2264
+ tt_mesh, ff_mesh = np.meshgrid(new_rest_times, new_rest_freqs, indexing='ij')
2265
+ points_to_evaluate = np.column_stack((tt_mesh.ravel(), ff_mesh.ravel()))
2266
+
2267
+ # Interpolate spectrum onto new grid
2268
+ interpolated_values = spectra_func(points_to_evaluate)
2269
+ interpolated_spectrum = interpolated_values.reshape(tt_mesh.shape) * observed_spectrum.unit
2270
+
2271
+ # Convert times to observer frame
2272
+ time_observer_frame = new_rest_times * (1 + redshift)
2273
+
2274
+ # Convert wavelengths to observer frame
2275
+ lambda_observer_frame = new_rest_freqs * (1 + redshift)
2276
+
2277
+ # Convert spectrum units using astropy
2278
+ interpolated_spectrum = interpolated_spectrum.to(
2279
+ uu.erg / uu.cm ** 2 / uu.s / uu.Angstrom,
2280
+ equivalencies=uu.spectral_density(wav=lambda_observer_frame * uu.Angstrom)
2281
+ )
2282
+
2283
+ # Create output structure
2284
+ if kwargs.get('output_format') == 'spectra':
2285
+ return namedtuple('output', ['time', 'lambdas', 'spectra'])(
2286
+ time=time_observer_frame,
2287
+ lambdas=lambda_observer_frame,
2288
+ spectra=interpolated_spectrum
2289
+ )
2290
+ else:
2291
+ # Get correct output format using redback utility
2292
+ return sed.get_correct_output_format_from_spectra(
2293
+ time=time, # Original observer frame time for evaluation
2294
+ time_eval=time_observer_frame,
2295
+ spectra=interpolated_spectrum,
2296
+ lambda_array=lambda_observer_frame,
2297
+ time_spline_degree=1,
2298
+ **kwargs
2299
+ )